Commit 629a4b1a authored by unknown's avatar unknown
Browse files

Bug#15583: BIN()/OCT()/CONV() do not work with BIT values

Converting BIT to a string (an intermediate step in conversion) does 
not yield an ASCII numeric string, so we skip that step for BIT and
get the integer value directly from the item.

This site in sql/item_strfunc.cc may be ripe for refactoring for
other types as well, where converting to a string is a waste of time.


mysql-test/r/type_bit.result:
  Test that conversion functions on BIT types work properly, including 
  NULL.
mysql-test/t/type_bit.test:
  Test that conversion functions on BIT types work properly.
sql/item_strfunc.cc:
  BIT is unlike the other numeric types, in that when we convert it
  to a String, it becomes a one-byte string with ordinal numeric value
  of the BIT field, not a several-byte string with the ASCII decimal
  representation.  As a special case for conversion functions, we take
  the integer directly from the bit type instead of representing it
  as a string in an intermediate step.
parent 1cf65f31
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -572,4 +572,34 @@ def test t1 t1 a a 16 7 1 Y 0 0 63
a
`
drop table t1;
create table bug15583(b BIT(8), n INT);
insert into bug15583 values(128, 128);
insert into bug15583 values(null, null);
insert into bug15583 values(0, 0);
insert into bug15583 values(255, 255);
select hex(b), bin(b), oct(b), hex(n), bin(n), oct(n) from bug15583;
hex(b)	bin(b)	oct(b)	hex(n)	bin(n)	oct(n)
80	10000000	200	80	10000000	200
NULL	NULL	NULL	NULL	NULL	NULL
0	0	0	0	0	0
FF	11111111	377	FF	11111111	377
select hex(b)=hex(n) as should_be_onetrue, bin(b)=bin(n) as should_be_onetrue, oct(b)=oct(n) as should_be_onetrue from bug15583;
should_be_onetrue	should_be_onetrue	should_be_onetrue
1	1	1
NULL	NULL	NULL
1	1	1
1	1	1
select hex(b + 0), bin(b + 0), oct(b + 0), hex(n), bin(n), oct(n) from bug15583;
hex(b + 0)	bin(b + 0)	oct(b + 0)	hex(n)	bin(n)	oct(n)
80	10000000	200	80	10000000	200
NULL	NULL	NULL	NULL	NULL	NULL
0	0	0	0	0	0
FF	11111111	377	FF	11111111	377
select conv(b, 10, 2), conv(b + 0, 10, 2) from bug15583;
conv(b, 10, 2)	conv(b + 0, 10, 2)
10000000	10000000
NULL	NULL
0	0
11111111	11111111
drop table bug15583;
End of 5.0 tests
+15 −0
Original line number Diff line number Diff line
@@ -238,4 +238,19 @@ select * from t1;
--disable_metadata
drop table t1;

#
# Bug#15583: BIN()/OCT()/CONV() do not work with BIT values
#
create table bug15583(b BIT(8), n INT);
insert into bug15583 values(128, 128);
insert into bug15583 values(null, null);
insert into bug15583 values(0, 0);
insert into bug15583 values(255, 255);
select hex(b), bin(b), oct(b), hex(n), bin(n), oct(n) from bug15583;
select hex(b)=hex(n) as should_be_onetrue, bin(b)=bin(n) as should_be_onetrue, oct(b)=oct(n) as should_be_onetrue from bug15583;
select hex(b + 0), bin(b + 0), oct(b + 0), hex(n), bin(n), oct(n) from bug15583; 
select conv(b, 10, 2), conv(b + 0, 10, 2) from bug15583;
drop table bug15583;


--echo End of 5.0 tests
+24 −8
Original line number Diff line number Diff line
@@ -2360,14 +2360,30 @@ String *Item_func_conv::val_str(String *str)
      abs(from_base) > 36 || abs(from_base) < 2 || !(res->length()))
  {
    null_value= 1;
    return 0;
    return NULL;
  }
  null_value= 0;
  unsigned_flag= !(from_base < 0);

  if (args[0]->field_type() == MYSQL_TYPE_BIT) 
  {
    /* 
     Special case: The string representation of BIT doesn't resemble the
     decimal representation, so we shouldn't change it to string and then to
     decimal. 
    */
    dec= args[0]->val_int();
  }
  else
  {
    if (from_base < 0)
    dec= my_strntoll(res->charset(),res->ptr(),res->length(),-from_base,&endptr,&err);
      dec= my_strntoll(res->charset(), res->ptr(), res->length(),
                       -from_base, &endptr, &err);
    else
    dec= (longlong) my_strntoull(res->charset(),res->ptr(),res->length(),from_base,&endptr,&err);
      dec= (longlong) my_strntoull(res->charset(), res->ptr(), res->length(),
                                   from_base, &endptr, &err);
  }

  ptr= longlong2str(dec, ans, to_base);
  if (str->copy(ans, (uint32) (ptr-ans), default_charset()))
    return &my_empty_string;