summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/m_ctype.h2
-rw-r--r--include/my_base.h3
-rw-r--r--include/my_handler.h17
-rw-r--r--include/mysql_com.h2
-rw-r--r--myisam/mi_key.c33
-rw-r--r--myisam/mi_open.c16
-rw-r--r--mysql-test/r/type_bit.result364
-rw-r--r--mysql-test/t/type_bit.test106
-rw-r--r--mysys/my_handler.c1
-rw-r--r--sql/field.cc247
-rw-r--r--sql/field.h49
-rw-r--r--sql/field_conv.cc3
-rw-r--r--sql/ha_myisam.cc7
-rw-r--r--sql/ha_myisam.h2
-rw-r--r--sql/handler.h1
-rw-r--r--sql/item.cc55
-rw-r--r--sql/item.h13
-rw-r--r--sql/key.cc30
-rw-r--r--sql/protocol.cc2
-rw-r--r--sql/sql_lex.cc35
-rw-r--r--sql/sql_parse.cc13
-rw-r--r--sql/sql_select.cc6
-rw-r--r--sql/sql_table.cc14
-rw-r--r--sql/sql_yacc.yy42
-rw-r--r--sql/table.cc23
-rw-r--r--sql/unireg.cc2
-rw-r--r--sql/unireg.h2
27 files changed, 1050 insertions, 40 deletions
diff --git a/include/m_ctype.h b/include/m_ctype.h
index d7a4af08b0f..50673b6d494 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -85,7 +85,7 @@ enum my_lex_states
{
MY_LEX_START, MY_LEX_CHAR, MY_LEX_IDENT,
MY_LEX_IDENT_SEP, MY_LEX_IDENT_START,
- MY_LEX_REAL, MY_LEX_HEX_NUMBER,
+ MY_LEX_REAL, MY_LEX_HEX_NUMBER, MY_LEX_BIN_NUMBER,
MY_LEX_CMP_OP, MY_LEX_LONG_CMP_OP, MY_LEX_STRING, MY_LEX_COMMENT, MY_LEX_END,
MY_LEX_OPERATOR_OR_IDENT, MY_LEX_NUMBER_IDENT, MY_LEX_INT_OR_REAL,
MY_LEX_REAL_OR_POINT, MY_LEX_BOOL, MY_LEX_EOL, MY_LEX_ESCAPE,
diff --git a/include/my_base.h b/include/my_base.h
index 88d3ec0b270..a1b14ecbb65 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -182,7 +182,8 @@ enum ha_base_keytype {
HA_KEYTYPE_UINT24=13,
HA_KEYTYPE_INT8=14,
HA_KEYTYPE_VARTEXT=15, /* Key is sorted as letters */
- HA_KEYTYPE_VARBINARY=16 /* Key is sorted as unsigned chars */
+ HA_KEYTYPE_VARBINARY=16, /* Key is sorted as unsigned chars */
+ HA_KEYTYPE_BIT=17
};
#define HA_MAX_KEYTYPE 31 /* Must be log2-1 */
diff --git a/include/my_handler.h b/include/my_handler.h
index d81c4590f8e..9ddc0c61eee 100644
--- a/include/my_handler.h
+++ b/include/my_handler.h
@@ -34,6 +34,8 @@ typedef struct st_HA_KEYSEG /* Key-portion */
uint32 start; /* Start of key in record */
uint32 null_pos; /* position to NULL indicator */
CHARSET_INFO *charset;
+ uint8 bit_length; /* Length of bit part */
+ uint16 bit_pos; /* Position to bit part */
} HA_KEYSEG;
#define get_key_length(length,key) \
@@ -64,6 +66,21 @@ typedef struct st_HA_KEYSEG /* Key-portion */
{ *(key)=255; mi_int2store((key)+1,(length)); (key)+=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_ofs)) - 1)) | \
+ ((bits) << (bit_ofs)); \
+ if ((bit_ofs) + (bit_len) > 8) \
+ (bit_ptr)[1]= ((bits) & ((1 << (bit_len)) - 1)) >> (8 - (bit_ofs)); \
+}
+
+#define clr_rec_bits(bit_ptr, bit_ofs, bit_len) \
+ set_rec_bits(0, bit_ptr, bit_ofs, bit_len)
+
extern int mi_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint ,
my_bool, my_bool);
extern int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 6a03fe90eb5..59b2ee743ec 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -210,6 +210,7 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
MYSQL_TYPE_DATE, MYSQL_TYPE_TIME,
MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR,
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
+ MYSQL_TYPE_BIT,
MYSQL_TYPE_ENUM=247,
MYSQL_TYPE_SET=248,
MYSQL_TYPE_TINY_BLOB=249,
@@ -250,6 +251,7 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
#define FIELD_TYPE_CHAR MYSQL_TYPE_TINY
#define FIELD_TYPE_INTERVAL MYSQL_TYPE_ENUM
#define FIELD_TYPE_GEOMETRY MYSQL_TYPE_GEOMETRY
+#define FIELD_TYPE_BIT MYSQL_TYPE_BIT
/* Shutdown/kill enums and constants */
diff --git a/myisam/mi_key.c b/myisam/mi_key.c
index a775e0ba2d0..c1400033254 100644
--- a/myisam/mi_key.c
+++ b/myisam/mi_key.c
@@ -82,6 +82,19 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
length);
pos= (byte*) record+keyseg->start;
+ if (type == HA_KEYTYPE_BIT)
+ {
+ if (keyseg->bit_length)
+ {
+ uchar bits= get_rec_bits((uchar*) record + keyseg->bit_pos,
+ keyseg->bit_start, keyseg->bit_length);
+ *key++= bits;
+ length--;
+ }
+ memcpy((byte*) key, pos, length);
+ key+= length;
+ continue;
+ }
if (keyseg->flag & HA_SPACE_PACK)
{
end=pos+length;
@@ -333,6 +346,26 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
}
record[keyseg->null_pos]&= ~keyseg->null_bit;
}
+ if (keyseg->type == HA_KEYTYPE_BIT)
+ {
+ uint length= keyseg->length;
+
+ if (keyseg->bit_length)
+ {
+ uchar bits= *key++;
+ set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
+ keyseg->bit_length);
+ length--;
+ }
+ else
+ {
+ clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
+ keyseg->bit_length);
+ }
+ memcpy(record + keyseg->start, (byte*) key, length);
+ key+= length;
+ continue;
+ }
if (keyseg->flag & HA_SPACE_PACK)
{
uint length;
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index 562227d2f03..615e6bb5dd1 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -1049,12 +1049,13 @@ int mi_keyseg_write(File file, const HA_KEYSEG *keyseg)
*ptr++ =keyseg->null_bit;
*ptr++ =keyseg->bit_start;
*ptr++ =keyseg->bit_end;
- *ptr++ =0; /* Not used */
+ *ptr++= keyseg->bit_length;
mi_int2store(ptr,keyseg->flag); ptr+=2;
mi_int2store(ptr,keyseg->length); ptr+=2;
mi_int4store(ptr,keyseg->start); ptr+=4;
- mi_int4store(ptr,keyseg->null_pos); ptr+=4;
-
+ mi_int4store(ptr, keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos);
+ ptr+=4;
+
return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
}
@@ -1066,12 +1067,19 @@ char *mi_keyseg_read(char *ptr, HA_KEYSEG *keyseg)
keyseg->null_bit = *ptr++;
keyseg->bit_start = *ptr++;
keyseg->bit_end = *ptr++;
- ptr++;
+ keyseg->bit_length = *ptr++;
keyseg->flag = mi_uint2korr(ptr); ptr +=2;
keyseg->length = mi_uint2korr(ptr); ptr +=2;
keyseg->start = mi_uint4korr(ptr); ptr +=4;
keyseg->null_pos = mi_uint4korr(ptr); ptr +=4;
keyseg->charset=0; /* Will be filled in later */
+ if (keyseg->null_bit)
+ keyseg->bit_pos= keyseg->null_pos + (keyseg->null_bit == 7);
+ else
+ {
+ keyseg->bit_pos= keyseg->null_pos;
+ keyseg->null_pos= 0;
+ }
return ptr;
}
diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result
new file mode 100644
index 00000000000..41d84584870
--- /dev/null
+++ b/mysql-test/r/type_bit.result
@@ -0,0 +1,364 @@
+select 0 + b'1';
+0 + b'1'
+1
+select 0 + b'0';
+0 + b'0'
+0
+select 0 + b'000001';
+0 + b'000001'
+1
+select 0 + b'000011';
+0 + b'000011'
+3
+select 0 + b'000101';
+0 + b'000101'
+5
+select 0 + b'000000';
+0 + b'000000'
+0
+select 0 + b'10000000';
+0 + b'10000000'
+128
+select 0 + b'11111111';
+0 + b'11111111'
+255
+select 0 + b'10000001';
+0 + b'10000001'
+129
+select 0 + b'1000000000000000';
+0 + b'1000000000000000'
+32768
+select 0 + b'1111111111111111';
+0 + b'1111111111111111'
+65535
+select 0 + b'1000000000000001';
+0 + b'1000000000000001'
+32769
+drop table if exists t1;
+create table t1 (a bit(65));
+ERROR 42000: Column length too big for column 'a' (max = 64); use BLOB instead
+create table t1 (a bit(0));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bit(1) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (a bit, key(a)) engine=innodb;
+ERROR 42000: The storage engine for the table doesn't support BIT FIELD
+create table t1 (a bit(64));
+insert into t1 values
+(b'1111111111111111111111111111111111111111111111111111111111111111'),
+(b'1000000000000000000000000000000000000000000000000000000000000000'),
+(b'0000000000000000000000000000000000000000000000000000000000000001'),
+(b'1010101010101010101010101010101010101010101010101010101010101010'),
+(b'0101010101010101010101010101010101010101010101010101010101010101');
+select hex(a) from t1;
+hex(a)
+FFFFFFFFFFFFFFFF
+8000000000000000
+1
+AAAAAAAAAAAAAAAA
+5555555555555555
+drop table t1;
+create table t1 (a bit);
+insert into t1 values (b'0'), (b'1'), (b'000'), (b'100'), (b'001');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 4
+select hex(a) from t1;
+hex(a)
+0
+1
+0
+1
+1
+alter table t1 add unique (a);
+ERROR 23000: Duplicate entry '' for key 1
+drop table t1;
+create table t1 (a bit(2));
+insert into t1 values (b'00'), (b'01'), (b'10'), (b'100');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 4
+select a+0 from t1;
+a+0
+0
+1
+2
+3
+alter table t1 add key (a);
+explain select a+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 2 NULL 4 Using index
+select a+0 from t1;
+a+0
+0
+1
+2
+3
+drop table t1;
+create table t1 (a bit(7), b bit(9), key(a, b));
+insert into t1 values
+(94, 46), (31, 438), (61, 152), (78, 123), (88, 411), (122, 118), (0, 177),
+(75, 42), (108, 67), (79, 349), (59, 188), (68, 206), (49, 345), (118, 380),
+(111, 368), (94, 468), (56, 379), (77, 133), (29, 399), (9, 363), (23, 36),
+(116, 390), (119, 368), (87, 351), (123, 411), (24, 398), (34, 202), (28, 499),
+(30, 83), (5, 178), (60, 343), (4, 245), (104, 280), (106, 446), (127, 403),
+(44, 307), (68, 454), (57, 135);
+explain select a+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 38 Using index
+select a+0 from t1;
+a+0
+0
+4
+5
+9
+23
+24
+28
+29
+30
+31
+34
+44
+49
+56
+57
+59
+60
+61
+68
+68
+75
+77
+78
+79
+87
+88
+94
+94
+104
+106
+108
+111
+116
+118
+119
+122
+123
+127
+explain select b+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 38 Using index
+select b+0 from t1;
+b+0
+177
+245
+178
+363
+36
+398
+499
+399
+83
+438
+202
+307
+345
+379
+135
+188
+343
+152
+206
+454
+42
+133
+123
+349
+351
+411
+46
+468
+280
+446
+67
+368
+390
+380
+368
+118
+411
+403
+explain select a+0, b+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 38 Using index
+select a+0, b+0 from t1;
+a+0 b+0
+0 177
+4 245
+5 178
+9 363
+23 36
+24 398
+28 499
+29 399
+30 83
+31 438
+34 202
+44 307
+49 345
+56 379
+57 135
+59 188
+60 343
+61 152
+68 206
+68 454
+75 42
+77 133
+78 123
+79 349
+87 351
+88 411
+94 46
+94 468
+104 280
+106 446
+108 67
+111 368
+116 390
+118 380
+119 368
+122 118
+123 411
+127 403
+explain select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 2 NULL 27 Using where; Using index; Using filesort
+select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+a+0 b+0
+44 307
+49 345
+56 379
+60 343
+68 206
+68 454
+79 349
+87 351
+88 411
+94 468
+104 280
+106 446
+111 368
+116 390
+118 380
+119 368
+123 411
+127 403
+explain select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 2 NULL 8 Using where; Using index; Using filesort
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+a+0 b+0
+57 135
+61 152
+59 188
+68 206
+44 307
+60 343
+49 345
+56 379
+68 454
+set @@max_length_for_sort_data=0;
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+a+0 b+0
+57 135
+61 152
+59 188
+68 206
+44 307
+60 343
+49 345
+56 379
+68 454
+select hex(min(a)) from t1;
+hex(min(a))
+0
+select hex(min(b)) from t1;
+hex(min(b))
+24
+select hex(min(a)), hex(max(a)), hex(min(b)), hex(max(b)) from t1;
+hex(min(a)) hex(max(a)) hex(min(b)) hex(max(b))
+0 7F 24 1F3
+drop table t1;
+create table t1 (a int not null, b bit, c bit(9), key(a, b, c));
+insert into t1 values
+(4, NULL, 1), (4, 0, 3), (2, 1, 4), (1, 1, 100), (4, 0, 23), (4, 0, 54),
+(56, 0, 22), (4, 1, 100), (23, 0, 1), (4, 0, 34);
+select a+0, b+0, c+0 from t1;
+a+0 b+0 c+0
+1 1 100
+2 1 4
+4 NULL 1
+4 0 3
+4 0 23
+4 0 34
+4 0 54
+4 1 100
+23 0 1
+56 0 22
+select hex(min(b)) from t1 where a = 4;
+hex(min(b))
+0
+select hex(min(c)) from t1 where a = 4 and b = 0;
+hex(min(c))
+3
+select hex(max(b)) from t1;
+hex(max(b))
+1
+select a+0, b+0, c+0 from t1 where a = 4 and b = 0 limit 2;
+a+0 b+0 c+0
+4 0 3
+4 0 23
+select a+0, b+0, c+0 from t1 order by b desc;
+a+0 b+0 c+0
+2 1 4
+1 1 100
+4 1 100
+4 0 3
+4 0 23
+4 0 54
+56 0 22
+23 0 1
+4 0 34
+4 NULL 1
+select a+0, b+0, c+0 from t1 order by c;
+a+0 b+0 c+0
+4 NULL 1
+23 0 1
+4 0 3
+2 1 4
+56 0 22
+4 0 23
+4 0 34
+4 0 54
+1 1 100
+4 1 100
+drop table t1;
+create table t1(a bit(2), b bit(2));
+insert into t1 (a) values (0x01), (0x03), (0x02);
+update t1 set b= concat(a);
+select a+0, b+0 from t1;
+a+0 b+0
+1 1
+3 3
+2 2
+drop table t1;
+create table t1 (a bit(7), key(a));
+insert into t1 values (44), (57);
+select a+0 from t1;
+a+0
+44
+57
+drop table t1;
diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test
new file mode 100644
index 00000000000..075fd5bce07
--- /dev/null
+++ b/mysql-test/t/type_bit.test
@@ -0,0 +1,106 @@
+#
+# testing of the BIT column type
+#
+
+select 0 + b'1';
+select 0 + b'0';
+select 0 + b'000001';
+select 0 + b'000011';
+select 0 + b'000101';
+select 0 + b'000000';
+select 0 + b'10000000';
+select 0 + b'11111111';
+select 0 + b'10000001';
+select 0 + b'1000000000000000';
+select 0 + b'1111111111111111';
+select 0 + b'1000000000000001';
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+--error 1074
+create table t1 (a bit(65));
+
+create table t1 (a bit(0));
+show create table t1;
+drop table t1;
+
+--error 1178
+create table t1 (a bit, key(a)) engine=innodb;
+
+create table t1 (a bit(64));
+insert into t1 values
+(b'1111111111111111111111111111111111111111111111111111111111111111'),
+(b'1000000000000000000000000000000000000000000000000000000000000000'),
+(b'0000000000000000000000000000000000000000000000000000000000000001'),
+(b'1010101010101010101010101010101010101010101010101010101010101010'),
+(b'0101010101010101010101010101010101010101010101010101010101010101');
+select hex(a) from t1;
+drop table t1;
+
+create table t1 (a bit);
+insert into t1 values (b'0'), (b'1'), (b'000'), (b'100'), (b'001');
+select hex(a) from t1;
+--error 1062
+alter table t1 add unique (a);
+drop table t1;
+
+create table t1 (a bit(2));
+insert into t1 values (b'00'), (b'01'), (b'10'), (b'100');
+select a+0 from t1;
+alter table t1 add key (a);
+explain select a+0 from t1;
+select a+0 from t1;
+drop table t1;
+
+create table t1 (a bit(7), b bit(9), key(a, b));
+insert into t1 values
+(94, 46), (31, 438), (61, 152), (78, 123), (88, 411), (122, 118), (0, 177),
+(75, 42), (108, 67), (79, 349), (59, 188), (68, 206), (49, 345), (118, 380),
+(111, 368), (94, 468), (56, 379), (77, 133), (29, 399), (9, 363), (23, 36),
+(116, 390), (119, 368), (87, 351), (123, 411), (24, 398), (34, 202), (28, 499),
+(30, 83), (5, 178), (60, 343), (4, 245), (104, 280), (106, 446), (127, 403),
+(44, 307), (68, 454), (57, 135);
+explain select a+0 from t1;
+select a+0 from t1;
+explain select b+0 from t1;
+select b+0 from t1;
+explain select a+0, b+0 from t1;
+select a+0, b+0 from t1;
+explain select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+explain select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+set @@max_length_for_sort_data=0;
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+select hex(min(a)) from t1;
+select hex(min(b)) from t1;
+select hex(min(a)), hex(max(a)), hex(min(b)), hex(max(b)) from t1;
+drop table t1;
+
+create table t1 (a int not null, b bit, c bit(9), key(a, b, c));
+insert into t1 values
+(4, NULL, 1), (4, 0, 3), (2, 1, 4), (1, 1, 100), (4, 0, 23), (4, 0, 54),
+(56, 0, 22), (4, 1, 100), (23, 0, 1), (4, 0, 34);
+select a+0, b+0, c+0 from t1;
+select hex(min(b)) from t1 where a = 4;
+select hex(min(c)) from t1 where a = 4 and b = 0;
+select hex(max(b)) from t1;
+select a+0, b+0, c+0 from t1 where a = 4 and b = 0 limit 2;
+select a+0, b+0, c+0 from t1 order by b desc;
+select a+0, b+0, c+0 from t1 order by c;
+drop table t1;
+
+create table t1(a bit(2), b bit(2));
+insert into t1 (a) values (0x01), (0x03), (0x02);
+update t1 set b= concat(a);
+select a+0, b+0 from t1;
+drop table t1;
+
+# Some magic numbers
+
+create table t1 (a bit(7), key(a));
+insert into t1 values (44), (57);
+select a+0 from t1;
+drop table t1;
diff --git a/mysys/my_handler.c b/mysys/my_handler.c
index cf8bde31e73..e4dc55964da 100644
--- a/mysys/my_handler.c
+++ b/mysys/my_handler.c
@@ -178,6 +178,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
}
break;
case HA_KEYTYPE_BINARY:
+ case HA_KEYTYPE_BIT:
if (keyseg->flag & HA_SPACE_PACK)
{
int a_length,b_length,pack_length;
diff --git a/sql/field.cc b/sql/field.cc
index 6f38bd3c85a..7b555571850 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -6048,6 +6048,227 @@ bool Field_num::eq_def(Field *field)
}
+/*
+ Bit field.
+
+ We store the first 0 - 6 uneven bits among the null bits
+ at the start of the record. The rest bytes are stored in
+ the record itself.
+
+ For example:
+
+ CREATE TABLE t1 (a int, b bit(17), c bit(21) not null, d bit(8));
+ We would store data as follows in the record:
+
+ Byte Bit
+ 1 7 - reserve for delete
+ 6 - null bit for 'a'
+ 5 - null bit for 'b'
+ 4 - first (high) bit of 'b'
+ 3 - first (high) bit of 'c'
+ 2 - second bit of 'c'
+ 1 - third bit of 'c'
+ 0 - forth bit of 'c'
+ 2 7 - firth bit of 'c'
+ 6 - null bit for 'd'
+ 3 - 6 four bytes for 'a'
+ 7 - 8 two bytes for 'b'
+ 9 - 10 two bytes for 'c'
+ 11 one byte for 'd'
+*/
+
+void Field_bit::make_field(Send_field *field)
+{
+ /* table_cache_key is not set for temp tables */
+ field->db_name= (orig_table->table_cache_key ? orig_table->table_cache_key :
+ "");
+ field->org_table_name= orig_table->real_name;
+ field->table_name= orig_table->table_name;
+ field->col_name= field->org_col_name= field_name;
+ field->charsetnr= charset()->number;
+ field->length= field_length;
+ field->type= type();
+ field->flags= table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
+ field->decimals= 0;
+}
+
+
+int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
+{
+ int delta;
+
+ for (; !*from && length; from++, length--); // skip left 0's
+ delta= field_length - 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);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ return 1;
+ }
+ /* delta is >= -1 here */
+ if (delta > 0)
+ {
+ if (bit_len)
+ clr_rec_bits(bit_ptr, bit_ofs, bit_len);
+ bzero(ptr, delta);
+ memcpy(ptr + delta, from, length);
+ }
+ else if (delta == 0)
+ {
+ if (bit_len)
+ clr_rec_bits(bit_ptr, bit_ofs, bit_len);
+ memcpy(ptr, from, length);
+ }
+ else
+ {
+ if (bit_len)
+ {
+ set_rec_bits((uchar) *from, bit_ptr, bit_ofs, bit_len);
+ from++;
+ }
+ memcpy(ptr, from, field_length);
+ }
+ return 0;
+}
+
+
+int Field_bit::store(double nr)
+{
+ return (Field_bit::store((longlong) nr));
+}
+
+
+int Field_bit::store(longlong nr)
+{
+ char buf[8];
+
+ mi_int8store(buf, nr);
+ return store(buf, 8, NULL);
+}
+
+
+double Field_bit::val_real(void)
+{
+ return (double) Field_bit::val_int();
+}
+
+
+longlong Field_bit::val_int(void)
+{
+ ulonglong bits= 0;
+ if (bit_len)
+ bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ bits<<= (field_length * 8);
+
+ switch (field_length) {
+ case 0: return bits;
+ case 1: return bits | (ulonglong) (uchar) ptr[0];
+ case 2: return bits | mi_uint2korr(ptr);
+ case 3: return bits | mi_uint3korr(ptr);
+ case 4: return bits | mi_uint4korr(ptr);
+ 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));
+ }
+}
+
+
+String *Field_bit::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ uint length= min(pack_length(), sizeof(longlong));
+ ulonglong bits= val_int();
+
+ val_buffer->alloc(length);
+ memcpy_fixed((char*) val_buffer->ptr(), (char*) &bits, length);
+ val_buffer->length(length);
+ val_buffer->set_charset(&my_charset_bin);
+ return val_buffer;
+}
+
+
+int Field_bit::key_cmp(const byte *str, uint length)
+{
+ if (bit_len)
+ {
+ int flag;
+ uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ if ((flag= (int) (bits - *str)))
+ return flag;
+ str++;
+ length--;
+ }
+ return bcmp(ptr, str, length);
+}
+
+
+int Field_bit::cmp_offset(uint row_offset)
+{
+ if (bit_len)
+ {
+ int flag;
+ uchar bits_a= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ uchar bits_b= get_rec_bits(bit_ptr + row_offset, bit_ofs, bit_len);
+ if ((flag= (int) (bits_a - bits_b)))
+ return flag;
+ }
+ return bcmp(ptr, ptr + row_offset, field_length);
+}
+
+
+void Field_bit::get_key_image(char *buff, uint length, imagetype type)
+{
+ if (bit_len)
+ {
+ uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ *buff++= bits;
+ length--;
+ }
+ memcpy(buff, ptr, min(length, field_length));
+}
+
+
+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);
+ 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);
+ if (bit_len)
+ {
+ uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ *to++= bits;
+ length--;
+ }
+ memcpy(to, from, length);
+ return to + length;
+}
+
+
+const char *Field_bit::unpack(char *to, const char *from)
+{
+ if (bit_len)
+ {
+ set_rec_bits(*from, bit_ptr, bit_ofs, bit_len);
+ from++;
+ }
+ memcpy(to, from, field_length);
+ return from + field_length;
+}
+
+
/*****************************************************************************
Handling of field and create_field
*****************************************************************************/
@@ -6124,6 +6345,7 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
case FIELD_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr;
case FIELD_TYPE_SET:
case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen
+ case FIELD_TYPE_BIT: return length / 8;
default: return 0;
}
return 0; // Keep compiler happy
@@ -6154,11 +6376,30 @@ Field *make_field(char *ptr, uint32 field_length,
const char *field_name,
struct st_table *table)
{
+ uchar *bit_ptr;
+ uchar bit_offset;
+ LINT_INIT(bit_ptr);
+ LINT_INIT(bit_offset);
+ if (field_type == FIELD_TYPE_BIT)
+ {
+ bit_ptr= null_pos;
+ bit_offset= null_bit;
+ if (f_maybe_null(pack_flag)) // if null field
+ {
+ bit_ptr+= (null_bit == 7); // shift bit_ptr and bit_offset
+ bit_offset= (bit_offset + 1) & 7;
+ }
+ }
+
if (!f_maybe_null(pack_flag))
{
null_pos=0;
null_bit=0;
}
+ else
+ {
+ null_bit= ((uchar) 1) << null_bit;
+ }
switch (field_type)
{
@@ -6280,6 +6521,9 @@ Field *make_field(char *ptr, uint32 field_length,
unireg_check, field_name, table, field_charset);
case FIELD_TYPE_NULL:
return new Field_null(ptr,field_length,unireg_check,field_name,table, field_charset);
+ case FIELD_TYPE_BIT:
+ return new Field_bit(ptr, field_length, null_pos, null_bit, bit_ptr,
+ bit_offset, unireg_check, field_name, table);
default: // Impossible (Wrong version)
break;
}
@@ -6338,6 +6582,9 @@ 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= ((Field_bit *) old_field)->bit_len + length * 8;
+ break;
default:
break;
}
diff --git a/sql/field.h b/sql/field.h
index e2411fb9400..cad8593117d 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -80,7 +80,7 @@ public:
FIELD_CAST_TIMESTAMP, FIELD_CAST_YEAR, FIELD_CAST_DATE, FIELD_CAST_NEWDATE,
FIELD_CAST_TIME, FIELD_CAST_DATETIME,
FIELD_CAST_STRING, FIELD_CAST_VARSTRING, FIELD_CAST_BLOB,
- FIELD_CAST_GEOM, FIELD_CAST_ENUM, FIELD_CAST_SET
+ FIELD_CAST_GEOM, FIELD_CAST_ENUM, FIELD_CAST_SET, FIELD_CAST_BIT
};
utype unireg_check;
@@ -1173,6 +1173,53 @@ public:
};
+class Field_bit :public Field {
+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
+ 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,
+ unireg_check_arg, field_name_arg, table_arg),
+ bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7)
+ { }
+ 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 + (bit_len > 0); }
+ uint size_of() const { return sizeof(*this); }
+ Item_result result_type () const { return INT_RESULT; }
+ void make_field(Send_field *);
+ void reset(void) { bzero(ptr, field_length); }
+ int store(const char *to, uint length, CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*, String *);
+ int cmp(const char *a, const char *b)
+ { return cmp_binary(a, b); }
+ int key_cmp(const byte *a, const byte *b)
+ { return cmp_binary(a, b); }
+ int key_cmp(const byte *str, uint length);
+ int cmp_offset(uint row_offset);
+ void get_key_image(char *buff, uint length, imagetype type);
+ void set_key_image(char *buff, uint length)
+ { 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); }
+ void sql_type(String &str) const;
+ field_cast_enum field_cast_type() { return FIELD_CAST_BIT; }
+ char *pack(char *to, const char *from, uint max_length=~(uint) 0);
+ const char *unpack(char* to, const char *from);
+};
+
+
/*
Create field class for CREATE TABLE
*/
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index f6cc851639a..f0887d8343a 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -485,6 +485,9 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
}
else
{
+ if (to->real_type() == FIELD_TYPE_BIT ||
+ from->real_type() == FIELD_TYPE_BIT)
+ return do_field_int;
// Check if identical fields
if (from->result_type() == STRING_RESULT)
{
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 726647cd131..c1516e61c88 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -1428,6 +1428,13 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
table_arg->blob_ptr_size);
}
+ else if (field->type() == FIELD_TYPE_BIT)
+ {
+ keydef[i].seg[j].bit_length= ((Field_bit *) field)->bit_len;
+ keydef[i].seg[j].bit_start= ((Field_bit *) field)->bit_ofs;
+ keydef[i].seg[j].bit_pos= (uint) (((Field_bit *) field)->bit_ptr -
+ (uchar*) table_arg->record[0]);
+ }
}
keyseg+=pos->key_parts;
}
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index 527e6a49aba..d2fe36c8357 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -47,7 +47,7 @@ class ha_myisam: public handler
int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
HA_DUPP_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME |
- HA_CAN_INSERT_DELAYED),
+ HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD),
can_enable_indexes(1)
{}
~ha_myisam() {}
diff --git a/sql/handler.h b/sql/handler.h
index c9adaefa888..e4ebe32f416 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -75,6 +75,7 @@
/* Table data are stored in separate files (for lower_case_table_names) */
#define HA_FILE_BASED (1 << 26)
#define HA_NO_VARCHAR (1 << 27)
+#define HA_CAN_BIT_FIELD (1 << 28) /* supports bit fields */
/* bits in index_flags(index_number) for what you can do with index */
diff --git a/sql/item.cc b/sql/item.cc
index f00a35fe628..9117105f26e 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2573,11 +2573,11 @@ void Item_real::print(String *str)
}
-/****************************************************************************
-** varbinary item
-** In string context this is a binary string
-** In number context this is a longlong value.
-****************************************************************************/
+/*
+ hex item
+ In string context this is a binary string.
+ In number context this is a longlong value.
+*/
inline uint char_val(char X)
{
@@ -2587,7 +2587,7 @@ inline uint char_val(char X)
}
-Item_varbinary::Item_varbinary(const char *str, uint str_length)
+Item_hex_string::Item_hex_string(const char *str, uint str_length)
{
name=(char*) str-2; // Lex makes this start with 0x
max_length=(str_length+1)/2;
@@ -2608,7 +2608,7 @@ Item_varbinary::Item_varbinary(const char *str, uint str_length)
fixed= 1;
}
-longlong Item_varbinary::val_int()
+longlong Item_hex_string::val_int()
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
@@ -2622,7 +2622,7 @@ longlong Item_varbinary::val_int()
}
-int Item_varbinary::save_in_field(Field *field, bool no_conversions)
+int Item_hex_string::save_in_field(Field *field, bool no_conversions)
{
int error;
field->set_notnull();
@@ -2640,6 +2640,44 @@ int Item_varbinary::save_in_field(Field *field, bool no_conversions)
/*
+ bin item.
+ In string context this is a binary string.
+ In number context this is a longlong value.
+*/
+
+Item_bin_string::Item_bin_string(const char *str, uint str_length)
+{
+ const char *end= str + str_length - 1;
+ uchar bits= 0;
+ uint power= 1;
+
+ name= (char*) str - 2;
+ max_length= (str_length + 7) >> 3;
+ char *ptr= (char*) sql_alloc(max_length + 1);
+ if (!ptr)
+ return;
+ str_value.set(ptr, max_length, &my_charset_bin);
+ ptr+= max_length - 1;
+ ptr[1]= 0; // Set end null for string
+ for (; end >= str; end--)
+ {
+ if (power == 256)
+ {
+ power= 1;
+ *ptr--= bits;
+ bits= 0;
+ }
+ if (*end == '1')
+ bits|= power;
+ power<<= 1;
+ }
+ *ptr= (char) bits;
+ collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
+ fixed= 1;
+}
+
+
+/*
Pack data in buffer for sending
*/
@@ -2672,6 +2710,7 @@ bool Item::send(Protocol *protocol, String *buffer)
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_BIT:
{
String *res;
if ((res=val_str(buffer)))
diff --git a/sql/item.h b/sql/item.h
index cf3dc8896a5..d5361bdcc8a 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -959,13 +959,14 @@ public:
};
-class Item_varbinary :public Item
+class Item_hex_string: public Item
{
public:
- Item_varbinary(const char *str,uint str_length);
+ Item_hex_string(): Item() {}
+ Item_hex_string(const char *str,uint str_length);
enum Type type() const { return VARBIN_ITEM; }
double val_real()
- { DBUG_ASSERT(fixed == 1); return (double) Item_varbinary::val_int(); }
+ { DBUG_ASSERT(fixed == 1); return (double) Item_hex_string::val_int(); }
longlong val_int();
bool basic_const_item() const { return 1; }
String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; }
@@ -977,6 +978,12 @@ public:
};
+class Item_bin_string: public Item_hex_string
+{
+public:
+ Item_bin_string(const char *str,uint str_length);
+};
+
class Item_result_field :public Item /* Item with result field */
{
public:
diff --git a/sql/key.cc b/sql/key.cc
index dfd924f1dc7..fe35638608d 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -102,6 +102,19 @@ void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length)
key_part->null_bit);
key_length--;
}
+ if (key_part->type == HA_KEYTYPE_BIT)
+ {
+ Field_bit *field= (Field_bit *) (key_part->field);
+ if (field->bit_len)
+ {
+ uchar bits= get_rec_bits((uchar*) from_record +
+ key_part->null_offset +
+ (key_part->null_bit == 128),
+ field->bit_ofs, field->bit_len);
+ *to_key++= bits;
+ key_length--;
+ }
+ }
if (key_part->key_part_flag & HA_BLOB_PART)
{
char *pos;
@@ -170,6 +183,23 @@ void key_restore(byte *to_record, byte *from_key, KEY *key_info,
to_record[key_part->null_offset]&= ~key_part->null_bit;
key_length--;
}
+ if (key_part->type == HA_KEYTYPE_BIT)
+ {
+ Field_bit *field= (Field_bit *) (key_part->field);
+ if (field->bit_len)
+ {
+ uchar bits= *(from_key + key_part->length - field->field_length -1);
+ set_rec_bits(bits, to_record + key_part->null_offset +
+ (key_part->null_bit == 128),
+ field->bit_ofs, field->bit_len);
+ }
+ else
+ {
+ clr_rec_bits(to_record + key_part->null_offset +
+ (key_part->null_bit == 128),
+ field->bit_ofs, field->bit_len);
+ }
+ }
if (key_part->key_part_flag & HA_BLOB_PART)
{
uint blob_length= uint2korr(from_key);
diff --git a/sql/protocol.cc b/sql/protocol.cc
index d2e63539610..4c916d78378 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -726,6 +726,7 @@ bool Protocol_simple::store(const char *from, uint length,
#ifndef DEBUG_OFF
DBUG_ASSERT(field_types == 0 ||
field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
+ field_types[field_pos] == MYSQL_TYPE_BIT ||
(field_types[field_pos] >= MYSQL_TYPE_ENUM &&
field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
field_pos++;
@@ -741,6 +742,7 @@ bool Protocol_simple::store(const char *from, uint length,
#ifndef DEBUG_OFF
DBUG_ASSERT(field_types == 0 ||
field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
+ field_types[field_pos] == MYSQL_TYPE_BIT ||
(field_types[field_pos] >= MYSQL_TYPE_ENUM &&
field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
field_pos++;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 12e4d912f15..2205ec504e9 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -567,8 +567,12 @@ int yylex(void *arg, void *yythd)
state= MY_LEX_HEX_NUMBER;
break;
}
- /* Fall through */
- case MY_LEX_IDENT_OR_BIN: // TODO: Add binary string handling
+ case MY_LEX_IDENT_OR_BIN:
+ if (yyPeek() == '\'')
+ { // Found b'bin-number'
+ state= MY_LEX_BIN_NUMBER;
+ break;
+ }
case MY_LEX_IDENT:
uchar *start;
#if defined(USE_MB) && defined(USE_MB_IDENT)
@@ -689,6 +693,20 @@ int yylex(void *arg, void *yythd)
}
yyUnget();
}
+ else if (c == 'b' && (lex->ptr - lex->tok_start) == 2 &&
+ lex->tok_start[0] == '0' )
+ { // b'bin-number'
+ while (my_isxdigit(cs,(c = yyGet()))) ;
+ if ((lex->ptr - lex->tok_start) >= 4 && !ident_map[c])
+ {
+ yylval->lex_str= get_token(lex, yyLength());
+ yylval->lex_str.str+= 2; // Skip 0x
+ yylval->lex_str.length-= 2;
+ lex->yytoklen-= 2;
+ return (BIN_NUM);
+ }
+ yyUnget();
+ }
// fall through
case MY_LEX_IDENT_START: // We come here after '.'
result_state= IDENT;
@@ -801,6 +819,19 @@ int yylex(void *arg, void *yythd)
lex->yytoklen-=3;
return (HEX_NUM);
+ case MY_LEX_BIN_NUMBER: // Found b'bin-string'
+ yyGet(); // Skip '
+ while ((c= yyGet()) == '0' || c == '1');
+ length= (lex->ptr - lex->tok_start); // Length of bin-num + 3
+ if (c != '\'')
+ return(ABORT_SYM); // Illegal hex constant
+ yyGet(); // get_token makes an unget
+ yylval->lex_str= get_token(lex, length);
+ yylval->lex_str.str+= 2; // Skip b'
+ yylval->lex_str.length-= 3; // Don't count b' and last '
+ lex->yytoklen-= 3;
+ return (BIN_NUM);
+
case MY_LEX_CMP_OP: // Incomplete comparison operator
if (state_map[yyPeek()] == MY_LEX_CMP_OP ||
state_map[yyPeek()] == MY_LEX_LONG_CMP_OP)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 3d4252a2b17..5720aac8dbd 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -5063,6 +5063,19 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
case MYSQL_TYPE_VAR_STRING:
DBUG_ASSERT(0); // Impossible
break;
+ case MYSQL_TYPE_BIT:
+ {
+ if (!length)
+ new_field->length= 1;
+ if (new_field->length > MAX_BIT_FIELD_LENGTH)
+ {
+ my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name,
+ MAX_BIT_FIELD_LENGTH);
+ DBUG_RETURN(1);
+ }
+ new_field->pack_length= (new_field->length + 7) / 8;
+ break;
+ }
}
if (!(new_field->flags & BLOB_FLAG) &&
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index ed3606856a0..5bf4480974f 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -7777,6 +7777,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
KEY_PART_INFO *key_part_info;
Item **copy_func;
MI_COLUMNDEF *recinfo;
+ uint total_uneven_bit_length= 0;
DBUG_ENTER("create_tmp_table");
DBUG_PRINT("enter",("distinct: %d save_sum_fields: %d rows_limit: %lu group: %d",
(int) distinct, (int) save_sum_fields,
@@ -7966,6 +7967,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
reclength+=new_field->pack_length();
if (!(new_field->flags & NOT_NULL_FLAG))
null_count++;
+ if (new_field->type() == FIELD_TYPE_BIT)
+ total_uneven_bit_length+= new_field->field_length & 7;
if (new_field->flags & BLOB_FLAG)
{
*blob_field++= new_field;
@@ -8014,7 +8017,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
null_count++;
}
hidden_null_pack_length=(hidden_null_count+7)/8;
- null_pack_length=hidden_null_count+(null_count+7)/8;
+ null_pack_length= hidden_null_count +
+ (null_count + total_uneven_bit_length + 7) / 8;
reclength+=null_pack_length;
if (!reclength)
reclength=1; // Dummy select
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 56605d1c6e0..8662eb63ce6 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -458,6 +458,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
int field_no,dup_no;
int select_field_pos,auto_increment=0;
List_iterator<create_field> it(fields),it2(fields);
+ uint total_uneven_bit_length= 0;
DBUG_ENTER("mysql_prepare_table");
select_field_pos=fields.elements - select_field_count;
@@ -614,6 +615,9 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (!(sql_field->flags & NOT_NULL_FLAG))
null_fields++;
+ if (sql_field->sql_type == FIELD_TYPE_BIT)
+ total_uneven_bit_length+= sql_field->length & 7;
+
if (check_column_name(sql_field->field_name))
{
my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name);
@@ -666,7 +670,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
/* If fixed row records, we need one bit to check for deleted rows */
if (!(db_options & HA_OPTION_PACK_RECORD))
null_fields++;
- pos=(null_fields+7)/8;
+ pos= (null_fields + total_uneven_bit_length + 7) / 8;
it.rewind();
while ((sql_field=it++))
@@ -762,6 +766,14 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
case FIELD_TYPE_NULL:
sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
break;
+ case FIELD_TYPE_BIT:
+ if (!(file->table_flags() & HA_CAN_BIT_FIELD))
+ {
+ my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "BIT FIELD");
+ DBUG_RETURN(-1);
+ }
+ sql_field->pack_flag= FIELDFLAG_NUMBER;
+ break;
case FIELD_TYPE_TIMESTAMP:
/* We should replace old TIMESTAMP fields with their newer analogs */
if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 3511777dd27..55a0f6ff692 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -208,6 +208,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token BACKUP_SYM
%token BERKELEY_DB_SYM
%token BINARY
+%token BIN_NUM
%token BIT_SYM
%token BOOL_SYM
%token BOOLEAN_SYM
@@ -664,7 +665,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text
UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
NCHAR_STRING opt_component key_cache_name
- sp_opt_label
+ sp_opt_label BIN_NUM
%type <lex_str_ptr>
opt_table_alias
@@ -2750,8 +2751,10 @@ type:
int_type opt_len field_options { $$=$1; }
| real_type opt_precision field_options { $$=$1; }
| FLOAT_SYM float_options field_options { $$=FIELD_TYPE_FLOAT; }
- | BIT_SYM opt_len { Lex->length=(char*) "1";
- $$=FIELD_TYPE_TINY; }
+ | BIT_SYM { Lex->length= (char*) "1";
+ $$=FIELD_TYPE_BIT; }
+ | BIT_SYM '(' NUM ')' { Lex->length= $3.str;
+ $$=FIELD_TYPE_BIT; }
| BOOL_SYM { Lex->length=(char*) "1";
$$=FIELD_TYPE_TINY; }
| BOOLEAN_SYM { Lex->length=(char*) "1";
@@ -6458,15 +6461,25 @@ text_string:
{ $$= new (YYTHD->mem_root) String($1.str,$1.length,YYTHD->variables.collation_connection); }
| HEX_NUM
{
- Item *tmp = new Item_varbinary($1.str,$1.length);
+ Item *tmp= new Item_hex_string($1.str, $1.length);
/*
- it is OK only emulate fix_fieds, because we need only
+ it is OK only emulate fix_fields, because we need only
value of constant
*/
$$= tmp ?
tmp->quick_fix_field(), tmp->val_str((String*) 0) :
(String*) 0;
}
+ | BIN_NUM
+ {
+ Item *tmp= new Item_bin_string($1.str, $1.length);
+ /*
+ it is OK only emulate fix_fields, because we need only
+ value of constant
+ */
+ $$= tmp ? tmp->quick_fix_field(), tmp->val_str((String*) 0) :
+ (String*) 0;
+ }
;
param_marker:
@@ -6508,10 +6521,11 @@ literal:
| NUM_literal { $$ = $1; }
| NULL_SYM { $$ = new Item_null();
Lex->next_state=MY_LEX_OPERATOR_OR_IDENT;}
- | HEX_NUM { $$ = new Item_varbinary($1.str,$1.length);}
+ | HEX_NUM { $$ = new Item_hex_string($1.str, $1.length);}
+ | BIN_NUM { $$= new Item_bin_string($1.str, $1.length); }
| UNDERSCORE_CHARSET HEX_NUM
{
- Item *tmp= new Item_varbinary($2.str,$2.length);
+ Item *tmp= new Item_hex_string($2.str, $2.length);
/*
it is OK only emulate fix_fieds, because we need only
value of constant
@@ -6523,6 +6537,20 @@ literal:
str ? str->length() : 0,
Lex->charset);
}
+ | UNDERSCORE_CHARSET BIN_NUM
+ {
+ Item *tmp= new Item_bin_string($2.str, $2.length);
+ /*
+ it is OK only emulate fix_fieds, because we need only
+ value of constant
+ */
+ String *str= tmp ?
+ tmp->quick_fix_field(), tmp->val_str((String*) 0) :
+ (String*) 0;
+ $$= new Item_string(str ? str->ptr() : "",
+ str ? str->length() : 0,
+ Lex->charset);
+ }
| DATE_SYM text_literal { $$ = $2; }
| TIME_SYM text_literal { $$ = $2; }
| TIMESTAMP text_literal { $$ = $2; };
diff --git a/sql/table.cc b/sql/table.cc
index b4a07448b14..e93c9893727 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -81,7 +81,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
KEY *keyinfo;
KEY_PART_INFO *key_part;
uchar *null_pos;
- uint null_bit, new_frm_ver, field_pack_length;
+ uint null_bit_pos, new_frm_ver, field_pack_length;
SQL_CRYPT *crypted=0;
MEM_ROOT **root_ptr, *old_root;
DBUG_ENTER("openfrm");
@@ -409,15 +409,15 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
if (null_field_first)
{
outparam->null_flags=null_pos=(uchar*) record+1;
- null_bit= (db_create_options & HA_OPTION_PACK_RECORD) ? 1 : 2;
- outparam->null_bytes=(outparam->null_fields+null_bit+6)/8;
+ null_bit_pos= (db_create_options & HA_OPTION_PACK_RECORD) ? 0 : 1;
+ outparam->null_bytes= (outparam->null_fields + null_bit_pos + 7) / 8;
}
else
{
outparam->null_bytes=(outparam->null_fields+7)/8;
outparam->null_flags=null_pos=
(uchar*) (record+1+outparam->reclength-outparam->null_bytes);
- null_bit=1;
+ null_bit_pos= 0;
}
use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH;
@@ -512,7 +512,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
*field_ptr=reg_field=
make_field(record+recpos,
(uint32) field_length,
- null_pos,null_bit,
+ null_pos, null_bit_pos,
pack_flag,
field_type,
charset,
@@ -529,14 +529,19 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
goto err_not_open; /* purecov: inspected */
}
reg_field->comment=comment;
- if (!(reg_field->flags & NOT_NULL_FLAG))
+ if (field_type == FIELD_TYPE_BIT)
{
- if ((null_bit<<=1) == 256)
+ if ((null_bit_pos+= field_length & 7) > 7)
{
- null_pos++;
- null_bit=1;
+ null_pos++;
+ null_bit_pos-= 8;
}
}
+ if (!(reg_field->flags & NOT_NULL_FLAG))
+ {
+ if (!(null_bit_pos= (null_bit_pos + 1) & 7))
+ null_pos++;
+ }
if (f_no_default(pack_flag))
reg_field->flags|= NO_DEFAULT_VALUE_FLAG;
if (reg_field->unireg_check == Field::NEXT_NUMBER)
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 636156940a4..dbd3da58a33 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -652,7 +652,7 @@ static bool make_empty_rec(File file,enum db_type table_type,
Field *regfield=make_field((char*) buff+field->offset,field->length,
field->flags & NOT_NULL_FLAG ? 0:
null_pos+null_count/8,
- 1 << (null_count & 7),
+ null_count & 7,
field->pack_flag,
field->sql_type,
field->charset,
diff --git a/sql/unireg.h b/sql/unireg.h
index 31b28da2423..932bdf4dfc5 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -66,6 +66,8 @@
/* Max column width +1 */
#define MAX_FIELD_WIDTH (MAX_FIELD_CHARLENGTH*MAX_MBWIDTH+1)
+#define MAX_BIT_FIELD_LENGTH 64 /* Max length in bits for bit fields */
+
#define MAX_DATE_WIDTH 10 /* YYYY-MM-DD */
#define MAX_TIME_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */
#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */