diff options
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 2014 |
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, ¬_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, - ¬_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, ¬_used); + return my_strntoll(&my_charset_bin, (char*) ptr, field_length, 10, NULL, + ¬_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, - ¬_used); + uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); + return my_strntod(field_charset, (char*) ptr+length_bytes, length, + &end_not_used, ¬_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, ¬_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); } } - |