diff --git a/mysql-test/r/partition_innodb.result b/mysql-test/r/partition_innodb.result index 5b1221dd64c..5e5931fdbf8 100644 --- a/mysql-test/r/partition_innodb.result +++ b/mysql-test/r/partition_innodb.result @@ -92,3 +92,18 @@ DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t0_aux; DROP TABLE IF EXISTS t0_definition; DROP TABLE IF EXISTS t0_template; +create table t1 (id varchar(64) primary key) engine=innodb +partition by key(id) partitions 5; +insert into t1 values ('a'); +insert into t1 values ('aa'); +insert into t1 values ('aaa'); +select * from t1 where id = 'a'; +id +a +select * from t1 where id = 'aa'; +id +aa +select * from t1 where id = 'aaa'; +id +aaa +drop table t1; diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index 950a83c6d4f..ee294242bf7 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -31,7 +31,7 @@ id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t2 p0,p1 ALL NULL NULL NULL NULL 3 Using where explain partitions select * from t2 where a=1 and b=1; id select_type table partitions type possible_keys key key_len ref rows Extra -1 SIMPLE t2 p0 ALL NULL NULL NULL NULL 3 Using where +1 SIMPLE t2 p0 ALL NULL NULL NULL NULL 2 Using where create table t3 ( a int ) diff --git a/mysql-test/t/partition_innodb.test b/mysql-test/t/partition_innodb.test index 6a95dd7c8b0..fb20f573a79 100644 --- a/mysql-test/t/partition_innodb.test +++ b/mysql-test/t/partition_innodb.test @@ -66,3 +66,15 @@ DROP TABLE IF EXISTS t0_definition; DROP TABLE IF EXISTS t0_template; --enable_warnings +# +# Bug#20086: Can't get data from key partitioned tables with VARCHAR key +# +create table t1 (id varchar(64) primary key) engine=innodb +partition by key(id) partitions 5; +insert into t1 values ('a'); +insert into t1 values ('aa'); +insert into t1 values ('aaa'); +select * from t1 where id = 'a'; +select * from t1 where id = 'aa'; +select * from t1 where id = 'aaa'; +drop table t1; diff --git a/sql/field.cc b/sql/field.cc index b51e5b63779..0105c780d12 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1243,6 +1243,21 @@ uint Field::offset() } +void Field::hash(ulong *nr, ulong *nr2) +{ + if (is_null()) + { + *nr^= (*nr << 1) | 1; + } + else + { + uint len= pack_length(); + CHARSET_INFO *cs= charset(); + cs->coll->hash_sort(cs, (uchar*) ptr, len, nr, nr2); + } +} + + void Field::copy_from_tmp(int row_offset) { memcpy(ptr,ptr+row_offset,pack_length()); @@ -6923,6 +6938,21 @@ uint Field_varstring::is_equal(create_field *new_field) } +void Field_varstring::hash(ulong *nr, ulong *nr2) +{ + if (is_null()) + { + *nr^= (*nr << 1) | 1; + } + else + { + uint len= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); + CHARSET_INFO *cs= charset(); + cs->coll->hash_sort(cs, (uchar*) ptr + length_bytes, len, nr, nr2); + } +} + + /**************************************************************************** ** blob type ** A blob is saved as a length and a pointer. The length is stored in the diff --git a/sql/field.h b/sql/field.h index 2ac7ec2c69d..6012e6cdd70 100644 --- a/sql/field.h +++ b/sql/field.h @@ -351,6 +351,8 @@ public: return field_length / charset()->mbmaxlen; } + /* Hash value */ + virtual void hash(ulong *nr, ulong *nr2); friend bool reopen_table(THD *,struct st_table *,bool); friend int cre_myisam(my_string name, register TABLE *form, uint options, ulonglong auto_increment_value); @@ -1120,6 +1122,7 @@ public: char *new_ptr, uchar *new_null_ptr, uint new_null_bit); uint is_equal(create_field *new_field); + void hash(ulong *nr, ulong *nr2); }; diff --git a/sql/key.cc b/sql/key.cc index 11dd267875f..69557d971e8 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -210,9 +210,13 @@ void key_restore(byte *to_record, byte *from_key, KEY *key_info, } else if (key_part->key_part_flag & HA_VAR_LENGTH_PART) { + my_bitmap_map *old_map; key_length-= HA_KEY_BLOB_LENGTH; length= min(key_length, key_part->length); + old_map= dbug_tmp_use_all_columns(key_part->field->table, + key_part->field->table->write_set); key_part->field->set_key_image((char *) from_key, length); + dbug_tmp_restore_column_map(key_part->field->table->write_set, old_map); from_key+= HA_KEY_BLOB_LENGTH; } else diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 00c15c2dbca..8eb9bfa1782 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2103,26 +2103,15 @@ static inline longlong part_val_int(Item *item_expr) static uint32 calculate_key_value(Field **field_array) { - uint32 hashnr= 0; + ulong nr1= 1; ulong nr2= 4; do { Field *field= *field_array; - if (field->is_null()) - { - hashnr^= (hashnr << 1) | 1; - } - else - { - uint len= field->pack_length(); - ulong nr1= 1; - CHARSET_INFO *cs= field->charset(); - cs->coll->hash_sort(cs, (uchar*)field->ptr, len, &nr1, &nr2); - hashnr^= (uint32)nr1; - } + field->hash(&nr1, &nr2); } while (*(++field_array)); - return hashnr; + return (uint32) nr1; }