summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2021-11-08 19:40:39 +0100
committerOleksandr Byelkin <sanja@mariadb.com>2021-11-08 19:40:39 +0100
commitd8d6e995282dd9485f65517efbb684eabaf52322 (patch)
tree136ac5691b565656de46f60c8a594661561d7817 /sql
parent8635be6a2962f8e256c27836c35064ccaabb7486 (diff)
parentcf06eaf1afd268e829b0b1213c9b157a8109aa3c (diff)
downloadmariadb-git-d8d6e995282dd9485f65517efbb684eabaf52322.tar.gz
Merge branch '10.5' into bb-10.5-release
Diffstat (limited to 'sql')
-rw-r--r--sql/handler.h8
-rw-r--r--sql/item_strfunc.cc6
-rw-r--r--sql/sql_alter.cc4
-rw-r--r--sql/sql_alter.h1
-rw-r--r--sql/sql_table.cc59
5 files changed, 64 insertions, 14 deletions
diff --git a/sql/handler.h b/sql/handler.h
index e1f98a579b5..47bab7f75e2 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -479,6 +479,7 @@ enum chf_create_flags {
#define HA_CREATE_TMP_ALTER 8U
#define HA_LEX_CREATE_SEQUENCE 16U
#define HA_VERSIONED_TABLE 32U
+#define HA_SKIP_KEY_SORT 64U
#define HA_MAX_REC_LENGTH 65535
@@ -785,6 +786,13 @@ typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);
*/
#define ALTER_COLUMN_INDEX_LENGTH (1ULL << 60)
+/**
+ Indicate that index order might have been changed. Disables inplace algorithm
+ by default (not for InnoDB).
+*/
+#define ALTER_INDEX_ORDER (1ULL << 61)
+
+
/*
Flags set in partition_flags when altering partitions
*/
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 2967a0b42aa..e7abb51893c 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -3552,10 +3552,12 @@ String *Item_func_set_collation::val_str(String *str)
bool Item_func_set_collation::fix_length_and_dec()
{
- if (!my_charset_same(args[0]->collation.collation, m_set_collation))
+ if (agg_arg_charsets_for_string_result(collation, args, 1))
+ return true;
+ if (!my_charset_same(collation.collation, m_set_collation))
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- m_set_collation->name, args[0]->collation.collation->csname);
+ m_set_collation->name, collation.collation->csname);
return TRUE;
}
collation.set(m_set_collation, DERIVATION_EXPLICIT,
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 7901c9b5e32..8562643df97 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -259,7 +259,7 @@ Alter_table_ctx::Alter_table_ctx()
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),
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
, tmp_table(false)
#endif
@@ -279,7 +279,7 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
tables_opened(tables_opened_arg),
new_db(*new_db_arg), new_name(*new_name_arg),
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
, tmp_table(false)
#endif
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index 89eb4ebb3e9..a499e978eef 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -324,6 +324,7 @@ public:
const char *fk_error_id;
/** Name of table for the above error. */
const char *fk_error_table;
+ bool modified_primary_key;
private:
char new_filename[FN_REFLEN + 1];
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 92fd6dd3ea6..b433d6b7af6 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4435,9 +4435,30 @@ without_overlaps_err:
my_message(ER_WRONG_AUTO_KEY, ER_THD(thd, ER_WRONG_AUTO_KEY), MYF(0));
DBUG_RETURN(TRUE);
}
- /* Sort keys in optimized order */
- my_qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY),
- (qsort_cmp) sort_keys);
+ /*
+ We cannot do qsort of key info if MyISAM/Aria does inplace. These engines
+ do not synchronise key info on inplace alter and that qsort is
+ indeterministic (MDEV-25803).
+
+ Yet we do not know whether we do inplace or not. That detection is done
+ after this create_table_impl() and that cannot be changed because of chicken
+ and egg problem (inplace processing requires key info made by
+ create_table_impl()).
+
+ 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.
+ */
+ if (!(create_info->options & HA_SKIP_KEY_SORT))
+ {
+ /*
+ Sort keys in optimized order.
+
+ Note: PK must be always first key, otherwise init_from_binary_frm_image()
+ can not understand it.
+ */
+ my_qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY),
+ (qsort_cmp) sort_keys);
+ }
create_info->null_bits= null_fields;
/* Check fields. */
@@ -8380,7 +8401,6 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
uint used_fields, dropped_sys_vers_fields= 0;
KEY *key_info=table->key_info;
bool rc= TRUE;
- bool modified_primary_key= FALSE;
bool vers_system_invisible= false;
Create_field *def;
Field **f_ptr,*field;
@@ -8804,6 +8824,12 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (key_info->flags & HA_INVISIBLE_KEY)
continue;
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;
drop_it.rewind();
while ((drop=drop_it++))
@@ -8817,7 +8843,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (table->s->tmp_table == NO_TMP_TABLE)
{
(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;
for (uint j=0; j < table->s->keys; j++, tab_key_info++)
@@ -8904,13 +8930,19 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
if (!cfield)
{
- if (table->s->primary_key == i)
- modified_primary_key= TRUE;
+ if (primary_key)
+ alter_ctx->modified_primary_key= true;
delete_index_stat= TRUE;
if (!(kfield->flags & VERS_SYSTEM_FIELD))
dropped_key_part= key_part_name;
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;
if (cfield->field) // Not new field
{
@@ -8959,7 +8991,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
{
if (delete_index_stat)
(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)
(void) delete_statistics_for_index(thd, table, key_info, TRUE);
}
@@ -9003,7 +9035,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
key_type= Key::SPATIAL;
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;
else
key_type= Key::UNIQUE;
@@ -10589,6 +10621,10 @@ do_continue:;
tmp_disable_binlog(thd);
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;
+ else
+ alter_info->flags|= ALTER_INDEX_ORDER;
create_info->alias= alter_ctx.table_name;
error= create_table_impl(thd, alter_ctx.db, alter_ctx.table_name,
alter_ctx.new_db, alter_ctx.tmp_name,
@@ -10625,7 +10661,7 @@ do_continue:;
*/
if (!(ha_alter_info.handler_flags &
- ~(ALTER_COLUMN_ORDER | ALTER_RENAME_COLUMN)))
+ ~(ALTER_COLUMN_ORDER | ALTER_RENAME_COLUMN | ALTER_INDEX_ORDER)))
{
/*
No-op ALTER, no need to call handler API functions.
@@ -10640,6 +10676,9 @@ do_continue:;
Also note that we ignore the LOCK clause here.
TODO don't create partitioning metadata in the first place
+
+ TODO: Now case-change index name is treated as noop which is not quite
+ correct.
*/
table->file->ha_create_partitioning_metadata(alter_ctx.get_tmp_path(),
NULL, CHF_DELETE_FLAG);