Commit 22544004 authored by Alexey Botchkov's avatar Alexey Botchkov

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.
parent 00dfe27f
......@@ -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 */
......
......@@ -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'
......@@ -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));
......@@ -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."
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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
{
......
......@@ -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;
}
......
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment