summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/field.h3
-rw-r--r--sql/ha_partition.cc8
-rw-r--r--sql/handler.cc10
-rw-r--r--sql/handler.h8
-rw-r--r--sql/item.h13
-rw-r--r--sql/item_cmpfunc.cc4
-rw-r--r--sql/item_strfunc.cc8
-rw-r--r--sql/mysqld.cc1
-rw-r--r--sql/sql_alter.cc20
-rw-r--r--sql/sql_alter.h17
-rw-r--r--sql/sql_table.cc59
-rw-r--r--sql/table.cc5
12 files changed, 104 insertions, 52 deletions
diff --git a/sql/field.h b/sql/field.h
index 0b8f317b5b8..7be16a1457e 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -517,6 +517,7 @@ enum enum_vcol_info_type
{
VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED,
VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE,
+ VCOL_USING_HASH,
/* Additional types should be added here */
/* Following is the highest value last */
VCOL_TYPE_NONE = 127 // Since the 0 value is already in use
@@ -534,6 +535,8 @@ static inline const char *vcol_type_name(enum_vcol_info_type type)
case VCOL_CHECK_FIELD:
case VCOL_CHECK_TABLE:
return "CHECK";
+ case VCOL_USING_HASH:
+ return "USING HASH";
case VCOL_TYPE_NONE:
return "UNTYPED";
}
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 1aa917d525b..f6c4b95dcbd 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -1203,7 +1203,6 @@ static const LEX_CSTRING opt_op_name[]=
};
-static const LEX_CSTRING msg_note= { STRING_WITH_LEN("note") };
static const LEX_CSTRING msg_warning= { STRING_WITH_LEN("warning") };
#define msg_error error_clex_str
@@ -11068,11 +11067,8 @@ int ha_partition::check_misplaced_rows(uint read_part_id, bool do_repair)
read_part_id != m_part_info->vers_info->now_part->id &&
!m_part_info->vers_info->interval.is_set())
{
- print_admin_msg(ha_thd(), MYSQL_ERRMSG_SIZE, &msg_note,
- table_share->db.str, table->alias,
- &opt_op_name[CHECK_PARTS],
- "Not supported for non-INTERVAL history partitions");
- DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
+ /* Skip this check as it is not supported for non-INTERVAL history partitions. */
+ DBUG_RETURN(HA_ADMIN_OK);
}
if (do_repair)
diff --git a/sql/handler.cc b/sql/handler.cc
index e4543bde5de..9fc9399d521 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -8285,15 +8285,16 @@ bool Table_scope_and_contents_source_st::vers_fix_system_fields(
if (!vers_info.need_check(alter_info))
return false;
- if (!vers_info.versioned_fields && vers_info.unversioned_fields &&
- !(alter_info->flags & ALTER_ADD_SYSTEM_VERSIONING))
+ const bool add_versioning= alter_info->flags & ALTER_ADD_SYSTEM_VERSIONING;
+
+ if (!vers_info.versioned_fields && vers_info.unversioned_fields && !add_versioning)
{
// All is correct but this table is not versioned.
options&= ~HA_VERSIONED_TABLE;
return false;
}
- if (!(alter_info->flags & ALTER_ADD_SYSTEM_VERSIONING) && vers_info)
+ if (!add_versioning && vers_info && !vers_info.versioned_fields)
{
my_error(ER_MISSING, MYF(0), create_table.table_name.str,
"WITH SYSTEM VERSIONING");
@@ -8303,8 +8304,7 @@ bool Table_scope_and_contents_source_st::vers_fix_system_fields(
List_iterator<Create_field> it(alter_info->create_list);
while (Create_field *f= it++)
{
- if ((f->versioning == Column_definition::VERSIONING_NOT_SET &&
- !(alter_info->flags & ALTER_ADD_SYSTEM_VERSIONING)) ||
+ if ((f->versioning == Column_definition::VERSIONING_NOT_SET && !add_versioning) ||
f->versioning == Column_definition::WITHOUT_VERSIONING)
{
f->flags|= VERS_UPDATE_UNVERSIONED_FLAG;
diff --git a/sql/handler.h b/sql/handler.h
index 0cdaf1dd698..5fe06ecd0bc 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -483,6 +483,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
@@ -789,11 +790,16 @@ 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)
/**
Means that the ignorability of an index is changed.
*/
-#define ALTER_INDEX_IGNORABILITY (1ULL << 61)
+#define ALTER_INDEX_IGNORABILITY (1ULL << 62)
/*
Flags set in partition_flags when altering partitions
diff --git a/sql/item.h b/sql/item.h
index 6b9223de122..468b9932f02 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -7696,6 +7696,19 @@ public:
/*
+ fix_escape_item() sets the out "escape" parameter to:
+ - native code in case of an 8bit character set
+ - Unicode code point in case of a multi-byte character set
+
+ The value meaning a not-initialized ESCAPE character must not be equal to
+ any valid value, so must be outside of these ranges:
+ - -128..+127, not to conflict with a valid 8bit charcter
+ - 0..0x10FFFF, not to conflict with a valid Unicode code point
+ The exact value does not matter.
+*/
+#define ESCAPE_NOT_INITIALIZED -1000
+
+/*
It's used in ::fix_fields() methods of LIKE and JSON_SEARCH
functions to handle the ESCAPE parameter.
This parameter is quite non-standard so the specific function.
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 227e65c9d94..5f21da17d8b 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -5607,7 +5607,7 @@ void Item_func_like::print(String *str, enum_query_type query_type)
longlong Item_func_like::val_int()
{
DBUG_ASSERT(fixed());
- DBUG_ASSERT(escape != -1);
+ DBUG_ASSERT(escape != ESCAPE_NOT_INITIALIZED);
String* res= args[0]->val_str(&cmp_value1);
if (args[0]->null_value)
{
@@ -5711,7 +5711,7 @@ bool fix_escape_item(THD *thd, Item *escape_item, String *tmp_str,
return TRUE;
}
- IF_DBUG(*escape= -1,);
+ IF_DBUG(*escape= ESCAPE_NOT_INITIALIZED,);
if (escape_item->const_item())
{
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 9399a566715..eb9c59d31f7 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2017, Oracle and/or its affiliates.
- Copyright (c) 2009, 2020, MariaDB Corporation.
+ Copyright (c) 2009, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -3579,11 +3579,13 @@ 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->coll_name.str,
- args[0]->collation.collation->cs_name.str);
+ collation.collation->cs_name.str);
return TRUE;
}
collation.set(m_set_collation, DERIVATION_EXPLICIT,
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index efdc3c8dcae..1ab3cbad4af 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -8524,7 +8524,6 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
{
/* Allow break with SIGINT, no core or stack trace */
test_flags|= TEST_SIGINT;
- opt_stack_trace= 1;
test_flags&= ~TEST_CORE_ON_SIGNAL;
}
/* Set global MyISAM variables from delay_key_write_options */
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 5827b7b104b..3d2884e8d85 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -254,16 +254,8 @@ Alter_info::algorithm(const THD *thd) const
Alter_table_ctx::Alter_table_ctx()
- : implicit_default_value_error_field(NULL),
- error_if_not_empty(false),
- tables_opened(0),
- 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)
-#ifdef DBUG_ASSERT_EXISTS
- , tmp_table(false)
-#endif
+ : 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)
{
}
@@ -276,12 +268,8 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
uint tables_opened_arg,
const LEX_CSTRING *new_db_arg,
const LEX_CSTRING *new_name_arg)
- : implicit_default_value_error_field(NULL), error_if_not_empty(false),
- 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),
- tmp_table(false)
+ : tables_opened(tables_opened_arg),
+ new_db(*new_db_arg), new_name(*new_name_arg)
{
/*
Assign members db, table_name, new_db and new_name
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index a0f89c28d2a..d91984d4b26 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, 2014, Oracle and/or its affiliates.
- Copyright (c) 2013, 2020, MariaDB Corporation.
+ Copyright (c) 2013, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -313,9 +313,9 @@ public:
void report_implicit_default_value_error(THD *thd, const TABLE_SHARE *) const;
public:
- Create_field *implicit_default_value_error_field;
- bool error_if_not_empty;
- uint tables_opened;
+ Create_field *implicit_default_value_error_field= nullptr;
+ bool error_if_not_empty= false;
+ uint tables_opened= 0;
LEX_CSTRING db;
LEX_CSTRING table_name;
LEX_CSTRING storage_engine_name;
@@ -337,13 +337,14 @@ public:
of table to the new version ER_FK_CANNOT_DELETE_PARENT error should be
emitted.
*/
- bool fk_error_if_delete_row;
+ bool fk_error_if_delete_row= false;
/** Name of foreign key for the above error. */
- const char *fk_error_id;
+ const char *fk_error_id= nullptr;
/** Name of table for the above error. */
- const char *fk_error_table;
+ const char *fk_error_table= nullptr;
+ bool modified_primary_key= false;
/** Indicates that we are altering temporary table */
- bool tmp_table;
+ bool tmp_table= false;
private:
char new_filename[FN_REFLEN + 1];
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 9b5c939ce95..6ab73458755 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -3452,9 +3452,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. */
@@ -7668,7 +7689,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;
@@ -8092,6 +8112,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.str);
+ const bool implicit_pk= primary_key && !explicit_pk;
+
Alter_drop *drop;
drop_it.rewind();
while ((drop=drop_it++))
@@ -8105,7 +8131,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++)
@@ -8204,13 +8230,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
{
@@ -8259,7 +8291,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);
}
@@ -8304,7 +8336,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.str))
+ if (explicit_pk)
key_type= Key::PRIMARY;
else
key_type= Key::UNIQUE;
@@ -10037,6 +10069,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;
/*
Create the .frm file for the new table. Storage engine table will not be
@@ -10095,7 +10131,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.
@@ -10110,6 +10146,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);
diff --git a/sql/table.cc b/sql/table.cc
index 0204250f650..5a622f9dbfa 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1119,6 +1119,8 @@ static void mysql57_calculate_null_position(TABLE_SHARE *share,
}
}
+static bool fix_and_check_vcol_expr(THD *thd, TABLE *table,
+ Virtual_column_info *vcol);
/** Parse TABLE_SHARE::vcol_defs
@@ -1304,6 +1306,9 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
Virtual_column_info *v= new (mem_root) Virtual_column_info();
field->vcol_info= v;
field->vcol_info->expr= hash_item;
+ field->vcol_info->set_vcol_type(VCOL_USING_HASH);
+ if (fix_and_check_vcol_expr(thd, table, v))
+ goto end;
key->user_defined_key_parts= key->ext_key_parts= key->usable_key_parts= 1;
key->key_part+= parts;