diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.h | 3 | ||||
-rw-r--r-- | sql/ha_partition.cc | 8 | ||||
-rw-r--r-- | sql/handler.cc | 10 | ||||
-rw-r--r-- | sql/handler.h | 8 | ||||
-rw-r--r-- | sql/item.h | 13 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 4 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 8 | ||||
-rw-r--r-- | sql/mysqld.cc | 1 | ||||
-rw-r--r-- | sql/sql_alter.cc | 20 | ||||
-rw-r--r-- | sql/sql_alter.h | 17 | ||||
-rw-r--r-- | sql/sql_table.cc | 59 | ||||
-rw-r--r-- | sql/table.cc | 5 |
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; |