Skip to content

Commit 44ca37e

Browse files
FooBarriorvuvova
authored andcommitted
MDEV-31631 Adding auto-increment to table with history online misbehaves
Adding an auto_increment column online leads to an undefined behavior. Basically any DEFAULTs that depend on a row order in the table, or on the non-deterministic (in scope of the ALTER TABLE statement) function is UB. For example, NOW() is considered generally non-deterministic (Item_func_now_utc is marked with VCOL_NON_DETERMINISTIC), but it's fixed in scope of a single statement. Same for any other function that depends only on the session/status vars apart from its arguments. Only two UB cases are known: * adding new AUTO_INCREMENT column. Modifying the existing column may be fine under certain circumstances, see MDEV-31058. * adding new column with DEFAULT(nextval(...)). Modifying the existing column is possible, since its value will be always present in the online event, except for the NULL -> NOT NULL modification
1 parent e026a36 commit 44ca37e

File tree

5 files changed

+76
-32
lines changed

5 files changed

+76
-32
lines changed

mysql-test/main/alter_table_online.result

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,3 +224,17 @@ alter table s engine=Aria, lock=none;
224224
ERROR 0A000: LOCK=NONE is not supported. Reason: SEQUENCE. Try LOCK=SHARED
225225
alter table s engine=Aria;
226226
drop sequence s;
227+
# MDEV-31631 Adding auto-increment column to a table with history online
228+
# behaves differently from non-online
229+
create sequence s;
230+
create table t1(a int, x int NULL default(nextval(s)));
231+
alter table t1 add b int default (nextval(s)), lock=none;
232+
ERROR 0A000: LOCK=NONE is not supported. Reason: Function or expression 'NEXTVAL()' cannot be used in the DEFAULT clause of `b`. Try LOCK=SHARED
233+
alter table t1 add b int primary key auto_increment, lock=none;
234+
ERROR 0A000: LOCK=NONE is not supported. Reason: ADD COLUMN ... AUTO_INCREMENT. Try LOCK=SHARED
235+
create table t2(a int, b int NULL default(nextval(s)));
236+
alter table t2 modify b int not null default (nextval(s)), lock=none;
237+
ERROR 0A000: LOCK=NONE is not supported. Reason: Function or expression 'NEXTVAL()' cannot be used in the DEFAULT clause of `b`. Try LOCK=SHARED
238+
drop table t2;
239+
drop table t1;
240+
drop sequence s;

mysql-test/main/alter_table_online.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,21 @@ create sequence s engine=MyISAM;
228228
alter table s engine=Aria, lock=none;
229229
alter table s engine=Aria;
230230
drop sequence s;
231+
232+
233+
--echo # MDEV-31631 Adding auto-increment column to a table with history online
234+
--echo # behaves differently from non-online
235+
create sequence s;
236+
create table t1(a int, x int NULL default(nextval(s)));
237+
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
238+
alter table t1 add b int default (nextval(s)), lock=none;
239+
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
240+
alter table t1 add b int primary key auto_increment, lock=none;
241+
242+
create table t2(a int, b int NULL default(nextval(s)));
243+
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
244+
alter table t2 modify b int not null default (nextval(s)), lock=none;
245+
246+
drop table t2;
247+
drop table t1;
248+
drop sequence s;

mysql-test/main/alter_table_online_debug.result

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -990,23 +990,6 @@ set debug_sync= reset;
990990
#
991991
set @old_dbug=@@debug_dbug;
992992
set debug_dbug="+d,rpl_report_chosen_key";
993-
create table t (a int);
994-
insert into t values (10),(20),(30);
995-
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
996-
alter table t add pk int auto_increment primary key, algorithm=copy, lock=none;
997-
connection con2;
998-
set debug_sync= 'now wait_for downgraded';
999-
delete from t where a = 20;
1000-
update t set a = a + 1 where a = 10;
1001-
set debug_sync= 'now signal goforit';
1002-
connection default;
1003-
Warnings:
1004-
Note 1105 Key chosen: -1
1005-
Note 1105 Key chosen: -1
1006-
select * from t;
1007-
a pk
1008-
11 1
1009-
30 3
1010993
#
1011994
# Add clumsy DEFAULT
1012995
#

mysql-test/main/alter_table_online_debug.test

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,21 +1172,23 @@ set debug_sync= reset;
11721172
set @old_dbug=@@debug_dbug;
11731173
set debug_dbug="+d,rpl_report_chosen_key";
11741174

1175-
create table t (a int);
1176-
insert into t values (10),(20),(30);
1177-
1178-
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
1179-
--send
1180-
alter table t add pk int auto_increment primary key, algorithm=copy, lock=none;
1181-
--connection con2
1182-
set debug_sync= 'now wait_for downgraded';
1183-
delete from t where a = 20;
1184-
update t set a = a + 1 where a = 10;
1185-
set debug_sync= 'now signal goforit';
1186-
1187-
--connection default
1188-
--reap
1189-
select * from t;
1175+
# UB
1176+
#
1177+
# create table t (a int);
1178+
# insert into t values (10),(20),(30);
1179+
#
1180+
# set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
1181+
# --send
1182+
# alter table t add pk int auto_increment primary key, algorithm=copy, lock=none;
1183+
# --connection con2
1184+
# set debug_sync= 'now wait_for downgraded';
1185+
# delete from t where a = 20;
1186+
# update t set a = a + 1 where a = 10;
1187+
# set debug_sync= 'now signal goforit';
1188+
#
1189+
# --connection default
1190+
# --reap
1191+
# select * from t;
11901192

11911193
--echo #
11921194
--echo # Add clumsy DEFAULT

sql/sql_table.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9953,6 +9953,33 @@ const char *online_alter_check_supported(const THD *thd,
99539953
}
99549954
}
99559955

9956+
for (auto &c: alter_info->create_list)
9957+
{
9958+
*online= c.field || !(c.flags & AUTO_INCREMENT_FLAG);
9959+
if (!*online)
9960+
return "ADD COLUMN ... AUTO_INCREMENT";
9961+
9962+
auto *def= c.default_value;
9963+
*online= !(def && def->flags & VCOL_NEXTVAL
9964+
// either it's a new field, or a NULL -> NOT NULL change
9965+
&& (!c.field || (!(c.field->flags & NOT_NULL_FLAG)
9966+
&& (c.flags & NOT_NULL_FLAG))));
9967+
if (!*online)
9968+
{
9969+
if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_NONE)
9970+
return NULL; // Avoid heavy string op
9971+
const char *fmt= ER_THD(thd, ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED);
9972+
9973+
LEX_CSTRING dflt{STRING_WITH_LEN("DEFAULT")};
9974+
LEX_CSTRING nxvl{STRING_WITH_LEN("NEXTVAL()")};
9975+
size_t len= strlen(fmt) + nxvl.length + c.field_name.length + dflt.length;
9976+
char *resp= (char*)thd->alloc(len);
9977+
// expression %s cannot be used in the %s clause of %`s
9978+
my_snprintf(resp, len, fmt, nxvl.str, dflt.str, c.field_name.str);
9979+
return resp;
9980+
}
9981+
}
9982+
99569983
*online= online_alter_check_autoinc(thd, alter_info, table);
99579984
if (!*online)
99589985
return "CHANGE COLUMN ... AUTO_INCREMENT";

0 commit comments

Comments
 (0)