1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

MDEV-25803 innodb.alter_candidate_key fix

There is a case when implicit primary key may be changed when removing
NOT NULL from the part of unique key. In that case we update
modified_primary_key which is then used to not skip key sorting.

According to is_candidate_key() there is no other cases when primary
kay may be changed implicitly.
This commit is contained in:
Aleksey Midenkov
2021-11-02 04:52:03 +03:00
parent 63c922ae0c
commit c6207ecba4
4 changed files with 24 additions and 10 deletions

View File

@ -426,6 +426,7 @@ enum enum_alter_inplace_result {
#define HA_CREATE_TMP_ALTER 8U #define HA_CREATE_TMP_ALTER 8U
#define HA_LEX_CREATE_SEQUENCE 16U #define HA_LEX_CREATE_SEQUENCE 16U
#define HA_VERSIONED_TABLE 32U #define HA_VERSIONED_TABLE 32U
#define HA_SKIP_KEY_SORT 64U
#define HA_MAX_REC_LENGTH 65535 #define HA_MAX_REC_LENGTH 65535

View File

@ -256,7 +256,7 @@ Alter_table_ctx::Alter_table_ctx()
db(null_clex_str), table_name(null_clex_str), alias(null_clex_str), db(null_clex_str), table_name(null_clex_str), alias(null_clex_str),
new_db(null_clex_str), new_name(null_clex_str), new_alias(null_clex_str), new_db(null_clex_str), new_name(null_clex_str), new_alias(null_clex_str),
fk_error_if_delete_row(false), fk_error_id(NULL), fk_error_if_delete_row(false), fk_error_id(NULL),
fk_error_table(NULL) fk_error_table(NULL), modified_primary_key(false)
#ifdef DBUG_ASSERT_EXISTS #ifdef DBUG_ASSERT_EXISTS
, tmp_table(false) , tmp_table(false)
#endif #endif
@ -276,7 +276,7 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
tables_opened(tables_opened_arg), tables_opened(tables_opened_arg),
new_db(*new_db_arg), new_name(*new_name_arg), new_db(*new_db_arg), new_name(*new_name_arg),
fk_error_if_delete_row(false), fk_error_id(NULL), fk_error_if_delete_row(false), fk_error_id(NULL),
fk_error_table(NULL) fk_error_table(NULL), modified_primary_key(false)
#ifdef DBUG_ASSERT_EXISTS #ifdef DBUG_ASSERT_EXISTS
, tmp_table(false) , tmp_table(false)
#endif #endif

View File

@ -324,6 +324,7 @@ public:
const char *fk_error_id; const char *fk_error_id;
/** Name of table for the above error. */ /** Name of table for the above error. */
const char *fk_error_table; const char *fk_error_table;
bool modified_primary_key;
private: private:
char new_filename[FN_REFLEN + 1]; char new_filename[FN_REFLEN + 1];

View File

@ -4215,8 +4215,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
MyISAM/Aria cannot add index inplace so we are safe to qsort key info in MyISAM/Aria cannot add index inplace so we are safe to qsort key info in
that case. And if we don't add index then we do not need qsort at all. that case. And if we don't add index then we do not need qsort at all.
*/ */
if (!(create_info->options & HA_CREATE_TMP_ALTER) || if (!(create_info->options & HA_SKIP_KEY_SORT))
alter_info->flags & ALTER_ADD_INDEX)
{ {
/* /*
Sort keys in optimized order. Sort keys in optimized order.
@ -8035,7 +8034,6 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
uint used_fields, dropped_sys_vers_fields= 0; uint used_fields, dropped_sys_vers_fields= 0;
KEY *key_info=table->key_info; KEY *key_info=table->key_info;
bool rc= TRUE; bool rc= TRUE;
bool modified_primary_key= FALSE;
bool vers_system_invisible= false; bool vers_system_invisible= false;
Create_field *def; Create_field *def;
Field **f_ptr,*field; Field **f_ptr,*field;
@ -8420,6 +8418,12 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (key_info->flags & HA_INVISIBLE_KEY) if (key_info->flags & HA_INVISIBLE_KEY)
continue; continue;
const char *key_name= key_info->name.str; const char *key_name= key_info->name.str;
const bool primary_key= table->s->primary_key == i;
const bool explicit_pk= primary_key &&
!my_strcasecmp(system_charset_info, key_name,
primary_key_name);
const bool implicit_pk= primary_key && !explicit_pk;
Alter_drop *drop; Alter_drop *drop;
drop_it.rewind(); drop_it.rewind();
while ((drop=drop_it++)) while ((drop=drop_it++))
@ -8433,7 +8437,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (table->s->tmp_table == NO_TMP_TABLE) if (table->s->tmp_table == NO_TMP_TABLE)
{ {
(void) delete_statistics_for_index(thd, table, key_info, FALSE); (void) delete_statistics_for_index(thd, table, key_info, FALSE);
if (i == table->s->primary_key) if (primary_key)
{ {
KEY *tab_key_info= table->key_info; KEY *tab_key_info= table->key_info;
for (uint j=0; j < table->s->keys; j++, tab_key_info++) for (uint j=0; j < table->s->keys; j++, tab_key_info++)
@ -8478,13 +8482,19 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
} }
if (!cfield) if (!cfield)
{ {
if (table->s->primary_key == i) if (primary_key)
modified_primary_key= TRUE; alter_ctx->modified_primary_key= true;
delete_index_stat= TRUE; delete_index_stat= TRUE;
if (!(kfield->flags & VERS_SYSTEM_FIELD)) if (!(kfield->flags & VERS_SYSTEM_FIELD))
dropped_key_part= key_part_name; dropped_key_part= key_part_name;
continue; // Field is removed continue; // Field is removed
} }
DBUG_ASSERT(!primary_key || kfield->flags & NOT_NULL_FLAG);
if (implicit_pk && !alter_ctx->modified_primary_key &&
!(cfield->flags & NOT_NULL_FLAG))
alter_ctx->modified_primary_key= true;
key_part_length= key_part->length; key_part_length= key_part->length;
if (cfield->field) // Not new field if (cfield->field) // Not new field
{ {
@ -8533,7 +8543,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
{ {
if (delete_index_stat) if (delete_index_stat)
(void) delete_statistics_for_index(thd, table, key_info, FALSE); (void) delete_statistics_for_index(thd, table, key_info, FALSE);
else if (modified_primary_key && else if (alter_ctx->modified_primary_key &&
key_info->user_defined_key_parts != key_info->ext_key_parts) key_info->user_defined_key_parts != key_info->ext_key_parts)
(void) delete_statistics_for_index(thd, table, key_info, TRUE); (void) delete_statistics_for_index(thd, table, key_info, TRUE);
} }
@ -8575,7 +8585,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
key_type= Key::SPATIAL; key_type= Key::SPATIAL;
else if (key_info->flags & HA_NOSAME) else if (key_info->flags & HA_NOSAME)
{ {
if (! my_strcasecmp(system_charset_info, key_name, primary_key_name)) if (explicit_pk)
key_type= Key::PRIMARY; key_type= Key::PRIMARY;
else else
key_type= Key::UNIQUE; key_type= Key::UNIQUE;
@ -9941,6 +9951,8 @@ do_continue:;
tmp_disable_binlog(thd); tmp_disable_binlog(thd);
create_info->options|=HA_CREATE_TMP_ALTER; create_info->options|=HA_CREATE_TMP_ALTER;
if (!(alter_info->flags & ALTER_ADD_INDEX) && !alter_ctx.modified_primary_key)
create_info->options|= HA_SKIP_KEY_SORT;
create_info->alias= alter_ctx.table_name; create_info->alias= alter_ctx.table_name;
error= create_table_impl(thd, error= create_table_impl(thd,
&alter_ctx.db, &alter_ctx.table_name, &alter_ctx.db, &alter_ctx.table_name,