Skip to content

Commit a7ee3bc

Browse files
committed
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.
1 parent 14d00fd commit a7ee3bc

File tree

6 files changed

+35
-4
lines changed

6 files changed

+35
-4
lines changed

mysql-test/main/long_unique_bugs.result

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,5 +651,14 @@ f1 f2 f3 f4 f5 f6 f7
651651
4 00004 0001009089999 netstes psit e
652652
drop table t1;
653653
#
654+
# MDEV-29954 Unique hash key on column prefix is computed incorrectly
655+
#
656+
create table t1 (c char(10),unique key a using hash (c(1)));
657+
insert into t1 values (0);
658+
check table t1 extended;
659+
Table Op Msg_type Msg_text
660+
test.t1 check status OK
661+
drop table t1;
662+
#
654663
# End of 10.5 tests
655664
#

mysql-test/main/long_unique_bugs.test

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,14 @@ replace t1 (f2, f3, f4, f5, f6, f7) values ('00004', '0001009089999', '', 'netst
634634
select * from t1;
635635
drop table t1;
636636

637+
--echo #
638+
--echo # MDEV-29954 Unique hash key on column prefix is computed incorrectly
639+
--echo #
640+
create table t1 (c char(10),unique key a using hash (c(1)));
641+
insert into t1 values (0);
642+
check table t1 extended;
643+
drop table t1;
644+
637645
--echo #
638646
--echo # End of 10.5 tests
639647
--echo #

sql/field.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7566,6 +7566,19 @@ int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) const
75667566
}
75677567

75687568

7569+
int Field_string::cmp_prefix(const uchar *a_ptr, const uchar *b_ptr,
7570+
size_t prefix_char_len) const
7571+
{
7572+
size_t field_len= table->field[field_index]->field_length;
7573+
7574+
return field_charset()->coll->strnncollsp_nchars(field_charset(),
7575+
a_ptr, field_len,
7576+
b_ptr, field_len,
7577+
prefix_char_len,
7578+
0);
7579+
}
7580+
7581+
75697582
void Field_string::sort_string(uchar *to,uint length)
75707583
{
75717584
#ifdef DBUG_ASSERT_EXISTS

sql/field.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4038,6 +4038,8 @@ class Field_string final :public Field_longstr {
40384038
String *val_str(String *, String *) override;
40394039
my_decimal *val_decimal(my_decimal *) override;
40404040
int cmp(const uchar *,const uchar *) const override;
4041+
int cmp_prefix(const uchar *a, const uchar *b, size_t prefix_char_len) const
4042+
override;
40414043
void sort_string(uchar *buff,uint length) override;
40424044
void update_data_type_statistics(Data_type_statistics *st) const override
40434045
{

sql/key.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ int key_rec_cmp(void *key_p, uchar *first_rec, uchar *second_rec)
605605
}
606606
/*
607607
No null values in the fields
608-
We use the virtual method cmp_max with a max length parameter.
608+
We use the virtual method cmp_prefix with a max length parameter.
609609
For most field types this translates into a cmp without
610610
max length. The exceptions are the BLOB and VARCHAR field types
611611
that take the max length into account.

sql/table.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,12 +1272,11 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
12721272
if (keypart->key_part_flag & HA_PART_KEY_SEG)
12731273
{
12741274
int length= keypart->length/keypart->field->charset()->mbmaxlen;
1275+
Field *kpf= table->field[keypart->field->field_index];
12751276
list_item= new (mem_root) Item_func_left(thd,
1276-
new (mem_root) Item_field(thd, keypart->field),
1277+
new (mem_root) Item_field(thd, kpf),
12771278
new (mem_root) Item_int(thd, length));
12781279
list_item->fix_fields(thd, NULL);
1279-
keypart->field->vcol_info=
1280-
table->field[keypart->field->field_index]->vcol_info;
12811280
}
12821281
else
12831282
list_item= new (mem_root) Item_field(thd, keypart->field);

0 commit comments

Comments
 (0)