summaryrefslogtreecommitdiff
path: root/sql/sql_table.cc
diff options
context:
space:
mode:
authorNikita Malyavin <nikitamalyavin@gmail.com>2020-10-20 15:21:28 +1000
committerNikita Malyavin <nikitamalyavin@gmail.com>2020-11-02 14:21:05 +1000
commite618f7e9f60acb89e6990d9f705f90220fda0252 (patch)
tree6b498ccd4dc8099da2cb5a649b785429f1fd258e /sql/sql_table.cc
parenta79c6e369e8d07786395a04493f2142f41f7befc (diff)
downloadmariadb-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.cc194
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;