1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

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
This commit is contained in:
Nikita Malyavin
2023-07-27 15:26:32 +04:00
committed by Sergei Golubchik
parent e026a366bf
commit 44ca37ef17
5 changed files with 76 additions and 32 deletions

View File

@ -9953,6 +9953,33 @@ const char *online_alter_check_supported(const THD *thd,
}
}
for (auto &c: alter_info->create_list)
{
*online= c.field || !(c.flags & AUTO_INCREMENT_FLAG);
if (!*online)
return "ADD COLUMN ... AUTO_INCREMENT";
auto *def= c.default_value;
*online= !(def && def->flags & VCOL_NEXTVAL
// either it's a new field, or a NULL -> NOT NULL change
&& (!c.field || (!(c.field->flags & NOT_NULL_FLAG)
&& (c.flags & NOT_NULL_FLAG))));
if (!*online)
{
if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_NONE)
return NULL; // Avoid heavy string op
const char *fmt= ER_THD(thd, ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED);
LEX_CSTRING dflt{STRING_WITH_LEN("DEFAULT")};
LEX_CSTRING nxvl{STRING_WITH_LEN("NEXTVAL()")};
size_t len= strlen(fmt) + nxvl.length + c.field_name.length + dflt.length;
char *resp= (char*)thd->alloc(len);
// expression %s cannot be used in the %s clause of %`s
my_snprintf(resp, len, fmt, nxvl.str, dflt.str, c.field_name.str);
return resp;
}
}
*online= online_alter_check_autoinc(thd, alter_info, table);
if (!*online)
return "CHANGE COLUMN ... AUTO_INCREMENT";