diff options
author | Nikita Malyavin <nikitamalyavin@gmail.com> | 2020-10-20 15:21:28 +1000 |
---|---|---|
committer | Nikita Malyavin <nikitamalyavin@gmail.com> | 2020-11-02 14:21:05 +1000 |
commit | e618f7e9f60acb89e6990d9f705f90220fda0252 (patch) | |
tree | 6b498ccd4dc8099da2cb5a649b785429f1fd258e /sql/sql_table.cc | |
parent | a79c6e369e8d07786395a04493f2142f41f7befc (diff) | |
download | mariadb-git-e618f7e9f60acb89e6990d9f705f90220fda0252.tar.gz |
MDEV-22506 Malformed error message for ER_KEY_CONTAINS_PERIOD_FIELDS
Though this is an error message task, the problem was deep in the
`mysql_prepare_create_table` implementation. The problem is described as
follows:
1. `append_system_key_parts` was called before
`mysql_prepare_create_table`, though key name generation was done close to
the latest stage of the latter.
2. We can't move `append_system_key_parts` in the end, because system keys
should be appended before some checks done.
3. If the checks from `append_system_key_parts` are moved to the end of
`mysql_prepare_create_table`, then some other inappropriate errors are
issued. like `ER_DUP_FIELDNAME`.
To have key name specified in error message, name generation should be done
before the checks, which consequenced in more changes.
The final design for key initialization in `mysql_prepare_create_table`
follows. The initialization is done in three phases:
1. Calculate a total number of keys created with respect to keys ignored.
Allocate KEY* buffer.
2. Generate unique names; calculate a total number of key parts.
Make early checks. Allocate KEY_PART_INFO* buffer.
3. Initialize key parts, make the rest of the checks.
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r-- | sql/sql_table.cc | 194 |
1 files changed, 106 insertions, 88 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 67a505d78bc..c2ba9bcadfb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -75,9 +75,8 @@ static int copy_data_between_tables(THD *, TABLE *,TABLE *, ha_rows *, ha_rows *, Alter_info::enum_enable_or_disable, Alter_table_ctx *); -static bool append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info, - Alter_info *alter_info, KEY **key_info, - uint key_count); +static int append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info, + Key *key); static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *, uint *, handler *, KEY **, uint *, int); static uint blob_length_by_type(enum_field_types type); @@ -1823,10 +1822,6 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) strxmov(shadow_frm_name, shadow_path, reg_ext, NullS); if (flags & WFRM_WRITE_SHADOW) { - if (append_system_key_parts(lpt->thd, lpt->create_info, lpt->alter_info, - &lpt->key_info_buffer, 0)) - DBUG_RETURN(true); - if (mysql_prepare_create_table(lpt->thd, lpt->create_info, lpt->alter_info, &lpt->db_options, lpt->table->file, &lpt->key_info_buffer, &lpt->key_count, @@ -3557,7 +3552,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, Create_field *sql_field,*dup_field; uint field,null_fields,max_key_length; ulong record_offset= 0; - KEY *key_info; KEY_PART_INFO *key_part_info; int field_no,dup_no; int select_field_pos,auto_increment=0; @@ -3875,6 +3869,57 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, thd->abort_on_warning= sav_abort_on_warning; } } + + KEY *key_info= *key_info_buffer= (KEY*)thd->calloc(sizeof(KEY) * (*key_count)); + if (!*key_info_buffer) + DBUG_RETURN(true); // Out of memory + + key_iterator.rewind(); + while ((key=key_iterator++)) + { + if (key->name.str == ignore_key || key->type == Key::FOREIGN_KEY) + continue; + /* Create the key->ame based on the first column (if not given) */ + if (key->type == Key::PRIMARY) + { + if (primary_key) + { + my_message(ER_MULTIPLE_PRI_KEY, ER_THD(thd, ER_MULTIPLE_PRI_KEY), + MYF(0)); + DBUG_RETURN(true); + } + key_name=primary_key_name; + primary_key=1; + } + else if (!(key_name= key->name.str)) + { + auto field_name= key->columns.elem(0)->field_name; + it.rewind(); + while ((sql_field=it++) && + lex_string_cmp(system_charset_info, + &field_name, + &sql_field->field_name)); + if (sql_field) + field_name= sql_field->field_name; + key_name=make_unique_key_name(thd, field_name.str, + *key_info_buffer, key_info); + } + if (check_if_keyname_exists(key_name, *key_info_buffer, key_info)) + { + my_error(ER_DUP_KEYNAME, MYF(0), key_name); + DBUG_RETURN(true); + } + + key_info->name.str= (char*) key_name; + key_info->name.length= strlen(key_name); + key->name= key_info->name; + + int parts_added= append_system_key_parts(thd, create_info, key); + if (parts_added < 0) + DBUG_RETURN(true); + key_parts += parts_added; + key_info++; + } tmp=file->max_keys(); if (*key_count > tmp) { @@ -3882,11 +3927,11 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(TRUE); } - (*key_info_buffer)= key_info= (KEY*) thd->calloc(sizeof(KEY) * (*key_count)); key_part_info=(KEY_PART_INFO*) thd->calloc(sizeof(KEY_PART_INFO)*key_parts); - if (!*key_info_buffer || ! key_part_info) - DBUG_RETURN(TRUE); // Out of memory + if (!key_part_info) + DBUG_RETURN(true); // Out of memory + key_info= *key_info_buffer; key_iterator.rewind(); key_number=0; for (; (key=key_iterator++) ; key_number++) @@ -4257,32 +4302,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_length+= key_part_length; key_part_info++; - - /* Create the key name based on the first column (if not given) */ - if (column_nr == 0) - { - if (key->type == Key::PRIMARY) - { - if (primary_key) - { - my_message(ER_MULTIPLE_PRI_KEY, ER_THD(thd, ER_MULTIPLE_PRI_KEY), - MYF(0)); - DBUG_RETURN(TRUE); - } - key_name=primary_key_name; - primary_key=1; - } - else if (!(key_name= key->name.str)) - key_name=make_unique_key_name(thd, sql_field->field_name.str, - *key_info_buffer, key_info); - if (check_if_keyname_exists(key_name, *key_info_buffer, key_info)) - { - my_error(ER_DUP_KEYNAME, MYF(0), key_name); - DBUG_RETURN(TRUE); - } - key_info->name.str= (char*) key_name; - key_info->name.length= strlen(key_name); - } } if (!key_info->name.str || check_column_name(key_info->name.str)) { @@ -4715,72 +4734,75 @@ bool Column_definition::sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root) } -static bool append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info, - Alter_info *alter_info, KEY **key_info, - uint key_count) +/** + Appends key parts generated by mariadb server. + Adds row_end in UNIQUE keys for system versioning, + and period fields for WITHOUT OVERLAPS. + @param thd Thread data + @param create_info Table create info + @param key Parsed key + @return a number of key parts added to key. + */ +static int append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info, + Key *key) { const Lex_ident &row_start_field= create_info->vers_info.as_row.start; const Lex_ident &row_end_field= create_info->vers_info.as_row.end; DBUG_ASSERT(!create_info->versioned() || (row_start_field && row_end_field)); - List_iterator<Key> key_it(alter_info->key_list); - Key *key= NULL; - - if (create_info->versioned()) + int result = 0; + if (create_info->versioned() && (key->type == Key::PRIMARY + || key->type == Key::UNIQUE)) { - while ((key=key_it++)) + Key_part_spec *key_part=NULL; + List_iterator<Key_part_spec> part_it(key->columns); + while ((key_part=part_it++)) { - if (key->type != Key::PRIMARY && key->type != Key::UNIQUE) - continue; - - Key_part_spec *key_part=NULL; - List_iterator<Key_part_spec> part_it(key->columns); - while ((key_part=part_it++)) - { - if (row_start_field.streq(key_part->field_name) || - row_end_field.streq(key_part->field_name)) - break; - } - if (!key_part) - key->columns.push_back(new (thd->mem_root) + if (row_start_field.streq(key_part->field_name) || + row_end_field.streq(key_part->field_name)) + break; + } + if (!key_part) + { + key->columns.push_back(new (thd->mem_root) Key_part_spec(&row_end_field, 0, true)); + result++; } - key_it.rewind(); + } - while ((key=key_it++)) + if (key->without_overlaps) { - if (key->without_overlaps) + DBUG_ASSERT(key->type == Key::PRIMARY || key->type == Key::UNIQUE); + if (!create_info->period_info.is_set() + || !key->period.streq(create_info->period_info.name)) { - DBUG_ASSERT(key->type == Key::PRIMARY || key->type == Key::UNIQUE); - if (!create_info->period_info.is_set() - || !key->period.streq(create_info->period_info.name)) - { - my_error(ER_PERIOD_NOT_FOUND, MYF(0), key->period.str); - return true; - } + my_error(ER_PERIOD_NOT_FOUND, MYF(0), key->period.str); + return -1; + } - const auto &period_start= create_info->period_info.period.start; - const auto &period_end= create_info->period_info.period.end; - List_iterator<Key_part_spec> part_it(key->columns); - while (Key_part_spec *key_part= part_it++) + const auto &period_start= create_info->period_info.period.start; + const auto &period_end= create_info->period_info.period.end; + List_iterator<Key_part_spec> part_it(key->columns); + while (Key_part_spec *key_part= part_it++) + { + if (period_start.streq(key_part->field_name) + || period_end.streq(key_part->field_name)) { - if (period_start.streq(key_part->field_name) - || period_end.streq(key_part->field_name)) - { - my_error(ER_KEY_CONTAINS_PERIOD_FIELDS, MYF(0), key->name.str, - key_part->field_name); - return true; - } + my_error(ER_KEY_CONTAINS_PERIOD_FIELDS, MYF(0), key->name.str, + key_part->field_name.str); + return -1; } - key->columns.push_back(new (thd->mem_root) - Key_part_spec(&period_end, 0)); - key->columns.push_back(new (thd->mem_root) - Key_part_spec(&period_start, 0)); } + const auto &period= create_info->period_info.period; + key->columns.push_back(new (thd->mem_root) + Key_part_spec(&period.end, 0, true)); + key->columns.push_back(new (thd->mem_root) + Key_part_spec(&period.start, 0, true)); + result += 2; } - return false; + return result; } handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db, @@ -5018,10 +5040,6 @@ handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db, } #endif - if (append_system_key_parts(thd, create_info, alter_info, key_info, - *key_count)) - goto err; - if (mysql_prepare_create_table(thd, create_info, alter_info, &db_options, file, key_info, key_count, create_table_mode)) goto err; |