diff options
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 1688 |
1 files changed, 752 insertions, 936 deletions
diff --git a/sql/field.cc b/sql/field.cc index 853b0c62f14..bf988fb5633 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -58,7 +58,7 @@ const char field_separator=','; ((ulong) ((1LL << MY_MIN(arg, 4) * 8) - 1)) // Column marked for read or the field set to read out of record[0] -inline bool Field::marked_for_read() const +bool Field::marked_for_read() const { return !table || (!table->read_set || @@ -73,7 +73,7 @@ inline bool Field::marked_for_read() const changed fields with DBUG_FIX_WRITE_SET() in table.cc */ -inline bool Field::marked_for_write_or_computed() const +bool Field::marked_for_write_or_computed() const { return (!table || (!table->write_set || @@ -984,7 +984,7 @@ static bool test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend) { if (cs != &my_charset_bin) - str+= cs->cset->scan(cs, str, strend, MY_SEQ_SPACES); + str+= cs->scan(str, strend, MY_SEQ_SPACES); return (str < strend); } @@ -1013,8 +1013,15 @@ CPP_UNNAMED_NS_END Static help functions *****************************************************************************/ +/* + @brief + Create a fixed size sort key part + + @param buff buffer where values are written + @param length fixed size of the sort column +*/ -void Field::make_sort_key(uchar *buff,uint length) +void Field::make_sort_key_part(uchar *buff,uint length) { if (maybe_null()) { @@ -1029,6 +1036,61 @@ void Field::make_sort_key(uchar *buff,uint length) } +/* + @brief + Create a packed sort key part + + @param buff buffer where values are written + @param sort_field sort column structure + + @retval + length of the bytes written, does not include the NULL bytes +*/ +uint +Field::make_packed_sort_key_part(uchar *buff, + const SORT_FIELD_ATTR *sort_field) +{ + if (maybe_null()) + { + if (is_null()) + { + *buff++= 0; + return 0; // For NULL values don't write any data + } + *buff++=1; + } + sort_string(buff, sort_field->original_length); + return sort_field->original_length; +} + + +uint +Field_longstr::make_packed_sort_key_part(uchar *buff, + const SORT_FIELD_ATTR *sort_field) +{ + if (maybe_null()) + { + if (is_null()) + { + *buff++= 0; + return 0; // For NULL values don't write any data + } + *buff++=1; + } + uchar *end= pack_sort_string(buff, sort_field); + return (uint) (end-buff); +} + + +uchar* +Field_longstr::pack_sort_string(uchar *to, const SORT_FIELD_ATTR *sort_field) +{ + StringBuffer<LONGLONG_BUFFER_SIZE+1> buf; + val_str(&buf, &buf); + return to + sort_field->pack_sort_string(to, &buf, field_charset()); +} + + /** @brief Determine the relative position of the field value in a numeric interval @@ -1120,15 +1182,15 @@ double Field::pos_in_interval_val_str(Field *min, Field *max, uint data_offset) uchar minp_prefix[sizeof(ulonglong)]; uchar maxp_prefix[sizeof(ulonglong)]; ulonglong mp, minp, maxp; - my_strnxfrm(charset(), mp_prefix, sizeof(mp), - ptr + data_offset, - data_length()); - my_strnxfrm(charset(), minp_prefix, sizeof(minp), - min->ptr + data_offset, - min->data_length()); - my_strnxfrm(charset(), maxp_prefix, sizeof(maxp), - max->ptr + data_offset, - max->data_length()); + charset()->strnxfrm(mp_prefix, sizeof(mp), + ptr + data_offset, + data_length()); + charset()->strnxfrm(minp_prefix, sizeof(minp), + min->ptr + data_offset, + min->data_length()); + charset()->strnxfrm(maxp_prefix, sizeof(maxp), + max->ptr + data_offset, + max->data_length()); mp= char_prefix_to_ulonglong(mp_prefix); minp= char_prefix_to_ulonglong(minp_prefix); maxp= char_prefix_to_ulonglong(maxp_prefix); @@ -1214,6 +1276,21 @@ bool Field::can_be_substituted_to_equal_item(const Context &ctx, } +bool Field::cmp_is_done_using_type_handler_of_this(const Item_bool_func *cond, + const Item *item) const +{ + /* + We could eventually take comparison_type_handler() from cond, + instead of calculating it again. But only some descendants of + Item_bool_func has this method. So this needs some hierarchy changes. + Another option is to pass "class Context" to this method. + */ + Type_handler_hybrid_field_type cmp(type_handler_for_comparison()); + return !cmp.aggregate_for_comparison(item->type_handler_for_comparison()) && + cmp.type_handler() == type_handler_for_comparison(); +} + + /* This handles all numeric and BIT data types. */ @@ -1582,7 +1659,7 @@ Value_source::Converter_string_to_number::check_edom_and_truncation(THD *thd, @note This is called after one has called one of the following functions: - strntoull10rnd() - - my_strntod() + - strntod() - str2my_decimal() @retval @@ -1662,9 +1739,9 @@ bool Field_num::get_int(CHARSET_INFO *cs, const char *from, size_t len, char *end; int error; - *rnd= (longlong) cs->cset->strntoull10rnd(cs, from, len, - unsigned_flag, &end, - &error); + *rnd= (longlong) cs->strntoull10rnd(from, len, + unsigned_flag, &end, + &error); if (unsigned_flag) { @@ -1703,7 +1780,7 @@ double Field_real::get_double(const char *str, size_t length, CHARSET_INFO *cs, int *error) { char *end; - double nr= my_strntod(cs,(char*) str, length, &end, error); + double nr= cs->strntod((char*) str, length, &end, error); if (unlikely(*error)) { set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); @@ -1760,10 +1837,10 @@ String *Field::val_int_as_str(String *val_buffer, bool unsigned_val) if (val_buffer->alloc(MY_INT64_NUM_DECIMAL_DIGITS)) return 0; - length= (uint) (*cs->cset->longlong10_to_str)(cs, (char*) val_buffer->ptr(), - MY_INT64_NUM_DECIMAL_DIGITS, - unsigned_val ? 10 : -10, - value); + length= (uint) (cs->longlong10_to_str)((char*) val_buffer->ptr(), + MY_INT64_NUM_DECIMAL_DIGITS, + unsigned_val ? 10 : -10, + value); val_buffer->length(length); return val_buffer; } @@ -1801,8 +1878,7 @@ void Field::hash(ulong *nr, ulong *nr2) else { uint len= pack_length(); - CHARSET_INFO *cs= sort_charset(); - cs->coll->hash_sort(cs, ptr, len, nr, nr2); + sort_charset()->hash_sort(ptr, len, nr, nr2); } } @@ -1827,7 +1903,7 @@ void Field::copy_from_tmp(int row_offset) } -bool Field::send_binary(Protocol *protocol) +bool Field::send(Protocol *protocol) { char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),charset()); @@ -1836,6 +1912,18 @@ bool Field::send_binary(Protocol *protocol) } +bool Field_num::send_numeric_zerofill_str(Protocol_text *protocol, + protocol_send_type_t send_type) +{ + DBUG_ASSERT(marked_for_read()); + StringBuffer<MAX_FIELD_WIDTH> tmp(&my_charset_latin1); + val_str(&tmp); + return protocol->store_numeric_zerofill_str(tmp.ptr(), + tmp.length(), + send_type); +} + + /** Check to see if field size is compatible with destination. @@ -1871,9 +1959,9 @@ bool Field::send_binary(Protocol *protocol) master's field size, @c false otherwise. */ bool Field::compatible_field_size(uint field_metadata, - Relay_log_info *rli_arg __attribute__((unused)), + const Relay_log_info *rli_arg __attribute__((unused)), uint16 mflags __attribute__((unused)), - int *order_var) + int *order_var) const { uint const source_size= pack_length_from_metadata(field_metadata); uint const destination_size= row_pack_length(); @@ -1887,16 +1975,41 @@ bool Field::compatible_field_size(uint field_metadata, int Field::store(const char *to, size_t length, CHARSET_INFO *cs, enum_check_fields check_level) { - Check_level_instant_set check_level_save(get_thd(), check_level); + Check_level_instant_set tmp_level(get_thd(), check_level); return store(to, length, cs); } +int Field::store_text(const char *to, size_t length, CHARSET_INFO *cs, + enum_check_fields check_level) +{ + Check_level_instant_set tmp_level(get_thd(), check_level); + return store_text(to, length, cs); +} + + int Field::store_timestamp_dec(const timeval &ts, uint dec) { return store_time_dec(Datetime(get_thd(), ts).get_mysql_time(), dec); } + +int Field::store_to_statistical_minmax_field(Field *field, String *val) +{ + val_str(val); + size_t length= Well_formed_prefix(val->charset(), val->ptr(), + MY_MIN(val->length(), field->field_length)).length(); + return field->store(val->ptr(), length, &my_charset_bin); +} + + +int Field::store_from_statistical_minmax_field(Field *stat_field, String *str) +{ + stat_field->val_str(str); + return store_text(str->ptr(), str->length(), &my_charset_bin); +} + + /** Pack the field into a format suitable for storage and transfer. @@ -2007,24 +2120,24 @@ void Field::make_send_field(Send_field *field) { if (orig_table && orig_table->s->db.str && *orig_table->s->db.str) { - field->db_name= orig_table->s->db.str; + field->db_name= orig_table->s->db; if (orig_table->pos_in_table_list && orig_table->pos_in_table_list->schema_table) - field->org_table_name= (orig_table->pos_in_table_list-> - schema_table->table_name); + field->org_table_name= Lex_cstring_strlen(orig_table->pos_in_table_list-> + schema_table->table_name); else - field->org_table_name= orig_table->s->table_name.str; + field->org_table_name= orig_table->s->table_name; } else - field->org_table_name= field->db_name= ""; + field->org_table_name= field->db_name= empty_clex_str; if (orig_table && orig_table->alias.ptr()) { - field->table_name= orig_table->alias.ptr(); + orig_table->alias.get_value(&field->table_name); field->org_col_name= field_name; } else { - field->table_name= ""; + field->table_name= empty_clex_str; field->org_col_name= empty_clex_str; } field->col_name= field_name; @@ -2183,11 +2296,9 @@ Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) { - field_charset= collation.collation; + m_collation= collation; if (collation.collation->state & MY_CS_BINSORT) flags|=BINARY_FLAG; - field_derivation= collation.derivation; - field_repertoire= collation.repertoire; } @@ -2201,7 +2312,7 @@ bool Field_str::test_if_equality_guarantees_uniqueness(const Item *item) const SELECT * FROM t1 WHERE varchar_column=DATE'2001-01-01' return non-unuque values, e.g. '2001-01-01' and '2001-01-01x'. */ - if (!field_charset->coll->propagate(field_charset, 0, 0) || + if (!field_charset()->propagate(0, 0) || item->cmp_type() != STRING_RESULT) return false; /* @@ -2212,8 +2323,8 @@ bool Field_str::test_if_equality_guarantees_uniqueness(const Item *item) const WHERE latin1_bin_column = _latin1'A' COLLATE latin1_swedish_ci return non-unique values 'a' and 'A'. */ - DTCollation tmp(field_charset, field_derivation, repertoire()); - return !tmp.aggregate(item->collation) && tmp.collation == field_charset; + DTCollation tmp(dtcollation()); + return !tmp.aggregate(item->collation) && tmp.collation == field_charset(); } @@ -2515,7 +2626,7 @@ bool Field_null::is_equal(const Column_definition &new_field) const { DBUG_ASSERT(!compression_method()); return new_field.type_handler() == type_handler() && - new_field.charset == field_charset && + new_field.charset == field_charset() && new_field.length == max_display_length(); } @@ -3061,8 +3172,7 @@ double Field_decimal::val_real(void) DBUG_ASSERT(marked_for_read()); int not_used; char *end_not_used; - return my_strntod(&my_charset_bin, (char*) ptr, field_length, &end_not_used, - ¬_used); + return my_charset_bin.strntod((char*) ptr, field_length, &end_not_used, ¬_used); } longlong Field_decimal::val_int(void) @@ -3070,10 +3180,8 @@ longlong Field_decimal::val_int(void) DBUG_ASSERT(marked_for_read()); int not_used; if (unsigned_flag) - 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); + return my_charset_bin.strntoull((char*) ptr, field_length, 10, NULL, ¬_used); + return my_charset_bin.strntoll((char*) ptr, field_length, 10, NULL, ¬_used); } @@ -3099,7 +3207,7 @@ 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 uchar *a_ptr,const uchar *b_ptr) +int Field_decimal::cmp(const uchar *a_ptr,const uchar *b_ptr) const { const uchar *end; int swap=0; @@ -3479,7 +3587,7 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value) } -int Field_new_decimal::cmp(const uchar *a,const uchar*b) +int Field_new_decimal::cmp(const uchar *a,const uchar*b) const { return memcmp(a, b, bin_size); } @@ -3511,11 +3619,12 @@ void Field_new_decimal::sql_type(String &str) const @returns number of bytes written to metadata_ptr */ -int Field_new_decimal::save_field_metadata(uchar *metadata_ptr) + +Binlog_type_info Field_new_decimal::binlog_type_info() const { - *metadata_ptr= precision; - *(metadata_ptr + 1)= decimals(); - return 2; + DBUG_ASSERT(Field_new_decimal::type() == binlog_type()); + return Binlog_type_info(Field_new_decimal::type(), precision + + (decimals() << 8), 2, binlog_signedness()); } @@ -3531,7 +3640,7 @@ int Field_new_decimal::save_field_metadata(uchar *metadata_ptr) @returns The size of the field based on the field metadata. */ -uint Field_new_decimal::pack_length_from_metadata(uint field_metadata) +uint Field_new_decimal::pack_length_from_metadata(uint field_metadata) const { uint const source_precision= (field_metadata >> 8U) & 0x00ff; uint const source_decimal= field_metadata & 0x00ff; @@ -3542,9 +3651,9 @@ uint Field_new_decimal::pack_length_from_metadata(uint field_metadata) bool Field_new_decimal::compatible_field_size(uint field_metadata, - Relay_log_info * __attribute__((unused)), + const Relay_log_info * __attribute__((unused)), uint16 mflags __attribute__((unused)), - int *order_var) + int *order_var) const { uint const source_precision= (field_metadata >> 8U) & 0x00ff; uint const source_decimal= field_metadata & 0x00ff; @@ -3665,6 +3774,17 @@ int Field_int::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg) } +void Field_int::sql_type(String &res) const +{ + CHARSET_INFO *cs=res.charset(); + Name name= type_handler()->type_handler_signed()->name(); + res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + "%.*s(%d)", (int) name.length(), name.ptr(), + (int) field_length)); + add_zerofill_and_unsigned(res); +} + + /**************************************************************************** ** tiny int ****************************************************************************/ @@ -3795,12 +3915,17 @@ String *Field_tiny::val_str(String *val_buffer, return val_str_from_long(val_buffer, 5, -10, nr); } -bool Field_tiny::send_binary(Protocol *protocol) +bool Field_tiny::send(Protocol *protocol) { - return protocol->store_tiny((longlong) (int8) ptr[0]); + DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast<Protocol_text*>(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_TINY); + return protocol->store_tiny(Field_tiny::val_int()); } -int Field_tiny::cmp(const uchar *a_ptr, const uchar *b_ptr) + +int Field_tiny::cmp(const uchar *a_ptr, const uchar *b_ptr) const { signed char a,b; a=(signed char) a_ptr[0]; b= (signed char) b_ptr[0]; @@ -3817,14 +3942,6 @@ void Field_tiny::sort_string(uchar *to,uint length __attribute__((unused))) to[0] = (char) (ptr[0] ^ (uchar) 128); /* Revers signbit */ } -void Field_tiny::sql_type(String &res) const -{ - CHARSET_INFO *cs=res.charset(); - res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "tinyint(%d)",(int) field_length)); - add_zerofill_and_unsigned(res); -} - /**************************************************************************** Field type short int (2 byte) ****************************************************************************/ @@ -3963,13 +4080,17 @@ String *Field_short::val_str(String *val_buffer, } -bool Field_short::send_binary(Protocol *protocol) +bool Field_short::send(Protocol *protocol) { + DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast<Protocol_text*>(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_SHORT); return protocol->store_short(Field_short::val_int()); } -int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr) const { short a,b; a=sint2korr(a_ptr); @@ -3990,15 +4111,6 @@ void Field_short::sort_string(uchar *to,uint length __attribute__((unused))) to[1] = ptr[0]; } -void Field_short::sql_type(String &res) const -{ - CHARSET_INFO *cs=res.charset(); - res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "smallint(%d)",(int) field_length)); - add_zerofill_and_unsigned(res); -} - - /**************************************************************************** Field type medium int (3 byte) ****************************************************************************/ @@ -4146,7 +4258,7 @@ String *Field_int::val_str_from_long(String *val_buffer, uint mlength= MY_MAX(field_length + 1, max_char_length * cs->mbmaxlen); val_buffer->alloc(mlength); char *to=(char*) val_buffer->ptr(); - length= (uint) cs->cset->long10_to_str(cs, to, mlength, radix, nr); + length= (uint) cs->long10_to_str(to, mlength, radix, nr); val_buffer->length(length); if (zerofill) prepend_zeros(val_buffer); /* purecov: inspected */ @@ -4155,14 +4267,17 @@ String *Field_int::val_str_from_long(String *val_buffer, } -bool Field_medium::send_binary(Protocol *protocol) +bool Field_medium::send(Protocol *protocol) { DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast<Protocol_text*>(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_LONG); return protocol->store_long(Field_medium::val_int()); } -int Field_medium::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_medium::cmp(const uchar *a_ptr, const uchar *b_ptr) const { long a,b; if (unsigned_flag) @@ -4189,14 +4304,6 @@ void Field_medium::sort_string(uchar *to,uint length __attribute__((unused))) } -void Field_medium::sql_type(String &res) const -{ - CHARSET_INFO *cs=res.charset(); - res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "mediumint(%d)",(int) field_length)); - add_zerofill_and_unsigned(res); -} - /**************************************************************************** ** long int ****************************************************************************/ @@ -4334,13 +4441,17 @@ String *Field_long::val_str(String *val_buffer, } -bool Field_long::send_binary(Protocol *protocol) +bool Field_long::send(Protocol *protocol) { DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast<Protocol_text*>(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_LONG); return protocol->store_long(Field_long::val_int()); } -int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr) + +int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr) const { int32 a,b; a=sint4korr(a_ptr); @@ -4362,14 +4473,6 @@ void Field_long::sort_string(uchar *to,uint length __attribute__((unused))) } -void Field_long::sql_type(String &res) const -{ - CHARSET_INFO *cs=res.charset(); - res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "int(%d)",(int) field_length)); - add_zerofill_and_unsigned(res); -} - /**************************************************************************** Field type longlong int (8 bytes) ****************************************************************************/ @@ -4381,7 +4484,7 @@ int Field_longlong::store(const char *from,size_t len,CHARSET_INFO *cs) char *end; ulonglong tmp; - tmp= cs->cset->strntoull10rnd(cs,from,len,unsigned_flag,&end,&error); + tmp= cs->strntoull10rnd(from, len, unsigned_flag, &end, &error); if (unlikely(error == MY_ERRNO_ERANGE)) { set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); @@ -4469,8 +4572,8 @@ String *Field_longlong::val_str(String *val_buffer, longlong j; j=sint8korr(ptr); - length=(uint) (cs->cset->longlong10_to_str)(cs,to,mlength, - unsigned_flag ? 10 : -10, j); + length=(uint) (cs->longlong10_to_str)(to, mlength, + unsigned_flag ? 10 : -10, j); val_buffer->length(length); if (zerofill) prepend_zeros(val_buffer); @@ -4479,14 +4582,17 @@ String *Field_longlong::val_str(String *val_buffer, } -bool Field_longlong::send_binary(Protocol *protocol) +bool Field_longlong::send(Protocol *protocol) { DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast<Protocol_text*>(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_LONGLONG); return protocol->store_longlong(Field_longlong::val_int(), unsigned_flag); } -int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr) const { longlong a,b; a=sint8korr(a_ptr); @@ -4513,14 +4619,6 @@ void Field_longlong::sort_string(uchar *to,uint length __attribute__((unused))) } -void Field_longlong::sql_type(String &res) const -{ - CHARSET_INFO *cs=res.charset(); - res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "bigint(%d)",(int) field_length)); - add_zerofill_and_unsigned(res); -} - void Field_longlong::set_max() { DBUG_ASSERT(marked_for_write_or_computed()); @@ -4621,7 +4719,7 @@ String *Field_float::val_str(String *val_buffer, } -int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr) const { float a,b; float4get(a,a_ptr); @@ -4667,10 +4765,13 @@ void Field_float::sort_string(uchar *to,uint length __attribute__((unused))) } -bool Field_float::send_binary(Protocol *protocol) +bool Field_float::send(Protocol *protocol) { DBUG_ASSERT(marked_for_read()); - return protocol->store((float) Field_float::val_real(), dec, (String*) 0); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast<Protocol_text*>(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_FLOAT); + return protocol->store_float((float) Field_float::val_real(), dec); } @@ -4683,26 +4784,11 @@ bool Field_float::send_binary(Protocol *protocol) @returns number of bytes written to metadata_ptr */ -int Field_float::save_field_metadata(uchar *metadata_ptr) +Binlog_type_info Field_float::binlog_type_info() const { - *metadata_ptr= pack_length(); - return 1; -} - - -void Field_float::sql_type(String &res) const -{ - if (dec >= FLOATING_POINT_DECIMALS) - { - res.set_ascii(STRING_WITH_LEN("float")); - } - else - { - CHARSET_INFO *cs= res.charset(); - res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "float(%d,%d)",(int) field_length,dec)); - } - add_zerofill_and_unsigned(res); + DBUG_ASSERT(Field_float::type() == binlog_type()); + return Binlog_type_info(Field_float::type(), pack_length(), 1, + binlog_signedness()); } @@ -4928,6 +5014,24 @@ Item *Field_real::get_equal_const_item(THD *thd, const Context &ctx, } +void Field_real::sql_type(String &res) const +{ + const Name name= type_handler()->name(); + if (dec >= FLOATING_POINT_DECIMALS) + { + res.set_ascii(name.ptr(), name.length()); + } + else + { + CHARSET_INFO *cs= res.charset(); + res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + "%.*s(%d,%d)", (int) name.length(), name.ptr(), + (int) field_length,dec)); + } + add_zerofill_and_unsigned(res); +} + + String *Field_double::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { @@ -4958,13 +5062,17 @@ String *Field_double::val_str(String *val_buffer, return val_buffer; } -bool Field_double::send_binary(Protocol *protocol) +bool Field_double::send(Protocol *protocol) { - return protocol->store((double) Field_double::val_real(), dec, (String*) 0); + DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast<Protocol_text*>(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_DOUBLE); + return protocol->store_double(Field_double::val_real(), dec); } -int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr) const { double a,b; float8get(a,a_ptr); @@ -4995,26 +5103,11 @@ void Field_double::sort_string(uchar *to,uint length __attribute__((unused))) @returns number of bytes written to metadata_ptr */ -int Field_double::save_field_metadata(uchar *metadata_ptr) -{ - *metadata_ptr= pack_length(); - return 1; -} - - -void Field_double::sql_type(String &res) const +Binlog_type_info Field_double::binlog_type_info() const { - CHARSET_INFO *cs=res.charset(); - if (dec >= FLOATING_POINT_DECIMALS) - { - res.set_ascii(STRING_WITH_LEN("double")); - } - else - { - res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "double(%d,%d)",(int) field_length,dec)); - } - add_zerofill_and_unsigned(res); + DBUG_ASSERT(Field_double::type() == binlog_type()); + return Binlog_type_info(Field_double::type(), pack_length(), 1, + binlog_signedness()); } @@ -5094,8 +5187,8 @@ int Field_timestamp::save_in_field(Field *to) return to->store_timestamp_dec(Timeval(ts, sec_part), decimals()); } -my_time_t Field_timestamp::get_timestamp(const uchar *pos, - ulong *sec_part) const +my_time_t Field_timestamp0::get_timestamp(const uchar *pos, + ulong *sec_part) const { DBUG_ASSERT(marked_for_read()); *sec_part= 0; @@ -5103,7 +5196,7 @@ my_time_t Field_timestamp::get_timestamp(const uchar *pos, } -bool Field_timestamp::val_native(Native *to) +bool Field_timestamp0::val_native(Native *to) { DBUG_ASSERT(marked_for_read()); my_time_t sec= (my_time_t) sint4korr(ptr); @@ -5268,12 +5361,6 @@ int Field_timestamp::store_native(const Native &value) } -double Field_timestamp::val_real(void) -{ - return (double) Field_timestamp::val_int(); -} - - longlong Field_timestamp::val_int(void) { MYSQL_TIME ltime; @@ -5377,15 +5464,15 @@ bool Field_timestamp::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) } -bool Field_timestamp::send_binary(Protocol *protocol) +bool Field_timestamp0::send(Protocol *protocol) { MYSQL_TIME ltime; - Field_timestamp::get_date(<ime, date_mode_t(0)); + Field_timestamp0::get_date(<ime, date_mode_t(0)); return protocol->store(<ime, 0); } -int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_timestamp0::cmp(const uchar *a_ptr, const uchar *b_ptr) const { int32 a,b; a=sint4korr(a_ptr); @@ -5394,7 +5481,7 @@ int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr) } -void Field_timestamp::sort_string(uchar *to,uint length __attribute__((unused))) +void Field_timestamp0::sort_string(uchar *to,uint length __attribute__((unused))) { to[0] = ptr[3]; to[1] = ptr[2]; @@ -5403,20 +5490,7 @@ void Field_timestamp::sort_string(uchar *to,uint length __attribute__((unused))) } -void Field_timestamp::sql_type(String &res) const -{ - if (!decimals()) - { - res.set_ascii(STRING_WITH_LEN("timestamp")); - return; - } - CHARSET_INFO *cs=res.charset(); - res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(), - "timestamp(%u)", decimals())); -} - - -int Field_timestamp::set_time() +int Field_timestamp0::set_time() { set_notnull(); store_TIMESTAMP(Timestamp(get_thd()->query_start(), 0)); @@ -5486,29 +5560,6 @@ static longlong read_native(const uchar *from, uint bytes) } #endif -static void store_lowendian(ulonglong num, uchar *to, uint bytes) -{ - switch(bytes) { - case 1: *to= (uchar)num; break; - case 2: int2store(to, num); break; - case 3: int3store(to, num); break; - case 4: int4store(to, num); break; - case 8: int8store(to, num); break; - default: DBUG_ASSERT(0); - } -} - -static longlong read_lowendian(const uchar *from, uint bytes) -{ - switch(bytes) { - case 1: return from[0]; - case 2: return uint2korr(from); - case 3: return uint3korr(from); - case 4: return uint4korr(from); - case 8: return sint8korr(from); - default: DBUG_ASSERT(0); return 0; - } -} void Field_timestamp_hires::store_TIMEVAL(const timeval &tv) { @@ -5573,7 +5624,7 @@ int Field_timestamp_with_dec::set_time() return 0; } -bool Field_timestamp_with_dec::send_binary(Protocol *protocol) +bool Field_timestamp_with_dec::send(Protocol *protocol) { MYSQL_TIME ltime; Field_timestamp::get_date(<ime, date_mode_t(0)); @@ -5581,7 +5632,7 @@ bool Field_timestamp_with_dec::send_binary(Protocol *protocol) } -int Field_timestamp_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_timestamp_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) const { int32 a,b; ulong a_sec_part, b_sec_part; @@ -5654,6 +5705,11 @@ bool Field_timestampf::val_native(Native *to) return Field::val_native(to); } +Binlog_type_info Field_timestampf::binlog_type_info() const +{ + return Binlog_type_info(Field_timestampf::binlog_type(), decimals(), 1); +} + /*************************************************************/ sql_mode_t Field_temporal::can_handle_sql_mode_dependency_on_store() const @@ -5690,6 +5746,44 @@ void Field_temporal::set_warnings(Sql_condition::enum_warning_level trunc_level, } +void Field_temporal::sql_type_dec_comment(String &res, + const Name &name, + uint dec, + const Name &comment) const +{ + CHARSET_INFO *cs=res.charset(); + res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(), + "%.*s(%u)%s%.*s%s", + (uint) name.length(), name.ptr(), + dec, + comment.length() ? " /* " : "", + (uint) comment.length(), comment.ptr(), + comment.length() ? " */" : "")); +} + + +void Field_temporal::sql_type_comment(String &res, + const Name &name, + const Name &comment) const +{ + CHARSET_INFO *cs=res.charset(); + res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(), + "%.*s%s%.*s%s", + (uint) name.length(), name.ptr(), + comment.length() ? " /* " : "", + (uint) comment.length(), comment.ptr(), + comment.length() ? " */" : "")); +} + + +const Name & Field_temporal::type_version_mysql56() +{ + DBUG_EXECUTE_IF("sql_type", return Type_handler::version_mysql56(); ); + static Name none(NULL, 0); + return none; +} + + /* Store string into a date/time field @@ -5871,7 +5965,7 @@ int Field_time::store_TIME_with_warning(const Time *t, } -void Field_time::store_TIME(const MYSQL_TIME *ltime) +void Field_time0::store_TIME(const MYSQL_TIME *ltime) { DBUG_ASSERT(ltime->year == 0); DBUG_ASSERT(ltime->month == 0); @@ -5959,14 +6053,14 @@ Field *Field_time::new_key_field(MEM_ROOT *root, TABLE *new_table, } -double Field_time::val_real(void) +double Field_time0::val_real(void) { DBUG_ASSERT(marked_for_read()); uint32 j= (uint32) uint3korr(ptr); return (double) j; } -longlong Field_time::val_int(void) +longlong Field_time0::val_int(void) { DBUG_ASSERT(marked_for_read()); return (longlong) sint3korr(ptr); @@ -6015,7 +6109,7 @@ bool Field_time::check_zero_in_date_with_warn(date_mode_t fuzzydate) DATE_FORMAT(time, "%l.%i %p") */ -bool Field_time::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) +bool Field_time0::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) { if (check_zero_in_date_with_warn(fuzzydate)) return true; @@ -6055,7 +6149,7 @@ bool Field_time::val_native(Native *to) } -bool Field_time::send_binary(Protocol *protocol) +bool Field_time::send(Protocol *protocol) { MYSQL_TIME ltime; get_date(<ime, Time::Options(TIME_TIME_ONLY, get_thd())); @@ -6063,7 +6157,7 @@ bool Field_time::send_binary(Protocol *protocol) } -int Field_time::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_time0::cmp(const uchar *a_ptr, const uchar *b_ptr) const { int32 a,b; a=(int32) sint3korr(a_ptr); @@ -6071,24 +6165,13 @@ int Field_time::cmp(const uchar *a_ptr, const uchar *b_ptr) return (a < b) ? -1 : (a > b) ? 1 : 0; } -void Field_time::sort_string(uchar *to,uint length __attribute__((unused))) +void Field_time0::sort_string(uchar *to,uint length __attribute__((unused))) { to[0] = (uchar) (ptr[2] ^ 128); to[1] = ptr[1]; to[2] = ptr[0]; } -void Field_time::sql_type(String &res) const -{ - if (decimals() == 0) - { - res.set_ascii(STRING_WITH_LEN("time")); - return; - } - CHARSET_INFO *cs= res.charset(); - res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(), - "time(%d)", decimals())); -} int Field_time_hires::reset() { @@ -6250,7 +6333,7 @@ bool Field_time_hires::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) } -int Field_time_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_time_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) const { ulonglong a=read_bigendian(a_ptr, Field_time_hires::pack_length()); ulonglong b=read_bigendian(b_ptr, Field_time_hires::pack_length()); @@ -6296,6 +6379,10 @@ bool Field_timef::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) TIME_from_longlong_time_packed(ltime, tmp); return false; } +Binlog_type_info Field_timef::binlog_type_info() const +{ + return Binlog_type_info(Field_timef::binlog_type(), decimals(), 1); +} longlong Field_timef::val_time_packed(THD *thd) @@ -6336,7 +6423,7 @@ int Field_year::store(const char *from, size_t len,CHARSET_INFO *cs) THD *thd= get_thd(); char *end; int error; - longlong nr= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error); + longlong nr= cs->strntoull10rnd(from, len, 0, &end, &error); if (nr < 0 || (nr >= 100 && nr <= 1900) || nr > 2155 || error == MY_ERRNO_ERANGE) @@ -6418,9 +6505,12 @@ int Field_year::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg) return 0; } -bool Field_year::send_binary(Protocol *protocol) +bool Field_year::send(Protocol *protocol) { DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if ((txt= dynamic_cast<Protocol_text*>(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_SHORT); ulonglong tmp= Field_year::val_int(); return protocol->store_short(tmp); } @@ -6555,7 +6645,7 @@ void Field_date::store_TIME(const MYSQL_TIME *ltime) int4store(ptr,tmp); } -bool Field_date::send_binary(Protocol *protocol) +bool Field_date::send(Protocol *protocol) { longlong tmp= Field_date::val_int(); MYSQL_TIME tm; @@ -6613,7 +6703,7 @@ String *Field_date::val_str(String *val_buffer, } -int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr) const { int32 a,b; a=sint4korr(a_ptr); @@ -6649,7 +6739,7 @@ void Field_newdate::store_TIME(const MYSQL_TIME *ltime) } -bool Field_newdate::send_binary(Protocol *protocol) +bool Field_newdate::send(Protocol *protocol) { MYSQL_TIME tm; Field_newdate::get_date(&tm, date_mode_t(0)); @@ -6725,7 +6815,7 @@ longlong Field_newdate::val_datetime_packed(THD *thd) } -int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr) const { uint32 a,b; a=(uint32) uint3korr(a_ptr); @@ -6814,7 +6904,7 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx, ** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int. ****************************************************************************/ -void Field_datetime::store_TIME(const MYSQL_TIME *ltime) +void Field_datetime0::store_TIME(const MYSQL_TIME *ltime) { ulonglong tmp= TIME_to_ulonglong_datetime(ltime); int8store(ptr,tmp); @@ -6829,20 +6919,15 @@ Field_datetime::conversion_depends_on_sql_mode(THD *thd, Item *expr) const } -bool Field_datetime::send_binary(Protocol *protocol) +bool Field_datetime0::send(Protocol *protocol) { MYSQL_TIME tm; - Field_datetime::get_date(&tm, date_mode_t(0)); + Field_datetime0::get_date(&tm, date_mode_t(0)); return protocol->store(&tm, 0); } -double Field_datetime::val_real(void) -{ - return (double) Field_datetime::val_int(); -} - -longlong Field_datetime::val_int(void) +longlong Field_datetime0::val_int(void) { DBUG_ASSERT(marked_for_read()); longlong j; @@ -6851,8 +6936,8 @@ longlong Field_datetime::val_int(void) } -String *Field_datetime::val_str(String *val_buffer, - String *val_ptr __attribute__((unused))) +String *Field_datetime0::val_str(String *val_buffer, + String *val_ptr __attribute__((unused))) { val_buffer->alloc(field_length); val_buffer->length(field_length); @@ -6863,7 +6948,7 @@ String *Field_datetime::val_str(String *val_buffer, char *pos; int part3; - tmp= Field_datetime::val_int(); + tmp= Field_datetime0::val_int(); /* Avoid problem with slow longlong arithmetic and sprintf @@ -6897,8 +6982,8 @@ String *Field_datetime::val_str(String *val_buffer, return val_buffer; } -bool Field_datetime::get_TIME(MYSQL_TIME *ltime, const uchar *pos, - date_mode_t fuzzydate) const +bool Field_datetime0::get_TIME(MYSQL_TIME *ltime, const uchar *pos, + date_mode_t fuzzydate) const { DBUG_ASSERT(marked_for_read()); longlong tmp= sint8korr(pos); @@ -6919,7 +7004,7 @@ bool Field_datetime::get_TIME(MYSQL_TIME *ltime, const uchar *pos, } -int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_datetime0::cmp(const uchar *a_ptr, const uchar *b_ptr) const { longlong a,b; a=sint8korr(a_ptr); @@ -6928,7 +7013,7 @@ int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr) ((ulonglong) a > (ulonglong) b) ? 1 : 0; } -void Field_datetime::sort_string(uchar *to,uint length __attribute__((unused))) +void Field_datetime0::sort_string(uchar *to,uint length __attribute__((unused))) { to[0] = ptr[7]; to[1] = ptr[6]; @@ -6941,19 +7026,6 @@ void Field_datetime::sort_string(uchar *to,uint length __attribute__((unused))) } -void Field_datetime::sql_type(String &res) const -{ - if (decimals() == 0) - { - res.set_ascii(STRING_WITH_LEN("datetime")); - return; - } - CHARSET_INFO *cs= res.charset(); - res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(), - "datetime(%u)", decimals())); -} - - int Field_datetime::set_time() { THD *thd= table->in_use; @@ -6975,7 +7047,7 @@ void Field_datetime_hires::store_TIME(const MYSQL_TIME *ltime) store_bigendian(packed, ptr, Field_datetime_hires::pack_length()); } -bool Field_datetime_with_dec::send_binary(Protocol *protocol) +bool Field_datetime_with_dec::send(Protocol *protocol) { MYSQL_TIME ltime; get_date(<ime, date_mode_t(0)); @@ -7021,7 +7093,7 @@ bool Field_datetime_hires::get_TIME(MYSQL_TIME *ltime, const uchar *pos, } -int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) const { ulonglong a=read_bigendian(a_ptr, Field_datetime_hires::pack_length()); ulonglong b=read_bigendian(b_ptr, Field_datetime_hires::pack_length()); @@ -7059,6 +7131,10 @@ bool Field_datetimef::get_TIME(MYSQL_TIME *ltime, const uchar *pos, TIME_from_longlong_datetime_packed(ltime, tmp); return validate_MMDD(tmp, ltime->month, ltime->day, fuzzydate); } +Binlog_type_info Field_datetimef::binlog_type_info() const +{ + return Binlog_type_info(Field_datetimef::binlog_type(), decimals(), 1); +} longlong Field_datetimef::val_datetime_packed(THD *thd) { @@ -7150,7 +7226,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end, if ((pstr < end) && (thd= get_thd())->count_cuted_fields > CHECK_FIELD_EXPRESSION) { - if (test_if_important_data(field_charset, pstr, end)) + if (test_if_important_data(field_charset(), pstr, end)) { if (thd->abort_on_warning) set_warning(ER_DATA_TOO_LONG, 1); @@ -7169,6 +7245,57 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end, } +/* + This is JSON specific. + We should eventually add Field_json_varchar and Field_json_blob + and move make_send_field() to the new classes. +*/ +void Field_longstr::make_send_field(Send_field *field) +{ + Field_str::make_send_field(field); + if (check_constraint) + { + /* + Append the format that is implicitly implied by the CHECK CONSTRAINT. + For example: + CREATE TABLE t1 (js longtext DEFAULT NULL CHECK (json_valid(a))); + SELECT j FROM t1; + will add "format=json" to the extended type info metadata for t1.js. + */ + check_constraint->expr->set_format_by_check_constraint(field); + } +} + + +/* + An optimized version that uses less stack than Field::send(). +*/ +bool Field_longstr::send(Protocol *protocol) +{ + String tmp; + val_str(&tmp, &tmp); + /* + Ensure this function is only used with classes that do not allocate + memory in val_str() + */ + DBUG_ASSERT(tmp.alloced_length() == 0); + return protocol->store(tmp.ptr(), tmp.length(), tmp.charset()); +} + + +const Type_handler *Field_string::type_handler() const +{ + if (is_var_string()) + return &type_handler_var_string; + /* + This is a temporary solution and will be fixed soon (in 10.9?). + Type_handler_string_json will provide its own Field_string_json. + */ + if (Type_handler_json_common::has_json_valid_constraint(this)) + return &type_handler_string_json; + return &type_handler_string; +} + /* Copy a string and fill with space */ int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs) @@ -7182,14 +7309,14 @@ int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs) rc= well_formed_copy_with_check((char*) ptr, field_length, cs, from, length, - field_length / field_charset->mbmaxlen, + Field_string::char_length(), false, ©_length); /* Append spaces if the string was shorter than the field. */ if (copy_length < field_length) - field_charset->cset->fill(field_charset,(char*) ptr+copy_length, - field_length-copy_length, - field_charset->pad_char); + field_charset()->fill((char*) ptr + copy_length, + field_length - copy_length, + field_charset()->pad_char); return rc; } @@ -7199,13 +7326,10 @@ int Field_str::store(longlong nr, bool unsigned_val) { char buff[64]; uint length; - length= (uint) (field_charset->cset->longlong10_to_str)(field_charset, - buff, - sizeof(buff), - (unsigned_val ? 10: - -10), - nr); - return store(buff, length, field_charset); + length= (uint) (field_charset()->longlong10_to_str)(buff, sizeof(buff), + (unsigned_val ? 10: -10), + nr); + return store(buff, length, field_charset()); } @@ -7221,8 +7345,7 @@ int Field_str::store(double nr) { DBUG_ASSERT(marked_for_write_or_computed()); char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; - uint local_char_length= MY_MIN(sizeof(buff), - field_length / field_charset->mbmaxlen); + uint local_char_length= MY_MIN(sizeof(buff), Field_str::char_length()); size_t length= 0; my_bool error= (local_char_length == 0); @@ -7245,7 +7368,7 @@ bool Field_string::is_equal(const Column_definition &new_field) const DBUG_ASSERT(!compression_method()); return new_field.type_handler() == type_handler() && new_field.char_length == char_length() && - new_field.charset == field_charset && + new_field.charset == field_charset() && new_field.length == max_display_length(); } @@ -7267,7 +7390,7 @@ bool Field_longstr::cmp_to_string_with_same_collation(const Item_bool_func *cond, const Item *item) const { - return item->cmp_type() == STRING_RESULT && + return cmp_is_done_using_type_handler_of_this(cond, item) && charset() == cond->compare_collation(); } @@ -7276,7 +7399,7 @@ bool Field_longstr::cmp_to_string_with_stricter_collation(const Item_bool_func *cond, const Item *item) const { - return item->cmp_type() == STRING_RESULT && + return cmp_is_done_using_type_handler_of_this(cond, item) && (charset() == cond->compare_collation() || cond->compare_collation()->state & MY_CS_BINSORT); } @@ -7331,7 +7454,7 @@ Field_string::Warn_filter_string::Warn_filter_string(const THD *thd, const Field_string *field) :Warn_filter(!thd->no_errors, !thd->no_errors && - field->Field_string::charset() == &my_charset_bin) + field->field_charset() == &my_charset_bin) { } @@ -7379,12 +7502,11 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)), size_t length; if (get_thd()->variables.sql_mode & MODE_PAD_CHAR_TO_FULL_LENGTH) - length= my_charpos(field_charset, ptr, ptr + field_length, - field_length / field_charset->mbmaxlen); + length= field_charset()->charpos(ptr, ptr + field_length, + Field_string::char_length()); else - length= field_charset->cset->lengthsp(field_charset, (const char*) ptr, - field_length); - val_ptr->set((const char*) ptr, length, field_charset); + length= field_charset()->lengthsp((const char*) ptr, field_length); + val_ptr->set((const char*) ptr, length, field_charset()); return val_ptr; } @@ -7404,7 +7526,7 @@ my_decimal *Field_string::val_decimal(my_decimal *decimal_value) struct Check_field_param { - Field *field; + const Field *field; }; #ifdef HAVE_REPLICATION @@ -7423,9 +7545,9 @@ check_field_for_37426(const void *param_arg) bool Field_string::compatible_field_size(uint field_metadata, - Relay_log_info *rli_arg, + const Relay_log_info *rli_arg, uint16 mflags __attribute__((unused)), - int *order_var) + int *order_var) const { #ifdef HAVE_REPLICATION const Check_field_param check_param = { this }; @@ -7437,12 +7559,12 @@ Field_string::compatible_field_size(uint field_metadata, } -int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) const { - return field_charset->coll->strnncollsp_nchars(field_charset, - a_ptr, field_length, - b_ptr, field_length, - Field_string::char_length()); + return field_charset()->coll->strnncollsp_nchars(field_charset(), + a_ptr, field_length, + b_ptr, field_length, + Field_string::char_length()); } @@ -7451,13 +7573,11 @@ void Field_string::sort_string(uchar *to,uint length) #ifdef DBUG_ASSERT_EXISTS size_t tmp= #endif - field_charset->coll->strnxfrm(field_charset, - to, length, - char_length() * - field_charset->strxfrm_multiply, - ptr, field_length, - MY_STRXFRM_PAD_WITH_SPACE | - MY_STRXFRM_PAD_TO_MAXLEN); + field_charset()->strnxfrm(to, length, + char_length() * field_charset()->strxfrm_multiply, + ptr, field_length, + MY_STRXFRM_PAD_WITH_SPACE | + MY_STRXFRM_PAD_TO_MAXLEN); DBUG_ASSERT(tmp == length); } @@ -7506,38 +7626,8 @@ void Field_string::sql_rpl_type(String *res) const uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) { - size_t length= MY_MIN(field_length,max_length); - size_t local_char_length= max_length/field_charset->mbmaxlen; - DBUG_PRINT("debug", ("Packing field '%s' - length: %zu ", field_name.str, - length)); - - if (length > local_char_length) - local_char_length= my_charpos(field_charset, from, from+length, - local_char_length); - set_if_smaller(length, local_char_length); - - /* - TODO: change charset interface to add a new function that does - the following or add a flag to lengthsp to do it itself - (this is for not packing padding adding bytes in BINARY - fields). - */ - if (field_charset->mbmaxlen == 1) - { - while (length && from[length-1] == field_charset->pad_char) - length --; - } - else - length= field_charset->cset->lengthsp(field_charset, (const char*) from, length); - - // Length always stored little-endian - *to++= (uchar) length; - if (field_length > 255) - *to++= (uchar) (length >> 8); - - // Store the actual bytes of the string - memcpy(to, from, length); - return to+length; + DBUG_PRINT("debug", ("Packing field '%s'", field_name.str)); + return StringPack(field_charset(), field_length).pack(to, from, max_length); } @@ -7564,44 +7654,8 @@ const uchar * Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end, uint param_data) { - uint from_length, length; - - /* - Compute the declared length of the field on the master. This is - used to decide if one or two bytes should be read as length. - */ - if (param_data) - from_length= (((param_data >> 4) & 0x300) ^ 0x300) + (param_data & 0x00ff); - else - from_length= field_length; - - DBUG_PRINT("debug", - ("param_data: 0x%x, field_length: %u, from_length: %u", - param_data, field_length, from_length)); - /* - Compute the actual length of the data by reading one or two bits - (depending on the declared field length on the master). - */ - if (from_length > 255) - { - if (from + 2 > from_end) - return 0; - length= uint2korr(from); - from+= 2; - } - else - { - if (from + 1 > from_end) - return 0; - length= (uint) *from++; - } - if (from + length > from_end || length > field_length) - return 0; - - memcpy(to, from, length); - // Pad the string with the pad character of the fields charset - field_charset->cset->fill(field_charset, (char*) to + length, field_length - length, field_charset->pad_char); - return from+length; + return StringPack(field_charset(), field_length).unpack(to, from, from_end, + param_data); } @@ -7635,41 +7689,51 @@ Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end, @returns number of bytes written to metadata_ptr */ -int Field_string::save_field_metadata(uchar *metadata_ptr) + +Binlog_type_info_fixed_string::Binlog_type_info_fixed_string(uchar type_code, + uint32 octets, + CHARSET_INFO *cs) + :Binlog_type_info(type_code, 0, 2, cs) { - DBUG_ASSERT(field_length < 1024); - DBUG_ASSERT((real_type() & 0xF0) == 0xF0); - DBUG_PRINT("debug", ("field_length: %u, real_type: %u", - field_length, real_type())); - *metadata_ptr= (real_type() ^ ((field_length & 0x300) >> 4)); - *(metadata_ptr + 1)= field_length & 0xFF; - return 2; + DBUG_ASSERT(octets < 1024); + DBUG_ASSERT((type_code & 0xF0) == 0xF0); + DBUG_PRINT("debug", ("octets: %u, type_code: %u", octets, type_code)); + m_metadata= (type_code ^ ((octets & 0x300) >> 4)) + + (((uint)(octets & 0xFF)) << 8); +} + + +Binlog_type_info Field_string::binlog_type_info() const +{ + DBUG_ASSERT(Field_string::type() == binlog_type()); + return Binlog_type_info_fixed_string(Field_string::binlog_type(), + field_length, charset()); } uint Field_string::packed_col_length(const uchar *data_ptr, uint length) { - if (length > 255) - return uint2korr(data_ptr)+2; - return (uint) *data_ptr + 1; + return StringPack::packed_col_length(data_ptr, length); } uint Field_string::max_packed_col_length(uint max_length) { - return (max_length > 255 ? 2 : 1)+max_length; + return StringPack::max_packed_col_length(max_length); } -uint Field_string::get_key_image(uchar *buff, uint length, imagetype type_arg) +uint Field_string::get_key_image(uchar *buff, uint length, const uchar *ptr_arg, + imagetype type_arg) const { - size_t bytes = my_charpos(field_charset, (char*) ptr, - (char*) ptr + field_length, - length / field_charset->mbmaxlen); - memcpy(buff, ptr, bytes); + size_t bytes= field_charset()->charpos((char*) ptr_arg, + (char*) ptr_arg + field_length, + length / mbmaxlen()); + memcpy(buff, ptr_arg, bytes); if (bytes < length) - field_charset->cset->fill(field_charset, (char*) buff + bytes, - length - bytes, field_charset->pad_char); + field_charset()->fill((char*) buff + bytes, + length - bytes, + field_charset()->pad_char); return (uint)bytes; } @@ -7695,6 +7759,12 @@ Field *Field_string::make_new_field(MEM_ROOT *root, TABLE *new_table, } +en_fieldtype Field_string::tmp_engine_column_type(bool use_packed_rows) const +{ + return field_length >= MIN_STRING_LENGTH_TO_PACK_ROWS ? FIELD_SKIP_ENDSPACE : + FIELD_NORMAL; +} + /**************************************************************************** VARCHAR type Data in field->ptr is stored as: @@ -7713,6 +7783,20 @@ Field *Field_string::make_new_field(MEM_ROOT *root, TABLE *new_table, const uint Field_varstring::MAX_SIZE= UINT_MAX16; + +const Type_handler *Field_varstring::type_handler() const +{ + /* + This is a temporary solution and will be fixed soon (in 10.9?). + Type_handler_varchar_json will provide its own Field_varstring_json + and Field_varstring_compressed_json + */ + if (Type_handler_json_common::has_json_valid_constraint(this)) + return &type_handler_varchar_json; + return &type_handler_varchar; +} + + /** Save the field metadata for varstring fields. @@ -7724,11 +7808,10 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16; @returns number of bytes written to metadata_ptr */ -int Field_varstring::save_field_metadata(uchar *metadata_ptr) +Binlog_type_info Field_varstring::binlog_type_info() const { - DBUG_ASSERT(field_length <= 65535); - int2store((char*)metadata_ptr, field_length); - return 2; + DBUG_ASSERT(Field_varstring::type() == binlog_type()); + return Binlog_type_info(Field_varstring::type(), field_length, 2, charset()); } @@ -7750,7 +7833,7 @@ int Field_varstring::store(const char *from,size_t length,CHARSET_INFO *cs) rc= well_formed_copy_with_check((char*) get_data(), field_length, cs, from, length, - field_length / field_charset->mbmaxlen, + Field_varstring::char_length(), true, ©_length); store_length(copy_length); @@ -7785,7 +7868,7 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)), String *val_ptr) { DBUG_ASSERT(marked_for_read()); - val_ptr->set((const char*) get_data(), get_length(), field_charset); + val_ptr->set((const char*) get_data(), get_length(), field_charset()); return val_ptr; } @@ -7804,7 +7887,18 @@ my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value) } -#ifdef HAVE_valgrind +/* + An optimized version that uses less stack and less temporary + variable initialization than Field_longstr::send() +*/ +bool Field_varstring::send(Protocol *protocol) +{ + return protocol->store((const char *) get_data(), get_length(), + field_charset()); +} + + +#ifdef HAVE_MEM_CHECK void Field_varstring::mark_unused_memory_as_defined() { uint used_length __attribute__((unused)) = get_length(); @@ -7813,7 +7907,7 @@ void Field_varstring::mark_unused_memory_as_defined() #endif -int Field_varstring::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_varstring::cmp(const uchar *a_ptr, const uchar *b_ptr) const { uint a_length, b_length; int diff; @@ -7830,19 +7924,14 @@ int Field_varstring::cmp(const uchar *a_ptr, const uchar *b_ptr) } set_if_smaller(a_length, field_length); set_if_smaller(b_length, field_length); - diff= field_charset->coll->strnncollsp(field_charset, - a_ptr+ - length_bytes, - a_length, - b_ptr+ - length_bytes, - b_length); + diff= field_charset()->strnncollsp(a_ptr + length_bytes, a_length, + b_ptr + length_bytes, b_length); return diff; } int Field_varstring::cmp_prefix(const uchar *a_ptr, const uchar *b_ptr, - size_t prefix_len) + size_t prefix_len) const { /* avoid expensive well_formed_char_length if possible */ if (prefix_len == table->field[field_index]->field_length) @@ -7860,12 +7949,13 @@ int Field_varstring::cmp_prefix(const uchar *a_ptr, const uchar *b_ptr, a_length= uint2korr(a_ptr); b_length= uint2korr(b_ptr); } - return field_charset->coll->strnncollsp_nchars(field_charset, - a_ptr + length_bytes, - a_length, - b_ptr + length_bytes, - b_length, - prefix_len / field_charset->mbmaxlen); + return field_charset()->coll->strnncollsp_nchars(field_charset(), + a_ptr + length_bytes, + a_length, + b_ptr + length_bytes, + b_length, + prefix_len / + field_charset()->mbmaxlen); } @@ -7874,20 +7964,19 @@ int Field_varstring::cmp_prefix(const uchar *a_ptr, const uchar *b_ptr, varstring and blob keys are ALWAYS stored with a 2 byte length prefix */ -int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length) +int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length) const { size_t length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); - size_t local_char_length= max_key_length / field_charset->mbmaxlen; + size_t local_char_length= max_key_length / mbmaxlen(); - local_char_length= my_charpos(field_charset, ptr + length_bytes, - ptr + length_bytes + length, local_char_length); + local_char_length= field_charset()->charpos(ptr + length_bytes, + ptr + length_bytes + length, + local_char_length); set_if_smaller(length, local_char_length); - return field_charset->coll->strnncollsp(field_charset, - ptr + length_bytes, - length, - key_ptr+ - HA_KEY_BLOB_LENGTH, - uint2korr(key_ptr)); + return field_charset()->strnncollsp(ptr + length_bytes, + length, + key_ptr + HA_KEY_BLOB_LENGTH, + uint2korr(key_ptr)); } @@ -7899,13 +7988,10 @@ int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length) (keys are created and compared in key.cc) */ -int Field_varstring::key_cmp(const uchar *a,const uchar *b) +int Field_varstring::key_cmp(const uchar *a,const uchar *b) const { - return field_charset->coll->strnncollsp(field_charset, - a + HA_KEY_BLOB_LENGTH, - uint2korr(a), - b + HA_KEY_BLOB_LENGTH, - uint2korr(b)); + return field_charset()->strnncollsp(a + HA_KEY_BLOB_LENGTH, uint2korr(a), + b + HA_KEY_BLOB_LENGTH, uint2korr(b)); } @@ -7915,7 +8001,7 @@ void Field_varstring::sort_string(uchar *to,uint length) val_str(&buf, &buf); - if (field_charset == &my_charset_bin) + if (field_charset() == &my_charset_bin) { /* Store length last in high-byte order to sort longer strings first */ if (length_bytes == 1) @@ -7928,11 +8014,11 @@ void Field_varstring::sort_string(uchar *to,uint length) #ifdef DBUG_ASSERT_EXISTS size_t rc= #endif - field_charset->coll->strnxfrm(field_charset, to, length, - char_length() * field_charset->strxfrm_multiply, - (const uchar*) buf.ptr(), buf.length(), - MY_STRXFRM_PAD_WITH_SPACE | - MY_STRXFRM_PAD_TO_MAXLEN); + field_charset()->strnxfrm(to, length, + char_length() * field_charset()->strxfrm_multiply, + (const uchar *) buf.ptr(), buf.length(), + MY_STRXFRM_PAD_WITH_SPACE | + MY_STRXFRM_PAD_TO_MAXLEN); DBUG_ASSERT(rc == length); } @@ -8085,17 +8171,19 @@ uint Field_varstring::max_packed_col_length(uint max_length) return (max_length > 255 ? 2 : 1)+max_length; } +void Field_varstring::val_str_from_ptr(String *val, const uchar *ptr) const +{ + val->set((const char*) get_data(ptr), get_length(ptr), field_charset()); +} + uint Field_varstring::get_key_image(uchar *buff, uint length, - imagetype type_arg) + const uchar *ptr_arg, + imagetype type_arg) const { String val; - uint local_char_length; + val_str_from_ptr(&val, ptr_arg); - MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->read_set); - val_str(&val, &val); - dbug_tmp_restore_column_map(&table->read_set, old_map); - - local_char_length= val.charpos(length / field_charset->mbmaxlen); + uint local_char_length= val.charpos(length / mbmaxlen()); if (local_char_length < val.length()) val.length(local_char_length); /* Key is always stored with 2 bytes */ @@ -8116,12 +8204,12 @@ uint Field_varstring::get_key_image(uchar *buff, uint length, void Field_varstring::set_key_image(const uchar *buff,uint length) { length= uint2korr(buff); // Real length is here - (void) store((const char*) buff + HA_KEY_BLOB_LENGTH, length, field_charset); + (void) store((const char*) buff + HA_KEY_BLOB_LENGTH, length, field_charset()); } int Field_varstring::cmp_binary(const uchar *a_ptr, const uchar *b_ptr, - uint32 max_length) + uint32 max_length) const { uint32 a_length,b_length; @@ -8176,7 +8264,7 @@ bool Field_varstring::is_equal(const Column_definition &new_field) const new_field.length == field_length && new_field.char_length == char_length() && !new_field.compression_method() == !compression_method() && - new_field.charset == field_charset; + new_field.charset == field_charset(); } @@ -8189,8 +8277,7 @@ void Field_varstring::hash(ulong *nr, ulong *nr2) 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); + charset()->hash_sort(ptr + length_bytes, len, nr, nr2); } } @@ -8240,11 +8327,11 @@ int Field_longstr::compress(char *to, uint to_length, uint buf_length; int rc= 0; - if (String::needs_conversion_on_storage(length, cs, field_charset) || + if (String::needs_conversion_on_storage(length, cs, field_charset()) || max_length < length) { - set_if_smaller(max_length, static_cast<ulonglong>(field_charset->mbmaxlen) * length + 1); - if (!(buf= (char*) my_malloc(max_length, MYF(MY_WME)))) + set_if_smaller(max_length, static_cast<ulonglong>(mbmaxlen()) * length + 1); + if (!(buf= (char*) my_malloc(PSI_INSTRUMENT_ME, max_length, MYF(MY_WME)))) { *out_length= 0; return -1; @@ -8294,7 +8381,7 @@ int Field_longstr::compress(char *to, uint to_length, */ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr, - const uchar *from, uint from_length) + const uchar *from, uint from_length) const { if (from_length) { @@ -8303,7 +8390,7 @@ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr, /* Uncompressed data */ if (!method) { - val_ptr->set((const char*) from + 1, from_length - 1, field_charset); + val_ptr->set((const char*) from + 1, from_length - 1, field_charset()); return val_ptr; } @@ -8312,7 +8399,7 @@ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr, if (!compression_methods[method].uncompress(val_buffer, from, from_length, field_length)) { - val_buffer->set_charset(field_charset); + val_buffer->set_charset(field_charset()); status_var_increment(get_thd()->status_var.column_decompressions); return val_buffer; } @@ -8324,7 +8411,7 @@ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr, safer route, let's return a zero string and let the general handler catch the error. */ - val_ptr->set("", 0, field_charset); + val_ptr->set("", 0, field_charset()); return val_ptr; } @@ -8342,6 +8429,11 @@ int Field_varstring_compressed::store(const char *from, size_t length, return rc; } +void Field_varstring_compressed::val_str_from_ptr(String *val, const uchar *ptr) const +{ + uncompress(val, val, get_data(ptr), get_length(ptr)); +} + String *Field_varstring_compressed::val_str(String *val_buffer, String *val_ptr) { @@ -8356,7 +8448,7 @@ double Field_varstring_compressed::val_real(void) THD *thd= get_thd(); String buf; val_str(&buf, &buf); - return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset, + return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset(), buf.ptr(), buf.length()).result(); } @@ -8367,12 +8459,13 @@ longlong Field_varstring_compressed::val_int(void) THD *thd= get_thd(); String buf; val_str(&buf, &buf); - return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset, + return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset(), buf.ptr(), buf.length()).result(); } -int Field_varstring_compressed::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_varstring_compressed::cmp(const uchar *a_ptr, + const uchar *b_ptr) const { String a, b; uint a_length, b_length; @@ -8391,7 +8484,14 @@ int Field_varstring_compressed::cmp(const uchar *a_ptr, const uchar *b_ptr) uncompress(&a, &a, a_ptr + length_bytes, a_length); uncompress(&b, &b, b_ptr + length_bytes, b_length); - return sortcmp(&a, &b, field_charset); + return sortcmp(&a, &b, field_charset()); +} + + +Binlog_type_info Field_varstring_compressed::binlog_type_info() const +{ + return Binlog_type_info(Field_varstring_compressed::binlog_type(), + field_length, 2, charset()); } @@ -8436,7 +8536,7 @@ uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg) const */ int Field_blob::copy_value(Field_blob *from) { - DBUG_ASSERT(field_charset == from->charset()); + DBUG_ASSERT(field_charset() == from->charset()); DBUG_ASSERT(!compression_method() == !from->compression_method()); int rc= 0; uint32 length= from->get_length(); @@ -8444,7 +8544,7 @@ int Field_blob::copy_value(Field_blob *from) if (packlength < from->packlength) { set_if_smaller(length, Field_blob::max_data_length()); - length= (uint32) Well_formed_prefix(field_charset, + length= (uint32) Well_formed_prefix(field_charset(), (const char *) data, length).length(); rc= report_if_important_data((const char *) data + length, (const char *) data + from->get_length(), @@ -8481,7 +8581,7 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs) if (table && table->blob_storage) // GROUP_CONCAT with ORDER BY | DISTINCT { DBUG_ASSERT(!f_is_hex_escape(flags)); - DBUG_ASSERT(field_charset == cs); + DBUG_ASSERT(field_charset() == cs); DBUG_ASSERT(length <= max_data_length()); new_length= length; @@ -8512,7 +8612,7 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs) If content of the 'from'-address is cached in the 'value'-object it is possible that the content needs a character conversion. */ - if (!String::needs_conversion_on_storage(length, cs, field_charset)) + if (!String::needs_conversion_on_storage(length, cs, field_charset())) { Field_blob::store_length(length); bmove(ptr + packlength, &from, sizeof(char*)); @@ -8523,14 +8623,14 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs) from= tmpstr.ptr(); } - new_length= MY_MIN(max_data_length(), field_charset->mbmaxlen * length); + new_length= MY_MIN(max_data_length(), mbmaxlen() * length); if (value.alloc(new_length)) goto oom_error; tmp= const_cast<char*>(value.ptr()); if (f_is_hex_escape(flags)) { - copy_length= my_copy_with_hex_escaping(field_charset, + copy_length= my_copy_with_hex_escaping(field_charset(), tmp, new_length, from, length); Field_blob::store_length(copy_length); @@ -8619,14 +8719,13 @@ my_decimal *Field_blob::val_decimal(my_decimal *decimal_value) int Field_blob::cmp(const uchar *a,uint32 a_length, const uchar *b, - uint32 b_length) + uint32 b_length) const { - return field_charset->coll->strnncollsp(field_charset, - a, a_length, b, b_length); + return field_charset()->strnncollsp(a, a_length, b, b_length); } -int Field_blob::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_blob::cmp(const uchar *a_ptr, const uchar *b_ptr) const { uchar *blob1,*blob2; memcpy(&blob1, a_ptr+packlength, sizeof(char*)); @@ -8637,21 +8736,22 @@ int Field_blob::cmp(const uchar *a_ptr, const uchar *b_ptr) int Field_blob::cmp_prefix(const uchar *a_ptr, const uchar *b_ptr, - size_t prefix_len) + size_t prefix_len) const { uchar *blob1,*blob2; memcpy(&blob1, a_ptr+packlength, sizeof(char*)); memcpy(&blob2, b_ptr+packlength, sizeof(char*)); size_t a_len= get_length(a_ptr), b_len= get_length(b_ptr); - return field_charset->coll->strnncollsp_nchars(field_charset, - blob1, a_len, - blob2, b_len, - prefix_len / field_charset->mbmaxlen); + return field_charset()->coll->strnncollsp_nchars(field_charset(), + blob1, a_len, + blob2, b_len, + prefix_len / + field_charset()->mbmaxlen); } int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr, - uint32 max_length) + uint32 max_length) const { char *a,*b; uint diff; @@ -8674,44 +8774,14 @@ int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr, /* The following is used only when comparing a key */ -uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg) +uint Field_blob::get_key_image_itRAW(const uchar *ptr_arg, uchar *buff, + uint length) const { - size_t blob_length= get_length(ptr); - uchar *blob; - -#ifdef HAVE_SPATIAL - if (type_arg == itMBR) - { - const char *dummy; - MBR mbr; - Geometry_buffer buffer; - Geometry *gobj; - const uint image_length= SIZEOF_STORED_DOUBLE*4; - - if (blob_length < SRID_SIZE) - { - bzero(buff, image_length); - return image_length; - } - blob= get_ptr(); - gobj= Geometry::construct(&buffer, (char*) blob, (uint32)blob_length); - if (!gobj || gobj->get_mbr(&mbr, &dummy)) - bzero(buff, image_length); - else - { - float8store(buff, mbr.xmin); - float8store(buff+8, mbr.xmax); - float8store(buff+16, mbr.ymin); - float8store(buff+24, mbr.ymax); - } - return image_length; - } -#endif /*HAVE_SPATIAL*/ - - blob= get_ptr(); - size_t local_char_length= length / field_charset->mbmaxlen; - local_char_length= my_charpos(field_charset, blob, blob + blob_length, - local_char_length); + size_t blob_length= get_length(ptr_arg); + const uchar *blob= get_ptr(ptr_arg); + size_t local_char_length= length / mbmaxlen(); + local_char_length= field_charset()->charpos(blob, blob + blob_length, + local_char_length); set_if_smaller(blob_length, local_char_length); if (length > blob_length) @@ -8734,26 +8804,26 @@ void Field_blob::set_key_image(const uchar *buff,uint length) { length= uint2korr(buff); (void) Field_blob::store((const char*) buff+HA_KEY_BLOB_LENGTH, length, - field_charset); + field_charset()); } -int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length) +int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length) const { uchar *blob1; size_t blob_length=get_length(ptr); memcpy(&blob1, ptr+packlength, sizeof(char*)); CHARSET_INFO *cs= charset(); size_t local_char_length= max_key_length / cs->mbmaxlen; - local_char_length= my_charpos(cs, blob1, blob1+blob_length, - local_char_length); + local_char_length= cs->charpos(blob1, blob1+blob_length, + local_char_length); set_if_smaller(blob_length, local_char_length); return Field_blob::cmp(blob1, (uint32)blob_length, key_ptr+HA_KEY_BLOB_LENGTH, uint2korr(key_ptr)); } -int Field_blob::key_cmp(const uchar *a,const uchar *b) +int Field_blob::key_cmp(const uchar *a,const uchar *b) const { return Field_blob::cmp(a+HA_KEY_BLOB_LENGTH, uint2korr(a), b+HA_KEY_BLOB_LENGTH, uint2korr(b)); @@ -8784,19 +8854,25 @@ Field *Field_blob::new_key_field(MEM_ROOT *root, TABLE *new_table, @returns number of bytes written to metadata_ptr */ -int Field_blob::save_field_metadata(uchar *metadata_ptr) +Binlog_type_info Field_blob::binlog_type_info() const { - DBUG_ENTER("Field_blob::save_field_metadata"); - *metadata_ptr= pack_length_no_ptr(); - DBUG_PRINT("debug", ("metadata: %u (pack_length_no_ptr)", *metadata_ptr)); - DBUG_RETURN(1); + DBUG_ASSERT(Field_blob::type() == binlog_type()); + return Binlog_type_info(Field_blob::type(), pack_length_no_ptr(), 1, + charset()); } uint32 Field_blob::sort_length() const { - return (uint32) (get_thd()->variables.max_sort_length + - (field_charset == &my_charset_bin ? 0 : packlength)); + return packlength == 4 ? + UINT_MAX32 : + (uint32) field_length + sort_suffix_length(); +} + + +uint32 Field_blob::sort_suffix_length() const +{ + return field_charset() == &my_charset_bin ? packlength : 0; } @@ -8805,11 +8881,11 @@ void Field_blob::sort_string(uchar *to,uint length) String buf; val_str(&buf, &buf); - if (!buf.length() && field_charset->pad_char == 0) + if (!buf.length() && field_charset()->pad_char == 0) bzero(to,length); else { - if (field_charset == &my_charset_bin) + if (field_charset() == &my_charset_bin) { /* Store length of blob last in blob to shorter blobs before longer blobs @@ -8821,10 +8897,10 @@ void Field_blob::sort_string(uchar *to,uint length) #ifdef DBUG_ASSERT_EXISTS size_t rc= #endif - field_charset->coll->strnxfrm(field_charset, to, length, length, - (const uchar*) buf.ptr(), buf.length(), - MY_STRXFRM_PAD_WITH_SPACE | - MY_STRXFRM_PAD_TO_MAXLEN); + field_charset()->strnxfrm(to, length, length, + (const uchar *) buf.ptr(), buf.length(), + MY_STRXFRM_PAD_WITH_SPACE | + MY_STRXFRM_PAD_TO_MAXLEN); DBUG_ASSERT(rc == length); } } @@ -8837,6 +8913,15 @@ void Field_blob::sort_string(uchar *to,uint length) */ const Type_handler *Field_blob::type_handler() const { + /* + This is a temporary solution and will be fixed soon (in 10.9?). + Type_handler_*blob_json will provide its own Field_blob_json + and Field_blob_compressed_json. + */ + if (Type_handler_json_common::has_json_valid_constraint(this)) + return Type_handler_json_common:: + json_blob_type_handler_by_length_bytes(packlength); + switch (packlength) { case 1: return &type_handler_tiny_blob; case 2: return &type_handler_blob; @@ -8871,9 +8956,7 @@ void Field_blob::sql_type(String &res) const uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length) { - uchar *save= ptr; - ptr= (uchar*) from; - uint32 length=get_length(); // Length of from string + uint32 length=get_length(from, packlength); // Length of from string /* Store max length, which will occupy packlength bytes. If the max @@ -8887,10 +8970,9 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length) */ if (length > 0) { - from= get_ptr(); + from= get_ptr(from); memcpy(to+packlength, from,length); } - ptr=save; // Restore org row pointer return to+packlength+length; } @@ -8959,7 +9041,7 @@ bool Field_blob::is_equal(const Column_definition &new_field) const return new_field.type_handler() == type_handler() && !new_field.compression_method() == !compression_method() && new_field.pack_length == pack_length() && - new_field.charset == field_charset; + new_field.charset == field_charset(); } @@ -8995,8 +9077,7 @@ int Field_blob_compressed::store(const char *from, size_t length, DBUG_ASSERT(marked_for_write_or_computed()); uint compressed_length; uint max_length= max_data_length(); - uint to_length= (uint) MY_MIN(max_length, - field_charset->mbmaxlen * length + 1); + uint to_length= (uint) MY_MIN(max_length, mbmaxlen() * length + 1); String tmp(from, length, cs); int rc; @@ -9030,7 +9111,7 @@ double Field_blob_compressed::val_real(void) THD *thd= get_thd(); String buf; val_str(&buf, &buf); - return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset, + return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset(), buf.ptr(), buf.length()).result(); } @@ -9041,285 +9122,16 @@ longlong Field_blob_compressed::val_int(void) THD *thd= get_thd(); String buf; val_str(&buf, &buf); - return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset, + return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset(), buf.ptr(), buf.length()).result(); } - -#ifdef HAVE_SPATIAL -/* Values 1-40 reserved for 1-byte options, - 41-80 for 2-byte options, - 81-120 for 4-byte options, - 121-160 for 8-byte options, - other - varied length in next 1-3 bytes. -*/ -enum extra2_gis_field_options { - FIELDGEOM_END=0, - FIELDGEOM_STORAGE_MODEL=1, - FIELDGEOM_PRECISION=2, - FIELDGEOM_SCALE=3, - FIELDGEOM_SRID=81, -}; - - -uint gis_field_options_image(uchar *buff, List<Create_field> &create_fields) +Binlog_type_info Field_blob_compressed::binlog_type_info() const { - uint image_size= 0; - List_iterator<Create_field> it(create_fields); - Create_field *field; - while ((field= it++)) - { - if (field->real_field_type() != MYSQL_TYPE_GEOMETRY) - continue; - if (buff) - { - uchar *cbuf= buff + image_size; - - cbuf[0]= FIELDGEOM_STORAGE_MODEL; - cbuf[1]= (uchar) Field_geom::GEOM_STORAGE_WKB; - - cbuf[2]= FIELDGEOM_PRECISION; - cbuf[3]= (uchar) field->length; - - cbuf[4]= FIELDGEOM_SCALE; - cbuf[5]= (uchar) field->decimals; - - cbuf[6]= FIELDGEOM_SRID; - int4store(cbuf + 7, ((uint32) field->srid)); - - cbuf[11]= FIELDGEOM_END; - } - image_size+= 12; - } - - return image_size; + return Binlog_type_info(Field_blob_compressed::binlog_type(), + pack_length_no_ptr(), 1, charset()); } - -uint gis_field_options_read(const uchar *buf, size_t buf_len, - Field_geom::storage_type *st_type,uint *precision, uint *scale, uint *srid) -{ - const uchar *buf_end= buf + buf_len; - const uchar *cbuf= buf; - int option_id; - - *precision= *scale= *srid= 0; - *st_type= Field_geom::GEOM_STORAGE_WKB; - - if (!buf) /* can only happen with the old FRM file */ - goto end_of_record; - - while (cbuf < buf_end) - { - switch ((option_id= *(cbuf++))) - { - case FIELDGEOM_STORAGE_MODEL: - *st_type= (Field_geom::storage_type) cbuf[0]; - break; - case FIELDGEOM_PRECISION: - *precision= cbuf[0]; - break; - case FIELDGEOM_SCALE: - *scale= cbuf[0]; - break; - case FIELDGEOM_SRID: - *srid= uint4korr(cbuf); - break; - case FIELDGEOM_END: - goto end_of_record; - } - if (option_id > 0 && option_id <= 40) - cbuf+= 1; - else if (option_id > 40 && option_id <= 80) - cbuf+= 2; - else if (option_id > 80 && option_id <= 120) - cbuf+= 4; - else if (option_id > 120 && option_id <= 160) - cbuf+= 8; - else /* > 160 and <=255 */ - cbuf+= cbuf[0] ? 1 + cbuf[0] : 3 + uint2korr(cbuf+1); - } - -end_of_record: - return (uint)(cbuf - buf); -} - - - -void Field_geom::sql_type(String &res) const -{ - CHARSET_INFO *cs= &my_charset_latin1; - switch (geom_type) - { - case GEOM_POINT: - res.set(STRING_WITH_LEN("point"), cs); - break; - case GEOM_LINESTRING: - res.set(STRING_WITH_LEN("linestring"), cs); - break; - case GEOM_POLYGON: - res.set(STRING_WITH_LEN("polygon"), cs); - break; - case GEOM_MULTIPOINT: - res.set(STRING_WITH_LEN("multipoint"), cs); - break; - case GEOM_MULTILINESTRING: - res.set(STRING_WITH_LEN("multilinestring"), cs); - break; - case GEOM_MULTIPOLYGON: - res.set(STRING_WITH_LEN("multipolygon"), cs); - break; - case GEOM_GEOMETRYCOLLECTION: - res.set(STRING_WITH_LEN("geometrycollection"), cs); - break; - default: - res.set(STRING_WITH_LEN("geometry"), cs); - } -} - - -int Field_geom::store(double nr) -{ - my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, - ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); - return -1; -} - - -int Field_geom::store(longlong nr, bool unsigned_val) -{ - my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, - ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); - return -1; -} - - -int Field_geom::store_decimal(const my_decimal *) -{ - my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, - ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); - return -1; -} - - -int Field_geom::store(const char *from, size_t length, CHARSET_INFO *cs) -{ - if (!length) - bzero(ptr, Field_blob::pack_length()); - else - { - if (from == Geometry::bad_geometry_data.ptr()) - goto err; - // Check given WKB - uint32 wkb_type; - if (length < SRID_SIZE + WKB_HEADER_SIZE + 4) - goto err; - wkb_type= uint4korr(from + SRID_SIZE + 1); - if (wkb_type < (uint32) Geometry::wkb_point || - wkb_type > (uint32) Geometry::wkb_last) - goto err; - - if (geom_type != Field::GEOM_GEOMETRY && - geom_type != Field::GEOM_GEOMETRYCOLLECTION && - (uint32) geom_type != wkb_type) - { - const char *db= table->s->db.str; - const char *tab_name= table->s->table_name.str; - Geometry_buffer buffer; - Geometry *geom= NULL; - String wkt; - const char *dummy; - - if (!db) - db= ""; - if (!tab_name) - tab_name= ""; - wkt.set_charset(&my_charset_latin1); - if (!(geom= Geometry::construct(&buffer, from, uint32(length))) || - geom->as_wkt(&wkt, &dummy)) - goto err; - - my_error(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, MYF(0), - Geometry::ci_collection[geom_type]->m_name.str, - wkt.c_ptr_safe(), db, tab_name, field_name.str, - (ulong) table->in_use->get_stmt_da()-> - current_row_for_warning()); - - goto err_exit; - } - - Field_blob::store_length(length); - if ((table->copy_blobs || length <= MAX_FIELD_WIDTH) && - from != value.ptr()) - { // Must make a copy - value.copy(from, length, cs); - from= value.ptr(); - } - bmove(ptr + packlength, &from, sizeof(char*)); - } - return 0; - -err: - my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, - ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); -err_exit: - bzero(ptr, Field_blob::pack_length()); - return -1; -} - -Field::geometry_type Field_geom::geometry_type_merge(geometry_type a, - geometry_type b) -{ - if (a == b) - return a; - return Field::GEOM_GEOMETRY; -} - - -bool Field_geom::is_equal(const Column_definition &new_field) const -{ - return new_field.type_handler() == type_handler() && - /* - - Allow ALTER..INPLACE to supertype (GEOMETRY), - e.g. POINT to GEOMETRY or POLYGON to GEOMETRY. - - Allow ALTER..INPLACE to the same geometry type: POINT -> POINT - */ - (new_field.geom_type == geom_type || - new_field.geom_type == GEOM_GEOMETRY); -} - - -bool Field_geom::can_optimize_range(const Item_bool_func *cond, - const Item *item, - bool is_eq_func) const -{ - return item->cmp_type() == STRING_RESULT; -} - - -bool Field_geom::load_data_set_no_data(THD *thd, bool fixed_format) -{ - return Field_geom::load_data_set_null(thd); -} - - -bool Field_geom::load_data_set_null(THD *thd) -{ - Field_blob::reset(); - if (!maybe_null()) - { - my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field_name.str, - thd->get_stmt_da()->current_row_for_warning()); - return true; - } - set_null(); - set_has_explicit_value(); // Do not auto-update this field - return false; -} - - -#endif /*HAVE_SPATIAL*/ - /**************************************************************************** ** enum type. ** This is a string which only can have a selection of different values. @@ -9363,24 +9175,24 @@ int Field_enum::store(const char *from,size_t length,CHARSET_INFO *cs) String tmpstr(buff,sizeof(buff), &my_charset_bin); /* Convert character set if necessary */ - if (String::needs_conversion_on_storage(length, cs, field_charset)) + if (String::needs_conversion_on_storage(length, cs, field_charset())) { uint dummy_errors; - tmpstr.copy(from, length, cs, field_charset, &dummy_errors); + tmpstr.copy(from, length, cs, field_charset(), &dummy_errors); from= tmpstr.ptr(); length= tmpstr.length(); } /* Remove end space */ - length= (uint)field_charset->cset->lengthsp(field_charset, from, length); - uint tmp=find_type2(typelib, from, length, field_charset); + length= (uint) field_charset()->lengthsp(from, length); + uint tmp=find_type2(typelib, from, length, field_charset()); if (!tmp) { if (length < 6) // Can't be more than 99999 enums { /* This is for reading numbers with LOAD DATA INFILE */ char *end; - tmp=(uint) my_strntoul(cs,from,length,10,&end,&err); + tmp=(uint) cs->strntoul(from,length,10,&end,&err); if (err || end != from+length || tmp > typelib->count) { tmp=0; @@ -9434,9 +9246,13 @@ double Field_enum::val_real(void) longlong Field_enum::val_int(void) { DBUG_ASSERT(marked_for_read()); - return read_lowendian(ptr, packlength); + return val_int(ptr); } +longlong Field_enum::val_int(const uchar *real_ptr) const +{ + return read_lowendian(real_ptr, packlength); +} /** Save the field metadata for enum fields. @@ -9449,11 +9265,11 @@ longlong Field_enum::val_int(void) @returns number of bytes written to metadata_ptr */ -int Field_enum::save_field_metadata(uchar *metadata_ptr) +Binlog_type_info Field_enum::binlog_type_info() const { - *metadata_ptr= real_type(); - *(metadata_ptr + 1)= pack_length(); - return 2; + DBUG_ASSERT(Field_enum::type() == binlog_type()); + return Binlog_type_info(Field_enum::type(), real_type() + (pack_length() << 8), + 2, charset(), (TYPELIB *)get_typelib(), NULL); } @@ -9462,22 +9278,18 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)), { uint tmp=(uint) Field_enum::val_int(); if (!tmp || tmp > typelib->count) - val_ptr->set("", 0, field_charset); + val_ptr->set("", 0, field_charset()); else val_ptr->set((const char*) typelib->type_names[tmp-1], typelib->type_lengths[tmp-1], - field_charset); + field_charset()); return val_ptr; } -int Field_enum::cmp(const uchar *a_ptr, const uchar *b_ptr) +int Field_enum::cmp(const uchar *a_ptr, const uchar *b_ptr) const { - uchar *old= ptr; - ptr= (uchar*) a_ptr; - ulonglong a=Field_enum::val_int(); - ptr= (uchar*) b_ptr; - ulonglong b=Field_enum::val_int(); - ptr= old; + ulonglong a=Field_enum::val_int(a_ptr); + ulonglong b=Field_enum::val_int(b_ptr); return (a < b) ? -1 : (a > b) ? 1 : 0; } @@ -9549,20 +9361,20 @@ int Field_set::store(const char *from,size_t length,CHARSET_INFO *cs) String tmpstr(buff,sizeof(buff), &my_charset_bin); /* Convert character set if necessary */ - if (String::needs_conversion_on_storage(length, cs, field_charset)) + if (String::needs_conversion_on_storage(length, cs, field_charset())) { uint dummy_errors; - tmpstr.copy(from, length, cs, field_charset, &dummy_errors); + tmpstr.copy(from, length, cs, field_charset(), &dummy_errors); from= tmpstr.ptr(); length= tmpstr.length(); } - ulonglong tmp= find_set(typelib, from, length, field_charset, + ulonglong tmp= find_set(typelib, from, length, field_charset(), ¬_used, ¬_used2, &got_warning); if (!tmp && length && length < 22) { /* This is for reading numbers with LOAD DATA INFILE */ char *end; - tmp=my_strntoull(cs,from,length,10,&end,&err); + tmp= cs->strntoull(from,length,10,&end,&err); if (err || end != from+length || tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1)) { @@ -9616,7 +9428,7 @@ String *Field_set::val_str(String *val_buffer, return val_buffer; } - val_buffer->set_charset(field_charset); + val_buffer->set_charset(field_charset()); val_buffer->length(0); while (tmp && bitnr < (uint) typelib->count) @@ -9627,7 +9439,7 @@ String *Field_set::val_str(String *val_buffer, val_buffer->append(&field_separator, 1, &my_charset_latin1); String str(typelib->type_names[bitnr], typelib->type_lengths[bitnr], - field_charset); + field_charset()); val_buffer->append(str); } tmp>>=1; @@ -9660,6 +9472,13 @@ void Field_set::sql_type(String &res) const res.append(')'); } +Binlog_type_info Field_set::binlog_type_info() const +{ + DBUG_ASSERT(Field_set::type() == binlog_type()); + return Binlog_type_info(Field_set::type(), real_type() + + (pack_length() << 8), 2, charset(), NULL, (TYPELIB *)get_typelib()); +} + /** @retval 1 if the fields are equally defined @@ -9682,14 +9501,12 @@ bool Field::eq_def(const Field *field) const @return TRUE if the type names of t1 match those of t2. FALSE otherwise. */ -static bool compare_type_names(CHARSET_INFO *charset, TYPELIB *t1, TYPELIB *t2) +static bool compare_type_names(CHARSET_INFO *charset, const TYPELIB *t1, + const TYPELIB *t2) { for (uint i= 0; i < t1->count; i++) - if (my_strnncoll(charset, - (const uchar*) t1->type_names[i], - t1->type_lengths[i], - (const uchar*) t2->type_names[i], - t2->type_lengths[i])) + if (charset->strnncoll(t1->type_names[i], t1->type_lengths[i], + t2->type_names[i], t2->type_lengths[i])) return FALSE; return TRUE; } @@ -9701,7 +9518,7 @@ static bool compare_type_names(CHARSET_INFO *charset, TYPELIB *t1, TYPELIB *t2) bool Field_enum::eq_def(const Field *field) const { - TYPELIB *values; + const TYPELIB *values; if (!Field::eq_def(field)) return FALSE; @@ -9712,7 +9529,7 @@ bool Field_enum::eq_def(const Field *field) const if (typelib->count != values->count) return FALSE; - return compare_type_names(field_charset, typelib, values); + return compare_type_names(field_charset(), typelib, values); } @@ -9727,14 +9544,14 @@ bool Field_enum::eq_def(const Field *field) const bool Field_enum::is_equal(const Column_definition &new_field) const { - TYPELIB *values= new_field.interval; + const TYPELIB *values= new_field.interval; /* The fields are compatible if they have the same flags, type, charset and have the same underlying length. */ if (new_field.type_handler() != type_handler() || - new_field.charset != field_charset || + new_field.charset != field_charset() || new_field.pack_length != pack_length()) return false; @@ -9747,7 +9564,7 @@ bool Field_enum::is_equal(const Column_definition &new_field) const return false; /* Check whether there are modification before the end. */ - if (! compare_type_names(field_charset, typelib, new_field.interval)) + if (! compare_type_names(field_charset(), typelib, new_field.interval)) return false; return true; @@ -9901,6 +9718,14 @@ Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, } +const DTCollation & Field_bit::dtcollation() const +{ + static DTCollation tmp(&my_charset_bin, + DERIVATION_IMPLICIT, MY_REPERTOIRE_UNICODE30); + return tmp; +} + + void Field_bit::hash(ulong *nr, ulong *nr2) { if (is_null()) @@ -9913,7 +9738,7 @@ void Field_bit::hash(ulong *nr, ulong *nr2) longlong value= Field_bit::val_int(); uchar tmp[8]; mi_int8store(tmp,value); - cs->coll->hash_sort(cs, tmp, 8, nr, nr2); + cs->hash_sort(tmp, 8, nr, nr2); } } @@ -10109,7 +9934,8 @@ my_decimal *Field_bit::val_decimal(my_decimal *deciaml_value) The a and b pointer must be pointers to the field in a record (not the table->record[0] necessarily) */ -int Field_bit::cmp_prefix(const uchar *a, const uchar *b, size_t prefix_len) +int Field_bit::cmp_prefix(const uchar *a, const uchar *b, + size_t prefix_len) const { my_ptrdiff_t a_diff= a - ptr; my_ptrdiff_t b_diff= b - ptr; @@ -10127,7 +9953,7 @@ int Field_bit::cmp_prefix(const uchar *a, const uchar *b, size_t prefix_len) } -int Field_bit::key_cmp(const uchar *str, uint) +int Field_bit::key_cmp(const uchar *str, uint) const { if (bit_len) { @@ -10155,11 +9981,12 @@ int Field_bit::cmp_offset(my_ptrdiff_t row_offset) } -uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg) +uint Field_bit::get_key_image(uchar *buff, uint length, const uchar *ptr_arg, imagetype type_arg) const { if (bit_len) { - uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len); + const uchar *bit_ptr_for_arg= ptr_arg + (bit_ptr - ptr); + uchar bits= get_rec_bits(bit_ptr_for_arg, bit_ofs, bit_len); *buff++= bits; length--; } @@ -10170,33 +9997,6 @@ uint Field_bit::get_key_image(uchar *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::save_field_metadata(uchar *metadata_ptr) -{ - DBUG_ENTER("Field_bit::save_field_metadata"); - DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d", - bit_len, bytes_in_rec)); - /* - Since this class and Field_bit_as_char have different ideas of - what should be stored here, we compute the values of the metadata - explicitly using the field_length. - */ - metadata_ptr[0]= field_length % 8; - metadata_ptr[1]= field_length / 8; - DBUG_RETURN(2); -} - - -/** Returns the number of bytes field uses in row-based replication row packed size. @@ -10208,7 +10008,7 @@ int Field_bit::save_field_metadata(uchar *metadata_ptr) @returns The size of the field based on the field metadata. */ -uint Field_bit::pack_length_from_metadata(uint field_metadata) +uint Field_bit::pack_length_from_metadata(uint field_metadata) const { uint const from_len= (field_metadata >> 8U) & 0x00ff; uint const from_bit_len= field_metadata & 0x00ff; @@ -10219,9 +10019,9 @@ uint Field_bit::pack_length_from_metadata(uint field_metadata) bool Field_bit::compatible_field_size(uint field_metadata, - Relay_log_info * __attribute__((unused)), + const Relay_log_info * __attribute__((unused)), uint16 mflags, - int *order_var) + int *order_var) const { DBUG_ENTER("Field_bit::compatible_field_size"); DBUG_ASSERT((field_metadata >> 16) == 0); @@ -10451,31 +10251,31 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root, { DBUG_ENTER("Column_definition::create_interval_from_interval_list"); DBUG_ASSERT(!interval); - if (!(interval= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB)))) + TYPELIB *tmpint; + if (!(interval= tmpint= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB)))) DBUG_RETURN(true); // EOM List_iterator<String> it(interval_list); StringBuffer<64> conv; char comma_buf[5]; /* 5 bytes for 'filename' charset */ DBUG_ASSERT(sizeof(comma_buf) >= charset->mbmaxlen); - int comma_length= charset->cset->wc_mb(charset, ',', - (uchar*) comma_buf, - (uchar*) comma_buf + - sizeof(comma_buf)); + int comma_length= charset->wc_mb(',', + (uchar*) comma_buf, + (uchar*) comma_buf + sizeof(comma_buf)); DBUG_ASSERT(comma_length >= 0 && comma_length <= (int) sizeof(comma_buf)); if (!multi_alloc_root(mem_root, - &interval->type_names, + &tmpint->type_names, sizeof(char*) * (interval_list.elements + 1), - &interval->type_lengths, + &tmpint->type_lengths, sizeof(uint) * (interval_list.elements + 1), NullS)) goto err; // EOM - interval->name= ""; - interval->count= interval_list.elements; + tmpint->name= ""; + tmpint->count= interval_list.elements; - for (uint i= 0; i < interval->count; i++) + for (uint i= 0; i < interval_list.elements; i++) { uint32 dummy; String *tmp= it++; @@ -10500,24 +10300,24 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root, goto err; // EOM // Strip trailing spaces. - value.length= charset->cset->lengthsp(charset, value.str, value.length); + value.length= charset->lengthsp(value.str, value.length); ((char*) value.str)[value.length]= '\0'; if (real_field_type() == MYSQL_TYPE_SET) { - if (charset->coll->instr(charset, value.str, value.length, - comma_buf, comma_length, NULL, 0)) + if (charset->instr(value.str, value.length, + comma_buf, comma_length, NULL, 0)) { ErrConvString err(tmp); my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", err.ptr()); goto err; } } - interval->type_names[i]= value.str; - interval->type_lengths[i]= (uint)value.length; + tmpint->type_names[i]= value.str; + tmpint->type_lengths[i]= (uint)value.length; } - interval->type_names[interval->count]= 0; // End marker - interval->type_lengths[interval->count]= 0; + tmpint->type_names[interval_list.elements]= 0; // End marker + tmpint->type_lengths[interval_list.elements]= 0; interval_list.empty(); // Don't need interval_list anymore DBUG_RETURN(false); err: @@ -10581,30 +10381,26 @@ bool Column_definition::prepare_interval_field(MEM_ROOT *mem_root, } -void Column_definition::set_attributes(const Lex_field_type_st &type, - CHARSET_INFO *cs) +bool Column_definition::set_attributes(THD *thd, + const Lex_field_type_st &def, + CHARSET_INFO *cs, + column_definition_type_t type) { DBUG_ASSERT(type_handler() == &type_handler_null); DBUG_ASSERT(charset == &my_charset_bin || charset == NULL); DBUG_ASSERT(length == 0); DBUG_ASSERT(decimals == 0); - set_handler(type.type_handler()); - charset= cs; + set_handler(def.type_handler()); + return type_handler()->Column_definition_set_attributes(thd, this, + def, cs, type); +} -#if MYSQL_VERSION_ID > 100500 -#error When merging to 10.5, please move the code below to -#error Type_handler_timestamp_common::Column_definition_set_attributes() -#else - /* - Unlike other types TIMESTAMP fields are NOT NULL by default. - Unless --explicit-defaults-for-timestamp is given. - */ - if (!opt_explicit_defaults_for_timestamp && - type.type_handler()->field_type() == MYSQL_TYPE_TIMESTAMP) - flags|= NOT_NULL_FLAG; -#endif +void +Column_definition_attributes::set_length_and_dec(const Lex_length_and_dec_st + &type) +{ if (type.length()) { int err; @@ -10622,13 +10418,11 @@ void Column_definition::create_length_to_internal_length_bit() { if (f_bit_as_char(pack_flag)) { - key_length= pack_length= ((length + 7) & ~7) / 8; + pack_length= ((length + 7) & ~7) / 8; } else { pack_length= (uint) length / 8; - /* We need one extra byte to store the bits we save among the null bits */ - key_length= pack_length + MY_TEST(length & 7); } } @@ -10637,16 +10431,17 @@ void Column_definition::create_length_to_internal_length_newdecimal() { DBUG_ASSERT(length < UINT_MAX32); uint prec= get_decimal_precision((uint)length, decimals, flags & UNSIGNED_FLAG); - key_length= pack_length= my_decimal_get_binary_size(prec, decimals); + pack_length= my_decimal_get_binary_size(prec, decimals); } -bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name, - enum_vcol_info_type type) +bool check_expression(Virtual_column_info *vcol, const LEX_CSTRING *name, + enum_vcol_info_type type, Alter_info *alter_info) { bool ret; Item::vcol_func_processor_result res; + res.alter_info= alter_info; if (!vcol->name.length) vcol->name= *name; @@ -10655,7 +10450,6 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name, Walk through the Item tree checking if all items are valid to be part of the virtual column */ - res.errors= 0; ret= vcol->expr->walk(&Item::check_vcol_func_processor, 0, &res); vcol->flags= res.errors; @@ -10766,6 +10560,7 @@ bool Column_definition::fix_attributes_temporal_with_time(uint int_part_length) MAX_DATETIME_PRECISION); return true; } + decimals= (uint) length; length+= int_part_length + (length ? 1 : 0); return false; } @@ -10871,7 +10666,7 @@ bool Column_definition::check(THD *thd) TIMESTAMP columns get implicit DEFAULT value when explicit_defaults_for_timestamp is not set. */ - if ((opt_explicit_defaults_for_timestamp || + if (((thd->variables.option_bits & OPTION_EXPLICIT_DEF_TIMESTAMP) || !is_timestamp_type()) && !vers_sys_field()) { flags|= NO_DEFAULT_VALUE_FLAG; @@ -10971,15 +10766,27 @@ bool Field_vers_trx_id::test_if_equality_guarantees_uniqueness(const Item* item) Column_definition_attributes::Column_definition_attributes(const Field *field) :length(field->character_octet_length() / field->charset()->mbmaxlen), + decimals(field->decimals()), unireg_check(field->unireg_check), interval(NULL), charset(field->charset()), // May be NULL ptr srid(0), - geom_type(Field::GEOM_GEOMETRY), pack_flag(0) {} +Column_definition_attributes:: + Column_definition_attributes(const Type_all_attributes &attr) + :length(attr.max_length), + decimals(attr.decimals), + unireg_check(Field::NONE), + interval(attr.get_typelib()), + charset(attr.collation.collation), + srid(0), + pack_flag(attr.unsigned_flag ? 0 : FIELDFLAG_DECIMAL) +{} + + /** Create a field suitable for create of table. */ Column_definition::Column_definition(THD *thd, Field *old_field, @@ -10990,12 +10797,11 @@ Column_definition::Column_definition(THD *thd, Field *old_field, field_name= old_field->field_name; flags= old_field->flags; pack_length=old_field->pack_length(); - key_length= old_field->key_length(); set_handler(old_field->type_handler()); comment= old_field->comment; - decimals= old_field->decimals(); vcol_info= old_field->vcol_info; option_list= old_field->option_list; + explicitly_nullable= !(old_field->flags & NOT_NULL_FLAG); compression_method_ptr= 0; versioning= VERSIONING_NOT_SET; invisible= old_field->invisible; @@ -11085,7 +10891,6 @@ Column_definition::redefine_stage1_common(const Column_definition *dup_field, charset= dup_field->charset; length= dup_field->char_length; pack_length= dup_field->pack_length; - key_length= dup_field->key_length; decimals= dup_field->decimals; unireg_check= dup_field->unireg_check; flags= dup_field->flags; @@ -11217,6 +11022,19 @@ Column_definition::set_compressed_deprecated_column_attribute(THD *thd, } +bool Column_definition::check_vcol_for_key(THD *thd) const +{ + if (vcol_info && (vcol_info->flags & VCOL_NOT_STRICTLY_DETERMINISTIC)) + { + /* use check_expression() to report an error */ + check_expression(vcol_info, &field_name, VCOL_GENERATED_STORED); + DBUG_ASSERT(thd->is_error()); + return true; + } + return false; +} + + Send_field::Send_field(THD *thd, Item *item) { item->make_send_field(thd, this); @@ -11236,11 +11054,11 @@ uint32 Field_blob::max_display_length() const switch (packlength) { case 1: - return 255 * field_charset->mbmaxlen; + return 255 * mbmaxlen(); case 2: - return 65535 * field_charset->mbmaxlen; + return 65535 * mbmaxlen(); case 3: - return 16777215 * field_charset->mbmaxlen; + return 16777215 * mbmaxlen(); case 4: return (uint32) UINT_MAX32; default: @@ -11392,7 +11210,7 @@ key_map Field::get_possible_keys() bool Field::validate_value_in_record_with_warn(THD *thd, const uchar *record) { - MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->read_set); + MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->read_set); bool rc; if ((rc= validate_value_in_record(thd, record))) { @@ -11484,8 +11302,7 @@ bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to) StringBuffer<MAX_FIELD_WIDTH> str; bool rc= false; THD *thd= get_thd(); - sql_mode_t sql_mode_backup= thd->variables.sql_mode; - thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; + Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH); val_str(&str); if (!(to->length= str.length())) @@ -11493,7 +11310,6 @@ bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to) else if ((rc= !(to->str= strmake_root(mem_root, str.ptr(), str.length())))) to->length= 0; - thd->variables.sql_mode= sql_mode_backup; return rc; } @@ -11511,7 +11327,7 @@ void Field_string::print_key_value(String *out, uint32 length) { if (charset() == &my_charset_bin) { - size_t len= field_charset->cset->lengthsp(field_charset, (const char*) ptr, length); + size_t len= field_charset()->lengthsp((const char*) ptr, length); print_key_value_binary(out, ptr, static_cast<uint32>(len)); } else |