From 444587d8a3c4b91421cd4cfd7bda2e3f4d1aebe4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 16 Jan 2018 23:00:21 +0100 Subject: BIT field woes * get_rec_bits() was always reading two bytes, even if the bit field contained only of one byte * In various places the code used field->pack_length() bytes starting from field->ptr, while it should be field->pack_length_in_rec() * Field_bit::key_cmp and Field_bit::cmp_max passed field_length as an argument to memcmp(), but field_length is the number of bits! --- include/my_compare.h | 24 +++++++++++++----------- sql/field.cc | 6 +++--- sql/field_conv.cc | 6 +++--- sql/sql_join_cache.cc | 2 +- sql/sql_select.cc | 2 +- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/include/my_compare.h b/include/my_compare.h index 0db22b593f4..87f0aa8f3ca 100644 --- a/include/my_compare.h +++ b/include/my_compare.h @@ -91,17 +91,19 @@ typedef struct st_HA_KEYSEG /* Key-portion */ #define size_to_store_key_length(length) ((length) < 255 ? 1 : 3) -#define get_rec_bits(bit_ptr, bit_ofs, bit_len) \ - (((((uint16) (bit_ptr)[1] << 8) | (uint16) (bit_ptr)[0]) >> (bit_ofs)) & \ - ((1 << (bit_len)) - 1)) - -#define set_rec_bits(bits, bit_ptr, bit_ofs, bit_len) \ -{ \ - (bit_ptr)[0]= ((bit_ptr)[0] & ~(((1 << (bit_len)) - 1) << (bit_ofs))) | \ - ((bits) << (bit_ofs)); \ - if ((bit_ofs) + (bit_len) > 8) \ - (bit_ptr)[1]= ((bit_ptr)[1] & ~((1 << ((bit_len) - 8 + (bit_ofs))) - 1)) | \ - ((bits) >> (8 - (bit_ofs))); \ +static inline uint16 get_rec_bits(const uchar *ptr, uchar ofs, uint len) +{ + uint16 val= ptr[0]; + if (ofs + len > 8) + val|= (uint16)(ptr[1]) << 8; + return (val >> ofs) & ((1 << len) - 1); +} + +static inline void set_rec_bits(uint16 bits, uchar *ptr, uchar ofs, uint len) +{ + ptr[0]= (ptr[0] & ~(((1 << len) - 1) << ofs)) | (bits << ofs); + if (ofs + len > 8) + ptr[1]= (ptr[1] & ~((1 << (len - 8 + ofs)) - 1)) | (bits >> (8 - ofs)); } #define clr_rec_bits(bit_ptr, bit_ofs, bit_len) \ diff --git a/sql/field.cc b/sql/field.cc index 08ba437fa30..5b111ab5e03 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1758,7 +1758,7 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) { uint store_length; copy->str= ptr; - copy->length= pack_length(); + copy->length= pack_length_in_rec(); copy->field= this; if (flags & BLOB_FLAG) { @@ -8422,7 +8422,7 @@ int Field_bit::cmp_max(const uchar *a, const uchar *b, uint max_len) if ((flag= (int) (bits_a - bits_b))) return flag; } - return memcmp(a, b, field_length); + return memcmp(a, b, bytes_in_rec); } @@ -8437,7 +8437,7 @@ int Field_bit::key_cmp(const uchar *str, uint length) str++; length--; } - return memcmp(ptr, str, length); + return memcmp(ptr, str, bytes_in_rec); } diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 5781f1da576..09792aa1660 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -589,7 +589,7 @@ void Copy_field::set(uchar *to,Field *from) { from_ptr=from->ptr; to_ptr=to; - from_length=from->pack_length(); + from_length=from->pack_length_in_rec(); if (from->maybe_null()) { from_null_ptr=from->null_ptr; @@ -640,9 +640,9 @@ void Copy_field::set(Field *to,Field *from,bool save) from_field=from; to_field=to; from_ptr=from->ptr; - from_length=from->pack_length(); + from_length=from->pack_length_in_rec(); to_ptr= to->ptr; - to_length=to_field->pack_length(); + to_length=to_field->pack_length_in_rec(); // set up null handling from_null_ptr=to_null_ptr=0; diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index 820ac75c885..13f06024b22 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -394,7 +394,7 @@ void JOIN_CACHE::create_flag_fields() TABLE *table= tab->table; /* Create a field for the null bitmap from table if needed */ - if (tab->used_null_fields || tab->used_uneven_bit_fields) + if (tab->used_null_fields || tab->used_uneven_bit_fields) length+= add_flag_field_to_join_cache(table->null_flags, table->s->null_bytes, ©); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8c2e90d8e57..c752d48e7c5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15537,7 +15537,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List &fields, else { field->set_notnull(); - memcpy(field->ptr, orig_field->ptr, field->pack_length()); + memcpy(field->ptr, orig_field->ptr, field->pack_length_in_rec()); } orig_field->move_field_offset(-diff); // Back to record[0] } -- cgit v1.2.1