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:
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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];
|
||||||
|
@ -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,
|
||||||
|
Reference in New Issue
Block a user