summaryrefslogtreecommitdiff
path: root/sql/table.cc
diff options
context:
space:
mode:
authorNikita Malyavin <nikita.malyavin@mariadb.com>2021-07-28 11:07:49 +0200
committerOleksandr Byelkin <sanja@mariadb.com>2021-07-28 11:13:24 +0200
commit9b8e207ce03b2ab7a766348738055be9520561bd (patch)
tree292d3ddf4182c9c5261bc3eb54dca2cff146b0f7 /sql/table.cc
parentfb8be6a631e68c57d36c1a0637033f6827105366 (diff)
downloadmariadb-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.cc113
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)
{