MDEV-29954 Unique hash key on column prefix is computed incorrectly

use the original, not the truncated, field in the long unique prefix,
that is, in the hash(left(field, length)) expression.

because MyISAM CHECK/REPAIR in compute_vcols() moves table->field
but not prefix fields from keyparts.

Also, implement Field_string::cmp_prefix() for prefix comparison
of CHAR columns to work.
This commit is contained in:
Sergei Golubchik 2024-01-22 18:02:11 +01:00
parent 14d00fdb15
commit a7ee3bc58b
6 changed files with 35 additions and 4 deletions

View File

@ -651,5 +651,14 @@ f1 f2 f3 f4 f5 f6 f7
4 00004 0001009089999 netstes psit e
drop table t1;
#
# MDEV-29954 Unique hash key on column prefix is computed incorrectly
#
create table t1 (c char(10),unique key a using hash (c(1)));
insert into t1 values (0);
check table t1 extended;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
#
# End of 10.5 tests
#

View File

@ -634,6 +634,14 @@ replace t1 (f2, f3, f4, f5, f6, f7) values ('00004', '0001009089999', '', 'netst
select * from t1;
drop table t1;
--echo #
--echo # MDEV-29954 Unique hash key on column prefix is computed incorrectly
--echo #
create table t1 (c char(10),unique key a using hash (c(1)));
insert into t1 values (0);
check table t1 extended;
drop table t1;
--echo #
--echo # End of 10.5 tests
--echo #

View File

@ -7566,6 +7566,19 @@ int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) const
}
int Field_string::cmp_prefix(const uchar *a_ptr, const uchar *b_ptr,
size_t prefix_char_len) const
{
size_t field_len= table->field[field_index]->field_length;
return field_charset()->coll->strnncollsp_nchars(field_charset(),
a_ptr, field_len,
b_ptr, field_len,
prefix_char_len,
0);
}
void Field_string::sort_string(uchar *to,uint length)
{
#ifdef DBUG_ASSERT_EXISTS

View File

@ -4038,6 +4038,8 @@ public:
String *val_str(String *, String *) override;
my_decimal *val_decimal(my_decimal *) override;
int cmp(const uchar *,const uchar *) const override;
int cmp_prefix(const uchar *a, const uchar *b, size_t prefix_char_len) const
override;
void sort_string(uchar *buff,uint length) override;
void update_data_type_statistics(Data_type_statistics *st) const override
{

View File

@ -605,7 +605,7 @@ int key_rec_cmp(void *key_p, uchar *first_rec, uchar *second_rec)
}
/*
No null values in the fields
We use the virtual method cmp_max with a max length parameter.
We use the virtual method cmp_prefix with a max length parameter.
For most field types this translates into a cmp without
max length. The exceptions are the BLOB and VARCHAR field types
that take the max length into account.

View File

@ -1272,12 +1272,11 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
if (keypart->key_part_flag & HA_PART_KEY_SEG)
{
int length= keypart->length/keypart->field->charset()->mbmaxlen;
Field *kpf= table->field[keypart->field->field_index];
list_item= new (mem_root) Item_func_left(thd,
new (mem_root) Item_field(thd, keypart->field),
new (mem_root) Item_field(thd, kpf),
new (mem_root) Item_int(thd, length));
list_item->fix_fields(thd, NULL);
keypart->field->vcol_info=
table->field[keypart->field->field_index]->vcol_info;
}
else
list_item= new (mem_root) Item_field(thd, keypart->field);