1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-16 00:42:55 +03:00

MDEV-20131 Assertion `!pk->has_virtual()' failed

Assertion `!pk->has_virtual()' failed in dict_index_build_internal_clust
while creating PRIMARY key longer than possible to store in the page.

This happened because the key was wrongly deduced as Long UNIQUE supported,
however PRIMARY KEY cannot be of that type. The main reason is that
only 8 bytes are used to store the hash, see HA_HASH_FIELD_LENGTH.

This is also why HA_NOSAME flag is removed (and caused the assertion in
turn) in open_table_from_share:
      if (key_info->algorithm == HA_KEY_ALG_LONG_HASH)
      {
        key_part_end++;
        key_info->flags&= ~HA_NOSAME;
      }

To make it unique, the additional check is done by
check_duplicate_long_entries call from ha_write_row, and similar one from
ha_update_row.

PRIMARY key is already forbidden, which is checked by the first test in
main.long_unique, however is_hash_field_needed was wrongly deduced to true
in mysql_prepare_create_table in this particular case.

FIX:

* Improve the check for Key::PRIMARY type
* Simplify is_hash_field_needed deduction for a more neat reading
This commit is contained in:
Nikita Malyavin
2021-10-07 15:04:56 +03:00
parent 4590f8b41c
commit d10c42b425
4 changed files with 19 additions and 8 deletions

View File

@ -3968,7 +3968,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (!column->length)
{
if (key->type == Key::UNIQUE)
is_hash_field_needed= true;
is_hash_field_needed= true; // for case "a BLOB UNIQUE"
else if (key->type == Key::MULTIPLE)
column->length= file->max_key_length() + 1;
else
@ -4064,8 +4064,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
/* Align key length to multibyte char boundary */
key_part_length-= key_part_length % sql_field->charset->mbmaxlen;
}
else
is_hash_field_needed= true;
}
}
// Catch invalid use of partial keys
@ -4111,11 +4109,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
else
{
if (key->type == Key::UNIQUE)
{
is_hash_field_needed= true;
}
else
if (key->type != Key::UNIQUE)
{
key_part_length= MY_MIN(max_key_length, file->max_key_part_length());
my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length);
@ -4123,6 +4117,14 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
}
if (key->type == Key::UNIQUE
&& key_part_length > MY_MIN(max_key_length,
file->max_key_part_length()))
{
is_hash_field_needed= true;
}
/* We can not store key_part_length more then 2^16 - 1 in frm */
if (is_hash_field_needed && column->length > UINT_MAX16)
{