diff --git a/mysql-test/main/long_unique_bugs.result b/mysql-test/main/long_unique_bugs.result index e5c14afd9c400..30ba3d0af9a73 100644 --- a/mysql-test/main/long_unique_bugs.result +++ b/mysql-test/main/long_unique_bugs.result @@ -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 # diff --git a/mysql-test/main/long_unique_bugs.test b/mysql-test/main/long_unique_bugs.test index 5fed7c72d9a26..12367b1deb8ce 100644 --- a/mysql-test/main/long_unique_bugs.test +++ b/mysql-test/main/long_unique_bugs.test @@ -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 # diff --git a/sql/field.cc b/sql/field.cc index 9e1e0931ef134..fc828dcc86c88 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -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 diff --git a/sql/field.h b/sql/field.h index 4a95a6e05568c..aeb2ae0d20a80 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4038,6 +4038,8 @@ class Field_string final :public Field_longstr { 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 { diff --git a/sql/key.cc b/sql/key.cc index d801bcc982b8f..2fa7d7066a4b5 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -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. diff --git a/sql/table.cc b/sql/table.cc index a5e33052d3f5b..f3d186f4d9db8 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -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);