diff options
author | Nikita Malyavin <nikita.malyavin@mariadb.com> | 2021-07-28 11:07:49 +0200 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2021-07-28 11:13:24 +0200 |
commit | 9b8e207ce03b2ab7a766348738055be9520561bd (patch) | |
tree | 292d3ddf4182c9c5261bc3eb54dca2cff146b0f7 /sql/table.cc | |
parent | fb8be6a631e68c57d36c1a0637033f6827105366 (diff) | |
download | mariadb-git-9b8e207ce03b2ab7a766348738055be9520561bd.tar.gz |
MDEV-26220 Server crashes with indexed by prefix virtual column
Server crashes in Field::register_field_in_read_map upon select from
partitioned table with indexed by prefix virtual column.
After several read-mark fixes a problem has surfaced:
Since KEY (c(10),a) uses only a prefix of c, a new field is created,
duplicated from table->field[3], with a new length. However,
vcol_inco->expr is not copied.
Therefore, (*key_info)->key_part[i].field->vcol_info->expr was left NULL
in ha_partition::index_init().
Solution: initialize vcols before key initialization
Also key initialization is moved to a function.
Diffstat (limited to 'sql/table.cc')
-rw-r--r-- | sql/table.cc | 113 |
1 files changed, 65 insertions, 48 deletions
diff --git a/sql/table.cc b/sql/table.cc index b7cf1274400..ab2429f469f 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3034,6 +3034,66 @@ static bool check_vcol_forward_refs(Field *field, Virtual_column_info *vcol) return res; } +/** + Copy keys from share to a table, so that fields in key_parts would match + fields in a table. + + Also if key_part uses a field prefix, clone a field and make its length match + that prefix. + + @retval true if success + @retval false if memory allocation fails + */ +static bool initialize_keys(TABLE_SHARE *share, TABLE *outparam) +{ + if (share->key_parts == 0) + return true; + uint n_length= share->keys * sizeof(KEY) + + share->ext_key_parts * sizeof(KEY_PART_INFO); + + KEY *key_info= (KEY*) alloc_root(&outparam->mem_root, n_length); + if (!key_info) + return false; + + outparam->key_info= key_info; + + KEY *key_info_end= key_info + share->keys; + KEY_PART_INFO *key_part= reinterpret_cast<KEY_PART_INFO*>(key_info_end); + + memcpy(key_info, share->key_info, sizeof(*key_info) * share->keys); + memcpy(key_part, share->key_info[0].key_part, (sizeof(*key_part) * + share->ext_key_parts)); + + for ( ; key_info < key_info_end; key_info++) + { + key_info->table= outparam; + key_info->key_part= key_part; + + KEY_PART_INFO *key_part_end= key_part + (share->use_ext_keys + ? key_info->ext_key_parts + : key_info->user_defined_key_parts); + for ( ; key_part < key_part_end; key_part++) + { + Field *field= key_part->field= outparam->field[key_part->fieldnr - 1]; + + if (field->key_length() != key_part->length && + !(field->flags & BLOB_FLAG)) + { + /* + We are using only a prefix of the column as a key: + Create a new field for the key part that matches the index + */ + field= key_part->field=field->make_new_field(&outparam->mem_root, + outparam, 0); + field->field_length= key_part->length; + } + } + if (!share->use_ext_keys) + key_part+= key_info->ext_key_parts - key_info->user_defined_key_parts; + } + return true; +} + /* Open a table based on a TABLE_SHARE @@ -3073,6 +3133,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, Field **field_ptr; uint8 save_context_analysis_only= thd->lex->context_analysis_only; TABLE_SHARE::enum_v_keys check_set_initialized= share->check_set_initialized; + bool success; DBUG_ENTER("open_table_from_share"); DBUG_PRINT("enter",("name: '%s.%s' form: %p", share->db.str, share->table_name.str, outparam)); @@ -3182,54 +3243,6 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, outparam->found_next_number_field= outparam->field[(uint) (share->found_next_number_field - share->field)]; - /* Fix key->name and key_part->field */ - if (share->key_parts) - { - KEY *key_info, *key_info_end; - KEY_PART_INFO *key_part; - uint n_length; - n_length= share->keys*sizeof(KEY) + share->ext_key_parts*sizeof(KEY_PART_INFO); - if (!(key_info= (KEY*) alloc_root(&outparam->mem_root, n_length))) - goto err; - outparam->key_info= key_info; - key_part= (reinterpret_cast<KEY_PART_INFO*>(key_info+share->keys)); - - memcpy(key_info, share->key_info, sizeof(*key_info)*share->keys); - memcpy(key_part, share->key_info[0].key_part, (sizeof(*key_part) * - share->ext_key_parts)); - - for (key_info_end= key_info + share->keys ; - key_info < key_info_end ; - key_info++) - { - KEY_PART_INFO *key_part_end; - - key_info->table= outparam; - key_info->key_part= key_part; - - key_part_end= key_part + (share->use_ext_keys ? key_info->ext_key_parts : - key_info->user_defined_key_parts) ; - for ( ; key_part < key_part_end; key_part++) - { - Field *field= key_part->field= outparam->field[key_part->fieldnr - 1]; - - if (field->key_length() != key_part->length && - !(field->flags & BLOB_FLAG)) - { - /* - We are using only a prefix of the column as a key: - Create a new field for the key part that matches the index - */ - field= key_part->field=field->make_new_field(&outparam->mem_root, - outparam, 0); - field->field_length= key_part->length; - } - } - if (!share->use_ext_keys) - key_part+= key_info->ext_key_parts - key_info->user_defined_key_parts; - } - } - /* Process virtual and default columns, if any. */ @@ -3286,6 +3299,10 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, switch_defaults_to_nullable_trigger_fields(outparam); } + success= initialize_keys(share, outparam); + if (!success) + goto err; + #ifdef WITH_PARTITION_STORAGE_ENGINE if (share->partition_info_str_len && outparam->file) { |