diff options
author | Monty <monty@mariadb.org> | 2023-01-29 20:39:37 +0200 |
---|---|---|
committer | Monty <monty@mariadb.org> | 2023-02-10 13:35:31 +0200 |
commit | 00704aff98400e3aed2624ff2a83b82f350df87c (patch) | |
tree | 0c0a1be98a144d394baad1334c191c391a398e6a | |
parent | fe1f4ca8ced02aad38fa3e71da67b2a172787bda (diff) | |
download | mariadb-git-00704aff98400e3aed2624ff2a83b82f350df87c.tar.gz |
Fixed bug in extended key handling when there is no primary key
Extended keys works by first checking if the engine supports extended
keys.
If yes, it extends secondary key with primary key components and mark the
secondary keys as HA_EXT_NOSAME (unique).
If we later notice that there where no primary key, the extended key
information for secondary keys in share->key_info is reset. However the
key_info->flag HA_EXT_NOSAME was not reset!
This causes some strange things to happen:
- Tables that have no primary key or secondary index that contained the
primary key would be wrongly optimized as the secondary key could be
thought to be unique when it was not and not unique when it was.
- The problem was not shown in EXPLAIN because of a bug in
create_ref_for_key() that caused EQ_REF to be displayed by EXPLAIN as REF
when extended keys where used and the secondary key contained the primary
key.
This is fixed with:
- Removed wrong test in make_join_select() which did not detect that key
where unique when a secondary key contains the primary.
- Moved initialization of extended keys from create_key_infos() to
init_from_binary_frm_image() after we know if there is a usable primary
key or not. One disadvantage with this approach is that
key_info->key_parts may have not used slots (for keys we thought could
be extended but could not). Fixed by adding a check for unused key_parts
to copy_keys_from_share().
Other things:
- Simplified copying of first key part in create_key_infos().
- Added a lot of code comments in code that I had to check as part of
finding the issue.
- Fixed some indentation.
- Replaced a couple of looks using references to pointers in C
context where the reference does not give any benefit.
- Updated Aria and Maria to not assume the all key_info->rec_per_key
are in one memory block (this could happen when using dervived
tables with many keys).
- Fixed a bug where key_info->rec_per_key where not allocated
- Optimized TABLE::add_tmp_key() to only call alloc() once.
(No logic changes)
Test case changes:
- innodb_mysql.test changed index as an index the optimizer thought
was unique, was not. (Table had no primary key)
TODO:
- Move code that checks for partial or too long keys to the primary loop
earlier that initally decides if we should add extended key fields.
This is needed to ensure that HA_EXT_NOSAME is not set for partial or
too long keys. It will also shorten the current code notable.
-rw-r--r-- | mysql-test/suite/innodb/r/innodb_mysql.result | 6 | ||||
-rw-r--r-- | sql/sql_class.h | 1 | ||||
-rw-r--r-- | sql/sql_select.cc | 26 | ||||
-rw-r--r-- | sql/sql_table.cc | 3 | ||||
-rw-r--r-- | sql/table.cc | 286 | ||||
-rw-r--r-- | storage/maria/ha_maria.cc | 18 | ||||
-rw-r--r-- | storage/myisam/ha_myisam.cc | 14 |
7 files changed, 225 insertions, 129 deletions
diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index 54c6f1ef262..7d5dc38f52c 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -2193,7 +2193,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 -2 DERIVED t1 ref c3,c2 c2 10 const,const 1 +2 DERIVED t1 ref c3,c2 c3 5 const 2 Using where DROP TABLE t1; CREATE TABLE t1 (c1 REAL, c2 REAL, c3 REAL, KEY (c3), KEY (c2, c3)) ENGINE=InnoDB; @@ -2207,7 +2207,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 -2 DERIVED t1 ref c3,c2 c2 18 const,const 1 +2 DERIVED t1 ref c3,c2 c3 9 const 2 Using where DROP TABLE t1; CREATE TABLE t1 (c1 DECIMAL(12,2), c2 DECIMAL(12,2), c3 DECIMAL(12,2), KEY (c3), KEY (c2, c3)) @@ -2222,7 +2222,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 -2 DERIVED t1 ref c3,c2 c2 14 const,const 1 +2 DERIVED t1 ref c3,c2 c3 7 const 2 Using where DROP TABLE t1; End of 5.1 tests # diff --git a/sql/sql_class.h b/sql/sql_class.h index 4e1a039b4e7..066a420e693 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6248,6 +6248,7 @@ public: Item **items_to_copy; /* Fields in tmp table */ TMP_ENGINE_COLUMNDEF *recinfo, *start_recinfo; KEY *keyinfo; + ulong *rec_per_key; ha_rows end_write_records; /** Number of normal fields in the query, including those referred to diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b1f28b9af51..bb90f3048d7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12528,16 +12528,14 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, j->table->const_table= 1; else if (!((keyparts == keyinfo->user_defined_key_parts && ( - (key_flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME || - /* Unique key and all keyparts are NULL rejecting */ - ((key_flags & HA_NOSAME) && keyparts == not_null_keyparts) - )) || - /* true only for extended keys */ - (keyparts > keyinfo->user_defined_key_parts && - MY_TEST(key_flags & HA_EXT_NOSAME) && - keyparts == keyinfo->ext_key_parts) - ) || - null_ref_key) + (key_flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME || + /* Unique key and all keyparts are NULL rejecting */ + ((key_flags & HA_NOSAME) && keyparts == not_null_keyparts) + )) || + /* true only for extended keys */ + (MY_TEST(key_flags & HA_EXT_NOSAME) && + keyparts == keyinfo->ext_key_parts) ) || + null_ref_key) { /* Must read with repeat */ j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF; @@ -20435,6 +20433,7 @@ TABLE *Create_tmp_table::start(THD *thd, sizeof(*m_key_part_info)*(param->group_parts+1), ¶m->start_recinfo, sizeof(*param->recinfo)*(field_count*2+4), + ¶m->rec_per_key, sizeof(ulong)*param->group_parts, &tmpname, (uint) strlen(path)+1, &m_group_buff, (m_group && ! m_using_unique_constraint ? param->group_length : 0), @@ -20967,13 +20966,15 @@ bool Create_tmp_table::finalize(THD *thd, keyinfo->usable_key_parts=keyinfo->user_defined_key_parts= param->group_parts; keyinfo->ext_key_parts= keyinfo->user_defined_key_parts; + share->ext_key_parts= share->key_parts= keyinfo->ext_key_parts; keyinfo->key_length=0; - keyinfo->rec_per_key=NULL; + keyinfo->rec_per_key= param->rec_per_key; keyinfo->read_stats= NULL; keyinfo->collected_stats= NULL; keyinfo->algorithm= HA_KEY_ALG_UNDEF; keyinfo->is_statistics_from_stat_tables= FALSE; keyinfo->name= group_key; + keyinfo->comment.str= 0; ORDER *cur_group= m_group; for (; cur_group ; cur_group= cur_group->next, m_key_part_info++) { @@ -21074,6 +21075,7 @@ bool Create_tmp_table::finalize(THD *thd, keyinfo->usable_key_parts= keyinfo->user_defined_key_parts; table->distinct= 1; share->keys= 1; + share->ext_key_parts= share->key_parts= keyinfo->ext_key_parts; if (!(m_key_part_info= (KEY_PART_INFO*) alloc_root(&table->mem_root, keyinfo->user_defined_key_parts * sizeof(KEY_PART_INFO)))) @@ -21570,6 +21572,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, /* Can't create a key; Make a unique constraint instead of a key */ share->keys= 0; + share->key_parts= share->ext_key_parts= 0; share->uniques= 1; using_unique_constraint=1; bzero((char*) &uniquedef,sizeof(uniquedef)); @@ -21766,6 +21769,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, { /* Can't create a key; Make a unique constraint instead of a key */ share->keys= 0; + share->key_parts= share->ext_key_parts= 0; share->uniques= 1; using_unique_constraint=1; bzero((char*) &uniquedef,sizeof(uniquedef)); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9a60da58022..db9a67da094 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2105,7 +2105,8 @@ static int sort_keys(KEY *a, KEY *b) return -1; /* Long Unique keys should always be last unique key. - Before this patch they used to change order wrt to partial keys (MDEV-19049) + Before this patch they used to change order wrt to partial keys + (MDEV-19049) */ if (a->algorithm == HA_KEY_ALG_LONG_HASH) return 1; diff --git a/sql/table.cc b/sql/table.cc index e7b1e459c37..3fffb974f0c 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -751,10 +751,10 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, LEX_STRING *keynames) { uint i, j, n_length; + uint primary_key_parts= 0; KEY_PART_INFO *key_part= NULL; ulong *rec_per_key= NULL; - KEY_PART_INFO *first_key_part= NULL; - uint first_key_parts= 0; + DBUG_ASSERT(keyinfo == first_keyinfo); if (!keys) { @@ -763,15 +763,15 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, bzero((char*) keyinfo, len); key_part= reinterpret_cast<KEY_PART_INFO*> (keyinfo); } + bzero((char*)first_keyinfo, sizeof(*first_keyinfo)); /* - If share->use_ext_keys is set to TRUE we assume that any key - can be extended by the components of the primary key whose - definition is read first from the frm file. - For each key only those fields of the assumed primary key are - added that are not included in the proper key definition. - If after all it turns out that there is no primary key the - added components are removed from each key. + If share->use_ext_keys is set to TRUE we assume that any not + primary key, can be extended by the components of the primary key + whose definition is read first from the frm file. + This code only allocates space for the extend key information as + we at this point don't know if there is a primary key or not. + The extend key information is added in init_from_binary_frm_image(). When in the future we support others schemes of extending of secondary keys with components of the primary key we'll have @@ -804,26 +804,31 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, if (i == 0) { - (*ext_key_parts)+= (share->use_ext_keys ? first_keyinfo->user_defined_key_parts*(keys-1) : 0); + /* + Allocate space for keys. We have to do it there as we need to know + the number of used_defined_key_parts for the first key when doing + this. + */ + primary_key_parts= first_keyinfo->user_defined_key_parts; + (*ext_key_parts)+= (share->use_ext_keys ? + primary_key_parts*(keys-1) : + 0); n_length=keys * sizeof(KEY) + *ext_key_parts * sizeof(KEY_PART_INFO); if (!(keyinfo= (KEY*) alloc_root(&share->mem_root, n_length + len))) return 1; - bzero((char*) keyinfo,n_length); share->key_info= keyinfo; + + /* Copy first keyinfo, read above */ + memcpy((char*) keyinfo, (char*) first_keyinfo, sizeof(*keyinfo)); + bzero(((char*) keyinfo) + sizeof(*keyinfo), n_length - sizeof(*keyinfo)); + key_part= reinterpret_cast<KEY_PART_INFO*> (keyinfo + keys); if (!(rec_per_key= (ulong*) alloc_root(&share->mem_root, sizeof(ulong) * *ext_key_parts))) return 1; - first_key_part= key_part; - first_key_parts= first_keyinfo->user_defined_key_parts; - keyinfo->flags= first_keyinfo->flags; - keyinfo->key_length= first_keyinfo->key_length; - keyinfo->user_defined_key_parts= first_keyinfo->user_defined_key_parts; - keyinfo->algorithm= first_keyinfo->algorithm; - if (new_frm_ver >= 3) - keyinfo->block_size= first_keyinfo->block_size; + bzero((char*) rec_per_key, sizeof(*rec_per_key) * *ext_key_parts); } keyinfo->key_part= key_part; @@ -833,7 +838,7 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, if (strpos + (new_frm_ver >= 1 ? 9 : 7) >= frm_image_end) return 1; if (!(keyinfo->algorithm == HA_KEY_ALG_LONG_HASH)) - *rec_per_key++=0; + rec_per_key++; key_part->fieldnr= (uint16) (uint2korr(strpos) & FIELD_NR_MASK); key_part->offset= (uint) uint2korr(strpos+2)-1; key_part->key_type= (uint) uint2korr(strpos+5); @@ -857,48 +862,33 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, } key_part->store_length=key_part->length; } + + keyinfo->ext_key_parts= keyinfo->user_defined_key_parts; + keyinfo->ext_key_flags= keyinfo->flags; + keyinfo->ext_key_part_map= 0; + if (keyinfo->algorithm == HA_KEY_ALG_LONG_HASH) { + /* + We should not increase keyinfo->ext_key_parts here as it will + later be changed to 1 as the engine will only see the generated hash + key. + */ keyinfo->key_length= HA_HASH_KEY_LENGTH_WITHOUT_NULL; - key_part++; // reserved for the hash value - *rec_per_key++=0; + key_part++; // This will be set to point to the hash key + rec_per_key++; // Only one rec_per_key needed for the hash + share->ext_key_parts++; } - /* - Add primary key to end of extended keys for non unique keys for - storage engines that supports it. - */ - keyinfo->ext_key_parts= keyinfo->user_defined_key_parts; - keyinfo->ext_key_flags= keyinfo->flags; - keyinfo->ext_key_part_map= 0; - if (share->use_ext_keys && i && !(keyinfo->flags & HA_NOSAME)) + if (i && share->use_ext_keys && !((keyinfo->flags & HA_NOSAME))) { - for (j= 0; - j < first_key_parts && keyinfo->ext_key_parts < MAX_REF_PARTS; - j++) - { - uint key_parts= keyinfo->user_defined_key_parts; - KEY_PART_INFO* curr_key_part= keyinfo->key_part; - KEY_PART_INFO* curr_key_part_end= curr_key_part+key_parts; - for ( ; curr_key_part < curr_key_part_end; curr_key_part++) - { - if (curr_key_part->fieldnr == first_key_part[j].fieldnr) - break; - } - if (curr_key_part == curr_key_part_end) - { - *key_part++= first_key_part[j]; - *rec_per_key++= 0; - keyinfo->ext_key_parts++; - keyinfo->ext_key_part_map|= 1 << j; - } - } - if (j == first_key_parts) - keyinfo->ext_key_flags= keyinfo->flags | HA_EXT_NOSAME; + /* Reserve place for extended key parts */ + key_part+= primary_key_parts; + rec_per_key+= primary_key_parts; + share->ext_key_parts+= primary_key_parts; // For copy_keys_from_share() } - if (keyinfo->algorithm == HA_KEY_ALG_LONG_HASH) - share->ext_key_parts++; share->ext_key_parts+= keyinfo->ext_key_parts; + DBUG_ASSERT(share->ext_key_parts <= *ext_key_parts); } keynames->str= (char*) key_part; keynames->length= strnmov(keynames->str, (char *) strpos, @@ -1292,10 +1282,10 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table, for (key_index= 0; key_index < table->s->keys; key_index++) { key=table->key_info + key_index; - parts= key->user_defined_key_parts; + parts= key->user_defined_key_parts; if (key->key_part[parts].fieldnr == field->field_index + 1) break; - } + } if (!key || key->algorithm != HA_KEY_ALG_LONG_HASH) goto end; KEY_PART_INFO *keypart; @@ -1323,7 +1313,13 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table, field->vcol_info->set_vcol_type(VCOL_USING_HASH); if (v->fix_and_check_expr(thd, table)) goto end; - key->user_defined_key_parts= key->ext_key_parts= key->usable_key_parts= 1; + /* + The hash key used by unique consist of one key_part. + It is stored in key_parts after the used defined parts. + The engine will only see the hash. + */ + key->user_defined_key_parts= key->usable_key_parts= + key->ext_key_parts= 1; key->key_part+= parts; if (key->flags & HA_NULL_PART_KEY) @@ -2046,6 +2042,10 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, next_chunk+= str_db_type_length + 2; } + /* + Check if engine supports extended keys. This is used by + create_key_infos() to allocate room for extended keys + */ share->set_use_ext_keys_flag(plugin_hton(se_plugin)->flags & HTON_SUPPORTS_EXTENDED_KEYS); @@ -2815,7 +2815,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, hash_keypart->type= HA_KEYTYPE_ULONGLONG; hash_keypart->key_part_flag= 0; hash_keypart->key_type= 32834; - /* Last n fields are unique_index_hash fields*/ + /* Last n fields are unique_index_hash fields */ hash_keypart->offset= offset; hash_keypart->fieldnr= hash_field_used_no + 1; hash_field= share->field[hash_field_used_no]; @@ -2829,7 +2829,6 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, offset+= HA_HASH_FIELD_LENGTH; } } - uint add_first_key_parts= 0; longlong ha_option= handler_file->ha_table_flags(); keyinfo= share->key_info; uint primary_key= my_strcasecmp(system_charset_info, @@ -2899,31 +2898,78 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, goto err; } + uint add_first_key_parts= 0; if (share->use_ext_keys) { if (primary_key >= MAX_KEY) - { - add_first_key_parts= 0; - share->set_use_ext_keys_flag(FALSE); - } + share->set_use_ext_keys_flag(false); else { - add_first_key_parts= first_keyinfo.user_defined_key_parts; - /* - Do not add components of the primary key starting from - the major component defined over the beginning of a field. - */ - for (i= 0; i < first_keyinfo.user_defined_key_parts; i++) - { + /* Add primary key to end of all non unique keys */ + + KEY *curr_keyinfo= keyinfo, *keyinfo_end= keyinfo+ keys; + KEY_PART_INFO *first_key_part= keyinfo->key_part; + uint first_key_parts= keyinfo->user_defined_key_parts; + + /* + We are skipping the first key (primary key) as it cannot be + extended + */ + while (++curr_keyinfo < keyinfo_end) + { + uint j; + if (!(curr_keyinfo->flags & HA_NOSAME)) + { + KEY_PART_INFO *key_part= (curr_keyinfo->key_part + + curr_keyinfo->user_defined_key_parts); + + /* Extend key with primary key parts */ + for (j= 0; + j < first_key_parts && + curr_keyinfo->ext_key_parts < MAX_REF_PARTS; + j++) + { + uint key_parts= curr_keyinfo->user_defined_key_parts; + KEY_PART_INFO *curr_key_part= curr_keyinfo->key_part; + KEY_PART_INFO *curr_key_part_end= curr_key_part+key_parts; + + for ( ; curr_key_part < curr_key_part_end; curr_key_part++) + { + if (curr_key_part->fieldnr == first_key_part[j].fieldnr) + break; + } + if (curr_key_part == curr_key_part_end) + { + /* Add primary key part not part of the current index */ + *key_part++= first_key_part[j]; + curr_keyinfo->ext_key_parts++; + curr_keyinfo->ext_key_part_map|= 1 << j; + } + } + if (j == first_key_parts) + { + /* Full primary key added to secondary keys makes it unique */ + curr_keyinfo->ext_key_flags= curr_keyinfo->flags | HA_EXT_NOSAME; + } + } + } + add_first_key_parts= keyinfo->user_defined_key_parts; + + /* + If a primary key part is using a partial key, don't use it or any key part after + it. + */ + for (i= 0; i < first_key_parts; i++) + { uint fieldnr= keyinfo[0].key_part[i].fieldnr; if (share->field[fieldnr-1]->key_length() != keyinfo[0].key_part[i].length) - { + { add_first_key_parts= i; break; } } - } + } } /* Primary key must be set early as engine may use it in index_flag() */ @@ -4055,6 +4101,11 @@ static void print_long_unique_table(TABLE *table) } #endif + +/** + Copy key information from TABLE_SHARE to TABLE +*/ + bool copy_keys_from_share(TABLE *outparam, MEM_ROOT *root) { TABLE_SHARE *share= outparam->s; @@ -4064,14 +4115,16 @@ bool copy_keys_from_share(TABLE *outparam, MEM_ROOT *root) KEY_PART_INFO *key_part; if (!multi_alloc_root(root, &key_info, share->keys*sizeof(KEY), - &key_part, share->ext_key_parts*sizeof(KEY_PART_INFO), + &key_part, + share->ext_key_parts*sizeof(KEY_PART_INFO), NullS)) return 1; outparam->key_info= key_info; memcpy(key_info, share->key_info, sizeof(*key_info)*share->keys); - memcpy(key_part, key_info->key_part, sizeof(*key_part)*share->ext_key_parts); + memcpy(key_part, key_info->key_part, + sizeof(*key_part)*share->ext_key_parts); my_ptrdiff_t adjust_ptrs= PTR_BYTE_DIFF(key_part, key_info->key_part); for (key_info_end= key_info + share->keys ; @@ -4082,22 +4135,44 @@ bool copy_keys_from_share(TABLE *outparam, MEM_ROOT *root) key_info->key_part= reinterpret_cast<KEY_PART_INFO*> (reinterpret_cast<char*>(key_info->key_part) + adjust_ptrs); if (key_info->algorithm == HA_KEY_ALG_LONG_HASH) + { + /* + From the user point of view, this key is unique. + However from the engine point, the value is not unique + as there can be hash collisions. + */ key_info->flags&= ~HA_NOSAME; + } } + + /* + We have to copy key parts separately as LONG HASH has invisible + key parts not seen by key_info + */ for (KEY_PART_INFO *key_part_end= key_part+share->ext_key_parts; 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)) + /* + key_part->field is not set for key_parts that are here not used. + This can happen with extended keys where a secondary key + contains a primary key. In this case no key_info will contain + this key_part, but it can still be part of the memory region of + share->key_part. + */ + if (key_part->field) { - /* - 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(root, outparam, 0); - field->field_length= key_part->length; + 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(root, outparam, 0); + field->field_length= key_part->length; + } } } } @@ -4339,15 +4414,15 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, for (uint k= 0; k < share->keys; k++) { - KEY &key_info= outparam->key_info[k]; - uint parts = (share->use_ext_keys ? key_info.ext_key_parts : - key_info.user_defined_key_parts); - for (uint p= 0; p < parts; p++) + KEY *key_info= &outparam->key_info[k]; + uint parts= (share->use_ext_keys ? key_info->ext_key_parts : + key_info->user_defined_key_parts); + for (uint p=0; p < parts; p++) { - KEY_PART_INFO &kp= key_info.key_part[p]; - if (kp.field != outparam->field[kp.fieldnr - 1]) + KEY_PART_INFO *kp= &key_info->key_part[p]; + if (kp->field != outparam->field[kp->fieldnr - 1]) { - kp.field->vcol_info = outparam->field[kp.fieldnr - 1]->vcol_info; + kp->field->vcol_info= outparam->field[kp->fieldnr - 1]->vcol_info; } } } @@ -8303,18 +8378,25 @@ bool TABLE::add_tmp_key(uint key, uint key_parts, DBUG_ASSERT(key < max_keys); char buf[NAME_CHAR_LEN]; - KEY* keyinfo; + KEY *keyinfo= key_info + key; + KEY_PART_INFO *key_part_info; Field **reg_field; uint i; - bool key_start= TRUE; - KEY_PART_INFO* key_part_info= - (KEY_PART_INFO*) alloc_root(&mem_root, sizeof(KEY_PART_INFO)*key_parts); - if (!key_part_info) + + keyinfo->name.length= sprintf(buf, "key%i", key); + + if (!multi_alloc_root(&mem_root, + &key_part_info, sizeof(KEY_PART_INFO)*key_parts, + &keyinfo->rec_per_key, + sizeof(key_info->rec_per_key) * key_parts, + &keyinfo->name.str, keyinfo->name.length+1, + NullS)) return TRUE; - keyinfo= key_info + key; keyinfo->key_part= key_part_info; - keyinfo->usable_key_parts= keyinfo->user_defined_key_parts = key_parts; + strmake((char*) keyinfo->name.str, buf, keyinfo->name.length); + + keyinfo->usable_key_parts= keyinfo->user_defined_key_parts= key_parts; keyinfo->ext_key_parts= keyinfo->user_defined_key_parts; keyinfo->key_length=0; keyinfo->algorithm= HA_KEY_ALG_UNDEF; @@ -8323,14 +8405,6 @@ bool TABLE::add_tmp_key(uint key, uint key_parts, keyinfo->is_statistics_from_stat_tables= FALSE; if (unique) keyinfo->flags|= HA_NOSAME; - sprintf(buf, "key%i", key); - keyinfo->name.length= strlen(buf); - if (!(keyinfo->name.str= strmake_root(&mem_root, buf, keyinfo->name.length))) - return TRUE; - keyinfo->rec_per_key= (ulong*) alloc_root(&mem_root, - sizeof(ulong)*key_parts); - if (!keyinfo->rec_per_key) - return TRUE; bzero(keyinfo->rec_per_key, sizeof(ulong)*key_parts); keyinfo->read_stats= NULL; keyinfo->collected_stats= NULL; @@ -8376,6 +8450,8 @@ bool TABLE::add_tmp_key(uint key, uint key_parts, set_if_bigger(s->max_key_length, keyinfo->key_length); s->keys++; + s->ext_key_parts+= keyinfo->ext_key_parts; + s->key_parts+= keyinfo->user_defined_key_parts; return FALSE; } diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 691edba8d55..8f59ce0a549 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2727,15 +2727,21 @@ int ha_maria::info(uint flag) share->db_record_offset= maria_info.record_offset; if (share->key_parts) { - ulong *to= table->key_info[0].rec_per_key, *end; double *from= maria_info.rec_per_key; - for (end= to+ share->key_parts ; to < end ; to++, from++) - *to= (ulong) (*from + 0.5); + KEY *key, *key_end; + for (key= table->key_info, key_end= key + share->keys; + key < key_end ; key++) + { + ulong *to= key->rec_per_key; + for (ulong *end= to+ key->user_defined_key_parts ; + to < end ; + to++, from++) + *to= (ulong) (*from + 0.5); + } } - /* - Set data_file_name and index_file_name to point at the symlink value - if table is symlinked (Ie; Real name is not same as generated name) + Set data_file_name and index_file_name to point at the symlink value + if table is symlinked (Ie; Real name is not same as generated name) */ data_file_name= index_file_name= 0; fn_format(name_buff, file->s->open_file_name.str, "", MARIA_NAME_DEXT, diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index bd6cfe0c3bc..b1b1e8fd57e 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -2152,9 +2152,17 @@ int ha_myisam::info(uint flag) share->keys_for_keyread.intersect(share->keys_in_use); share->db_record_offset= misam_info.record_offset; if (share->key_parts) - memcpy((char*) table->key_info[0].rec_per_key, - (char*) misam_info.rec_per_key, - sizeof(table->key_info[0].rec_per_key[0])*share->key_parts); + { + ulong *from= misam_info.rec_per_key; + KEY *key, *key_end; + for (key= table->key_info, key_end= key + share->keys; + key < key_end ; key++) + { + memcpy(key->rec_per_key, from, + key->user_defined_key_parts * sizeof(*from)); + from+= key->user_defined_key_parts; + } + } if (table_share->tmp_table == NO_TMP_TABLE) mysql_mutex_unlock(&table_share->LOCK_share); } |