From ef5adf520760536c7396bdfe884fc509ac065694 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 4 Feb 2021 16:06:54 +0100 Subject: [PATCH] MDEV-24274 ALTER TABLE with CHECK CONSTRAINTS gives "Out of Memory" error partially revert 76063c2a13. Item::clone() is not an all-purpose Item copying machine, it was specifically created for pushdown of predicates into derived tables and views and it does not copy everything. In particular, it does not copy Item_func_regex. Fix the bug differently by preserving the old constraint name. But keep setting automatic_name=true to have it regenerated for cases like ALTER TABLE ... ADD CONSTRAINT. --- mysql-test/main/check_constraint.result | 12 ++++++++ mysql-test/main/check_constraint.test | 8 ++++++ sql/sql_table.cc | 38 +++++++++---------------- sql/unireg.cc | 8 +----- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/mysql-test/main/check_constraint.result b/mysql-test/main/check_constraint.result index 3511af84166..f851b99e5c1 100644 --- a/mysql-test/main/check_constraint.result +++ b/mysql-test/main/check_constraint.result @@ -235,3 +235,15 @@ a b insert t1 (b) values (1); ERROR 23000: CONSTRAINT `CONSTRAINT_1` failed for `test`.`t1` drop table t1; +# +# MDEV-24274 ALTER TABLE with CHECK CONSTRAINTS gives "Out of Memory" error +# +create table t1 (id varchar(2), constraint id check (id regexp '[a-z]')); +alter table t1 force; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` varchar(2) DEFAULT NULL, + CONSTRAINT `id` CHECK (`id` regexp '[a-z]') +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/main/check_constraint.test b/mysql-test/main/check_constraint.test index 93538fd1666..1258a9e3be6 100644 --- a/mysql-test/main/check_constraint.test +++ b/mysql-test/main/check_constraint.test @@ -176,3 +176,11 @@ select * from t1 where a is null; --error ER_CONSTRAINT_FAILED insert t1 (b) values (1); drop table t1; + +--echo # +--echo # MDEV-24274 ALTER TABLE with CHECK CONSTRAINTS gives "Out of Memory" error +--echo # +create table t1 (id varchar(2), constraint id check (id regexp '[a-z]')); +alter table t1 force; +show create table t1; +drop table t1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4ddfcabf6c8..50fe0eb3a6f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -76,9 +76,8 @@ static int copy_data_between_tables(THD *, TABLE *,TABLE *, static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *, uint *, handler *, KEY **, uint *, int); static uint blob_length_by_type(enum_field_types type); -static bool fix_constraints_names(THD *thd, List - *check_constraint_list, - const HA_CREATE_INFO *create_info); +static bool fix_constraints_names(THD *, List *, + const HA_CREATE_INFO *); /** @brief Helper function for explain_filename @@ -4347,8 +4346,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, const Virtual_column_info *dup_check; while ((dup_check= dup_it++) && dup_check != check) { - if (!dup_check->name.length || dup_check->automatic_name) - continue; if (!lex_string_cmp(system_charset_info, &check->name, &dup_check->name)) { @@ -8682,37 +8679,28 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, } } - // NB: `check` is TABLE resident, we must keep it intact. - if (keep) - { - check= check->clone(thd); - if (!check) - { - my_error(ER_OUT_OF_RESOURCES, MYF(0)); - goto err; - } - } - if (share->period.constr_name.streq(check->name.str)) { - if (drop_period) - { - keep= false; - } - else if(!keep) + if (!drop_period && !keep) { my_error(ER_PERIOD_CONSTRAINT_DROP, MYF(0), check->name.str, share->period.name.str); goto err; } - else + keep= keep && !drop_period; + + DBUG_ASSERT(create_info->period_info.constr == NULL || drop_period); + + if (keep) { - DBUG_ASSERT(create_info->period_info.constr == NULL); + Item *expr_copy= check->expr->get_copy(thd); + check= new Virtual_column_info(); + check->name= share->period.constr_name; + check->automatic_name= true; + check->expr= expr_copy; create_info->period_info.constr= check; - create_info->period_info.constr->automatic_name= true; } } - /* see if the constraint depends on *only* on dropped fields */ if (keep && dropped_fields) { diff --git a/sql/unireg.cc b/sql/unireg.cc index 17222efe791..8e432c54b15 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -57,13 +57,7 @@ static bool make_empty_rec(THD *, uchar *, uint, List &, uint, */ static uchar *extra2_write_len(uchar *pos, size_t len) { - /* TODO: should be - if (len > 0 && len <= 255) - *pos++= (uchar)len; - ... - because extra2_read_len() uses 0 for 2-byte lengths. - extra2_str_size() must be fixed too. - */ + DBUG_ASSERT(len); if (len <= 255) *pos++= (uchar)len; else