[Commits] 2254400: MDEV-10421 duplicate CHECK CONSTRAINTs.

Alexey Botchkov holyfoot at askmonty.org
Tue Sep 6 14:01:10 EEST 2016


revision-id: 225440047d145bbe6a92bff05c5d4aa33e0aca91 (mariadb-10.1.8-240-g2254400)
parent(s): 00dfe27f7c5a0382d16cac832e879ae9f1cc45e9
committer: Alexey Botchkov
timestamp: 2016-09-06 14:42:33 +0400
message:

MDEV-10421 duplicate CHECK CONSTRAINTs.

        mysql_prepare_create_table fixed so it doesn't let duplicating
        constraint names. Syntax for CONSTRAINT IF NOT EXISTS added
        and handled in mysql_alter_table.

---
 include/mysql.h                           |  1 +
 mysql-test/r/alter_table.result           | 23 +++++++++++++++
 mysql-test/t/alter_table.test             | 16 ++++++++++
 sql/share/errmsg-utf8.txt                 |  4 +--
 sql/sql_alter.h                           |  2 ++
 sql/sql_lex.h                             |  5 +++-
 sql/sql_table.cc                          | 49 +++++++++++++++++++++++++++++++
 sql/sql_yacc.yy                           |  7 ++++-
 storage/innobase/handler/handler0alter.cc |  4 +--
 storage/xtradb/handler/handler0alter.cc   |  4 +--
 10 files changed, 107 insertions(+), 8 deletions(-)

diff --git a/include/mysql.h b/include/mysql.h
index 19099b4..eab85927 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -137,6 +137,7 @@ typedef unsigned long long my_ulonglong;
 /* backward compatibility define - to be removed eventually */
 #define ER_WARN_DATA_TRUNCATED WARN_DATA_TRUNCATED
 #define WARN_PLUGIN_DELETE_BUILTIN ER_PLUGIN_DELETE_BUILTIN
+#define ER_FK_DUP_NAME ER_DUP_CONSTRAINT_NAME
 
 typedef struct st_mysql_rows {
   struct st_mysql_rows *next;		/* list of rows */
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index 0801890..de93fab 100644
--- a/mysql-test/r/alter_table.result
+++ b/mysql-test/r/alter_table.result
@@ -2057,3 +2057,26 @@ t1	CREATE TABLE `t1` (
   KEY `i1` (`a`) COMMENT 'comment2'
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 DROP TABLE t1;
+#
+# MDEV-10421 duplicate CHECK CONSTRAINTs
+#
+CREATE TABLE t1 (a INT, b INT) engine=myisam;
+ALTER TABLE t1 ADD CONSTRAINT IF NOT EXISTS `min` CHECK (a+b > 100);
+ALTER TABLE t1 ADD CONSTRAINT `min` CHECK (a+b > 100);
+ERROR HY000: Duplicate CHECK constraint name 'min'
+ALTER TABLE t1 ADD CONSTRAINT IF NOT EXISTS `min` CHECK (a+b > 100);
+Warnings:
+Note	1826	Duplicate CHECK constraint name 'min'
+ALTER TABLE t1 ADD CONSTRAINT `mini` CHECK (a+b > 100);
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL,
+  `b` int(11) DEFAULT NULL,
+  CONSTRAINT `min` CHECK (a+b > 100),
+  CONSTRAINT `mini` CHECK (a+b > 100)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(a INT, b INT, CONSTRAINT min check (a>5),
+CONSTRAINT min check (b>5));
+ERROR HY000: Duplicate CHECK constraint name 'min'
diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test
index 7811de0..1ff38e4 100644
--- a/mysql-test/t/alter_table.test
+++ b/mysql-test/t/alter_table.test
@@ -1732,3 +1732,19 @@ ALTER TABLE t1 DROP INDEX i1, ADD INDEX i1(a) COMMENT 'comment2';
 SHOW CREATE TABLE t1;
 DROP TABLE t1;
 
+--echo #
+--echo # MDEV-10421 duplicate CHECK CONSTRAINTs
+--echo #
+CREATE TABLE t1 (a INT, b INT) engine=myisam;
+ALTER TABLE t1 ADD CONSTRAINT IF NOT EXISTS `min` CHECK (a+b > 100);
+--error ER_DUP_CONSTRAINT_NAME
+ALTER TABLE t1 ADD CONSTRAINT `min` CHECK (a+b > 100);
+ALTER TABLE t1 ADD CONSTRAINT IF NOT EXISTS `min` CHECK (a+b > 100);
+ALTER TABLE t1 ADD CONSTRAINT `mini` CHECK (a+b > 100);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+--error ER_DUP_CONSTRAINT_NAME
+CREATE TABLE t1(a INT, b INT, CONSTRAINT min check (a>5),
+                              CONSTRAINT min check (b>5));
+
+
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 43de678..37012c1 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6762,8 +6762,8 @@ ER_FK_CANNOT_OPEN_PARENT
 ER_FK_INCORRECT_OPTION
         eng "Failed to add the foreign key constraint on table '%s'. Incorrect options in FOREIGN KEY constraint '%s'"
 
-ER_FK_DUP_NAME
-	eng "Duplicate foreign key constraint name '%s'"
+ER_DUP_CONSTRAINT_NAME
+       eng "Duplicate %s constraint name '%s'"
 
 ER_PASSWORD_FORMAT
   eng "The password hash doesn't have the expected format. Check if the correct password algorithm is being used with the PASSWORD() function."
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index 9e5fbaa..faba3a1 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -174,6 +174,8 @@ class Alter_info
   List<Key>                     key_list;
   // List of columns, used by both CREATE and ALTER TABLE.
   List<Create_field>            create_list;
+
+  static const uint CHECK_CONSTRAINT_IF_NOT_EXISTS= 1;
   List<Virtual_column_info>     check_constraint_list;
   // Type of ALTER TABLE operation.
   uint                          flags;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index e034460..af461d0 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -3003,9 +3003,12 @@ struct LEX: public Query_tables_list
     return false;
   }
   // Add a constraint as a part of CREATE TABLE or ALTER TABLE
-  bool add_constraint(LEX_STRING *name, Virtual_column_info *constr)
+  bool add_constraint(LEX_STRING *name, Virtual_column_info *constr,
+                      bool if_not_exists)
   {
     constr->name= *name;
+    constr->flags= if_not_exists ?
+                   Alter_info::CHECK_CONSTRAINT_IF_NOT_EXISTS : 0;
     alter_info.check_constraint_list.push_back(constr);
     return false;
   }
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 7784a2b..80fadde 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4201,6 +4201,22 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
         make_unique_constraint_name(thd, &check->name,
                                     &alter_info->check_constraint_list,
                                     &nr);
+      {
+        /* Check that there's no repeating constraint names. */
+        List_iterator_fast<Virtual_column_info>
+          dup_it(alter_info->check_constraint_list);
+        Virtual_column_info *dup_check;
+        while ((dup_check= dup_it++) && dup_check != check)
+        {
+          if (check->name.length == dup_check->name.length &&
+              my_strcasecmp(system_charset_info,
+                            check->name.str, dup_check->name.str) == 0)
+          {
+            my_error(ER_DUP_CONSTRAINT_NAME, MYF(0), "CHECK", check->name);
+            DBUG_RETURN(TRUE);
+          }
+        }
+      }
 
       if (check_string_char_length(&check->name, 0, NAME_CHAR_LEN,
                                    system_charset_info, 1))
@@ -6153,6 +6169,39 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
   }
 #endif /*WITH_PARTITION_STORAGE_ENGINE*/
 
+  /* ADD CONSTRAINT IF NOT EXISTS. */
+  {
+    List_iterator<Virtual_column_info> it(alter_info->check_constraint_list);
+    Virtual_column_info *check;
+    TABLE_SHARE *share= table->s;
+    uint c;
+    while ((check=it++))
+    {
+      if ((!check->flags & Alter_info::CHECK_CONSTRAINT_IF_NOT_EXISTS) &&
+          check->name.length)
+        continue;
+      check->flags= 0;
+      for (c= share->field_check_constraints;
+           c < share->table_check_constraints ; c++)
+      {
+        Virtual_column_info *dup= table->check_constraints[c];
+        if (dup->name.length == check->name.length &&
+            my_strcasecmp(system_charset_info,
+                          check->name.str, dup->name.str) == 0)
+        {
+          push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+            ER_DUP_CONSTRAINT_NAME, ER_THD(thd, ER_DUP_CONSTRAINT_NAME),
+            "CHECK", check->name.str);
+          it.remove();
+          if (alter_info->check_constraint_list.elements == 0)
+            alter_info->flags&= ~Alter_info::ALTER_ADD_CHECK_CONSTRAINT;
+
+          break;
+        }
+      }
+    }
+  }
+
   DBUG_VOID_RETURN;
 }
 
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 63ba77c..5908c7d 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -6073,7 +6073,7 @@ key_def:
 constraint_def:
          opt_constraint check_constraint
          {
-           Lex->add_constraint(&$1, $2);
+           Lex->add_constraint(&$1, $2, FALSE);
          }
        ;
 
@@ -7560,6 +7560,11 @@ alter_list_item:
           {
             Lex->alter_info.flags|= Alter_info::ALTER_ADD_CHECK_CONSTRAINT;
 	  }
+        | ADD CONSTRAINT IF_SYM not EXISTS field_ident check_constraint
+         {
+           Lex->alter_info.flags|= Alter_info::ALTER_ADD_CHECK_CONSTRAINT;
+           Lex->add_constraint(&$6, $7, TRUE);
+         }
         | CHANGE opt_column opt_if_exists_table_element field_ident
           field_spec opt_place
           {
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index bb7efa1..29d49dc 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -1125,9 +1125,9 @@ innobase_get_foreign_key_info(
 			    referenced_column_names, referenced_num_col)) {
 			mutex_exit(&dict_sys->mutex);
 			my_error(
-				ER_FK_DUP_NAME,
+				ER_DUP_CONSTRAINT_NAME,
 				MYF(0),
-				add_fk[num_fk]->id);
+                                "FOREIGN KEY", add_fk[num_fk]->id);
 			goto err_exit;
 		}
 
diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc
index 5724d9f..7459c4c 100644
--- a/storage/xtradb/handler/handler0alter.cc
+++ b/storage/xtradb/handler/handler0alter.cc
@@ -1128,9 +1128,9 @@ innobase_get_foreign_key_info(
 			    referenced_column_names, referenced_num_col)) {
 			mutex_exit(&dict_sys->mutex);
 			my_error(
-				ER_FK_DUP_NAME,
+				ER_DUP_CONSTRAINT_NAME,
 				MYF(0),
-				add_fk[num_fk]->id);
+                                "FOREIGN KEY", add_fk[num_fk]->id);
 			goto err_exit;
 		}
 


More information about the commits mailing list