diff options
author | unknown <ram@gw.mysql.r18.ru> | 2004-12-17 18:06:05 +0400 |
---|---|---|
committer | unknown <ram@gw.mysql.r18.ru> | 2004-12-17 18:06:05 +0400 |
commit | d7285006cfcd93b13ec9c0f886ec542d7365fbfd (patch) | |
tree | 2e6c553f1097aea129caca8a5d200ff4f446a230 /sql | |
parent | eaec00b19b0dfe26bbe4297edfea04e277af27ed (diff) | |
download | mariadb-git-d7285006cfcd93b13ec9c0f886ec542d7365fbfd.tar.gz |
bit type
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 247 | ||||
-rw-r--r-- | sql/field.h | 49 | ||||
-rw-r--r-- | sql/field_conv.cc | 3 | ||||
-rw-r--r-- | sql/ha_myisam.cc | 7 | ||||
-rw-r--r-- | sql/ha_myisam.h | 2 | ||||
-rw-r--r-- | sql/handler.h | 1 | ||||
-rw-r--r-- | sql/item.cc | 55 | ||||
-rw-r--r-- | sql/item.h | 13 | ||||
-rw-r--r-- | sql/key.cc | 30 | ||||
-rw-r--r-- | sql/protocol.cc | 2 | ||||
-rw-r--r-- | sql/sql_lex.cc | 35 | ||||
-rw-r--r-- | sql/sql_parse.cc | 13 | ||||
-rw-r--r-- | sql/sql_select.cc | 6 | ||||
-rw-r--r-- | sql/sql_table.cc | 14 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 42 | ||||
-rw-r--r-- | sql/table.cc | 23 | ||||
-rw-r--r-- | sql/unireg.cc | 2 | ||||
-rw-r--r-- | sql/unireg.h | 2 |
18 files changed, 512 insertions, 34 deletions
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 */ |