summaryrefslogtreecommitdiff
path: root/sql/field.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/field.cc')
-rw-r--r--sql/field.cc2014
1 files changed, 1438 insertions, 576 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 8191d885a27..fa93454c757 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -38,8 +38,8 @@
*****************************************************************************/
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List<create_field>;
-template class List_iterator<create_field>;
+template class List<Create_field>;
+template class List_iterator<Create_field>;
#endif
uchar Field_null::null[1]={1};
@@ -51,6 +51,9 @@ const char field_separator=',';
#define BLOB_PACK_LENGTH_TO_MAX_LENGH(arg) \
((ulong) ((LL(1) << min(arg, 4) * 8) - LL(1)))
+#define ASSERT_COLUMN_MARKED_FOR_READ DBUG_ASSERT(!table || (!table->read_set || bitmap_is_set(table->read_set, field_index)))
+#define ASSERT_COLUMN_MARKED_FOR_WRITE DBUG_ASSERT(!table || (!table->write_set || bitmap_is_set(table->write_set, field_index)))
+
/*
Rules for merging different types of fields in UNION
@@ -68,6 +71,7 @@ inline int field_type2index (enum_field_types field_type)
((int)FIELDTYPE_TEAR_FROM) + (field_type - FIELDTYPE_TEAR_TO) - 1);
}
+
static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
{
/* MYSQL_TYPE_DECIMAL -> */
@@ -1047,13 +1051,12 @@ bool Field::type_can_have_key_part(enum enum_field_types type)
/*
Numeric fields base class constructor
*/
-Field_num::Field_num(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
+Field_num::Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
- struct st_table *table_arg,
uint8 dec_arg, bool zero_arg, bool unsigned_arg)
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg),
+ unireg_check_arg, field_name_arg),
dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg)
{
if (zerofill)
@@ -1068,9 +1071,10 @@ void Field_num::prepend_zeros(String *value)
int diff;
if ((diff= (int) (field_length - value->length())) > 0)
{
- bmove_upp((char*) value->ptr()+field_length,value->ptr()+value->length(),
+ bmove_upp((uchar*) value->ptr()+field_length,
+ (uchar*) value->ptr()+value->length(),
value->length());
- bfill((char*) value->ptr(),diff,'0');
+ bfill((uchar*) value->ptr(),diff,'0');
value->length(field_length);
(void) value->c_ptr_quick(); // Avoid warnings in purify
}
@@ -1152,7 +1156,8 @@ bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len,
char *end;
int error;
- *rnd= (longlong) cs->cset->strntoull10rnd(cs, from, len, unsigned_flag, &end,
+ *rnd= (longlong) cs->cset->strntoull10rnd(cs, from, len,
+ unsigned_flag, &end,
&error);
if (unsigned_flag)
{
@@ -1176,7 +1181,8 @@ bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len,
goto out_of_range;
}
}
- if (table->in_use->count_cuted_fields && check_int(cs, from, len, end, error))
+ if (table->in_use->count_cuted_fields &&
+ check_int(cs, from, len, end, error))
return 1;
return 0;
@@ -1277,9 +1283,11 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_bin;
uint length;
longlong value= val_int();
+
if (val_buffer->alloc(MY_INT64_NUM_DECIMAL_DIGITS))
return 0;
length= (uint) (*cs->cset->longlong10_to_str)(cs, (char*) val_buffer->ptr(),
@@ -1291,29 +1299,44 @@ String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val)
}
-/* This is used as a table name when the table structure is not set up */
-const char *unknown_table_name= 0;
-
-Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
+Field::Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
uchar null_bit_arg,
- utype unireg_check_arg, const char *field_name_arg,
- struct st_table *table_arg)
+ utype unireg_check_arg, const char *field_name_arg)
:ptr(ptr_arg), null_ptr(null_ptr_arg),
- table(table_arg),orig_table(table_arg),
- table_name(table_arg ? &table_arg->alias : &unknown_table_name),
+ table(0), orig_table(0), table_name(0),
field_name(field_name_arg),
- query_id(0), key_start(0), part_of_key(0), part_of_sortkey(0),
- unireg_check(unireg_check_arg),
- field_length(length_arg), null_bit(null_bit_arg)
+ key_start(0), part_of_key(0), part_of_key_not_clustered(0),
+ part_of_sortkey(0), unireg_check(unireg_check_arg),
+ field_length(length_arg), null_bit(null_bit_arg)
{
flags=null_ptr ? 0: NOT_NULL_FLAG;
comment.str= (char*) "";
comment.length=0;
+ field_index= 0;
}
-uint Field::offset()
+
+void Field::hash(ulong *nr, ulong *nr2)
{
- return (uint) (ptr - (char*) table->record[0]);
+ if (is_null())
+ {
+ *nr^= (*nr << 1) | 1;
+ }
+ else
+ {
+ uint len= pack_length();
+ CHARSET_INFO *cs= charset();
+ cs->coll->hash_sort(cs, ptr, len, nr, nr2);
+ }
+}
+
+size_t
+Field::do_last_null_byte() const
+{
+ DBUG_ASSERT(null_ptr == NULL || null_ptr >= table->record[0]);
+ if (null_ptr)
+ return (size_t) (null_ptr - table->record[0]) + 1;
+ return LAST_NULL_BYTE_UNDEF;
}
@@ -1337,6 +1360,84 @@ bool Field::send_binary(Protocol *protocol)
}
+/**
+ Check to see if field size is compatible with destination.
+
+ This method is used in row-based replication to verify that the slave's
+ field size is less than or equal to the master's field size. The
+ encoded field metadata (from the master or source) is decoded and compared
+ to the size of this field (the slave or destination).
+
+ @param field_metadata Encoded size in field metadata
+
+ @retval 0 if this field's size is < the source field's size
+ @retval 1 if this field's size is >= the source field's size
+*/
+int Field::compatible_field_size(uint field_metadata)
+{
+ uint const source_size= pack_length_from_metadata(field_metadata);
+ uint const destination_size= row_pack_length();
+ return (source_size <= destination_size);
+}
+
+
+int Field::store(const char *to, uint length, CHARSET_INFO *cs,
+ enum_check_fields check_level)
+{
+ int res;
+ enum_check_fields old_check_level= table->in_use->count_cuted_fields;
+ table->in_use->count_cuted_fields= check_level;
+ res= store(to, length, cs);
+ table->in_use->count_cuted_fields= old_check_level;
+ return res;
+}
+
+
+/**
+ Unpack a field from row data.
+
+ This method is used to unpack a field from a master whose size
+ of the field is less than that of the slave.
+
+ @param to Destination of the data
+ @param from Source of the data
+ @param param_data Pack length of the field data
+
+ @return New pointer into memory based on from + length of the data
+*/
+const uchar *Field::unpack(uchar* to,
+ const uchar *from,
+ uint param_data)
+{
+ uint length=pack_length();
+ int from_type= 0;
+ /*
+ If from length is > 255, it has encoded data in the upper bits. Need
+ to mask it out.
+ */
+ if (param_data > 255)
+ {
+ from_type= (param_data & 0xff00) >> 8U; // real_type.
+ param_data= param_data & 0x00ff; // length.
+ }
+ uint len= (param_data && (param_data < length)) ?
+ param_data : length;
+ /*
+ If the length is the same, use old unpack method.
+ If the param_data is 0, use the old unpack method.
+ This is possible if the table map was generated from a down-level
+ master or if the data was not available on the master.
+ If the real_types are not the same, use the old unpack method.
+ */
+ if ((length == param_data) ||
+ (param_data == 0) ||
+ (from_type != real_type()))
+ return(unpack(to, from));
+ memcpy(to, from, param_data > length ? length : len);
+ return from+len;
+}
+
+
my_decimal *Field::val_decimal(my_decimal *decimal)
{
/* This never have to be called */
@@ -1356,10 +1457,10 @@ void Field_num::add_zerofill_and_unsigned(String &res) const
void Field::make_field(Send_field *field)
{
- if (orig_table->s->table_cache_key && *(orig_table->s->table_cache_key))
+ if (orig_table->s->db.str && *orig_table->s->db.str)
{
- field->org_table_name= orig_table->s->table_name;
- field->db_name= orig_table->s->table_cache_key;
+ field->db_name= orig_table->s->db.str;
+ field->org_table_name= orig_table->s->table_name.str;
}
else
field->org_table_name= field->db_name= "";
@@ -1434,6 +1535,7 @@ longlong Field::convert_decimal2longlong(const my_decimal *val,
int Field_num::store_decimal(const my_decimal *val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int err= 0;
longlong i= convert_decimal2longlong(val, unsigned_flag, &err);
return test(err | store(i, unsigned_flag));
@@ -1458,6 +1560,7 @@ int Field_num::store_decimal(const my_decimal *val)
my_decimal* Field_num::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
DBUG_ASSERT(result_type() == INT_RESULT);
longlong nr= val_int();
int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value);
@@ -1465,12 +1568,11 @@ my_decimal* Field_num::val_decimal(my_decimal *decimal_value)
}
-Field_str::Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
+Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
- const char *field_name_arg,
- struct st_table *table_arg, CHARSET_INFO *charset_arg)
+ const char *field_name_arg, CHARSET_INFO *charset_arg)
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg)
+ unireg_check_arg, field_name_arg)
{
field_charset= charset_arg;
if (charset_arg->state & MY_CS_BINSORT)
@@ -1505,6 +1607,7 @@ void Field_num::make_field(Send_field *field)
int Field_str::store_decimal(const my_decimal *d)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
double val;
/* TODO: use decimal2string? */
int err= warn_if_overflow(my_decimal2double(E_DEC_FATAL_ERROR &
@@ -1515,6 +1618,7 @@ int Field_str::store_decimal(const my_decimal *d)
my_decimal *Field_str::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
longlong nr= val_int();
int2my_decimal(E_DEC_FATAL_ERROR, nr, 0, decimal_value);
return decimal_value;
@@ -1580,6 +1684,7 @@ bool Field::get_time(MYSQL_TIME *ltime)
int Field::store_time(MYSQL_TIME *ltime, timestamp_type type_arg)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[MAX_DATE_STRING_REP_LENGTH];
uint length= (uint) my_TIME_to_str(ltime, buff);
return store(buff, length, &my_charset_bin);
@@ -1605,7 +1710,7 @@ Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table,
tmp->key_start.init(0);
tmp->part_of_key.init(0);
tmp->part_of_sortkey.init(0);
- tmp->unireg_check=Field::NONE;
+ tmp->unireg_check= Field::NONE;
tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG |
ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
tmp->reset_fields();
@@ -1614,7 +1719,7 @@ Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table,
Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table,
- char *new_ptr, uchar *new_null_ptr,
+ uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
Field *tmp;
@@ -1628,6 +1733,21 @@ Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table,
}
+/* This is used to generate a field in TABLE from TABLE_SHARE */
+
+Field *Field::clone(MEM_ROOT *root, struct st_table *new_table)
+{
+ Field *tmp;
+ if ((tmp= (Field*) memdup_root(root,(char*) this,size_of())))
+ {
+ tmp->init(new_table);
+ tmp->move_field_offset((my_ptrdiff_t) (new_table->record[0] -
+ new_table->s->default_values));
+ }
+ return tmp;
+}
+
+
/****************************************************************************
Field_null, a field that always return NULL
****************************************************************************/
@@ -1653,7 +1773,7 @@ Field_decimal::reset(void)
void Field_decimal::overflow(bool negative)
{
uint len=field_length;
- char *to=ptr, filler= '9';
+ uchar *to=ptr, filler= '9';
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
if (negative)
@@ -1689,35 +1809,37 @@ void Field_decimal::overflow(bool negative)
}
-int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
+int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff,sizeof(buff), &my_charset_bin);
+ const uchar *from= (uchar*) from_arg;
- /* Convert character set if the old one is multi byte */
+ /* Convert character set if the old one is multi uchar */
if (cs->mbmaxlen > 1)
{
uint dummy_errors;
- tmp.copy(from, len, cs, &my_charset_bin, &dummy_errors);
- from= tmp.ptr();
+ tmp.copy((char*) from, len, cs, &my_charset_bin, &dummy_errors);
+ from= (uchar*) tmp.ptr();
len= tmp.length();
}
- const char *end= from+len;
+ const uchar *end= from+len;
/* The pointer where the field value starts (i.e., "where to write") */
- char *to=ptr;
+ uchar *to= ptr;
uint tmp_dec, tmp_uint;
/*
The sign of the number : will be 0 (means positive but sign not
specified), '+' or '-'
*/
- char sign_char=0;
+ uchar sign_char=0;
/* The pointers where prezeros start and stop */
- const char *pre_zeros_from, *pre_zeros_end;
+ const uchar *pre_zeros_from, *pre_zeros_end;
/* The pointers where digits at the left of '.' start and stop */
- const char *int_digits_from, *int_digits_end;
+ const uchar *int_digits_from, *int_digits_end;
/* The pointers where digits at the right of '.' start and stop */
- const char *frac_digits_from, *frac_digits_end;
+ const uchar *frac_digits_from, *frac_digits_end;
/* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
char expo_sign_char=0;
uint exponent=0; // value of the exponent
@@ -1725,20 +1847,20 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
Pointers used when digits move from the left of the '.' to the
right of the '.' (explained below)
*/
- const char *int_digits_tail_from;
+ const uchar *int_digits_tail_from;
/* Number of 0 that need to be added at the left of the '.' (1E3: 3 zeros) */
uint int_digits_added_zeros;
/*
Pointer used when digits move from the right of the '.' to the left
of the '.'
*/
- const char *frac_digits_head_end;
+ const uchar *frac_digits_head_end;
/* Number of 0 that need to be added at the right of the '.' (for 1E-3) */
uint frac_digits_added_zeros;
- char *pos,*tmp_left_pos,*tmp_right_pos;
+ uchar *pos,*tmp_left_pos,*tmp_right_pos;
/* Pointers that are used as limits (begin and end of the field buffer) */
- char *left_wall,*right_wall;
- char tmp_char;
+ uchar *left_wall,*right_wall;
+ uchar tmp_char;
/*
To remember if table->in_use->cuted_fields has already been incremented,
to do that only once
@@ -2060,6 +2182,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
int Field_decimal::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
if (unsigned_flag && nr < 0)
{
overflow(1);
@@ -2074,17 +2197,18 @@ int Field_decimal::store(double nr)
}
#endif
- reg4 uint i,length;
- char fyllchar,*to;
+ reg4 uint i;
+ size_t length;
+ uchar fyllchar,*to;
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
fyllchar = zerofill ? (char) '0' : (char) ' ';
#ifdef HAVE_SNPRINTF
buff[sizeof(buff)-1]=0; // Safety
snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr);
- length=(uint) strlen(buff);
+ length= strlen(buff);
#else
- length=(uint) my_sprintf(buff,(buff,"%.*f",dec,nr));
+ length= my_sprintf(buff,(buff,"%.*f",dec,nr));
#endif
if (length > field_length)
@@ -2105,9 +2229,11 @@ int Field_decimal::store(double nr)
int Field_decimal::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[22];
uint length, int_part;
- char fyllchar, *to;
+ char fyllchar;
+ uchar *to;
if (nr < 0 && unsigned_flag && !unsigned_val)
{
@@ -2139,31 +2265,35 @@ int Field_decimal::store(longlong nr, bool unsigned_val)
double Field_decimal::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used;
- return my_strntod(&my_charset_bin, ptr, field_length, &end_not_used,
+ return my_strntod(&my_charset_bin, (char*) ptr, field_length, &end_not_used,
&not_used);
}
longlong Field_decimal::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
if (unsigned_flag)
- return my_strntoull(&my_charset_bin, ptr, field_length, 10, NULL,
- &not_used);
- else
- return my_strntoll(&my_charset_bin, ptr, field_length, 10, NULL,
+ return my_strntoull(&my_charset_bin, (char*) ptr, field_length, 10, NULL,
&not_used);
+ return my_strntoll(&my_charset_bin, (char*) ptr, field_length, 10, NULL,
+ &not_used);
}
String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
- char *str;
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ uchar *str;
+ size_t tmp_length;
+
for (str=ptr ; *str == ' ' ; str++) ;
- uint tmp_length=(uint) (str-ptr);
val_ptr->set_charset(&my_charset_bin);
+ tmp_length= (size_t) (str-ptr);
if (field_length < tmp_length) // Error in data
val_ptr->length(0);
else
@@ -2176,9 +2306,9 @@ String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
** 5.00 , -1.0, 05, -05, +5 with optional pre/end space
*/
-int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
+int Field_decimal::cmp(const uchar *a_ptr,const uchar *b_ptr)
{
- const char *end;
+ const uchar *end;
int swap=0;
/* First remove prefixes '0', ' ', and '-' */
for (end=a_ptr+field_length;
@@ -2209,9 +2339,9 @@ int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
}
-void Field_decimal::sort_string(char *to,uint length)
+void Field_decimal::sort_string(uchar *to,uint length)
{
- char *str,*end;
+ uchar *str,*end;
for (str=ptr,end=ptr+length;
str != end &&
((my_isspace(&my_charset_bin,*str) || *str == '+' ||
@@ -2253,18 +2383,15 @@ void Field_decimal::sql_type(String &res) const
** Field_new_decimal
****************************************************************************/
-Field_new_decimal::Field_new_decimal(char *ptr_arg,
+Field_new_decimal::Field_new_decimal(uchar *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,
uint8 dec_arg,bool zero_arg,
bool unsigned_arg)
- :Field_num(ptr_arg, len_arg,
- null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg,
- dec_arg, zero_arg, unsigned_arg)
+ :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg)
{
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
set_if_smaller(precision, DECIMAL_MAX_PRECISION);
@@ -2277,14 +2404,11 @@ Field_new_decimal::Field_new_decimal(char *ptr_arg,
Field_new_decimal::Field_new_decimal(uint32 len_arg,
bool maybe_null_arg,
const char *name,
- struct st_table *t_arg,
uint8 dec_arg,
bool unsigned_arg)
- :Field_num((char*) 0, len_arg,
+ :Field_num((uchar*) 0, len_arg,
maybe_null_arg ? (uchar*) "": 0, 0,
- NONE, name, t_arg,
- dec_arg,
- 0, unsigned_arg)
+ NONE, name, dec_arg, 0, unsigned_arg)
{
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
set_if_smaller(precision, DECIMAL_MAX_PRECISION);
@@ -2345,6 +2469,7 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
bool Field_new_decimal::store_value(const my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
DBUG_ENTER("Field_new_decimal::store_value");
#ifndef DBUG_OFF
@@ -2365,7 +2490,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
#ifndef DBUG_OFF
{
char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
- DBUG_PRINT("info", ("saving with precision %d, scale: %d, value %s",
+ DBUG_PRINT("info", ("saving with precision %d scale: %d value %s",
(int)precision, (int)dec,
dbug_decimal_as_string(dbug_buff, decimal_value)));
}
@@ -2380,7 +2505,8 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
error= 1;
}
- DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr, bin_size););
+ DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (uchar *) ptr,
+ bin_size););
DBUG_RETURN(error);
}
@@ -2388,13 +2514,15 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
int Field_new_decimal::store(const char *from, uint length,
CHARSET_INFO *charset_arg)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int err;
my_decimal decimal_value;
DBUG_ENTER("Field_new_decimal::store(char*)");
if ((err= str2my_decimal(E_DEC_FATAL_ERROR &
- ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
- from, length, charset_arg, &decimal_value)) &&
+ ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
+ from, length, charset_arg,
+ &decimal_value)) &&
table->in_use->abort_on_warning)
{
/* Because "from" is not NUL-terminated and we use %s in the ER() */
@@ -2447,6 +2575,7 @@ int Field_new_decimal::store(const char *from, uint length,
int Field_new_decimal::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
my_decimal decimal_value;
int err;
DBUG_ENTER("Field_new_decimal::store(double)");
@@ -2481,6 +2610,7 @@ int Field_new_decimal::store(double nr)
int Field_new_decimal::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
my_decimal decimal_value;
int err;
@@ -2502,6 +2632,7 @@ int Field_new_decimal::store(longlong nr, bool unsigned_val)
int Field_new_decimal::store_decimal(const my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
return store_value(decimal_value);
}
@@ -2515,6 +2646,7 @@ int Field_new_decimal::store_time(MYSQL_TIME *ltime, timestamp_type t_type)
double Field_new_decimal::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double dbl;
my_decimal decimal_value;
my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl);
@@ -2524,6 +2656,7 @@ double Field_new_decimal::val_real(void)
longlong Field_new_decimal::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
longlong i;
my_decimal decimal_value;
my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
@@ -2534,10 +2667,11 @@ longlong Field_new_decimal::val_int(void)
my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
DBUG_ENTER("Field_new_decimal::val_decimal");
binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value,
precision, dec);
- DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr,
+ DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (uchar *) ptr,
bin_size););
DBUG_RETURN(decimal_value);
}
@@ -2546,6 +2680,7 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
String *Field_new_decimal::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
my_decimal decimal_value;
uint fixed_precision= zerofill ? precision : 0;
my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
@@ -2554,13 +2689,13 @@ String *Field_new_decimal::val_str(String *val_buffer,
}
-int Field_new_decimal::cmp(const char *a,const char*b)
+int Field_new_decimal::cmp(const uchar *a,const uchar*b)
{
return memcmp(a, b, bin_size);
}
-void Field_new_decimal::sort_string(char *buff,
+void Field_new_decimal::sort_string(uchar *buff,
uint length __attribute__((unused)))
{
memcpy(buff, ptr, bin_size);
@@ -2576,12 +2711,143 @@ void Field_new_decimal::sql_type(String &str) const
}
+/**
+ Save the field metadata for new decimal fields.
+
+ Saves the precision in the first byte and decimals() in the second
+ byte of the field metadata array at index of *metadata_ptr and
+ *(metadata_ptr + 1).
+
+ @param metadata_ptr First byte of field metadata
+
+ @returns number of bytes written to metadata_ptr
+*/
+int Field_new_decimal::do_save_field_metadata(uchar *metadata_ptr)
+{
+ *metadata_ptr= precision;
+ *(metadata_ptr + 1)= decimals();
+ return 2;
+}
+
+
+/**
+ Returns the number of bytes field uses in row-based replication
+ row packed size.
+
+ This method is used in row-based replication to determine the number
+ of bytes that the field consumes in the row record format. This is
+ used to skip fields in the master that do not exist on the slave.
+
+ @param field_metadata Encoded size in field metadata
+
+ @returns The size of the field based on the field metadata.
+*/
+uint Field_new_decimal::pack_length_from_metadata(uint field_metadata)
+{
+ uint const source_precision= (field_metadata >> 8U) & 0x00ff;
+ uint const source_decimal= field_metadata & 0x00ff;
+ uint const source_size= my_decimal_get_binary_size(source_precision,
+ source_decimal);
+ return (source_size);
+}
+
+
+/**
+ Check to see if field size is compatible with destination.
+
+ This method is used in row-based replication to verify that the slave's
+ field size is less than or equal to the master's field size. The
+ encoded field metadata (from the master or source) is decoded and compared
+ to the size of this field (the slave or destination).
+
+ @param field_metadata Encoded size in field metadata
+
+ @retval 0 if this field's size is < the source field's size
+ @retval 1 if this field's size is >= the source field's size
+*/
+int Field_new_decimal::compatible_field_size(uint field_metadata)
+{
+ int compatible= 0;
+ uint const source_precision= (field_metadata >> 8U) & 0x00ff;
+ uint const source_decimal= field_metadata & 0x00ff;
+ uint const source_size= my_decimal_get_binary_size(source_precision,
+ source_decimal);
+ uint const destination_size= row_pack_length();
+ compatible= (source_size <= destination_size);
+ if (compatible)
+ compatible= (source_precision <= precision) &&
+ (source_decimal <= decimals());
+ return (compatible);
+}
+
+
+uint Field_new_decimal::is_equal(Create_field *new_field)
+{
+ return ((new_field->sql_type == real_type()) &&
+ ((new_field->flags & UNSIGNED_FLAG) ==
+ (uint) (flags & UNSIGNED_FLAG)) &&
+ ((new_field->flags & AUTO_INCREMENT_FLAG) ==
+ (uint) (flags & AUTO_INCREMENT_FLAG)) &&
+ (new_field->length == max_display_length()) &&
+ (new_field->decimals == dec));
+}
+
+
+/**
+ Unpack a decimal field from row data.
+
+ This method is used to unpack a decimal or numeric field from a master
+ whose size of the field is less than that of the slave.
+
+ @param to Destination of the data
+ @param from Source of the data
+ @param param_data Precision (upper) and decimal (lower) values
+
+ @return New pointer into memory based on from + length of the data
+*/
+const uchar *Field_new_decimal::unpack(uchar* to,
+ const uchar *from,
+ uint param_data)
+{
+ uint from_precision= (param_data & 0xff00) >> 8U;
+ uint from_decimal= param_data & 0x00ff;
+ uint length=pack_length();
+ uint from_pack_len= my_decimal_get_binary_size(from_precision, from_decimal);
+ uint len= (param_data && (from_pack_len < length)) ?
+ from_pack_len : length;
+ if ((from_pack_len && (from_pack_len < length)) ||
+ (from_precision < precision) ||
+ (from_decimal < decimals()))
+ {
+ /*
+ If the master's data is smaller than the slave, we need to convert
+ the binary to decimal then resize the decimal converting it back to
+ a decimal and write that to the raw data buffer.
+ */
+ decimal_digit_t dec_buf[DECIMAL_MAX_PRECISION];
+ decimal_t dec;
+ dec.len= from_precision;
+ dec.buf= dec_buf;
+ /*
+ Note: bin2decimal does not change the length of the field. So it is
+ just the first step the resizing operation. The second step does the
+ resizing using the precision and decimals from the slave.
+ */
+ bin2decimal((uchar *)from, &dec, from_precision, from_decimal);
+ decimal2bin(&dec, to, precision, decimals());
+ }
+ else
+ memcpy(to, from, len); // Sizes are the same, just copy the data.
+ return from+len;
+}
+
/****************************************************************************
** tiny int
****************************************************************************/
int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error;
longlong rnd;
@@ -2593,6 +2859,7 @@ int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_tiny::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
nr=rint(nr);
if (unsigned_flag)
@@ -2635,6 +2902,7 @@ int Field_tiny::store(double nr)
int Field_tiny::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if (unsigned_flag)
@@ -2679,7 +2947,8 @@ int Field_tiny::store(longlong nr, bool unsigned_val)
double Field_tiny::val_real(void)
{
- int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ int tmp= unsigned_flag ? (int) ptr[0] :
(int) ((signed char*) ptr)[0];
return (double) tmp;
}
@@ -2687,7 +2956,8 @@ double Field_tiny::val_real(void)
longlong Field_tiny::val_int(void)
{
- int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ int tmp= unsigned_flag ? (int) ptr[0] :
(int) ((signed char*) ptr)[0];
return (longlong) tmp;
}
@@ -2696,6 +2966,7 @@ longlong Field_tiny::val_int(void)
String *Field_tiny::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_bin;
uint length;
uint mlength=max(field_length+1,5*cs->mbmaxlen);
@@ -2704,7 +2975,7 @@ String *Field_tiny::val_str(String *val_buffer,
if (unsigned_flag)
length= (uint) cs->cset->long10_to_str(cs,to,mlength, 10,
- (long) *((uchar*) ptr));
+ (long) *ptr);
else
length= (uint) cs->cset->long10_to_str(cs,to,mlength,-10,
(long) *((signed char*) ptr));
@@ -2720,7 +2991,7 @@ bool Field_tiny::send_binary(Protocol *protocol)
return protocol->store_tiny((longlong) (int8) ptr[0]);
}
-int Field_tiny::cmp(const char *a_ptr, const char *b_ptr)
+int Field_tiny::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
signed char a,b;
a=(signed char) a_ptr[0]; b= (signed char) b_ptr[0];
@@ -2729,12 +3000,12 @@ int Field_tiny::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_tiny::sort_string(char *to,uint length __attribute__((unused)))
+void Field_tiny::sort_string(uchar *to,uint length __attribute__((unused)))
{
if (unsigned_flag)
*to= *ptr;
else
- to[0] = (char) ((uchar) ptr[0] ^ (uchar) 128); /* Revers signbit */
+ to[0] = (char) (ptr[0] ^ (uchar) 128); /* Revers signbit */
}
void Field_tiny::sql_type(String &res) const
@@ -2751,6 +3022,7 @@ void Field_tiny::sql_type(String &res) const
int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int store_tmp;
int error;
longlong rnd;
@@ -2771,6 +3043,7 @@ int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_short::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int16 res;
nr=rint(nr);
@@ -2822,6 +3095,7 @@ int Field_short::store(double nr)
int Field_short::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int16 res;
@@ -2876,6 +3150,7 @@ int Field_short::store(longlong nr, bool unsigned_val)
double Field_short::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
short j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -2888,6 +3163,7 @@ double Field_short::val_real(void)
longlong Field_short::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
short j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -2902,6 +3178,7 @@ longlong Field_short::val_int(void)
String *Field_short::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_bin;
uint length;
uint mlength=max(field_length+1,7*cs->mbmaxlen);
@@ -2933,7 +3210,7 @@ bool Field_short::send_binary(Protocol *protocol)
}
-int Field_short::cmp(const char *a_ptr, const char *b_ptr)
+int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
short a,b;
#ifdef WORDS_BIGENDIAN
@@ -2955,7 +3232,7 @@ int Field_short::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_short::sort_string(char *to,uint length __attribute__((unused)))
+void Field_short::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table->s->db_low_byte_first)
@@ -2992,6 +3269,7 @@ void Field_short::sql_type(String &res) const
int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int store_tmp;
int error;
longlong rnd;
@@ -3005,6 +3283,7 @@ int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_medium::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
nr=rint(nr);
if (unsigned_flag)
@@ -3050,6 +3329,7 @@ int Field_medium::store(double nr)
int Field_medium::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if (unsigned_flag)
@@ -3098,6 +3378,7 @@ int Field_medium::store(longlong nr, bool unsigned_val)
double Field_medium::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
return (double) j;
}
@@ -3105,6 +3386,7 @@ double Field_medium::val_real(void)
longlong Field_medium::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
return (longlong) j;
}
@@ -3113,6 +3395,7 @@ longlong Field_medium::val_int(void)
String *Field_medium::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_bin;
uint length;
uint mlength=max(field_length+1,10*cs->mbmaxlen);
@@ -3130,11 +3413,12 @@ String *Field_medium::val_str(String *val_buffer,
bool Field_medium::send_binary(Protocol *protocol)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return protocol->store_long(Field_medium::val_int());
}
-int Field_medium::cmp(const char *a_ptr, const char *b_ptr)
+int Field_medium::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
long a,b;
if (unsigned_flag)
@@ -3150,7 +3434,7 @@ int Field_medium::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_medium::sort_string(char *to,uint length __attribute__((unused)))
+void Field_medium::sort_string(uchar *to,uint length __attribute__((unused)))
{
if (unsigned_flag)
to[0] = ptr[2];
@@ -3175,6 +3459,7 @@ void Field_medium::sql_type(String &res) const
int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
long store_tmp;
int error;
longlong rnd;
@@ -3195,6 +3480,7 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_long::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int32 res;
nr=rint(nr);
@@ -3246,10 +3532,10 @@ int Field_long::store(double nr)
int Field_long::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int32 res;
- DBUG_ASSERT(table->in_use == current_thd); // General safety
-
+
if (unsigned_flag)
{
if (nr < 0 && !unsigned_val)
@@ -3299,6 +3585,7 @@ int Field_long::store(longlong nr, bool unsigned_val)
double Field_long::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -3311,6 +3598,7 @@ double Field_long::val_real(void)
longlong Field_long::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
/* See the comment in Field_long::store(long long) */
DBUG_ASSERT(table->in_use == current_thd);
@@ -3326,6 +3614,7 @@ longlong Field_long::val_int(void)
String *Field_long::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_bin;
uint length;
uint mlength=max(field_length+1,12*cs->mbmaxlen);
@@ -3352,10 +3641,11 @@ String *Field_long::val_str(String *val_buffer,
bool Field_long::send_binary(Protocol *protocol)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return protocol->store_long(Field_long::val_int());
}
-int Field_long::cmp(const char *a_ptr, const char *b_ptr)
+int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
#ifdef WORDS_BIGENDIAN
@@ -3375,7 +3665,7 @@ int Field_long::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_long::sort_string(char *to,uint length __attribute__((unused)))
+void Field_long::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table->s->db_low_byte_first)
@@ -3416,7 +3706,8 @@ void Field_long::sql_type(String &res) const
int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
{
- int error;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
+ int error= 0;
char *end;
ulonglong tmp;
@@ -3445,6 +3736,7 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_longlong::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
longlong res;
@@ -3496,6 +3788,7 @@ int Field_longlong::store(double nr)
int Field_longlong::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if (nr < 0) // Only possible error
@@ -3526,6 +3819,7 @@ int Field_longlong::store(longlong nr, bool unsigned_val)
double Field_longlong::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -3547,6 +3841,7 @@ double Field_longlong::val_real(void)
longlong Field_longlong::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -3585,11 +3880,12 @@ String *Field_longlong::val_str(String *val_buffer,
bool Field_longlong::send_binary(Protocol *protocol)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return protocol->store_longlong(Field_longlong::val_int(), unsigned_flag);
}
-int Field_longlong::cmp(const char *a_ptr, const char *b_ptr)
+int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
longlong a,b;
#ifdef WORDS_BIGENDIAN
@@ -3610,7 +3906,7 @@ int Field_longlong::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_longlong::sort_string(char *to,uint length __attribute__((unused)))
+void Field_longlong::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table->s->db_low_byte_first)
@@ -3677,6 +3973,7 @@ int Field_float::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_float::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= truncate(&nr, FLT_MAX);
float j= (float)nr;
@@ -3687,19 +3984,21 @@ int Field_float::store(double nr)
}
else
#endif
- memcpy_fixed(ptr,(byte*) &j,sizeof(j));
+ memcpy_fixed(ptr,(uchar*) &j,sizeof(j));
return error;
}
int Field_float::store(longlong nr, bool unsigned_val)
{
- return store(unsigned_val ? ulonglong2double((ulonglong) nr) : (double) nr);
+ return Field_float::store(unsigned_val ? ulonglong2double((ulonglong) nr) :
+ (double) nr);
}
double Field_float::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
float j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -3708,7 +4007,7 @@ double Field_float::val_real(void)
}
else
#endif
- memcpy_fixed((byte*) &j,ptr,sizeof(j));
+ memcpy_fixed((uchar*) &j,ptr,sizeof(j));
return ((double) j);
}
@@ -3722,7 +4021,7 @@ longlong Field_float::val_int(void)
}
else
#endif
- memcpy_fixed((byte*) &j,ptr,sizeof(j));
+ memcpy_fixed((uchar*) &j,ptr,sizeof(j));
return (longlong) rint(j);
}
@@ -3730,6 +4029,7 @@ longlong Field_float::val_int(void)
String *Field_float::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
float nr;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -3738,7 +4038,7 @@ String *Field_float::val_str(String *val_buffer,
}
else
#endif
- memcpy_fixed((byte*) &nr,ptr,sizeof(nr));
+ memcpy_fixed((uchar*) &nr,ptr,sizeof(nr));
uint to_length=max(field_length,70);
val_buffer->alloc(to_length);
@@ -3810,7 +4110,7 @@ String *Field_float::val_str(String *val_buffer,
}
-int Field_float::cmp(const char *a_ptr, const char *b_ptr)
+int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
float a,b;
#ifdef WORDS_BIGENDIAN
@@ -3830,7 +4130,7 @@ int Field_float::cmp(const char *a_ptr, const char *b_ptr)
#define FLT_EXP_DIG (sizeof(float)*8-FLT_MANT_DIG)
-void Field_float::sort_string(char *to,uint length __attribute__((unused)))
+void Field_float::sort_string(uchar *to,uint length __attribute__((unused)))
{
float nr;
#ifdef WORDS_BIGENDIAN
@@ -3842,7 +4142,7 @@ void Field_float::sort_string(char *to,uint length __attribute__((unused)))
#endif
memcpy_fixed(&nr,ptr,sizeof(float));
- uchar *tmp= (uchar*) to;
+ uchar *tmp= to;
if (nr == (float) 0.0)
{ /* Change to zero string */
tmp[0]=(uchar) 128;
@@ -3875,10 +4175,27 @@ void Field_float::sort_string(char *to,uint length __attribute__((unused)))
bool Field_float::send_binary(Protocol *protocol)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return protocol->store((float) Field_float::val_real(), dec, (String*) 0);
}
+/**
+ Save the field metadata for float fields.
+
+ Saves the pack length in the first byte.
+
+ @param metadata_ptr First byte of field metadata
+
+ @returns number of bytes written to metadata_ptr
+*/
+int Field_float::do_save_field_metadata(uchar *metadata_ptr)
+{
+ *metadata_ptr= pack_length();
+ return 1;
+}
+
+
void Field_float::sql_type(String &res) const
{
if (dec == NOT_FIXED_DEC)
@@ -3918,6 +4235,7 @@ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_double::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= truncate(&nr, DBL_MAX);
#ifdef WORDS_BIGENDIAN
@@ -3934,7 +4252,8 @@ int Field_double::store(double nr)
int Field_double::store(longlong nr, bool unsigned_val)
{
- return store(unsigned_val ? ulonglong2double((ulonglong) nr) : (double) nr);
+ return Field_double::store(unsigned_val ? ulonglong2double((ulonglong) nr) :
+ (double) nr);
}
/*
@@ -4004,6 +4323,7 @@ int Field_real::store_decimal(const my_decimal *dm)
double Field_double::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double j;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -4018,6 +4338,7 @@ double Field_double::val_real(void)
longlong Field_double::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double j;
longlong res;
#ifdef WORDS_BIGENDIAN
@@ -4057,6 +4378,7 @@ warn:
my_decimal *Field_real::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double2my_decimal(E_DEC_FATAL_ERROR, val_real(), decimal_value);
return decimal_value;
}
@@ -4065,6 +4387,7 @@ my_decimal *Field_real::val_decimal(my_decimal *decimal_value)
String *Field_double::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double nr;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -4151,8 +4474,9 @@ bool Field_double::send_binary(Protocol *protocol)
}
-int Field_double::cmp(const char *a_ptr, const char *b_ptr)
+int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
double a,b;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -4174,7 +4498,7 @@ int Field_double::cmp(const char *a_ptr, const char *b_ptr)
/* The following should work for IEEE */
-void Field_double::sort_string(char *to,uint length __attribute__((unused)))
+void Field_double::sort_string(uchar *to,uint length __attribute__((unused)))
{
double nr;
#ifdef WORDS_BIGENDIAN
@@ -4185,7 +4509,24 @@ void Field_double::sort_string(char *to,uint length __attribute__((unused)))
else
#endif
doubleget(nr,ptr);
- change_double_for_sort(nr, (byte*) to);
+ change_double_for_sort(nr, to);
+}
+
+
+/**
+ Save the field metadata for double fields.
+
+ Saves the pack length in the first byte of the field metadata array
+ at index of *metadata_ptr.
+
+ @param metadata_ptr First byte of field metadata
+
+ @returns number of bytes written to metadata_ptr
+*/
+int Field_double::do_save_field_metadata(uchar *metadata_ptr)
+{
+ *metadata_ptr= pack_length();
+ return 1;
}
@@ -4250,43 +4591,35 @@ void Field_double::sql_type(String &res) const
exception is different behavior of old/new timestamps during ALTER TABLE.
*/
-Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
+Field_timestamp::Field_timestamp(uchar *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,
+ TABLE_SHARE *share,
CHARSET_INFO *cs)
:Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg, cs)
+ unireg_check_arg, field_name_arg, cs)
{
/* For 4.0 MYD and 4.0 InnoDB compatibility */
flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
- if (table && !table->timestamp_field &&
- unireg_check != NONE)
+ if (!share->timestamp_field && unireg_check != NONE)
{
/* This timestamp has auto-update */
- table->timestamp_field= this;
- flags|=TIMESTAMP_FLAG;
+ share->timestamp_field= this;
+ flags|= TIMESTAMP_FLAG;
}
}
Field_timestamp::Field_timestamp(bool maybe_null_arg,
const char *field_name_arg,
- struct st_table *table_arg, CHARSET_INFO *cs)
- :Field_str((char*) 0, MAX_DATETIME_WIDTH,
+ CHARSET_INFO *cs)
+ :Field_str((uchar*) 0, MAX_DATETIME_WIDTH,
maybe_null_arg ? (uchar*) "": 0, 0,
- NONE, field_name_arg, table_arg, cs)
+ NONE, field_name_arg, cs)
{
/* For 4.0 MYD and 4.0 InnoDB compatibility */
flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
- if (table && !table->timestamp_field &&
- unireg_check != NONE)
- {
- /* This timestamp has auto-update */
- table->timestamp_field= this;
- flags|=TIMESTAMP_FLAG;
- }
}
@@ -4331,7 +4664,7 @@ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
{
-
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
MYSQL_TIME l_time;
my_time_t tmp= 0;
int error;
@@ -4371,15 +4704,7 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
error= 1;
}
}
-
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
- int4store(ptr,tmp);
- }
- else
-#endif
- longstore(ptr,tmp);
+ store_timestamp(tmp);
return error;
}
@@ -4402,6 +4727,7 @@ int Field_timestamp::store(double nr)
int Field_timestamp::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
MYSQL_TIME l_time;
my_time_t timestamp= 0;
int error;
@@ -4438,26 +4764,19 @@ int Field_timestamp::store(longlong nr, bool unsigned_val)
WARN_DATA_TRUNCATED,
nr, MYSQL_TIMESTAMP_DATETIME, 1);
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
- int4store(ptr,timestamp);
- }
- else
-#endif
- longstore(ptr,(uint32) timestamp);
-
+ store_timestamp(timestamp);
return error;
}
-
double Field_timestamp::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return (double) Field_timestamp::val_int();
}
longlong Field_timestamp::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
uint32 temp;
MYSQL_TIME time_tmp;
THD *thd= table ? table->in_use : current_thd;
@@ -4483,6 +4802,7 @@ longlong Field_timestamp::val_int(void)
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
uint32 temp, temp2;
MYSQL_TIME time_tmp;
THD *thd= table ? table->in_use : current_thd;
@@ -4591,7 +4911,7 @@ bool Field_timestamp::send_binary(Protocol *protocol)
}
-int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
+int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
#ifdef WORDS_BIGENDIAN
@@ -4610,7 +4930,7 @@ int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
}
-void Field_timestamp::sort_string(char *to,uint length __attribute__((unused)))
+void Field_timestamp::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table || !table->s->db_low_byte_first)
@@ -4642,14 +4962,7 @@ void Field_timestamp::set_time()
THD *thd= table ? table->in_use : current_thd;
long tmp= (long) thd->query_start();
set_notnull();
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
- int4store(ptr,tmp);
- }
- else
-#endif
- longstore(ptr,tmp);
+ store_timestamp(tmp);
}
/****************************************************************************
@@ -4713,12 +5026,13 @@ int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type)
int Field_time::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
long tmp;
int error= 0;
if (nr > (double)TIME_MAX_VALUE)
{
tmp= TIME_MAX_VALUE;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME);
error= 1;
}
@@ -4750,6 +5064,7 @@ int Field_time::store(double nr)
int Field_time::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
long tmp;
int error= 0;
if (nr < (longlong) -TIME_MAX_VALUE && !unsigned_val)
@@ -4787,12 +5102,14 @@ int Field_time::store(longlong nr, bool unsigned_val)
double Field_time::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
uint32 j= (uint32) uint3korr(ptr);
return (double) j;
}
longlong Field_time::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return (longlong) sint3korr(ptr);
}
@@ -4805,6 +5122,7 @@ longlong Field_time::val_int(void)
String *Field_time::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
MYSQL_TIME ltime;
val_buffer->alloc(MAX_DATE_STRING_REP_LENGTH);
long tmp=(long) sint3korr(ptr);
@@ -4887,7 +5205,7 @@ bool Field_time::send_binary(Protocol *protocol)
}
-int Field_time::cmp(const char *a_ptr, const char *b_ptr)
+int Field_time::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
a=(int32) sint3korr(a_ptr);
@@ -4895,7 +5213,7 @@ int Field_time::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_time::sort_string(char *to,uint length __attribute__((unused)))
+void Field_time::sort_string(uchar *to,uint length __attribute__((unused)))
{
to[0] = (uchar) (ptr[2] ^ 128);
to[1] = ptr[1];
@@ -4915,6 +5233,7 @@ void Field_time::sql_type(String &res) const
int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char *end;
int error;
longlong nr= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
@@ -4944,7 +5263,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
else if (nr > 1900)
nr-= 1900;
}
- *ptr= (char) (unsigned char) nr;
+ *ptr= (char) (uchar) nr;
return error;
}
@@ -4962,6 +5281,7 @@ int Field_year::store(double nr)
int Field_year::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
{
*ptr= 0;
@@ -4975,13 +5295,14 @@ int Field_year::store(longlong nr, bool unsigned_val)
else if (nr > 1900)
nr-= 1900;
}
- *ptr= (char) (unsigned char) nr;
+ *ptr= (char) (uchar) nr;
return 0;
}
bool Field_year::send_binary(Protocol *protocol)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
ulonglong tmp= Field_year::val_int();
return protocol->store_short(tmp);
}
@@ -4995,7 +5316,8 @@ double Field_year::val_real(void)
longlong Field_year::val_int(void)
{
- int tmp= (int) ((uchar*) ptr)[0];
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ int tmp= (int) ptr[0];
if (field_length != 4)
tmp%=100; // Return last 2 char
else if (tmp)
@@ -5032,6 +5354,7 @@ void Field_year::sql_type(String &res) const
int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
MYSQL_TIME l_time;
uint32 tmp;
int error;
@@ -5088,6 +5411,7 @@ int Field_date::store(double nr)
int Field_date::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
MYSQL_TIME not_used;
int error;
longlong initial_nr= nr;
@@ -5139,6 +5463,7 @@ bool Field_date::send_binary(Protocol *protocol)
double Field_date::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
#ifdef WORDS_BIGENDIAN
if (table && table->s->db_low_byte_first)
@@ -5152,6 +5477,7 @@ double Field_date::val_real(void)
longlong Field_date::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
#ifdef WORDS_BIGENDIAN
if (table && table->s->db_low_byte_first)
@@ -5166,6 +5492,7 @@ longlong Field_date::val_int(void)
String *Field_date::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
MYSQL_TIME ltime;
val_buffer->alloc(field_length);
int32 tmp;
@@ -5184,7 +5511,7 @@ String *Field_date::val_str(String *val_buffer,
}
-int Field_date::cmp(const char *a_ptr, const char *b_ptr)
+int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
#ifdef WORDS_BIGENDIAN
@@ -5203,7 +5530,7 @@ int Field_date::cmp(const char *a_ptr, const char *b_ptr)
}
-void Field_date::sort_string(char *to,uint length __attribute__((unused)))
+void Field_date::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table || !table->s->db_low_byte_first)
@@ -5253,6 +5580,7 @@ void Field_date::sql_type(String &res) const
int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
long tmp;
MYSQL_TIME l_time;
int error;
@@ -5302,6 +5630,7 @@ int Field_newdate::store(double nr)
int Field_newdate::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
MYSQL_TIME l_time;
longlong tmp;
int error;
@@ -5329,8 +5658,9 @@ int Field_newdate::store(longlong nr, bool unsigned_val)
}
-int Field_newdate::store_time(MYSQL_TIME *ltime, timestamp_type time_type)
+int Field_newdate::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
long tmp;
int error= 0;
if (time_type == MYSQL_TIMESTAMP_DATE ||
@@ -5371,12 +5701,14 @@ bool Field_newdate::send_binary(Protocol *protocol)
double Field_newdate::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
return (double) Field_newdate::val_int();
}
longlong Field_newdate::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
ulong j= uint3korr(ptr);
j= (j % 32L)+(j / 32L % 16L)*100L + (j/(16L*32L))*10000L;
return (longlong) j;
@@ -5386,6 +5718,7 @@ longlong Field_newdate::val_int(void)
String *Field_newdate::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
val_buffer->alloc(field_length);
val_buffer->length(field_length);
uint32 tmp=(uint32) uint3korr(ptr);
@@ -5430,7 +5763,7 @@ bool Field_newdate::get_time(MYSQL_TIME *ltime)
}
-int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
+int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
uint32 a,b;
a=(uint32) uint3korr(a_ptr);
@@ -5439,7 +5772,7 @@ int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
}
-void Field_newdate::sort_string(char *to,uint length __attribute__((unused)))
+void Field_newdate::sort_string(uchar *to,uint length __attribute__((unused)))
{
to[0] = ptr[2];
to[1] = ptr[1];
@@ -5462,6 +5795,7 @@ void Field_newdate::sql_type(String &res) const
int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
MYSQL_TIME time_tmp;
int error;
ulonglong tmp= 0;
@@ -5514,6 +5848,7 @@ int Field_datetime::store(double nr)
int Field_datetime::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
MYSQL_TIME not_used;
int error;
longlong initial_nr= nr;
@@ -5551,10 +5886,11 @@ int Field_datetime::store(longlong nr, bool unsigned_val)
int Field_datetime::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
longlong tmp;
int error= 0;
/*
- We don't perform range checking here since values stored in MYSQL_TIME
+ We don't perform range checking here since values stored in TIME
structure always fit into DATETIME range.
*/
if (time_type == MYSQL_TIMESTAMP_DATE ||
@@ -5607,6 +5943,7 @@ double Field_datetime::val_real(void)
longlong Field_datetime::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
#ifdef WORDS_BIGENDIAN
if (table && table->s->db_low_byte_first)
@@ -5621,6 +5958,7 @@ longlong Field_datetime::val_int(void)
String *Field_datetime::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
val_buffer->alloc(field_length);
val_buffer->length(field_length);
ulonglong tmp;
@@ -5642,7 +5980,7 @@ String *Field_datetime::val_str(String *val_buffer,
part1=(long) (tmp/LL(1000000));
part2=(long) (tmp - (ulonglong) part1*LL(1000000));
- pos= (char*) val_buffer->ptr() + MAX_DATETIME_WIDTH;
+ pos=(char*) val_buffer->ptr() + MAX_DATETIME_WIDTH;
*pos--=0;
*pos--= (char) ('0'+(char) (part2%10)); part2/=10;
*pos--= (char) ('0'+(char) (part2%10)); part3= (int) (part2 / 10);
@@ -5690,7 +6028,7 @@ bool Field_datetime::get_time(MYSQL_TIME *ltime)
return Field_datetime::get_date(ltime,0);
}
-int Field_datetime::cmp(const char *a_ptr, const char *b_ptr)
+int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
longlong a,b;
#ifdef WORDS_BIGENDIAN
@@ -5709,7 +6047,7 @@ int Field_datetime::cmp(const char *a_ptr, const char *b_ptr)
((ulonglong) a > (ulonglong) b) ? 1 : 0;
}
-void Field_datetime::sort_string(char *to,uint length __attribute__((unused)))
+void Field_datetime::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table || !table->s->db_low_byte_first)
@@ -5758,6 +6096,7 @@ void Field_datetime::sql_type(String &res) const
well_formed_error_pos - where not well formed data was first met
cannot_convert_error_pos - where a not-convertable character was first met
end - end of the string
+ cs - character set of the string
NOTES
As of version 5.0 both cases return the same error:
@@ -5777,7 +6116,8 @@ static bool
check_string_copy_error(Field_str *field,
const char *well_formed_error_pos,
const char *cannot_convert_error_pos,
- const char *end)
+ const char *end,
+ CHARSET_INFO *cs)
{
const char *pos, *end_orig;
char tmp[64], *t;
@@ -5791,8 +6131,18 @@ check_string_copy_error(Field_str *field,
for (t= tmp; pos < end; pos++)
{
+ /*
+ If the source string is ASCII compatible (mbminlen==1)
+ and the source character is in ASCII printable range (0x20..0x7F),
+ then display the character as is.
+
+ Otherwise, if the source string is not ASCII compatible (e.g. UCS2),
+ or the source character is not in the printable range,
+ then print the character using HEX notation.
+ */
if (((unsigned char) *pos) >= 0x20 &&
- ((unsigned char) *pos) <= 0x7F)
+ ((unsigned char) *pos) <= 0x7F &&
+ cs->mbminlen == 1)
{
*t++= *pos;
}
@@ -5850,6 +6200,7 @@ report_data_too_long(Field_str *field)
int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
uint copy_length;
const char *well_formed_error_pos;
const char *cannot_convert_error_pos;
@@ -5859,7 +6210,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
DBUG_ASSERT(table->in_use == current_thd);
copy_length= well_formed_copy_nchars(field_charset,
- ptr, field_length,
+ (char*) ptr, field_length,
cs, from, length,
field_length / field_charset->mbmaxlen,
&well_formed_error_pos,
@@ -5868,12 +6219,12 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
/* Append spaces if the string was shorter than the field. */
if (copy_length < field_length)
- field_charset->cset->fill(field_charset,ptr+copy_length,
+ field_charset->cset->fill(field_charset,(char*) ptr+copy_length,
field_length-copy_length,
field_charset->pad_char);
if (check_string_copy_error(this, well_formed_error_pos,
- cannot_convert_error_pos, from + length))
+ cannot_convert_error_pos, from + length, cs))
return 2;
/*
@@ -5905,6 +6256,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
int Field_str::store(double nr)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
uint length;
bool use_scientific_notation= TRUE;
@@ -5917,7 +6269,7 @@ int Field_str::store(double nr)
int neg= (nr < 0.0) ? 1 : 0;
if (local_char_length > 4 && local_char_length < 32 &&
(anr < 1.0 ? anr > 1/(log_10[max(0,(int) local_char_length-neg-2)]) /* -2 for "0." */
- : anr < log_10[local_char_length-neg]-1))
+ : anr < log_10[local_char_length-neg]-1))
use_scientific_notation= FALSE;
length= (uint) my_sprintf(buff, (buff, "%-.*g",
@@ -5934,7 +6286,35 @@ int Field_str::store(double nr)
like inserting 500.0 in char(1)
*/
DBUG_ASSERT(local_char_length < 5 || length <= local_char_length+1);
- return store((const char *) buff, length, charset());
+ return store(buff, length, charset());
+}
+
+
+uint Field::is_equal(Create_field *new_field)
+{
+ return (new_field->sql_type == real_type());
+}
+
+
+/* If one of the fields is binary and the other one isn't return 1 else 0 */
+
+bool Field_str::compare_str_field_flags(Create_field *new_field, uint32 flag_arg)
+{
+ return (((new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) &&
+ !(flag_arg & (BINCMP_FLAG | BINARY_FLAG))) ||
+ (!(new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) &&
+ (flag_arg & (BINCMP_FLAG | BINARY_FLAG))));
+}
+
+
+uint Field_str::is_equal(Create_field *new_field)
+{
+ if (compare_str_field_flags(new_field, flags))
+ return 0;
+
+ return ((new_field->sql_type == real_type()) &&
+ new_field->charset == field_charset &&
+ new_field->length == max_display_length());
}
@@ -5960,19 +6340,21 @@ int Field_longstr::store_decimal(const my_decimal *d)
double Field_string::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int error;
char *end;
CHARSET_INFO *cs= charset();
double result;
- result= my_strntod(cs,ptr,field_length,&end,&error);
+ result= my_strntod(cs,(char*) ptr,field_length,&end,&error);
if (!table->in_use->no_errors &&
- (error || (field_length != (uint32)(end - ptr) &&
- !check_if_only_end_space(cs, end, ptr + field_length))))
+ (error || (field_length != (uint32)(end - (char*) ptr) &&
+ !check_if_only_end_space(cs, end,
+ (char*) ptr + field_length))))
{
char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
String tmp(buf, sizeof(buf), cs);
- tmp.copy(ptr, field_length, cs);
+ tmp.copy((char*) ptr, field_length, cs);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE),
@@ -5984,19 +6366,21 @@ double Field_string::val_real(void)
longlong Field_string::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int error;
char *end;
CHARSET_INFO *cs= charset();
longlong result;
- result= my_strntoll(cs,ptr,field_length,10,&end,&error);
+ result= my_strntoll(cs, (char*) ptr,field_length,10,&end,&error);
if (!table->in_use->no_errors &&
- (error || (field_length != (uint32)(end - ptr) &&
- !check_if_only_end_space(cs, end, ptr + field_length))))
+ (error || (field_length != (uint32)(end - (char*) ptr) &&
+ !check_if_only_end_space(cs, end,
+ (char*) ptr + field_length))))
{
char buf[LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE];
String tmp(buf, sizeof(buf), cs);
- tmp.copy(ptr, field_length, cs);
+ tmp.copy((char*) ptr, field_length, cs);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE),
@@ -6009,9 +6393,16 @@ longlong Field_string::val_int(void)
String *Field_string::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
- uint length= field_charset->cset->lengthsp(field_charset, ptr, field_length);
+ ASSERT_COLUMN_MARKED_FOR_READ;
/* See the comment for Field_long::store(long long) */
DBUG_ASSERT(table->in_use == current_thd);
+ uint length;
+ if (table->in_use->variables.sql_mode &
+ MODE_PAD_CHAR_TO_FULL_LENGTH)
+ length= my_charpos(field_charset, ptr, ptr + field_length, field_length);
+ else
+ length= field_charset->cset->lengthsp(field_charset, (const char*) ptr,
+ field_length);
val_ptr->set((const char*) ptr, length, field_charset);
return val_ptr;
}
@@ -6019,14 +6410,15 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
{
- int err= str2my_decimal(E_DEC_FATAL_ERROR, ptr, field_length, charset(),
- decimal_value);
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ int err= str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr, field_length,
+ charset(), decimal_value);
if (!table->in_use->no_errors && err)
{
char buf[DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE];
CHARSET_INFO *cs= charset();
String tmp(buf, sizeof(buf), cs);
- tmp.copy(ptr, field_length, cs);
+ tmp.copy((char*) ptr, field_length, cs);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE),
@@ -6037,7 +6429,7 @@ my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
}
-int Field_string::cmp(const char *a_ptr, const char *b_ptr)
+int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
uint a_len, b_len;
@@ -6054,17 +6446,17 @@ int Field_string::cmp(const char *a_ptr, const char *b_ptr)
like in latin_de 'ae' and 0xe4
*/
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a_ptr, a_len,
- (const uchar*) b_ptr, b_len,
+ a_ptr, a_len,
+ b_ptr, b_len,
0);
}
-void Field_string::sort_string(char *to,uint length)
+void Field_string::sort_string(uchar *to,uint length)
{
IF_DBUG(uint tmp=) my_strnxfrm(field_charset,
- (unsigned char *) to, length,
- (unsigned char *) ptr, field_length);
+ to, length,
+ ptr, field_length);
DBUG_ASSERT(tmp == length);
}
@@ -6089,7 +6481,7 @@ void Field_string::sql_type(String &res) const
}
-char *Field_string::pack(char *to, const char *from, uint max_length)
+uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
{
uint length= min(field_length,max_length);
uint local_char_length= max_length/field_charset->mbmaxlen;
@@ -6099,15 +6491,47 @@ char *Field_string::pack(char *to, const char *from, uint max_length)
set_if_smaller(length, local_char_length);
while (length && from[length-1] == ' ')
length--;
- *to++= (char) (uchar) length;
+ *to++= (uchar) length;
if (field_length > 255)
- *to++= (char) (uchar) (length >> 8);
+ *to++= (uchar) (length >> 8);
memcpy(to, from, length);
return to+length;
}
-const char *Field_string::unpack(char *to, const char *from)
+/**
+ Unpack a string field from row data.
+
+ This method is used to unpack a string field from a master whose size
+ of the field is less than that of the slave. Note that there can be a
+ variety of field types represented with this class. Certain types like
+ ENUM or SET are processed differently. Hence, the upper byte of the
+ @c param_data argument contains the result of field->real_type() from
+ the master.
+
+ @param to Destination of the data
+ @param from Source of the data
+ @param param_data Real type (upper) and length (lower) values
+
+ @return New pointer into memory based on from + length of the data
+*/
+const uchar *Field_string::unpack(uchar *to,
+ const uchar *from,
+ uint param_data)
+{
+ uint from_len= param_data & 0x00ff; // length.
+ uint length= 0;
+ uint f_length;
+ f_length= (from_len < field_length) ? from_len : field_length;
+ DBUG_ASSERT(f_length <= 255);
+ length= (uint) *from++;
+ bitmap_set_bit(table->write_set,field_index);
+ store((const char *)from, length, system_charset_info);
+ return from+length;
+}
+
+
+const uchar *Field_string::unpack(uchar *to, const uchar *from)
{
uint length;
if (field_length > 255)
@@ -6116,13 +6540,32 @@ const char *Field_string::unpack(char *to, const char *from)
from+= 2;
}
else
- length= (uint) (uchar) *from++;
+ length= (uint) *from++;
memcpy(to, from, (int) length);
bfill(to+length, field_length - length, ' ');
return from+length;
}
+/**
+ Save the field metadata for string fields.
+
+ Saves the real type in the first byte and the field length in the
+ second byte of the field metadata array at index of *metadata_ptr and
+ *(metadata_ptr + 1).
+
+ @param metadata_ptr First byte of field metadata
+
+ @returns number of bytes written to metadata_ptr
+*/
+int Field_string::do_save_field_metadata(uchar *metadata_ptr)
+{
+ *metadata_ptr= real_type();
+ *(metadata_ptr + 1)= field_length;
+ return 2;
+}
+
+
/*
Compare two packed keys
@@ -6139,7 +6582,7 @@ const char *Field_string::unpack(char *to, const char *from)
> 0 a > b
*/
-int Field_string::pack_cmp(const char *a, const char *b, uint length,
+int Field_string::pack_cmp(const uchar *a, const uchar *b, uint length,
my_bool insert_or_update)
{
uint a_length, b_length;
@@ -6152,12 +6595,12 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length,
}
else
{
- a_length= (uint) (uchar) *a++;
- b_length= (uint) (uchar) *b++;
+ a_length= (uint) *a++;
+ b_length= (uint) *b++;
}
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length,
+ a, a_length,
+ b, b_length,
insert_or_update);
}
@@ -6177,18 +6620,18 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length,
> 0 row > key
*/
-int Field_string::pack_cmp(const char *key, uint length,
+int Field_string::pack_cmp(const uchar *key, uint length,
my_bool insert_or_update)
{
uint row_length, local_key_length;
- char *end;
+ uchar *end;
if (length > 255)
{
local_key_length= uint2korr(key);
key+= 2;
}
else
- local_key_length= (uint) (uchar) *key++;
+ local_key_length= (uint) *key++;
/* Only use 'length' of key, not field_length */
end= ptr + length;
@@ -6197,17 +6640,17 @@ int Field_string::pack_cmp(const char *key, uint length,
row_length= (uint) (end - ptr);
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) ptr, row_length,
- (const uchar*) key, local_key_length,
+ ptr, row_length,
+ key, local_key_length,
insert_or_update);
}
-uint Field_string::packed_col_length(const char *data_ptr, uint length)
+uint Field_string::packed_col_length(const uchar *data_ptr, uint length)
{
if (length > 255)
return uint2korr(data_ptr)+2;
- return (uint) ((uchar) *data_ptr)+1;
+ return (uint) *data_ptr + 1;
}
@@ -6216,34 +6659,35 @@ uint Field_string::max_packed_col_length(uint max_length)
return (max_length > 255 ? 2 : 1)+max_length;
}
-uint Field_string::get_key_image(char *buff, uint length, imagetype type_arg)
+
+uint Field_string::get_key_image(uchar *buff, uint length, imagetype type_arg)
{
- uint bytes = my_charpos(field_charset, ptr, ptr + field_length,
+ uint bytes = my_charpos(field_charset, (char*) ptr,
+ (char*) ptr + field_length,
length / field_charset->mbmaxlen);
memcpy(buff, ptr, bytes);
if (bytes < length)
- field_charset->cset->fill(field_charset, buff + bytes, length - bytes,
- field_charset->pad_char);
+ field_charset->cset->fill(field_charset, (char*) buff + bytes,
+ length - bytes, field_charset->pad_char);
return bytes;
}
+
Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
bool keep_type)
{
Field *field;
-
if (type() != MYSQL_TYPE_VAR_STRING || keep_type)
field= Field::new_field(root, new_table, keep_type);
- else
+ else if ((field= new Field_varstring(field_length, maybe_null(), field_name,
+ new_table->s, charset())))
{
-
/*
Old VARCHAR field which should be modified to a VARCHAR on copy
This is done to ensure that ALTER TABLE will convert old VARCHAR fields
to now VARCHAR fields.
*/
- field= new Field_varstring(field_length, maybe_null(),
- field_name, new_table, charset());
+ field->init(new_table);
/*
Normally orig_table is different from table only if field was created
via ::new_field. Here we alter the type of field, so ::new_field is
@@ -6255,6 +6699,7 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
return field;
}
+
/****************************************************************************
VARCHAR type
Data in field->ptr is stored as:
@@ -6273,15 +6718,35 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
const uint Field_varstring::MAX_SIZE= UINT_MAX16;
+/**
+ Save the field metadata for varstring fields.
+
+ Saves the field length in the first byte. Note: may consume
+ 2 bytes. Caller must ensure second byte is contiguous with
+ first byte (e.g. array index 0,1).
+
+ @param metadata_ptr First byte of field metadata
+
+ @returns number of bytes written to metadata_ptr
+*/
+int Field_varstring::do_save_field_metadata(uchar *metadata_ptr)
+{
+ char *ptr= (char *)metadata_ptr;
+ int2store(ptr, field_length);
+ return 2;
+}
+
int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
uint copy_length;
const char *well_formed_error_pos;
const char *cannot_convert_error_pos;
const char *from_end_pos;
copy_length= well_formed_copy_nchars(field_charset,
- ptr + length_bytes, field_length,
+ (char*) ptr + length_bytes,
+ field_length,
cs, from, length,
field_length / field_charset->mbmaxlen,
&well_formed_error_pos,
@@ -6294,7 +6759,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
int2store(ptr, copy_length);
if (check_string_copy_error(this, well_formed_error_pos,
- cannot_convert_error_pos, from + length))
+ cannot_convert_error_pos, from + length, cs))
return 2;
// Check if we lost something other than just trailing spaces
@@ -6326,27 +6791,30 @@ int Field_varstring::store(longlong nr, bool unsigned_val)
double Field_varstring::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used;
- uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- return my_strntod(field_charset, ptr+length_bytes, length, &end_not_used,
- &not_used);
+ uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
+ return my_strntod(field_charset, (char*) ptr+length_bytes, length,
+ &end_not_used, &not_used);
}
longlong Field_varstring::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used;
- uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- return my_strntoll(field_charset, ptr+length_bytes, length, 10,
+ uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
+ return my_strntoll(field_charset, (char*) ptr+length_bytes, length, 10,
&end_not_used, &not_used);
}
String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
- uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
val_ptr->set((const char*) ptr+length_bytes, length, field_charset);
return val_ptr;
}
@@ -6354,33 +6822,37 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value)
{
- uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- str2my_decimal(E_DEC_FATAL_ERROR, ptr+length_bytes, length, charset(),
- decimal_value);
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
+ str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr+length_bytes, length,
+ charset(), decimal_value);
return decimal_value;
}
-int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
+int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
+ uint max_len)
{
uint a_length, b_length;
int diff;
if (length_bytes == 1)
{
- a_length= (uint) (uchar) *a_ptr;
- b_length= (uint) (uchar) *b_ptr;
+ a_length= (uint) *a_ptr;
+ b_length= (uint) *b_ptr;
}
else
{
a_length= uint2korr(a_ptr);
b_length= uint2korr(b_ptr);
}
+ set_if_smaller(a_length, max_len);
+ set_if_smaller(b_length, max_len);
diff= field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a_ptr+
+ a_ptr+
length_bytes,
a_length,
- (const uchar*) b_ptr+
+ b_ptr+
length_bytes,
b_length,0);
return diff;
@@ -6391,18 +6863,18 @@ int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
NOTE: varstring and blob keys are ALWAYS stored with a 2 byte length prefix
*/
-int Field_varstring::key_cmp(const byte *key_ptr, uint max_key_length)
+int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length)
{
- uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
uint local_char_length= max_key_length / field_charset->mbmaxlen;
local_char_length= my_charpos(field_charset, ptr + length_bytes,
ptr + length_bytes + length, local_char_length);
set_if_smaller(length, local_char_length);
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) ptr + length_bytes,
+ ptr + length_bytes,
length,
- (const uchar*) key_ptr+
+ key_ptr+
HA_KEY_BLOB_LENGTH,
uint2korr(key_ptr), 0);
}
@@ -6416,22 +6888,20 @@ int Field_varstring::key_cmp(const byte *key_ptr, uint max_key_length)
(keys are created and compared in key.cc)
*/
-int Field_varstring::key_cmp(const byte *a,const byte *b)
+int Field_varstring::key_cmp(const uchar *a,const uchar *b)
{
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a +
- HA_KEY_BLOB_LENGTH,
+ a + HA_KEY_BLOB_LENGTH,
uint2korr(a),
- (const uchar*) b +
- HA_KEY_BLOB_LENGTH,
+ b + HA_KEY_BLOB_LENGTH,
uint2korr(b),
0);
}
-void Field_varstring::sort_string(char *to,uint length)
+void Field_varstring::sort_string(uchar *to,uint length)
{
- uint tot_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ uint tot_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
if (field_charset == &my_charset_bin)
{
@@ -6444,8 +6914,7 @@ void Field_varstring::sort_string(char *to,uint length)
}
tot_length= my_strnxfrm(field_charset,
- (uchar*) to, length,
- (uchar*) ptr + length_bytes,
+ to, length, ptr + length_bytes,
tot_length);
DBUG_ASSERT(tot_length == length);
}
@@ -6480,9 +6949,9 @@ void Field_varstring::sql_type(String &res) const
}
-uint32 Field_varstring::data_length(const char *from)
+uint32 Field_varstring::data_length()
{
- return length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ return length_bytes == 1 ? (uint32) *ptr : uint2korr(ptr);
}
/*
@@ -6490,9 +6959,9 @@ uint32 Field_varstring::data_length(const char *from)
Here the number of length bytes are depending on the given max_length
*/
-char *Field_varstring::pack(char *to, const char *from, uint max_length)
+uchar *Field_varstring::pack(uchar *to, const uchar *from, uint max_length)
{
- uint length= length_bytes == 1 ? (uint) (uchar) *from : uint2korr(from);
+ uint length= length_bytes == 1 ? (uint) *from : uint2korr(from);
set_if_smaller(max_length, field_length);
if (length > max_length)
length=max_length;
@@ -6505,9 +6974,9 @@ char *Field_varstring::pack(char *to, const char *from, uint max_length)
}
-char *Field_varstring::pack_key(char *to, const char *key, uint max_length)
+uchar *Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length)
{
- uint length= length_bytes == 1 ? (uint) (uchar) *key : uint2korr(key);
+ uint length= length_bytes == 1 ? (uint) *key : uint2korr(key);
uint local_char_length= ((field_charset->mbmaxlen > 1) ?
max_length/field_charset->mbmaxlen : max_length);
key+= length_bytes;
@@ -6544,13 +7013,13 @@ char *Field_varstring::pack_key(char *to, const char *key, uint max_length)
Pointer to end of 'key' (To the next key part if multi-segment key)
*/
-const char *Field_varstring::unpack_key(char *to, const char *key,
- uint max_length)
+const uchar *Field_varstring::unpack_key(uchar *to, const uchar *key,
+ uint max_length)
{
/* get length of the blob key */
- uint32 length= *((uchar*) key++);
+ uint32 length= *key++;
if (max_length > 255)
- length+= (*((uchar*) key++)) << 8;
+ length+= (*key++) << 8;
/* put the length into the record buffer */
if (length_bytes == 1)
@@ -6574,8 +7043,8 @@ const char *Field_varstring::unpack_key(char *to, const char *key,
end of key storage
*/
-char *Field_varstring::pack_key_from_key_image(char *to, const char *from,
- uint max_length)
+uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from,
+ uint max_length)
{
/* Key length is always stored as 2 bytes */
uint length= uint2korr(from);
@@ -6590,15 +7059,53 @@ char *Field_varstring::pack_key_from_key_image(char *to, const char *from,
}
+/**
+ Unpack a varstring field from row data.
+
+ This method is used to unpack a varstring field from a master
+ whose size of the field is less than that of the slave.
+
+ @param to Destination of the data
+ @param from Source of the data
+ @param param_data Length bytes from the master's field data
+
+ @return New pointer into memory based on from + length of the data
+*/
+const uchar *Field_varstring::unpack(uchar *to,
+ const uchar *from,
+ uint param_data)
+{
+ uint length;
+ uint l_bytes= (param_data && (param_data < field_length)) ?
+ (param_data <= 255) ? 1 : 2 : length_bytes;
+ if (l_bytes == 1)
+ {
+ to[0]= *from++;
+ length= to[0];
+ if (length_bytes == 2)
+ to[1]= 0;
+ }
+ else
+ {
+ length= uint2korr(from);
+ to[0]= *from++;
+ to[1]= *from++;
+ }
+ if (length)
+ memcpy(to+ length_bytes, from, length);
+ return from+length;
+}
+
+
/*
unpack field packed with Field_varstring::pack()
*/
-const char *Field_varstring::unpack(char *to, const char *from)
+const uchar *Field_varstring::unpack(uchar *to, const uchar *from)
{
uint length;
if (length_bytes == 1)
- length= (uint) (uchar) (*to= *from++);
+ length= (uint) (*to= *from++);
else
{
length= uint2korr(from);
@@ -6611,7 +7118,7 @@ const char *Field_varstring::unpack(char *to, const char *from)
}
-int Field_varstring::pack_cmp(const char *a, const char *b,
+int Field_varstring::pack_cmp(const uchar *a, const uchar *b,
uint key_length_arg,
my_bool insert_or_update)
{
@@ -6623,21 +7130,21 @@ int Field_varstring::pack_cmp(const char *a, const char *b,
}
else
{
- a_length= (uint) (uchar) *a++;
- b_length= (uint) (uchar) *b++;
+ a_length= (uint) *a++;
+ b_length= (uint) *b++;
}
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length,
+ a, a_length,
+ b, b_length,
insert_or_update);
}
-int Field_varstring::pack_cmp(const char *b, uint key_length_arg,
+int Field_varstring::pack_cmp(const uchar *b, uint key_length_arg,
my_bool insert_or_update)
{
- char *a= ptr+ length_bytes;
- uint a_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ uchar *a= ptr+ length_bytes;
+ uint a_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
uint b_length;
uint local_char_length= ((field_charset->mbmaxlen > 1) ?
key_length_arg / field_charset->mbmaxlen :
@@ -6648,7 +7155,7 @@ int Field_varstring::pack_cmp(const char *b, uint key_length_arg,
b_length=uint2korr(b); b+= HA_KEY_BLOB_LENGTH;
}
else
- b_length= (uint) (uchar) *b++;
+ b_length= (uint) *b++;
if (a_length > local_char_length)
{
@@ -6658,18 +7165,17 @@ int Field_varstring::pack_cmp(const char *b, uint key_length_arg,
}
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a,
- a_length,
- (const uchar*) b, b_length,
+ a, a_length,
+ b, b_length,
insert_or_update);
}
-uint Field_varstring::packed_col_length(const char *data_ptr, uint length)
+uint Field_varstring::packed_col_length(const uchar *data_ptr, uint length)
{
if (length > 255)
return uint2korr(data_ptr)+2;
- return (uint) ((uchar) *data_ptr)+1;
+ return (uint) *data_ptr + 1;
}
@@ -6678,11 +7184,11 @@ uint Field_varstring::max_packed_col_length(uint max_length)
return (max_length > 255 ? 2 : 1)+max_length;
}
-uint Field_varstring::get_key_image(char *buff, uint length, imagetype type)
+uint Field_varstring::get_key_image(uchar *buff, uint length, imagetype type)
{
- uint f_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ uint f_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
uint local_char_length= length / field_charset->mbmaxlen;
- char *pos= ptr+length_bytes;
+ uchar *pos= ptr+length_bytes;
local_char_length= my_charpos(field_charset, pos, pos + f_length,
local_char_length);
set_if_smaller(f_length, local_char_length);
@@ -6701,23 +7207,23 @@ uint Field_varstring::get_key_image(char *buff, uint length, imagetype type)
}
-void Field_varstring::set_key_image(char *buff,uint length)
+void Field_varstring::set_key_image(const uchar *buff,uint length)
{
length= uint2korr(buff); // Real length is here
- (void) Field_varstring::store(buff+HA_KEY_BLOB_LENGTH, length,
+ (void) Field_varstring::store((const char*) buff+HA_KEY_BLOB_LENGTH, length,
field_charset);
}
-int Field_varstring::cmp_binary(const char *a_ptr, const char *b_ptr,
+int Field_varstring::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
uint32 max_length)
{
uint32 a_length,b_length;
if (length_bytes == 1)
{
- a_length= (uint) (uchar) *a_ptr;
- b_length= (uint) (uchar) *b_ptr;
+ a_length= (uint) *a_ptr;
+ b_length= (uint) *b_ptr;
}
else
{
@@ -6745,7 +7251,7 @@ Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table,
Field *Field_varstring::new_key_field(MEM_ROOT *root,
struct st_table *new_table,
- char *new_ptr, uchar *new_null_ptr,
+ uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
Field_varstring *res;
@@ -6762,72 +7268,103 @@ Field *Field_varstring::new_key_field(MEM_ROOT *root,
}
+uint Field_varstring::is_equal(Create_field *new_field)
+{
+ if (new_field->sql_type == real_type() &&
+ new_field->charset == field_charset)
+ {
+ if (new_field->length == max_display_length())
+ return IS_EQUAL_YES;
+ if (new_field->length > max_display_length() &&
+ ((new_field->length <= 255 && max_display_length() <= 255) ||
+ (new_field->length > 255 && max_display_length() > 255)))
+ return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer variable length
+ }
+ return IS_EQUAL_NO;
+}
+
+
+void Field_varstring::hash(ulong *nr, ulong *nr2)
+{
+ if (is_null())
+ {
+ *nr^= (*nr << 1) | 1;
+ }
+ else
+ {
+ uint len= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
+ CHARSET_INFO *cs= charset();
+ cs->coll->hash_sort(cs, ptr + length_bytes, len, nr, nr2);
+ }
+}
+
+
/****************************************************************************
** blob type
** A blob is saved as a length and a pointer. The length is stored in the
** packlength slot and may be from 1-4.
****************************************************************************/
-Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+Field_blob::Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
- struct st_table *table_arg,uint blob_pack_length,
+ TABLE_SHARE *share, uint blob_pack_length,
CHARSET_INFO *cs)
:Field_longstr(ptr_arg, BLOB_PACK_LENGTH_TO_MAX_LENGH(blob_pack_length),
- null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
- table_arg, cs),
+ null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
+ cs),
packlength(blob_pack_length)
{
flags|= BLOB_FLAG;
- if (table)
- {
- table->s->blob_fields++;
- /* TODO: why do not fill table->s->blob_field array here? */
- }
+ share->blob_fields++;
+ /* TODO: why do not fill table->s->blob_field array here? */
}
-void Field_blob::store_length(uint32 number)
+void Field_blob::store_length(uchar *i_ptr,
+ uint i_packlength,
+ uint32 i_number,
+ bool low_byte_first)
{
- switch (packlength) {
+ switch (i_packlength) {
case 1:
- ptr[0]= (uchar) number;
+ i_ptr[0]= (uchar) i_number;
break;
case 2:
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (low_byte_first)
{
- int2store(ptr,(unsigned short) number);
+ int2store(i_ptr,(unsigned short) i_number);
}
else
#endif
- shortstore(ptr,(unsigned short) number);
+ shortstore(i_ptr,(unsigned short) i_number);
break;
case 3:
- int3store(ptr,number);
+ int3store(i_ptr,i_number);
break;
case 4:
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (low_byte_first)
{
- int4store(ptr,number);
+ int4store(i_ptr,i_number);
}
else
#endif
- longstore(ptr,number);
+ longstore(i_ptr,i_number);
}
}
-uint32 Field_blob::get_length(const char *pos)
+uint32 Field_blob::get_length(const uchar *pos, bool low_byte_first)
{
switch (packlength) {
case 1:
- return (uint32) (uchar) pos[0];
+ return (uint32) pos[0];
case 2:
{
uint16 tmp;
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (low_byte_first)
tmp=sint2korr(pos);
else
#endif
@@ -6840,7 +7377,7 @@ uint32 Field_blob::get_length(const char *pos)
{
uint32 tmp;
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (low_byte_first)
tmp=uint4korr(pos);
else
#endif
@@ -6869,7 +7406,7 @@ uint32 Field_blob::get_length(const char *pos)
nothing
*/
-void Field_blob::put_length(char *pos, uint32 length)
+void Field_blob::put_length(uchar *pos, uint32 length)
{
switch (packlength) {
case 1:
@@ -6890,6 +7427,7 @@ void Field_blob::put_length(char *pos, uint32 length)
int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
uint copy_length, new_length;
const char *well_formed_error_pos;
const char *cannot_convert_error_pos;
@@ -6936,10 +7474,10 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
Field_blob::store_length(copy_length);
tmp= value.ptr();
- bmove(ptr+packlength,(char*) &tmp,sizeof(char*));
+ bmove(ptr+packlength,(uchar*) &tmp,sizeof(char*));
if (check_string_copy_error(this, well_formed_error_pos,
- cannot_convert_error_pos, from + length))
+ cannot_convert_error_pos, from + length, cs))
return 2;
if (from_end_pos < from + length)
@@ -6960,7 +7498,7 @@ oom_error:
int Field_blob::store(double nr)
{
CHARSET_INFO *cs=charset();
- value.set(nr, 2, cs);
+ value.set_real(nr, 2, cs);
return Field_blob::store(value.ptr(),(uint) value.length(), cs);
}
@@ -6968,16 +7506,14 @@ int Field_blob::store(double nr)
int Field_blob::store(longlong nr, bool unsigned_val)
{
CHARSET_INFO *cs=charset();
- if (unsigned_val)
- value.set((ulonglong) nr, cs);
- else
- value.set(nr, cs);
+ value.set_int(nr, unsigned_val, cs);
return Field_blob::store(value.ptr(), (uint) value.length(), cs);
}
double Field_blob::val_real(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used, *blob;
uint32 length;
@@ -6994,6 +7530,7 @@ double Field_blob::val_real(void)
longlong Field_blob::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *blob;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
@@ -7006,6 +7543,7 @@ longlong Field_blob::val_int(void)
String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
char *blob;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
@@ -7018,37 +7556,47 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
my_decimal *Field_blob::val_decimal(my_decimal *decimal_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
const char *blob;
- memcpy_fixed(&blob, ptr+packlength, sizeof(const char*));
+ size_t length;
+ memcpy_fixed(&blob, ptr+packlength, sizeof(const uchar*));
if (!blob)
+ {
blob= "";
- str2my_decimal(E_DEC_FATAL_ERROR, blob, get_length(ptr), charset(),
+ length= 0;
+ }
+ else
+ length= get_length(ptr);
+
+ str2my_decimal(E_DEC_FATAL_ERROR, blob, length, charset(),
decimal_value);
return decimal_value;
}
-int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
+int Field_blob::cmp(const uchar *a,uint32 a_length, const uchar *b,
uint32 b_length)
{
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*)a, a_length,
- (const uchar*)b, b_length,
+ a, a_length, b, b_length,
0);
}
-int Field_blob::cmp(const char *a_ptr, const char *b_ptr)
+int Field_blob::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
+ uint max_length)
{
- char *blob1,*blob2;
+ uchar *blob1,*blob2;
memcpy_fixed(&blob1,a_ptr+packlength,sizeof(char*));
memcpy_fixed(&blob2,b_ptr+packlength,sizeof(char*));
- return Field_blob::cmp(blob1,get_length(a_ptr),
- blob2,get_length(b_ptr));
+ uint a_len= get_length(a_ptr), b_len= get_length(b_ptr);
+ set_if_smaller(a_len, max_length);
+ set_if_smaller(b_len, max_length);
+ return Field_blob::cmp(blob1,a_len,blob2,b_len);
}
-int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
+int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
uint32 max_length)
{
char *a,*b;
@@ -7069,10 +7617,10 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
/* The following is used only when comparing a key */
-uint Field_blob::get_key_image(char *buff,uint length, imagetype type_arg)
+uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg)
{
uint32 blob_length= get_length(ptr);
- char *blob;
+ uchar *blob;
#ifdef HAVE_SPATIAL
if (type_arg == itMBR)
@@ -7089,7 +7637,7 @@ uint Field_blob::get_key_image(char *buff,uint length, imagetype type_arg)
return image_length;
}
get_ptr(&blob);
- gobj= Geometry::construct(&buffer, blob, blob_length);
+ gobj= Geometry::construct(&buffer, (char*) blob, blob_length);
if (!gobj || gobj->get_mbr(&mbr, &dummy))
bzero(buff, image_length);
else
@@ -7124,16 +7672,17 @@ uint Field_blob::get_key_image(char *buff,uint length, imagetype type_arg)
}
-void Field_blob::set_key_image(char *buff,uint length)
+void Field_blob::set_key_image(const uchar *buff,uint length)
{
length= uint2korr(buff);
- (void) Field_blob::store(buff+HA_KEY_BLOB_LENGTH, length, field_charset);
+ (void) Field_blob::store((const char*) buff+HA_KEY_BLOB_LENGTH, length,
+ field_charset);
}
-int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
+int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length)
{
- char *blob1;
+ uchar *blob1;
uint blob_length=get_length(ptr);
memcpy_fixed(&blob1,ptr+packlength,sizeof(char*));
CHARSET_INFO *cs= charset();
@@ -7142,14 +7691,31 @@ int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
local_char_length);
set_if_smaller(blob_length, local_char_length);
return Field_blob::cmp(blob1, blob_length,
- (char*) key_ptr+HA_KEY_BLOB_LENGTH,
+ key_ptr+HA_KEY_BLOB_LENGTH,
uint2korr(key_ptr));
}
-int Field_blob::key_cmp(const byte *a,const byte *b)
+int Field_blob::key_cmp(const uchar *a,const uchar *b)
{
- return Field_blob::cmp((char*) a+HA_KEY_BLOB_LENGTH, uint2korr(a),
- (char*) b+HA_KEY_BLOB_LENGTH, uint2korr(b));
+ return Field_blob::cmp(a+HA_KEY_BLOB_LENGTH, uint2korr(a),
+ b+HA_KEY_BLOB_LENGTH, uint2korr(b));
+}
+
+
+/**
+ Save the field metadata for blob fields.
+
+ Saves the pack length in the first byte of the field metadata array
+ at index of *metadata_ptr.
+
+ @param metadata_ptr First byte of field metadata
+
+ @returns number of bytes written to metadata_ptr
+*/
+int Field_blob::do_save_field_metadata(uchar *metadata_ptr)
+{
+ *metadata_ptr= pack_length_no_ptr();
+ return 1;
}
@@ -7160,9 +7726,9 @@ uint32 Field_blob::sort_length() const
}
-void Field_blob::sort_string(char *to,uint length)
+void Field_blob::sort_string(uchar *to,uint length)
{
- char *blob;
+ uchar *blob;
uint blob_length=get_length();
if (!blob_length)
@@ -7171,7 +7737,7 @@ void Field_blob::sort_string(char *to,uint length)
{
if (field_charset == &my_charset_bin)
{
- char *pos;
+ uchar *pos;
/*
Store length of blob last in blob to shorter blobs before longer blobs
@@ -7197,8 +7763,7 @@ void Field_blob::sort_string(char *to,uint length)
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
blob_length=my_strnxfrm(field_charset,
- (uchar*) to, length,
- (uchar*) blob, blob_length);
+ to, length, blob, blob_length);
DBUG_ASSERT(blob_length == length);
}
}
@@ -7224,23 +7789,21 @@ void Field_blob::sql_type(String &res) const
}
-char *Field_blob::pack(char *to, const char *from, uint max_length)
+uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length)
{
- char *save=ptr;
- ptr=(char*) from;
+ uchar *save= ptr;
+ ptr= (uchar*) from;
uint32 length=get_length(); // Length of from string
if (length > max_length)
{
- ptr=to;
length=max_length;
- store_length(length); // Store max length
- ptr=(char*) from;
+ store_length(to,packlength,length,TRUE);
}
else
memcpy(to,from,packlength); // Copy length
if (length)
{
- get_ptr((char**) &from);
+ get_ptr((uchar**) &from);
memcpy(to+packlength, from,length);
}
ptr=save; // Restore org row pointer
@@ -7248,10 +7811,33 @@ char *Field_blob::pack(char *to, const char *from, uint max_length)
}
-const char *Field_blob::unpack(char *to, const char *from)
+/**
+ Unpack a blob field from row data.
+
+ This method is used to unpack a blob field from a master whose size of
+ the field is less than that of the slave. Note: This method is included
+ to satisfy inheritance rules, but is not needed for blob fields. It
+ simply is used as a pass-through to the original unpack() method for
+ blob fields.
+
+ @param to Destination of the data
+ @param from Source of the data
+ @param param_data not used
+
+ @return New pointer into memory based on from + length of the data
+*/
+const uchar *Field_blob::unpack(uchar *to,
+ const uchar *from,
+ uint param_data)
+{
+ return unpack(to, from);
+}
+
+
+const uchar *Field_blob::unpack(uchar *to, const uchar *from)
{
- memcpy(to,from,packlength);
uint32 length=get_length(from);
+ memcpy(to,from,packlength);
from+=packlength;
if (length)
memcpy_fixed(to+packlength, &from, sizeof(from));
@@ -7262,7 +7848,7 @@ const char *Field_blob::unpack(char *to, const char *from)
/* Keys for blobs are like keys on varchars */
-int Field_blob::pack_cmp(const char *a, const char *b, uint key_length_arg,
+int Field_blob::pack_cmp(const uchar *a, const uchar *b, uint key_length_arg,
my_bool insert_or_update)
{
uint a_length, b_length;
@@ -7273,20 +7859,20 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length_arg,
}
else
{
- a_length= (uint) (uchar) *a++;
- b_length= (uint) (uchar) *b++;
+ a_length= (uint) *a++;
+ b_length= (uint) *b++;
}
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length,
+ a, a_length,
+ b, b_length,
insert_or_update);
}
-int Field_blob::pack_cmp(const char *b, uint key_length_arg,
+int Field_blob::pack_cmp(const uchar *b, uint key_length_arg,
my_bool insert_or_update)
{
- char *a;
+ uchar *a;
uint a_length, b_length;
memcpy_fixed(&a,ptr+packlength,sizeof(char*));
if (!a)
@@ -7298,24 +7884,24 @@ int Field_blob::pack_cmp(const char *b, uint key_length_arg,
b_length= uint2korr(b); b+=2;
}
else
- b_length= (uint) (uchar) *b++;
+ b_length= (uint) *b++;
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length,
+ a, a_length,
+ b, b_length,
insert_or_update);
}
/* Create a packed key that will be used for storage from a MySQL row */
-char *Field_blob::pack_key(char *to, const char *from, uint max_length)
+uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length)
{
- char *save=ptr;
- ptr=(char*) from;
- uint32 length=get_length(); // Length of from string
+ uchar *save= ptr;
+ ptr= (uchar*) from;
+ uint32 length=get_length(); // Length of from string
uint local_char_length= ((field_charset->mbmaxlen > 1) ?
- max_length/field_charset->mbmaxlen : max_length);
+ max_length/field_charset->mbmaxlen : max_length);
if (length)
- get_ptr((char**) &from);
+ get_ptr((uchar**) &from);
if (length > local_char_length)
local_char_length= my_charpos(field_charset, from, from+length,
local_char_length);
@@ -7352,12 +7938,13 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length)
Pointer into 'from' past the last byte copied from packed key.
*/
-const char *Field_blob::unpack_key(char *to, const char *from, uint max_length)
+const uchar *Field_blob::unpack_key(uchar *to, const uchar *from,
+ uint max_length)
{
/* get length of the blob key */
- uint32 length= *((uchar*) from++);
+ uint32 length= *from++;
if (max_length > 255)
- length+= (*((uchar*) from++)) << 8;
+ length+= *from++ << 8;
/* put the length into the record buffer */
put_length(to, length);
@@ -7375,8 +7962,8 @@ const char *Field_blob::unpack_key(char *to, const char *from, uint max_length)
/* Create a packed key that will be used for storage from a MySQL key */
-char *Field_blob::pack_key_from_key_image(char *to, const char *from,
- uint max_length)
+uchar *Field_blob::pack_key_from_key_image(uchar *to, const uchar *from,
+ uint max_length)
{
uint length=uint2korr(from);
if (length > max_length)
@@ -7390,11 +7977,11 @@ char *Field_blob::pack_key_from_key_image(char *to, const char *from,
}
-uint Field_blob::packed_col_length(const char *data_ptr, uint length)
+uint Field_blob::packed_col_length(const uchar *data_ptr, uint length)
{
if (length > 255)
return uint2korr(data_ptr)+2;
- return (uint) ((uchar) *data_ptr)+1;
+ return (uint) *data_ptr + 1;
}
@@ -7404,11 +7991,23 @@ uint Field_blob::max_packed_col_length(uint max_length)
}
+uint Field_blob::is_equal(Create_field *new_field)
+{
+ if (compare_str_field_flags(new_field, flags))
+ return 0;
+
+ return ((new_field->sql_type == get_blob_type_from_length(max_data_length()))
+ && new_field->charset == field_charset &&
+ ((Field_blob *)new_field->field)->max_data_length() ==
+ max_data_length());
+}
+
+
#ifdef HAVE_SPATIAL
-uint Field_geom::get_key_image(char *buff, uint length, imagetype type)
+uint Field_geom::get_key_image(uchar *buff, uint length, imagetype type)
{
- char *blob;
+ uchar *blob;
const char *dummy;
MBR mbr;
ulong blob_length= get_length(ptr);
@@ -7422,7 +8021,7 @@ uint Field_geom::get_key_image(char *buff, uint length, imagetype type)
return image_length;
}
get_ptr(&blob);
- gobj= Geometry::construct(&buffer, blob, blob_length);
+ gobj= Geometry::construct(&buffer, (char*) blob, blob_length);
if (!gobj || gobj->get_mbr(&mbr, &dummy))
bzero(buff, image_length);
else
@@ -7589,6 +8188,7 @@ void Field_enum::store_type(ulonglong value)
int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int err= 0;
uint32 not_used;
char buff[STRING_BUFFER_USUAL_SIZE];
@@ -7637,6 +8237,7 @@ int Field_enum::store(double nr)
int Field_enum::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if ((ulonglong) nr > typelib->count || nr == 0)
{
@@ -7660,49 +8261,69 @@ double Field_enum::val_real(void)
longlong Field_enum::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
switch (packlength) {
case 1:
- return (longlong) (uchar) ptr[0];
+ return (longlong) ptr[0];
case 2:
- {
- uint16 tmp;
+ {
+ uint16 tmp;
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- tmp=sint2korr(ptr);
- else
+ if (table->s->db_low_byte_first)
+ tmp=sint2korr(ptr);
+ else
#endif
- shortget(tmp,ptr);
- return (longlong) tmp;
- }
+ shortget(tmp,ptr);
+ return (longlong) tmp;
+ }
case 3:
return (longlong) uint3korr(ptr);
case 4:
- {
- uint32 tmp;
+ {
+ uint32 tmp;
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- tmp=uint4korr(ptr);
- else
+ if (table->s->db_low_byte_first)
+ tmp=uint4korr(ptr);
+ else
#endif
- longget(tmp,ptr);
- return (longlong) tmp;
- }
+ longget(tmp,ptr);
+ return (longlong) tmp;
+ }
case 8:
- {
- longlong tmp;
+ {
+ longlong tmp;
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- tmp=sint8korr(ptr);
- else
+ if (table->s->db_low_byte_first)
+ tmp=sint8korr(ptr);
+ else
#endif
- longlongget(tmp,ptr);
- return tmp;
- }
+ longlongget(tmp,ptr);
+ return tmp;
+ }
}
return 0; // impossible
}
+/**
+ Save the field metadata for enum fields.
+
+ Saves the real type in the first byte and the pack length in the
+ second byte of the field metadata array at index of *metadata_ptr and
+ *(metadata_ptr + 1).
+
+ @param metadata_ptr First byte of field metadata
+
+ @returns number of bytes written to metadata_ptr
+*/
+int Field_enum::do_save_field_metadata(uchar *metadata_ptr)
+{
+ *metadata_ptr= real_type();
+ *(metadata_ptr + 1)= pack_length();
+ return 2;
+}
+
+
String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
@@ -7716,18 +8337,18 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
return val_ptr;
}
-int Field_enum::cmp(const char *a_ptr, const char *b_ptr)
+int Field_enum::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
- char *old=ptr;
- ptr=(char*) a_ptr;
+ uchar *old= ptr;
+ ptr= (uchar*) a_ptr;
ulonglong a=Field_enum::val_int();
- ptr=(char*) b_ptr;
+ ptr= (uchar*) b_ptr;
ulonglong b=Field_enum::val_int();
- ptr=old;
+ ptr= old;
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_enum::sort_string(char *to,uint length __attribute__((unused)))
+void Field_enum::sort_string(uchar *to,uint length __attribute__((unused)))
{
ulonglong value=Field_enum::val_int();
to+=packlength-1;
@@ -7785,6 +8406,7 @@ Field *Field_enum::new_field(MEM_ROOT *root, struct st_table *new_table,
int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
bool got_warning= 0;
int err= 0;
char *not_used;
@@ -7824,6 +8446,7 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
int Field_set::store(longlong nr, bool unsigned_val)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) -
(longlong) 1))
@@ -7907,9 +8530,9 @@ bool Field_enum::eq_def(Field *field)
for (uint i=0 ; i < from_lib->count ; i++)
if (my_strnncoll(field_charset,
(const uchar*)typelib->type_names[i],
- (uint) strlen(typelib->type_names[i]),
+ strlen(typelib->type_names[i]),
(const uchar*)from_lib->type_names[i],
- (uint) strlen(from_lib->type_names[i])))
+ strlen(from_lib->type_names[i])))
return 0;
return 1;
}
@@ -7928,6 +8551,17 @@ bool Field_num::eq_def(Field *field)
}
+uint Field_num::is_equal(Create_field *new_field)
+{
+ return ((new_field->sql_type == real_type()) &&
+ ((new_field->flags & UNSIGNED_FLAG) == (uint) (flags &
+ UNSIGNED_FLAG)) &&
+ ((new_field->flags & AUTO_INCREMENT_FLAG) ==
+ (uint) (flags & AUTO_INCREMENT_FLAG)) &&
+ (new_field->length <= max_display_length()));
+}
+
+
/*
Bit field.
@@ -7957,12 +8591,11 @@ bool Field_num::eq_def(Field *field)
11 one byte for 'd'
*/
-Field_bit::Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+Field_bit::Field_bit(uchar *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 utype unireg_check_arg, const char *field_name_arg)
: Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg),
+ unireg_check_arg, field_name_arg),
bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7),
bytes_in_rec(len_arg / 8)
{
@@ -7976,9 +8609,36 @@ Field_bit::Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
}
+size_t
+Field_bit::do_last_null_byte() const
+{
+ /*
+ Code elsewhere is assuming that bytes are 8 bits, so I'm using
+ that value instead of the correct one: CHAR_BIT.
+
+ REFACTOR SUGGESTION (Matz): Change to use the correct number of
+ bits. On systems with CHAR_BIT > 8 (not very common), the storage
+ will lose the extra bits.
+ */
+ DBUG_PRINT("test", ("bit_ofs: %d, bit_len: %d bit_ptr: 0x%lx",
+ bit_ofs, bit_len, (long) bit_ptr));
+ uchar *result;
+ if (bit_len == 0)
+ result= null_ptr;
+ else if (bit_ofs + bit_len > 8)
+ result= bit_ptr + 1;
+ else
+ result= bit_ptr;
+
+ if (result)
+ return (size_t) (result - table->record[0]) + 1;
+ return LAST_NULL_BYTE_UNDEF;
+}
+
+
Field *Field_bit::new_key_field(MEM_ROOT *root,
struct st_table *new_table,
- char *new_ptr, uchar *new_null_ptr,
+ uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
Field_bit *res;
@@ -7987,7 +8647,7 @@ Field *Field_bit::new_key_field(MEM_ROOT *root,
new_null_bit)))
{
/* Move bits normally stored in null_pointer to new_ptr */
- res->bit_ptr= (uchar*) new_ptr;
+ res->bit_ptr= new_ptr;
res->bit_ofs= 0;
if (bit_len)
res->ptr++; // Store rest of data here
@@ -7996,8 +8656,16 @@ Field *Field_bit::new_key_field(MEM_ROOT *root,
}
+uint Field_bit::is_equal(Create_field *new_field)
+{
+ return (new_field->sql_type == real_type() &&
+ new_field->length == max_display_length());
+}
+
+
int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int delta;
for (; length && !*from; from++, length--); // skip left 0's
@@ -8044,7 +8712,7 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
int Field_bit::store(double nr)
{
- return store((longlong) nr, FALSE);
+ return Field_bit::store((longlong) nr, FALSE);
}
@@ -8073,6 +8741,7 @@ double Field_bit::val_real(void)
longlong Field_bit::val_int(void)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
ulonglong bits= 0;
if (bit_len)
{
@@ -8082,7 +8751,7 @@ longlong Field_bit::val_int(void)
switch (bytes_in_rec) {
case 0: return bits;
- case 1: return bits | (ulonglong) (uchar) ptr[0];
+ case 1: return bits | (ulonglong) ptr[0];
case 2: return bits | mi_uint2korr(ptr);
case 3: return bits | mi_uint3korr(ptr);
case 4: return bits | mi_uint4korr(ptr);
@@ -8097,6 +8766,7 @@ longlong Field_bit::val_int(void)
String *Field_bit::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
char buff[sizeof(longlong)];
uint length= min(pack_length(), sizeof(longlong));
ulonglong bits= val_int();
@@ -8112,18 +8782,48 @@ String *Field_bit::val_str(String *val_buffer,
my_decimal *Field_bit::val_decimal(my_decimal *deciaml_value)
{
+ ASSERT_COLUMN_MARKED_FOR_READ;
int2my_decimal(E_DEC_FATAL_ERROR, val_int(), 1, deciaml_value);
return deciaml_value;
}
-int Field_bit::key_cmp(const byte *str, uint length)
+/*
+ Compare two bit fields using pointers within the record.
+ SYNOPSIS
+ cmp_max()
+ a Pointer to field->ptr in first record
+ b Pointer to field->ptr in second record
+ max_len Maximum length used in index
+ DESCRIPTION
+ This method is used from key_rec_cmp used by merge sorts used
+ by partitioned index read and later other similar places.
+ The a and b pointer must be pointers to the field in a record
+ (not the table->record[0] necessarily)
+*/
+int Field_bit::cmp_max(const uchar *a, const uchar *b, uint max_len)
+{
+ my_ptrdiff_t a_diff= a - ptr;
+ my_ptrdiff_t b_diff= b - ptr;
+ if (bit_len)
+ {
+ int flag;
+ uchar bits_a= get_rec_bits(bit_ptr+a_diff, bit_ofs, bit_len);
+ uchar bits_b= get_rec_bits(bit_ptr+b_diff, bit_ofs, bit_len);
+ if ((flag= (int) (bits_a - bits_b)))
+ return flag;
+ }
+ return memcmp(a, b, field_length);
+}
+
+
+int Field_bit::key_cmp(const uchar *str, uint length)
{
if (bit_len)
{
int flag;
uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
- if ((flag= (int) (bits - *(uchar*) str)))
+ if ((flag= (int) (bits - *str)))
return flag;
str++;
length--;
@@ -8146,7 +8846,7 @@ int Field_bit::cmp_offset(uint row_offset)
}
-uint Field_bit::get_key_image(char *buff, uint length, imagetype type_arg)
+uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg)
{
if (bit_len)
{
@@ -8160,6 +8860,77 @@ uint Field_bit::get_key_image(char *buff, uint length, imagetype type_arg)
}
+/**
+ Save the field metadata for bit fields.
+
+ Saves the bit length in the first byte and bytes in record in the
+ second byte of the field metadata array at index of *metadata_ptr and
+ *(metadata_ptr + 1).
+
+ @param metadata_ptr First byte of field metadata
+
+ @returns number of bytes written to metadata_ptr
+*/
+int Field_bit::do_save_field_metadata(uchar *metadata_ptr)
+{
+ *metadata_ptr= bit_len;
+ *(metadata_ptr + 1)= bytes_in_rec;
+ return 2;
+}
+
+
+/**
+ Returns the number of bytes field uses in row-based replication
+ row packed size.
+
+ This method is used in row-based replication to determine the number
+ of bytes that the field consumes in the row record format. This is
+ used to skip fields in the master that do not exist on the slave.
+
+ @param field_metadata Encoded size in field metadata
+
+ @returns The size of the field based on the field metadata.
+*/
+uint Field_bit::pack_length_from_metadata(uint field_metadata)
+{
+ uint const from_len= (field_metadata >> 8U) & 0x00ff;
+ uint const from_bit_len= field_metadata & 0x00ff;
+ uint const source_size= from_len + ((from_bit_len > 0) ? 1 : 0);
+ return (source_size);
+}
+
+
+/**
+ Check to see if field size is compatible with destination.
+
+ This method is used in row-based replication to verify that the slave's
+ field size is less than or equal to the master's field size. The
+ encoded field metadata (from the master or source) is decoded and compared
+ to the size of this field (the slave or destination).
+
+ @param field_metadata Encoded size in field metadata
+
+ @retval 0 if this field's size is < the source field's size
+ @retval 1 if this field's size is >= the source field's size
+*/
+int Field_bit::compatible_field_size(uint field_metadata)
+{
+ int compatible= 0;
+ uint const source_size= pack_length_from_metadata(field_metadata);
+ uint const destination_size= row_pack_length();
+ uint const from_bit_len= field_metadata & 0x00ff;
+ uint const from_len= (field_metadata >> 8U) & 0x00ff;
+ if ((bit_len == 0) || (from_bit_len == 0))
+ compatible= (source_size <= destination_size);
+ else if (from_bit_len > bit_len)
+ compatible= (from_len < bytes_in_rec);
+ else
+ compatible= ((from_bit_len <= bit_len) && (from_len <= bytes_in_rec));
+ return (compatible);
+}
+
+
+
void Field_bit::sql_type(String &res) const
{
CHARSET_INFO *cs= res.charset();
@@ -8169,13 +8940,32 @@ void Field_bit::sql_type(String &res) const
}
-char *Field_bit::pack(char *to, const char *from, uint max_length)
+uchar *Field_bit::pack(uchar *to, const uchar *from, uint max_length)
{
DBUG_ASSERT(max_length);
uint length;
- if (bit_len)
+ if (bit_len > 0)
{
- uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ /*
+ We have the following:
+
+ ptr Points into a field in record R1
+ from Points to a field in a record R2
+ bit_ptr Points to the byte (in the null bytes) that holds the
+ odd bits of R1
+ from_bitp Points to the byte that holds the odd bits of R2
+
+ We have the following:
+
+ ptr - bit_ptr = from - from_bitp
+
+ We want to isolate 'from_bitp', so this gives:
+
+ ptr - bit_ptr - from = - from_bitp
+ - ptr + bit_ptr + from = from_bitp
+ bit_ptr + from - ptr = from_bitp
+ */
+ uchar bits= get_rec_bits(bit_ptr + (from - ptr), bit_ofs, bit_len);
*to++= bits;
}
length= min(bytes_in_rec, max_length - (bit_len > 0));
@@ -8184,11 +8974,70 @@ char *Field_bit::pack(char *to, const char *from, uint max_length)
}
-const char *Field_bit::unpack(char *to, const char *from)
+/**
+ Unpack a bit field from row data.
+
+ This method is used to unpack a bit field from a master whose size
+ of the field is less than that of the slave.
+
+ @param to Destination of the data
+ @param from Source of the data
+ @param param_data Bit length (upper) and length (lower) values
+
+ @return New pointer into memory based on from + length of the data
+*/
+const uchar *Field_bit::unpack(uchar *to,
+ const uchar *from,
+ uint param_data)
+{
+ uint const from_len= (param_data >> 8U) & 0x00ff;
+ uint const from_bit_len= param_data & 0x00ff;
+ /*
+ If the master and slave have the same sizes, then use the old
+ unpack() method.
+ */
+ if ((from_bit_len == bit_len) &&
+ (from_len == bytes_in_rec))
+ return(unpack(to, from));
+ /*
+ We are converting a smaller bit field to a larger one here.
+ To do that, we first need to construct a raw value for the original
+ bit value stored in the from buffer. Then that needs to be converted
+ to the larger field then sent to store() for writing to the field.
+ Lastly the odd bits need to be masked out if the bytes_in_rec > 0.
+ Otherwise stray bits can cause spurious values.
+ */
+ uint new_len= (field_length + 7) / 8;
+ char *value= (char *)my_alloca(new_len);
+ bzero(value, new_len);
+ uint len= from_len + ((from_bit_len > 0) ? 1 : 0);
+ memcpy(value + (new_len - len), from, len);
+ /*
+ Mask out the unused bits in the partial byte.
+ TODO: Add code to the master to always mask these bits and remove
+ the following.
+ */
+ if ((from_bit_len > 0) && (from_len > 0))
+ value[new_len - len]= value[new_len - len] & ((1U << from_bit_len) - 1);
+ bitmap_set_bit(table->write_set,field_index);
+ store(value, new_len, system_charset_info);
+ my_afree(value);
+ return from + len;
+}
+
+
+const uchar *Field_bit::unpack(uchar *to, const uchar *from)
{
- if (bit_len)
+ if (bit_len > 0)
{
- set_rec_bits(*from, bit_ptr, bit_ofs, bit_len);
+ /*
+ set_rec_bits is a macro, don't put the post-increment in the
+ argument since that might cause strange side-effects.
+
+ For the choice of the second argument, see the explanation for
+ Field_bit::pack().
+ */
+ set_rec_bits(*from, bit_ptr + (to - ptr), bit_ofs, bit_len);
from++;
}
memcpy(to, from, bytes_in_rec);
@@ -8196,17 +9045,27 @@ const char *Field_bit::unpack(char *to, const char *from)
}
+void Field_bit::set_default()
+{
+ if (bit_len > 0)
+ {
+ my_ptrdiff_t const offset= table->s->default_values - table->record[0];
+ uchar bits= get_rec_bits(bit_ptr + offset, bit_ofs, bit_len);
+ set_rec_bits(bits, bit_ptr, bit_ofs, bit_len);
+ }
+ Field::set_default();
+}
+
/*
Bit field support for non-MyISAM tables.
*/
-Field_bit_as_char::Field_bit_as_char(char *ptr_arg, uint32 len_arg,
+Field_bit_as_char::Field_bit_as_char(uchar *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)
- : Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, 0,
- 0, unireg_check_arg, field_name_arg, table_arg)
+ const char *field_name_arg)
+ :Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, 0, 0,
+ unireg_check_arg, field_name_arg)
{
flags|= UNSIGNED_FLAG;
bit_len= 0;
@@ -8216,6 +9075,7 @@ Field_bit_as_char::Field_bit_as_char(char *ptr_arg, uint32 len_arg,
int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int delta;
uchar bits= (uchar) (field_length & 7);
@@ -8227,7 +9087,7 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
{
memset(ptr, 0xff, bytes_in_rec);
if (bits)
- *ptr&= ((1 << bits) - 1); /* set first byte */
+ *ptr&= ((1 << bits) - 1); /* set first uchar */
if (table->in_use->really_abort_on_warning())
set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
else
@@ -8250,20 +9110,20 @@ void Field_bit_as_char::sql_type(String &res) const
/*****************************************************************************
- Handling of field and create_field
+ Handling of field and Create_field
*****************************************************************************/
/*
- Convert create_field::length from number of characters to number of bytes
+ Convert Create_field::length from number of characters to number of bytes
SYNOPSIS
- create_field::create_length_to_internal_length()
+ Create_field::create_length_to_internal_length()
DESCRIPTION
- Convert create_field::length from number of characters to number of bytes.
+ Convert Create_field::length from number of characters to number of bytes.
*/
-void create_field::create_length_to_internal_length(void)
+void Create_field::create_length_to_internal_length(void)
{
switch (sql_type) {
case MYSQL_TYPE_TINY_BLOB:
@@ -8310,7 +9170,7 @@ void create_field::create_length_to_internal_length(void)
}
-void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
+void Create_field::init_for_tmp_table(enum_field_types sql_type_arg,
uint32 length_arg, uint32 decimals_arg,
bool maybe_null, bool is_unsigned)
{
@@ -8351,7 +9211,7 @@ void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
TRUE on error
*/
-bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
+bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
char *fld_length, char *fld_decimals,
uint fld_type_modifier, Item *fld_default_value,
Item *fld_on_update_value, LEX_STRING *fld_comment,
@@ -8361,7 +9221,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
uint sign_len, allowed_type_modifier= 0;
ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
- DBUG_ENTER("create_field::init()");
+ DBUG_ENTER("Create_field::init()");
field= 0;
field_name= fld_name;
@@ -8392,7 +9252,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
it is NOT NULL, not an AUTO_INCREMENT field and not a TIMESTAMP.
*/
if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) &&
- (fld_type_modifier & NOT_NULL_FLAG) && fld_type != FIELD_TYPE_TIMESTAMP)
+ (fld_type_modifier & NOT_NULL_FLAG) && fld_type != MYSQL_TYPE_TIMESTAMP)
flags|= NO_DEFAULT_VALUE_FLAG;
if (fld_length && !(length= (uint) atoi(fld_length)))
@@ -8400,34 +9260,34 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1;
switch (fld_type) {
- case FIELD_TYPE_TINY:
+ case MYSQL_TYPE_TINY:
if (!fld_length)
length= MAX_TINYINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_SHORT:
+ case MYSQL_TYPE_SHORT:
if (!fld_length)
length= MAX_SMALLINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_INT24:
+ case MYSQL_TYPE_INT24:
if (!fld_length)
length= MAX_MEDIUMINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_LONG:
+ case MYSQL_TYPE_LONG:
if (!fld_length)
length= MAX_INT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_LONGLONG:
+ case MYSQL_TYPE_LONGLONG:
if (!fld_length)
length= MAX_BIGINT_WIDTH;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_NULL:
+ case MYSQL_TYPE_NULL:
break;
- case FIELD_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
my_decimal_trim(&length, &decimals);
if (length > DECIMAL_MAX_PRECISION)
{
@@ -8455,11 +9315,11 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
break;
case MYSQL_TYPE_STRING:
break;
- case FIELD_TYPE_BLOB:
- case FIELD_TYPE_TINY_BLOB:
- case FIELD_TYPE_LONG_BLOB:
- case FIELD_TYPE_MEDIUM_BLOB:
- case FIELD_TYPE_GEOMETRY:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
if (fld_default_value)
{
/* Allow empty as default value. */
@@ -8491,12 +9351,12 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
}
flags|= BLOB_FLAG;
break;
- case FIELD_TYPE_YEAR:
+ case MYSQL_TYPE_YEAR:
if (!fld_length || length != 2)
length= 4; /* Default length */
flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
break;
- case FIELD_TYPE_FLOAT:
+ case MYSQL_TYPE_FLOAT:
/* change FLOAT(precision) to FLOAT or DOUBLE */
allowed_type_modifier= AUTO_INCREMENT_FLAG;
if (fld_length && !fld_decimals)
@@ -8509,7 +9369,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
}
else if (tmp_length > PRECISION_FOR_FLOAT)
{
- sql_type= FIELD_TYPE_DOUBLE;
+ sql_type= MYSQL_TYPE_DOUBLE;
length= DBL_DIG+7; /* -[digits].E+### */
}
else
@@ -8529,7 +9389,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
DBUG_RETURN(TRUE);
}
break;
- case FIELD_TYPE_DOUBLE:
+ case MYSQL_TYPE_DOUBLE:
allowed_type_modifier= AUTO_INCREMENT_FLAG;
if (!fld_length && !fld_decimals)
{
@@ -8543,7 +9403,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
DBUG_RETURN(TRUE);
}
break;
- case FIELD_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP:
if (!fld_length)
{
/* Compressed date YYYYMMDDHHMMSS */
@@ -8597,21 +9457,21 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
Field::NONE));
}
break;
- case FIELD_TYPE_DATE:
+ case MYSQL_TYPE_DATE:
/* Old date type. */
if (protocol_version != PROTOCOL_VERSION-1)
- sql_type= FIELD_TYPE_NEWDATE;
+ sql_type= MYSQL_TYPE_NEWDATE;
/* fall trough */
- case FIELD_TYPE_NEWDATE:
+ case MYSQL_TYPE_NEWDATE:
length= 10;
break;
- case FIELD_TYPE_TIME:
+ case MYSQL_TYPE_TIME:
length= 10;
break;
- case FIELD_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME:
length= MAX_DATETIME_WIDTH;
break;
- case FIELD_TYPE_SET:
+ case MYSQL_TYPE_SET:
{
pack_length= get_set_pack_length(fld_interval_list->elements);
@@ -8627,7 +9487,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
length= 1;
break;
}
- case FIELD_TYPE_ENUM:
+ case MYSQL_TYPE_ENUM:
{
/* Should be safe. */
pack_length= get_enum_pack_length(fld_interval_list->elements);
@@ -8636,7 +9496,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
String *tmp;
while ((tmp= it++))
interval_list.push_back(tmp);
- length= 1; /* See comment for FIELD_TYPE_SET above. */
+ length= 1; /* See comment for MYSQL_TYPE_SET above. */
break;
}
case MYSQL_TYPE_VAR_STRING:
@@ -8655,19 +9515,19 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
pack_length= (length + 7) / 8;
break;
}
- case FIELD_TYPE_DECIMAL:
+ case MYSQL_TYPE_DECIMAL:
DBUG_ASSERT(0); /* Was obsolete */
}
/* Remember the value of length */
char_length= length;
if (!(flags & BLOB_FLAG) &&
- ((length > max_field_charlength && fld_type != FIELD_TYPE_SET &&
- fld_type != FIELD_TYPE_ENUM &&
+ ((length > max_field_charlength && fld_type != MYSQL_TYPE_SET &&
+ fld_type != MYSQL_TYPE_ENUM &&
(fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) ||
(!length &&
fld_type != MYSQL_TYPE_STRING &&
- fld_type != MYSQL_TYPE_VARCHAR && fld_type != FIELD_TYPE_GEOMETRY)))
+ fld_type != MYSQL_TYPE_VARCHAR && fld_type != MYSQL_TYPE_GEOMETRY)))
{
my_error((fld_type == MYSQL_TYPE_VAR_STRING ||
fld_type == MYSQL_TYPE_VARCHAR ||
@@ -8692,13 +9552,13 @@ enum_field_types get_blob_type_from_length(ulong length)
{
enum_field_types type;
if (length < 256)
- type= FIELD_TYPE_TINY_BLOB;
+ type= MYSQL_TYPE_TINY_BLOB;
else if (length < 65536)
- type= FIELD_TYPE_BLOB;
+ type= MYSQL_TYPE_BLOB;
else if (length < 256L*256L*256L)
- type= FIELD_TYPE_MEDIUM_BLOB;
+ type= MYSQL_TYPE_MEDIUM_BLOB;
else
- type= FIELD_TYPE_LONG_BLOB;
+ type= MYSQL_TYPE_LONG_BLOB;
return type;
}
@@ -8712,32 +9572,32 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
switch (type) {
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
- case FIELD_TYPE_DECIMAL: return (length);
+ case MYSQL_TYPE_DECIMAL: return (length);
case MYSQL_TYPE_VARCHAR: return (length + (length < 256 ? 1: 2));
- case FIELD_TYPE_YEAR:
- case FIELD_TYPE_TINY : return 1;
- case FIELD_TYPE_SHORT : return 2;
- case FIELD_TYPE_INT24:
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_TIME: return 3;
- case FIELD_TYPE_TIMESTAMP:
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_LONG : return 4;
- case FIELD_TYPE_FLOAT : return sizeof(float);
- case FIELD_TYPE_DOUBLE: return sizeof(double);
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */
- case FIELD_TYPE_NULL : return 0;
- case FIELD_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr;
- case FIELD_TYPE_BLOB: return 2+portable_sizeof_char_ptr;
- case FIELD_TYPE_MEDIUM_BLOB: return 3+portable_sizeof_char_ptr;
- case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
- case FIELD_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr;
- case FIELD_TYPE_SET:
- case FIELD_TYPE_ENUM:
- case FIELD_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_TINY : return 1;
+ case MYSQL_TYPE_SHORT : return 2;
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_TIME: return 3;
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_LONG : return 4;
+ case MYSQL_TYPE_FLOAT : return sizeof(float);
+ case MYSQL_TYPE_DOUBLE: return sizeof(double);
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */
+ case MYSQL_TYPE_NULL : return 0;
+ case MYSQL_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr;
+ case MYSQL_TYPE_BLOB: return 2+portable_sizeof_char_ptr;
+ case MYSQL_TYPE_MEDIUM_BLOB: return 3+portable_sizeof_char_ptr;
+ case MYSQL_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
+ case MYSQL_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr;
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_NEWDECIMAL:
abort(); return 0; // This shouldn't happen
- case FIELD_TYPE_BIT: return length / 8;
+ case MYSQL_TYPE_BIT: return length / 8;
default:
return 0;
}
@@ -8747,17 +9607,17 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
uint pack_length_to_packflag(uint type)
{
switch (type) {
- case 1: return f_settype((uint) FIELD_TYPE_TINY);
- case 2: return f_settype((uint) FIELD_TYPE_SHORT);
- case 3: return f_settype((uint) FIELD_TYPE_INT24);
- case 4: return f_settype((uint) FIELD_TYPE_LONG);
- case 8: return f_settype((uint) FIELD_TYPE_LONGLONG);
+ case 1: return f_settype((uint) MYSQL_TYPE_TINY);
+ case 2: return f_settype((uint) MYSQL_TYPE_SHORT);
+ case 3: return f_settype((uint) MYSQL_TYPE_INT24);
+ case 4: return f_settype((uint) MYSQL_TYPE_LONG);
+ case 8: return f_settype((uint) MYSQL_TYPE_LONGLONG);
}
return 0; // This shouldn't happen
}
-Field *make_field(char *ptr, uint32 field_length,
+Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
uchar *null_pos, uchar null_bit,
uint pack_flag,
enum_field_types field_type,
@@ -8765,14 +9625,13 @@ Field *make_field(char *ptr, uint32 field_length,
Field::geometry_type geom_type,
Field::utype unireg_check,
TYPELIB *interval,
- const char *field_name,
- struct st_table *table)
+ const char *field_name)
{
uchar *bit_ptr;
uchar bit_offset;
LINT_INIT(bit_ptr);
LINT_INIT(bit_offset);
- if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag))
+ if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag))
{
bit_ptr= null_pos;
bit_offset= null_bit;
@@ -8793,15 +9652,14 @@ Field *make_field(char *ptr, uint32 field_length,
null_bit= ((uchar) 1) << null_bit;
}
- switch (field_type)
- {
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_TIME:
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_TIMESTAMP:
- field_charset= &my_charset_bin;
- default: break;
+ switch (field_type) {
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ field_charset= &my_charset_bin;
+ default: break;
}
if (f_is_alpha(pack_flag))
@@ -8809,16 +9667,17 @@ Field *make_field(char *ptr, uint32 field_length,
if (!f_is_packed(pack_flag))
{
if (field_type == MYSQL_TYPE_STRING ||
- field_type == FIELD_TYPE_DECIMAL || // 3.23 or 4.0 string
+ field_type == MYSQL_TYPE_DECIMAL || // 3.23 or 4.0 string
field_type == MYSQL_TYPE_VAR_STRING)
return new Field_string(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
field_charset);
if (field_type == MYSQL_TYPE_VARCHAR)
return new Field_varstring(ptr,field_length,
HA_VARCHAR_PACKLENGTH(field_length),
null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
+ share,
field_charset);
return 0; // Error
}
@@ -8830,103 +9689,105 @@ Field *make_field(char *ptr, uint32 field_length,
#ifdef HAVE_SPATIAL
if (f_is_geom(pack_flag))
return new Field_geom(ptr,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name, share,
pack_length, geom_type);
#endif
if (f_is_blob(pack_flag))
return new Field_blob(ptr,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name, share,
pack_length, field_charset);
if (interval)
{
if (f_is_enum(pack_flag))
return new Field_enum(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
pack_length, interval, field_charset);
else
return new Field_set(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
pack_length, interval, field_charset);
}
}
switch (field_type) {
- case FIELD_TYPE_DECIMAL:
+ case MYSQL_TYPE_DECIMAL:
return new Field_decimal(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
return new Field_new_decimal(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_FLOAT:
+ case MYSQL_TYPE_FLOAT:
return new Field_float(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag)== 0);
- case FIELD_TYPE_DOUBLE:
+ case MYSQL_TYPE_DOUBLE:
return new Field_double(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag)== 0);
- case FIELD_TYPE_TINY:
+ case MYSQL_TYPE_TINY:
return new Field_tiny(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_SHORT:
+ case MYSQL_TYPE_SHORT:
return new Field_short(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_INT24:
+ case MYSQL_TYPE_INT24:
return new Field_medium(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_LONG:
+ case MYSQL_TYPE_LONG:
return new Field_long(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_LONGLONG:
+ case MYSQL_TYPE_LONGLONG:
return new Field_longlong(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP:
return new Field_timestamp(ptr,field_length, null_pos, null_bit,
- unireg_check, field_name, table,
+ unireg_check, field_name, share,
field_charset);
- case FIELD_TYPE_YEAR:
+ case MYSQL_TYPE_YEAR:
return new Field_year(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table);
- case FIELD_TYPE_DATE:
+ unireg_check, field_name);
+ case MYSQL_TYPE_DATE:
return new Field_date(ptr,null_pos,null_bit,
- unireg_check, field_name, table, field_charset);
- case FIELD_TYPE_NEWDATE:
+ unireg_check, field_name, field_charset);
+ case MYSQL_TYPE_NEWDATE:
return new Field_newdate(ptr,null_pos,null_bit,
- unireg_check, field_name, table, field_charset);
- case FIELD_TYPE_TIME:
+ unireg_check, field_name, field_charset);
+ case MYSQL_TYPE_TIME:
return new Field_time(ptr,null_pos,null_bit,
- unireg_check, field_name, table, field_charset);
- case FIELD_TYPE_DATETIME:
+ unireg_check, field_name, field_charset);
+ case MYSQL_TYPE_DATETIME:
return new Field_datetime(ptr,null_pos,null_bit,
- 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:
+ unireg_check, field_name, field_charset);
+ case MYSQL_TYPE_NULL:
+ return new Field_null(ptr, field_length, unireg_check, field_name,
+ field_charset);
+ case MYSQL_TYPE_BIT:
return f_bit_as_char(pack_flag) ?
new Field_bit_as_char(ptr, field_length, null_pos, null_bit,
- unireg_check, field_name, table) :
+ unireg_check, field_name) :
new Field_bit(ptr, field_length, null_pos, null_bit, bit_ptr,
- bit_offset, unireg_check, field_name, table);
+ bit_offset, unireg_check, field_name);
+
default: // Impossible (Wrong version)
break;
}
@@ -8936,7 +9797,7 @@ Field *make_field(char *ptr, uint32 field_length,
/* Create a field suitable for create of table */
-create_field::create_field(Field *old_field,Field *orig_field)
+Create_field::Create_field(Field *old_field,Field *orig_field)
{
field= old_field;
field_name=change=old_field->field_name;
@@ -8956,12 +9817,12 @@ create_field::create_field(Field *old_field,Field *orig_field)
portable_sizeof_char_ptr);
switch (sql_type) {
- case FIELD_TYPE_BLOB:
+ case MYSQL_TYPE_BLOB:
switch (pack_length - portable_sizeof_char_ptr) {
- case 1: sql_type= FIELD_TYPE_TINY_BLOB; break;
- case 2: sql_type= FIELD_TYPE_BLOB; break;
- case 3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break;
- default: sql_type= FIELD_TYPE_LONG_BLOB; break;
+ case 1: sql_type= MYSQL_TYPE_TINY_BLOB; break;
+ case 2: sql_type= MYSQL_TYPE_BLOB; break;
+ case 3: sql_type= MYSQL_TYPE_MEDIUM_BLOB; break;
+ default: sql_type= MYSQL_TYPE_LONG_BLOB; break;
}
length/= charset->mbmaxlen;
key_length/= charset->mbmaxlen;
@@ -8980,7 +9841,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
length= (length+charset->mbmaxlen-1) / charset->mbmaxlen;
break;
#ifdef HAVE_SPATIAL
- case FIELD_TYPE_GEOMETRY:
+ case MYSQL_TYPE_GEOMETRY:
geom_type= ((Field_geom*)old_field)->geom_type;
break;
#endif
@@ -8997,25 +9858,27 @@ create_field::create_field(Field *old_field,Field *orig_field)
if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) &&
old_field->ptr && orig_field &&
- (sql_type != FIELD_TYPE_TIMESTAMP || /* set def only if */
+ (sql_type != MYSQL_TYPE_TIMESTAMP || /* set def only if */
old_field->table->timestamp_field != old_field || /* timestamp field */
unireg_check == Field::TIMESTAMP_UN_FIELD)) /* has default val */
{
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff), charset);
my_ptrdiff_t diff;
/* Get the value from default_values */
diff= (my_ptrdiff_t) (orig_field->table->s->default_values-
orig_field->table->record[0]);
- orig_field->move_field(diff); // Points now at default_values
+ orig_field->move_field_offset(diff); // Points now at default_values
if (!orig_field->is_real_null())
{
- char buff[MAX_FIELD_WIDTH],*pos;
- String tmp(buff,sizeof(buff), charset), *res;
+ char buff[MAX_FIELD_WIDTH], *pos;
+ String tmp(buff, sizeof(buff), charset), *res;
res= orig_field->val_str(&tmp);
pos= (char*) sql_strmake(res->ptr(), res->length());
def= new Item_string(pos, res->length(), charset);
}
- orig_field->move_field(-diff); // Back to record[0]
+ orig_field->move_field_offset(-diff); // Back to record[0]
}
}
@@ -9191,4 +10054,3 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
field_name);
}
}
-