summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <ramil@mysql.com>2005-04-12 12:27:43 +0500
committerunknown <ramil@mysql.com>2005-04-12 12:27:43 +0500
commitdcb61639e7f72e23e6f0af8994c02c0893594129 (patch)
tree1e7496e90016ee8cc32875c8464a349bcbd4bcb4 /sql
parent1ef9b97209526d735adf87cdc204e300f5ca2759 (diff)
downloadmariadb-git-dcb61639e7f72e23e6f0af8994c02c0893594129.tar.gz
Bit type support for non-MyISAM tables.
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc72
-rw-r--r--sql/field.h19
-rw-r--r--sql/field_conv.cc3
-rw-r--r--sql/ha_innodb.cc2
-rw-r--r--sql/sql_table.cc18
-rw-r--r--sql/table.cc2
6 files changed, 100 insertions, 16 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 3afc8a2eb12..05dbfc8271d 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -7945,6 +7945,58 @@ const char *Field_bit::unpack(char *to, const char *from)
}
+/*
+ Bit field support for non-MyISAM tables.
+*/
+
+Field_bit_as_char::Field_bit_as_char(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_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, bit_ptr_arg,
+ bit_ofs_arg, unireg_check_arg, field_name_arg, table_arg),
+ create_length(len_arg)
+{
+ bit_ptr= 0;
+ bit_ofs= 0;
+ bit_len= 0;
+ field_length= ((len_arg + 7) & ~7) / 8;
+}
+
+
+int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
+{
+ int delta;
+ uchar bits= create_length & 7;
+
+ for (; !*from && length; from++, length--); // skip left 0's
+ delta= field_length - length;
+
+ if (delta < 0 ||
+ (delta == 0 && bits && (uint) (uchar) *from >= (uint) (1 << bits)))
+ {
+ memset(ptr, 0xff, field_length);
+ *ptr&= ((1 << bits) - 1); /* set first byte */
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ return 1;
+ }
+ bzero(ptr, delta);
+ memcpy(ptr + delta, from, length);
+ return 0;
+}
+
+
+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);
+ res.length((uint) length);
+}
+
+
/*****************************************************************************
Handling of field and create_field
*****************************************************************************/
@@ -7970,9 +8022,16 @@ void create_field::create_length_to_internal_length(void)
key_length= pack_length;
break;
case MYSQL_TYPE_BIT:
- pack_length= calc_pack_length(sql_type, length);
- /* We need one extra byte to store the bits we save among the null bits */
- key_length= pack_length+ test(length & 7);
+ if (f_bit_as_char(pack_flag))
+ {
+ key_length= pack_length= ((length + 7) & ~7) / 8;
+ }
+ else
+ {
+ pack_length= length / 8;
+ /* We need one extra byte to store the bits we save among the null bits */
+ key_length= pack_length + test(length & 7);
+ }
break;
case MYSQL_TYPE_NEWDECIMAL:
key_length= pack_length= my_decimal_get_binary_size(length, decimals);
@@ -8086,7 +8145,7 @@ Field *make_field(char *ptr, uint32 field_length,
uchar bit_offset;
LINT_INIT(bit_ptr);
LINT_INIT(bit_offset);
- if (field_type == FIELD_TYPE_BIT)
+ if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag))
{
bit_ptr= null_pos;
bit_offset= null_bit;
@@ -8236,7 +8295,10 @@ Field *make_field(char *ptr, uint32 field_length,
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,
+ return f_bit_as_char(pack_flag) ?
+ new Field_bit_as_char(ptr, field_length, null_pos, null_bit, bit_ptr,
+ bit_offset, unireg_check, field_name, table) :
+ new Field_bit(ptr, field_length, null_pos, null_bit, bit_ptr,
bit_offset, unireg_check, field_name, table);
default: // Impossible (Wrong version)
break;
diff --git a/sql/field.h b/sql/field.h
index 365f2c323b9..fd0937b2f4c 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1312,6 +1312,22 @@ public:
};
+class Field_bit_as_char: public Field_bit {
+protected:
+ uchar create_length;
+public:
+ Field_bit_as_char(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 ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
+ int store(const char *to, uint length, CHARSET_INFO *charset);
+ int store(double nr) { return Field_bit::store(nr); }
+ int store(longlong nr) { return Field_bit::store(nr); }
+ void sql_type(String &str) const;
+};
+
+
/*
Create field class for CREATE TABLE
*/
@@ -1415,6 +1431,8 @@ int set_field_to_null_with_conversions(Field *field, bool no_conversions);
#define FIELDFLAG_BLOB 1024 // mangled with decimals!
#define FIELDFLAG_GEOM 2048 // mangled with decimals!
+#define FIELDFLAG_TREAT_BIT_AS_CHAR 4096 /* use Field_bit_as_char */
+
#define FIELDFLAG_LEFT_FULLSCREEN 8192
#define FIELDFLAG_RIGHT_FULLSCREEN 16384
#define FIELDFLAG_FORMAT_NUMBER 16384 // predit: ###,,## in output
@@ -1445,3 +1463,4 @@ int set_field_to_null_with_conversions(Field *field, bool no_conversions);
#define f_settype(x) (((int) x) << FIELDFLAG_PACK_SHIFT)
#define f_maybe_null(x) (x & FIELDFLAG_MAYBE_NULL)
#define f_no_default(x) (x & FIELDFLAG_NO_DEFAULT)
+#define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index bbdd6619bf3..ae784ae0293 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -511,7 +511,7 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
/*
If we are copying date or datetime's we have to check the dates
if we don't allow 'all' dates.
-p */
+ */
if (to->real_type() != from->real_type() ||
!compatible_db_low_byte_first ||
((to->table->in_use->variables.sql_mode &
@@ -594,6 +594,7 @@ void field_conv(Field *to,Field *from)
!(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) &&
to->real_type() != FIELD_TYPE_ENUM &&
to->real_type() != FIELD_TYPE_SET &&
+ to->real_type() != FIELD_TYPE_BIT &&
(to->real_type() != FIELD_TYPE_NEWDECIMAL ||
(to->field_length == from->field_length &&
(((Field_num*)to)->dec == ((Field_num*)from)->dec))) &&
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index cfc649a5963..9de76abbb18 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -2233,6 +2233,7 @@ innobase_mysql_cmp(
switch (mysql_tp) {
+ case MYSQL_TYPE_BIT:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
case FIELD_TYPE_TINY_BLOB:
@@ -2342,6 +2343,7 @@ get_innobase_type_from_mysql_type(
} else {
return(DATA_VARMYSQL);
}
+ case MYSQL_TYPE_BIT:
case MYSQL_TYPE_STRING: if (field->binary()) {
return(DATA_FIXBINARY);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 4b40ff7638c..686e38104ab 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -563,12 +563,7 @@ int prepare_create_field(create_field *sql_field,
sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
break;
case FIELD_TYPE_BIT:
- if (!(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;
+ sql_field->pack_flag|= FIELDFLAG_NUMBER;
break;
case FIELD_TYPE_NEWDECIMAL:
sql_field->pack_flag=(FIELDFLAG_NUMBER |
@@ -774,6 +769,14 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
}
+ if (sql_field->sql_type == FIELD_TYPE_BIT)
+ {
+ if (file->table_flags() & HA_CAN_BIT_FIELD)
+ total_uneven_bit_length+= sql_field->length & 7;
+ else
+ sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
+ }
+
sql_field->create_length_to_internal_length();
if (sql_field->length > MAX_FIELD_VARCHARLENGTH &&
!(sql_field->flags & BLOB_FLAG))
@@ -810,9 +813,6 @@ static 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);
diff --git a/sql/table.cc b/sql/table.cc
index e1f15926c03..8e0f52e1910 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -568,7 +568,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
goto err; /* purecov: inspected */
}
reg_field->comment=comment;
- if (field_type == FIELD_TYPE_BIT)
+ if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag))
{
if ((null_bit_pos+= field_length & 7) > 7)
{