mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Bug #13601: Wrong int type for bit
The wrong value was being reported as the field_length for BIT fields, resulting in confusion for at least Connector/J. The field_length is now always the number of bits in the field, as it should be.
This commit is contained in:
parent
0903941d05
commit
1a59580dcd
8 changed files with 75 additions and 39 deletions
|
@ -564,3 +564,12 @@ b1+0 sum(b1) sum(b2)
|
|||
1 4 4
|
||||
2 2 2
|
||||
drop table t1, t2;
|
||||
create table t1 (a bit(7));
|
||||
insert into t1 values (0x60);
|
||||
select * from t1;
|
||||
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||
def test t1 t1 a a 16 7 1 Y 0 0 63
|
||||
a
|
||||
`
|
||||
drop table t1;
|
||||
End of 5.0 tests
|
||||
|
|
|
@ -402,3 +402,12 @@ t1 CREATE TABLE `t1` (
|
|||
`b` bit(10) default NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
create table t1 (a bit(7)) engine=innodb;
|
||||
insert into t1 values (0x60);
|
||||
select * from t1;
|
||||
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||
def test t1 t1 a a 16 7 1 Y 0 0 63
|
||||
a
|
||||
`
|
||||
drop table t1;
|
||||
End of 5.0 tests
|
||||
|
|
|
@ -227,3 +227,15 @@ select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1;
|
|||
select 1 from t1 join t2 on b1 = b2 group by b1 order by 1;
|
||||
select b1+0,sum(b1), sum(b2) from t1 join t2 on b1 = b2 group by b1 order by 1;
|
||||
drop table t1, t2;
|
||||
|
||||
#
|
||||
# Bug #13601: Wrong field length reported for BIT fields
|
||||
#
|
||||
create table t1 (a bit(7));
|
||||
insert into t1 values (0x60);
|
||||
--enable_metadata
|
||||
select * from t1;
|
||||
--disable_metadata
|
||||
drop table t1;
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
|
|
@ -133,3 +133,15 @@ show create table t1;
|
|||
alter table t1 engine=innodb;
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Bug #13601: Wrong field length reported for BIT fields
|
||||
#
|
||||
create table t1 (a bit(7)) engine=innodb;
|
||||
insert into t1 values (0x60);
|
||||
--enable_metadata
|
||||
select * from t1;
|
||||
--disable_metadata
|
||||
drop table t1;
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
|
53
sql/field.cc
53
sql/field.cc
|
@ -7918,9 +7918,10 @@ Field_bit::Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
|
|||
uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
|
||||
enum utype unireg_check_arg, const char *field_name_arg,
|
||||
struct st_table *table_arg)
|
||||
: Field(ptr_arg, len_arg >> 3, null_ptr_arg, null_bit_arg,
|
||||
: Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
|
||||
unireg_check_arg, field_name_arg, table_arg),
|
||||
bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7)
|
||||
bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7),
|
||||
bytes_in_rec(len_arg / 8)
|
||||
{
|
||||
/*
|
||||
Ensure that Field::eq() can distinguish between two different bit fields.
|
||||
|
@ -7956,14 +7957,14 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
|
|||
int delta;
|
||||
|
||||
for (; length && !*from; from++, length--); // skip left 0's
|
||||
delta= field_length - length;
|
||||
delta= bytes_in_rec - length;
|
||||
|
||||
if (delta < -1 ||
|
||||
(delta == -1 && (uchar) *from > ((1 << bit_len) - 1)) ||
|
||||
(!bit_len && delta < 0))
|
||||
{
|
||||
set_rec_bits(0xff, bit_ptr, bit_ofs, bit_len);
|
||||
memset(ptr, 0xff, field_length);
|
||||
memset(ptr, 0xff, bytes_in_rec);
|
||||
if (table->in_use->really_abort_on_warning())
|
||||
set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
|
||||
else
|
||||
|
@ -7991,7 +7992,7 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
|
|||
set_rec_bits((uchar) *from, bit_ptr, bit_ofs, bit_len);
|
||||
from++;
|
||||
}
|
||||
memcpy(ptr, from, field_length);
|
||||
memcpy(ptr, from, bytes_in_rec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -8032,10 +8033,10 @@ longlong Field_bit::val_int(void)
|
|||
if (bit_len)
|
||||
{
|
||||
bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
|
||||
bits<<= (field_length * 8);
|
||||
bits<<= (bytes_in_rec * 8);
|
||||
}
|
||||
|
||||
switch (field_length) {
|
||||
switch (bytes_in_rec) {
|
||||
case 0: return bits;
|
||||
case 1: return bits | (ulonglong) (uchar) ptr[0];
|
||||
case 2: return bits | mi_uint2korr(ptr);
|
||||
|
@ -8044,7 +8045,7 @@ longlong Field_bit::val_int(void)
|
|||
case 5: return bits | mi_uint5korr(ptr);
|
||||
case 6: return bits | mi_uint6korr(ptr);
|
||||
case 7: return bits | mi_uint7korr(ptr);
|
||||
default: return mi_uint8korr(ptr + field_length - sizeof(longlong));
|
||||
default: return mi_uint8korr(ptr + bytes_in_rec - sizeof(longlong));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8097,7 +8098,7 @@ int Field_bit::cmp_offset(uint row_offset)
|
|||
if ((flag= (int) (bits_a - bits_b)))
|
||||
return flag;
|
||||
}
|
||||
return memcmp(ptr, ptr + row_offset, field_length);
|
||||
return memcmp(ptr, ptr + row_offset, bytes_in_rec);
|
||||
}
|
||||
|
||||
|
||||
|
@ -8109,7 +8110,7 @@ void Field_bit::get_key_image(char *buff, uint length, imagetype type)
|
|||
*buff++= bits;
|
||||
length--;
|
||||
}
|
||||
memcpy(buff, ptr, min(length, field_length));
|
||||
memcpy(buff, ptr, min(length, bytes_in_rec));
|
||||
}
|
||||
|
||||
|
||||
|
@ -8117,22 +8118,22 @@ void Field_bit::sql_type(String &res) const
|
|||
{
|
||||
CHARSET_INFO *cs= res.charset();
|
||||
ulong length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
|
||||
"bit(%d)",
|
||||
(int) field_length * 8 + bit_len);
|
||||
"bit(%d)", (int) field_length);
|
||||
res.length((uint) length);
|
||||
}
|
||||
|
||||
|
||||
char *Field_bit::pack(char *to, const char *from, uint max_length)
|
||||
{
|
||||
uint length= min(field_length + (bit_len > 0), max_length);
|
||||
DBUG_ASSERT(max_length);
|
||||
uint length;
|
||||
if (bit_len)
|
||||
{
|
||||
uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
|
||||
*to++= bits;
|
||||
length--;
|
||||
}
|
||||
memcpy(to, from, length);
|
||||
length= min(bytes_in_rec, max_length - (bit_len > 0));
|
||||
memcpy(to, from, length);
|
||||
return to + length;
|
||||
}
|
||||
|
||||
|
@ -8144,8 +8145,8 @@ const char *Field_bit::unpack(char *to, const char *from)
|
|||
set_rec_bits(*from, bit_ptr, bit_ofs, bit_len);
|
||||
from++;
|
||||
}
|
||||
memcpy(to, from, field_length);
|
||||
return from + field_length;
|
||||
memcpy(to, from, bytes_in_rec);
|
||||
return from + bytes_in_rec;
|
||||
}
|
||||
|
||||
|
||||
|
@ -8159,26 +8160,25 @@ Field_bit_as_char::Field_bit_as_char(char *ptr_arg, uint32 len_arg,
|
|||
const char *field_name_arg,
|
||||
struct st_table *table_arg)
|
||||
: Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, 0,
|
||||
0, unireg_check_arg, field_name_arg, table_arg),
|
||||
create_length(len_arg)
|
||||
0, unireg_check_arg, field_name_arg, table_arg)
|
||||
{
|
||||
bit_len= 0;
|
||||
field_length= ((len_arg + 7) & ~7) / 8;
|
||||
bytes_in_rec= (len_arg + 7) / 8;
|
||||
}
|
||||
|
||||
|
||||
int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
|
||||
{
|
||||
int delta;
|
||||
uchar bits= create_length & 7;
|
||||
uchar bits= field_length & 7;
|
||||
|
||||
for (; length && !*from; from++, length--); // skip left 0's
|
||||
delta= field_length - length;
|
||||
delta= bytes_in_rec - length;
|
||||
|
||||
if (delta < 0 ||
|
||||
(delta == 0 && bits && (uint) (uchar) *from >= (uint) (1 << bits)))
|
||||
{
|
||||
memset(ptr, 0xff, field_length);
|
||||
memset(ptr, 0xff, bytes_in_rec);
|
||||
if (bits)
|
||||
*ptr&= ((1 << bits) - 1); /* set first byte */
|
||||
if (table->in_use->really_abort_on_warning())
|
||||
|
@ -8197,7 +8197,7 @@ void Field_bit_as_char::sql_type(String &res) const
|
|||
{
|
||||
CHARSET_INFO *cs= res.charset();
|
||||
ulong length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
|
||||
"bit(%d)", (int) create_length);
|
||||
"bit(%d)", (int) field_length);
|
||||
res.length((uint) length);
|
||||
}
|
||||
|
||||
|
@ -8923,11 +8923,6 @@ create_field::create_field(Field *old_field,Field *orig_field)
|
|||
geom_type= ((Field_geom*)old_field)->geom_type;
|
||||
break;
|
||||
#endif
|
||||
case FIELD_TYPE_BIT:
|
||||
length= (old_field->key_type() == HA_KEYTYPE_BIT) ?
|
||||
((Field_bit *) old_field)->bit_len + length * 8 :
|
||||
((Field_bit_as_char *) old_field)->create_length;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
14
sql/field.h
14
sql/field.h
|
@ -1303,17 +1303,18 @@ public:
|
|||
uchar *bit_ptr; // position in record where 'uneven' bits store
|
||||
uchar bit_ofs; // offset to 'uneven' high bits
|
||||
uint bit_len; // number of 'uneven' high bits
|
||||
uint bytes_in_rec;
|
||||
Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
|
||||
uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
|
||||
enum utype unireg_check_arg, const char *field_name_arg,
|
||||
struct st_table *table_arg);
|
||||
enum_field_types type() const { return FIELD_TYPE_BIT; }
|
||||
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; }
|
||||
uint32 key_length() const { return (uint32) field_length + (bit_len > 0); }
|
||||
uint32 max_length() { return (uint32) field_length * 8 + bit_len; }
|
||||
uint32 key_length() const { return (uint32) (field_length + 7) / 8; }
|
||||
uint32 max_length() { return field_length; }
|
||||
uint size_of() const { return sizeof(*this); }
|
||||
Item_result result_type () const { return INT_RESULT; }
|
||||
void reset(void) { bzero(ptr, field_length); }
|
||||
void reset(void) { bzero(ptr, bytes_in_rec); }
|
||||
int store(const char *to, uint length, CHARSET_INFO *charset);
|
||||
int store(double nr);
|
||||
int store(longlong nr, bool unsigned_val);
|
||||
|
@ -1335,9 +1336,8 @@ public:
|
|||
{ Field_bit::store(buff, length, &my_charset_bin); }
|
||||
void sort_string(char *buff, uint length)
|
||||
{ get_key_image(buff, length, itRAW); }
|
||||
uint32 pack_length() const
|
||||
{ return (uint32) field_length + (bit_len > 0); }
|
||||
uint32 pack_length_in_rec() const { return field_length; }
|
||||
uint32 pack_length() const { return (uint32) (field_length + 7) / 8; }
|
||||
uint32 pack_length_in_rec() const { return bytes_in_rec; }
|
||||
void sql_type(String &str) const;
|
||||
char *pack(char *to, const char *from, uint max_length=~(uint) 0);
|
||||
const char *unpack(char* to, const char *from);
|
||||
|
@ -1354,13 +1354,11 @@ public:
|
|||
|
||||
class Field_bit_as_char: public Field_bit {
|
||||
public:
|
||||
uchar create_length;
|
||||
Field_bit_as_char(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
|
||||
uchar null_bit_arg,
|
||||
enum utype unireg_check_arg, const char *field_name_arg,
|
||||
struct st_table *table_arg);
|
||||
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
|
||||
uint32 max_length() { return (uint32) create_length; }
|
||||
uint size_of() const { return sizeof(*this); }
|
||||
int store(const char *to, uint length, CHARSET_INFO *charset);
|
||||
int store(double nr) { return Field_bit::store(nr); }
|
||||
|
|
|
@ -3819,7 +3819,7 @@ static int create_ndb_column(NDBCOL &col,
|
|||
break;
|
||||
case MYSQL_TYPE_BIT:
|
||||
{
|
||||
int no_of_bits= field->field_length*8 + ((Field_bit *) field)->bit_len;
|
||||
int no_of_bits= field->field_length;
|
||||
col.setType(NDBCOL::Bit);
|
||||
if (!no_of_bits)
|
||||
col.setLength(1);
|
||||
|
|
|
@ -192,7 +192,8 @@ void key_restore(byte *to_record, byte *from_key, KEY *key_info,
|
|||
Field_bit *field= (Field_bit *) (key_part->field);
|
||||
if (field->bit_len)
|
||||
{
|
||||
uchar bits= *(from_key + key_part->length - field->field_length -1);
|
||||
uchar bits= *(from_key + key_part->length -
|
||||
field->pack_length_in_rec() - 1);
|
||||
set_rec_bits(bits, to_record + key_part->null_offset +
|
||||
(key_part->null_bit == 128),
|
||||
field->bit_ofs, field->bit_len);
|
||||
|
|
Loading…
Reference in a new issue