diff options
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 843 |
1 files changed, 608 insertions, 235 deletions
diff --git a/sql/field.cc b/sql/field.cc index 9b6465988f6..1f97e587eb3 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -27,7 +27,7 @@ #pragma implementation // gcc: Class implementation #endif -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_select.h" #include "rpl_rli.h" // Pull in Relay_log_info @@ -51,7 +51,7 @@ *****************************************************************************/ static const char *zero_timestamp="0000-00-00 00:00:00.000000"; -LEX_CSTRING temp_lex_str= {"temp", 4}; +LEX_CSTRING temp_lex_str= {STRING_WITH_LEN("temp")}; uchar Field_null::null[1]={1}; const char field_separator=','; @@ -1228,7 +1228,7 @@ bool Field::can_optimize_range(const Item_bool_func *cond, } -int Field::store_hex_hybrid(const char *str, uint length) +int Field::store_hex_hybrid(const char *str, size_t length) { DBUG_ASSERT(result_type() != STRING_RESULT); ulonglong nr; @@ -1467,8 +1467,7 @@ Value_source::Converter_string_to_number::check_edom_and_truncation(THD *thd, int Field_num::check_edom_and_important_data_truncation(const char *type, bool edom, CHARSET_INFO *cs, - const char *str, - uint length, + const char *str, size_t length, const char *end) { /* Test if we get an empty string or garbage */ @@ -1490,7 +1489,7 @@ int Field_num::check_edom_and_important_data_truncation(const char *type, int Field_num::check_edom_and_truncation(const char *type, bool edom, CHARSET_INFO *cs, - const char *str, uint length, + const char *str, size_t length, const char *end) { int rc= check_edom_and_important_data_truncation(type, edom, @@ -1524,7 +1523,7 @@ int Field_num::check_edom_and_truncation(const char *type, bool edom, 1 error */ -bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len, +bool Field_num::get_int(CHARSET_INFO *cs, const char *from, size_t len, longlong *rnd, ulonglong unsigned_max, longlong signed_min, longlong signed_max) { @@ -1557,7 +1556,7 @@ bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len, goto out_of_range; } } - if (get_thd()->count_cuted_fields && + if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION && check_int(cs, from, len, end, error)) return 1; return 0; @@ -1568,7 +1567,7 @@ out_of_range: } -double Field_real::get_double(const char *str, uint length, CHARSET_INFO *cs, +double Field_real::get_double(const char *str, size_t length, CHARSET_INFO *cs, int *error) { char *end; @@ -1578,7 +1577,7 @@ double Field_real::get_double(const char *str, uint length, CHARSET_INFO *cs, set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); *error= 1; } - else if (get_thd()->count_cuted_fields && + else if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION && check_edom_and_truncation("double", str == end, cs, str, length, end)) *error= 1; @@ -1642,7 +1641,8 @@ String *Field::val_int_as_str(String *val_buffer, bool unsigned_val) Field::Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg) - :ptr(ptr_arg), null_ptr(null_ptr_arg), table(0), orig_table(0), + :ptr(ptr_arg), invisible(VISIBLE), + null_ptr(null_ptr_arg), table(0), orig_table(0), table_name(0), field_name(*field_name_arg), option_list(0), option_struct(0), key_start(0), part_of_key(0), part_of_key_not_clustered(0), part_of_sortkey(0), @@ -1753,7 +1753,7 @@ bool Field::compatible_field_size(uint field_metadata, } -int Field::store(const char *to, uint length, CHARSET_INFO *cs, +int Field::store(const char *to, size_t length, CHARSET_INFO *cs, enum_check_fields check_level) { int res; @@ -1912,7 +1912,7 @@ void Field::make_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; - if (orig_table->pos_in_table_list && + 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); @@ -2040,6 +2040,48 @@ bool Field_num::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) } +bool Field_vers_trx_id::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglong trx_id) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + DBUG_ASSERT(ltime); + if (!table || !table->s) + return true; + DBUG_ASSERT(table->versioned(VERS_TRX_ID) || + (table->versioned() && table->s->table_category == TABLE_CATEGORY_TEMPORARY)); + if (!trx_id) + return true; + + THD *thd= get_thd(); + DBUG_ASSERT(thd); + if (trx_id == ULONGLONG_MAX) + { + thd->variables.time_zone->gmt_sec_to_TIME(ltime, TIMESTAMP_MAX_VALUE); + ltime->second_part= TIME_MAX_SECOND_PART; + return false; + } + if (cached == trx_id) + { + *ltime= cache; + return false; + } + + TR_table trt(thd); + bool found= trt.query(trx_id); + if (found) + { + trt[TR_table::FLD_COMMIT_TS]->get_date(&cache, fuzzydate); + *ltime= cache; + cached= trx_id; + return false; + } + + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_VERS_NO_TRX_ID, ER_THD(thd, ER_VERS_NO_TRX_ID), + (longlong) trx_id); + return true; +} + + Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg, @@ -2232,8 +2274,11 @@ Field *Field::make_new_field(MEM_ROOT *root, TABLE *new_table, */ tmp->unireg_check= Field::NONE; tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG | - ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG); + ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG | + VERS_SYS_START_FLAG | VERS_SYS_END_FLAG | + VERS_UPDATE_UNVERSIONED_FLAG); tmp->reset_fields(); + tmp->invisible= VISIBLE; return tmp; } @@ -2420,7 +2465,7 @@ void Field_decimal::overflow(bool negative) } -int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs) +int Field_decimal::store(const char *from_arg, size_t len, CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; char buff[STRING_BUFFER_USUAL_SIZE]; @@ -2564,7 +2609,7 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs) it makes the code easer to read. */ - if (get_thd()->count_cuted_fields) + if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION) { // Skip end spaces for (;from != end && my_isspace(&my_charset_bin, *from); from++) ; @@ -2734,7 +2779,8 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs) { if (pos == right_wall) { - if (get_thd()->count_cuted_fields && !is_cuted_fields_incr) + if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION && + !is_cuted_fields_incr) break; // Go on below to see if we lose non zero digits return 0; } @@ -2800,7 +2846,6 @@ int Field_decimal::store(double nr) return 1; } - reg4 uint i; size_t length; uchar fyllchar,*to; char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; @@ -2816,7 +2861,7 @@ int Field_decimal::store(double nr) else { to=ptr; - for (i=field_length-length ; i-- > 0 ;) + for (size_t i=field_length-length ; i-- > 0 ;) *to++ = fyllchar; memcpy(to,buff,length); return 0; @@ -3102,7 +3147,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) } -int Field_new_decimal::store(const char *from, uint length, +int Field_new_decimal::store(const char *from, size_t length, CHARSET_INFO *charset_arg) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; @@ -3127,7 +3172,7 @@ int Field_new_decimal::store(const char *from, uint length, DBUG_RETURN(1); } - if (thd->count_cuted_fields) + if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION) { if (check_edom_and_important_data_truncation("decimal", err && err != E_DEC_TRUNCATED, @@ -3172,7 +3217,7 @@ int Field_new_decimal::store(const char *from, uint length, - in err2: store_value() truncated 1.123 to 1.12, e.g. for DECIMAL(10,2) Also, we send a note if a string had some trailing spaces: '1.12 ' */ - if (thd->count_cuted_fields && + if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION && (err == E_DEC_TRUNCATED || err2 == E_DEC_TRUNCATED || end < from + length)) @@ -3309,7 +3354,7 @@ int Field_new_decimal::cmp(const uchar *a,const uchar*b) void Field_new_decimal::sort_string(uchar *buff, - uint length __attribute__((unused))) + uint) { memcpy(buff, ptr, bin_size); } @@ -3335,7 +3380,7 @@ void Field_new_decimal::sql_type(String &str) const @returns number of bytes written to metadata_ptr */ -int Field_new_decimal::do_save_field_metadata(uchar *metadata_ptr) +int Field_new_decimal::save_field_metadata(uchar *metadata_ptr) { *metadata_ptr= precision; *(metadata_ptr + 1)= decimals(); @@ -3493,7 +3538,7 @@ int Field_num::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg) ** tiny int ****************************************************************************/ -int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs) +int Field_tiny::store(const char *from,size_t len,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; int error; @@ -3669,7 +3714,7 @@ void Field_tiny::sql_type(String &res) const Field type short int (2 byte) ****************************************************************************/ -int Field_short::store(const char *from,uint len,CHARSET_INFO *cs) +int Field_short::store(const char *from,size_t len,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; int store_tmp; @@ -3858,7 +3903,7 @@ void Field_short::sql_type(String &res) const Field type medium int (3 byte) ****************************************************************************/ -int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs) +int Field_medium::store(const char *from,size_t len,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; int store_tmp; @@ -4049,7 +4094,7 @@ void Field_medium::sql_type(String &res) const ** long int ****************************************************************************/ -int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) +int Field_long::store(const char *from,size_t len,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; long store_tmp; @@ -4177,17 +4222,17 @@ String *Field_long::val_str(String *val_buffer, { ASSERT_COLUMN_MARKED_FOR_READ; CHARSET_INFO *cs= &my_charset_numeric; - uint length; - uint mlength=MY_MAX(field_length+1,12*cs->mbmaxlen); + size_t length; + size_t mlength=MY_MAX(field_length+1,12*cs->mbmaxlen); val_buffer->alloc(mlength); char *to=(char*) val_buffer->ptr(); int32 j; j=sint4korr(ptr); if (unsigned_flag) - length=cs->cset->long10_to_str(cs,to,mlength, 10,(long) (uint32)j); + length=cs->cset->long10_to_str(cs,to,mlength, 10,(uint32) j); else - length=cs->cset->long10_to_str(cs,to,mlength,-10,(long) j); + length=cs->cset->long10_to_str(cs,to,mlength,-10,j); val_buffer->length(length); if (zerofill) prepend_zeros(val_buffer); @@ -4236,7 +4281,7 @@ void Field_long::sql_type(String &res) const Field type longlong int (8 bytes) ****************************************************************************/ -int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) +int Field_longlong::store(const char *from,size_t len,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; int error= 0; @@ -4249,7 +4294,7 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } - else if (get_thd()->count_cuted_fields && + else if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION && check_int(cs, from, len, end, error)) error= 1; else @@ -4383,6 +4428,26 @@ void Field_longlong::sql_type(String &res) const add_zerofill_and_unsigned(res); } +void Field_longlong::set_max() +{ + ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + set_notnull(); + int8store(ptr, unsigned_flag ? ULONGLONG_MAX : LONGLONG_MAX); +} + +bool Field_longlong::is_max() +{ + ASSERT_COLUMN_MARKED_FOR_READ; + if (unsigned_flag) + { + ulonglong j; + j= uint8korr(ptr); + return j == ULONGLONG_MAX; + } + longlong j; + j= sint8korr(ptr); + return j == LONGLONG_MAX; +} /* Floating-point numbers @@ -4392,7 +4457,7 @@ void Field_longlong::sql_type(String &res) const single precision float ****************************************************************************/ -int Field_float::store(const char *from,uint len,CHARSET_INFO *cs) +int Field_float::store(const char *from,size_t len,CHARSET_INFO *cs) { int error; Field_float::store(get_double(from, len, cs, &error)); @@ -4544,7 +4609,7 @@ bool Field_float::send_binary(Protocol *protocol) @returns number of bytes written to metadata_ptr */ -int Field_float::do_save_field_metadata(uchar *metadata_ptr) +int Field_float::save_field_metadata(uchar *metadata_ptr) { *metadata_ptr= pack_length(); return 1; @@ -4571,7 +4636,7 @@ void Field_float::sql_type(String &res) const double precision floating point numbers ****************************************************************************/ -int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) +int Field_double::store(const char *from,size_t len,CHARSET_INFO *cs) { int error; Field_double::store(get_double(from, len, cs, &error)); @@ -4861,7 +4926,7 @@ void Field_double::sort_string(uchar *to,uint length __attribute__((unused))) @returns number of bytes written to metadata_ptr */ -int Field_double::do_save_field_metadata(uchar *metadata_ptr) +int Field_double::save_field_metadata(uchar *metadata_ptr) { *metadata_ptr= pack_length(); return 1; @@ -5031,7 +5096,7 @@ int Field_timestamp::store_time_dec(const MYSQL_TIME *ltime, uint dec) } -int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) +int Field_timestamp::store(const char *from,size_t len,CHARSET_INFO *cs) { MYSQL_TIME l_time; MYSQL_TIME_STATUS status; @@ -5320,36 +5385,6 @@ static longlong read_lowendian(const uchar *from, uint bytes) } } -static void store_bigendian(ulonglong num, uchar *to, uint bytes) -{ - switch(bytes) { - case 1: mi_int1store(to, num); break; - case 2: mi_int2store(to, num); break; - case 3: mi_int3store(to, num); break; - case 4: mi_int4store(to, num); break; - case 5: mi_int5store(to, num); break; - case 6: mi_int6store(to, num); break; - case 7: mi_int7store(to, num); break; - case 8: mi_int8store(to, num); break; - default: DBUG_ASSERT(0); - } -} - -static longlong read_bigendian(const uchar *from, uint bytes) -{ - switch(bytes) { - case 1: return mi_uint1korr(from); - case 2: return mi_uint2korr(from); - case 3: return mi_uint3korr(from); - case 4: return mi_uint4korr(from); - case 5: return mi_uint5korr(from); - case 6: return mi_uint6korr(from); - case 7: return mi_uint7korr(from); - case 8: return mi_sint8korr(from); - default: DBUG_ASSERT(0); return 0; - } -} - void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) { mi_int4store(ptr, timestamp); @@ -5455,6 +5490,27 @@ void Field_timestampf::store_TIME(my_time_t timestamp, ulong sec_part) my_timestamp_to_binary(&tm, ptr, dec); } +void Field_timestampf::set_max() +{ + DBUG_ENTER("Field_timestampf::set_max"); + ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + DBUG_ASSERT(dec == TIME_SECOND_PART_DIGITS); + + set_notnull(); + mi_int4store(ptr, TIMESTAMP_MAX_VALUE); + mi_int3store(ptr + 4, TIME_MAX_SECOND_PART); + + DBUG_VOID_RETURN; +} + +bool Field_timestampf::is_max() +{ + DBUG_ENTER("Field_timestampf::is_max"); + ASSERT_COLUMN_MARKED_FOR_READ; + + DBUG_RETURN(mi_sint4korr(ptr) == TIMESTAMP_MAX_VALUE && + mi_sint3korr(ptr + 4) == TIME_MAX_SECOND_PART); +} my_time_t Field_timestampf::get_timestamp(const uchar *pos, ulong *sec_part) const @@ -5541,7 +5597,7 @@ int Field_temporal_with_date::store_TIME_with_warning(MYSQL_TIME *ltime, } -int Field_temporal_with_date::store(const char *from, uint len, CHARSET_INFO *cs) +int Field_temporal_with_date::store(const char *from, size_t len, CHARSET_INFO *cs) { MYSQL_TIME ltime; MYSQL_TIME_STATUS status; @@ -5737,7 +5793,7 @@ void Field_time::store_TIME(const MYSQL_TIME *ltime) int3store(ptr,tmp); } -int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) +int Field_time::store(const char *from,size_t len,CHARSET_INFO *cs) { MYSQL_TIME ltime; MYSQL_TIME_STATUS status; @@ -6164,7 +6220,7 @@ bool Field_timef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) ** Can handle 2 byte or 4 byte years! ****************************************************************************/ -int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) +int Field_year::store(const char *from, size_t len,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; char *end; @@ -6178,7 +6234,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; } - if (get_thd()->count_cuted_fields && + if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION && (error= check_int(cs, from, len, end, error))) { if (error == 1) /* empty or incorrect string */ @@ -6886,7 +6942,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end, bool count_spaces) { THD *thd= get_thd(); - if ((pstr < end) && thd->count_cuted_fields) + if ((pstr < end) && thd->count_cuted_fields > CHECK_FIELD_EXPRESSION) { if (test_if_important_data(field_charset, pstr, end)) { @@ -6908,7 +6964,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end, /* Copy a string and fill with space */ -int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) +int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; uint copy_length; @@ -6932,6 +6988,20 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) } +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); +} + + /** Store double value in Field_string or Field_varstring. @@ -6944,7 +7014,8 @@ int Field_str::store(double nr) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; - uint local_char_length= field_length / charset()->mbmaxlen; + uint local_char_length= MY_MIN(sizeof(buff), + field_length / field_charset->mbmaxlen); size_t length= 0; my_bool error= (local_char_length == 0); @@ -6959,7 +7030,7 @@ int Field_str::store(double nr) else set_warning(WARN_DATA_TRUNCATED, 1); } - return store(buff, length, &my_charset_numeric); + return store(buff, (uint)length, &my_charset_numeric); } uint Field::is_equal(Create_field *new_field) @@ -6976,17 +7047,6 @@ uint Field_str::is_equal(Create_field *new_field) } -int Field_string::store(longlong nr, bool unsigned_val) -{ - char buff[64]; - int l; - CHARSET_INFO *cs=charset(); - l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff), - unsigned_val ? 10 : -10, nr); - return Field_string::store(buff,(uint)l,cs); -} - - int Field_longstr::store_decimal(const my_decimal *d) { char buff[DECIMAL_MAX_STR_LENGTH+1]; @@ -7102,7 +7162,7 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)), ASSERT_COLUMN_MARKED_FOR_READ; /* See the comment for Field_long::store(long long) */ DBUG_ASSERT(!table || table->in_use == current_thd); - uint length; + size_t length; if (get_thd()->variables.sql_mode & MODE_PAD_CHAR_TO_FULL_LENGTH) length= my_charpos(field_charset, ptr, ptr + field_length, @@ -7165,11 +7225,11 @@ Field_string::compatible_field_size(uint field_metadata, int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) { - uint a_len, b_len; + size_t a_len, b_len; if (field_charset->mbmaxlen != 1) { - uint char_len= field_length/field_charset->mbmaxlen; + size_t char_len= field_length/field_charset->mbmaxlen; a_len= my_charpos(field_charset, a_ptr, a_ptr + field_length, char_len); b_len= my_charpos(field_charset, b_ptr, b_ptr + field_length, char_len); } @@ -7187,7 +7247,7 @@ int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) void Field_string::sort_string(uchar *to,uint length) { - uint tmp __attribute__((unused))= + IF_DBUG(size_t tmp= ,) field_charset->coll->strnxfrm(field_charset, to, length, char_length() * @@ -7203,7 +7263,7 @@ void Field_string::sql_type(String &res) const { THD *thd= table->in_use; CHARSET_INFO *cs=res.charset(); - ulong length; + size_t length; length= cs->cset->snprintf(cs,(char*) res.ptr(), res.alloced_length(), "%s(%d)", @@ -7220,9 +7280,9 @@ void Field_string::sql_type(String &res) const uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) { - uint length= MY_MIN(field_length,max_length); - uint local_char_length= max_length/field_charset->mbmaxlen; - DBUG_PRINT("debug", ("Packing field '%s' - length: %u ", field_name.str, + 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) @@ -7266,7 +7326,7 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) the master. @note For information about how the length is packed, see @c - Field_string::do_save_field_metadata + Field_string::save_field_metadata @param to Destination of the data @param from Source of the data @@ -7349,7 +7409,7 @@ Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end, @returns number of bytes written to metadata_ptr */ -int Field_string::do_save_field_metadata(uchar *metadata_ptr) +int Field_string::save_field_metadata(uchar *metadata_ptr) { DBUG_ASSERT(field_length < 1024); DBUG_ASSERT((real_type() & 0xF0) == 0xF0); @@ -7377,14 +7437,14 @@ uint Field_string::max_packed_col_length(uint max_length) uint Field_string::get_key_image(uchar *buff, uint length, imagetype type_arg) { - uint bytes = my_charpos(field_charset, (char*) ptr, + size_t bytes = my_charpos(field_charset, (char*) ptr, (char*) ptr + field_length, length / field_charset->mbmaxlen); memcpy(buff, ptr, bytes); if (bytes < length) field_charset->cset->fill(field_charset, (char*) buff + bytes, length - bytes, field_charset->pad_char); - return bytes; + return (uint)bytes; } @@ -7446,14 +7506,14 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16; @returns number of bytes written to metadata_ptr */ -int Field_varstring::do_save_field_metadata(uchar *metadata_ptr) +int Field_varstring::save_field_metadata(uchar *metadata_ptr) { DBUG_ASSERT(field_length <= 65535); int2store((char*)metadata_ptr, field_length); return 2; } -int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) +int Field_varstring::store(const char *from,size_t length,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; uint copy_length; @@ -7473,20 +7533,6 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) } -int Field_varstring::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 Field_varstring::store(buff, length, field_charset); -} - - double Field_varstring::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; @@ -7568,8 +7614,8 @@ int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr, int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length) { - uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); - uint local_char_length= max_key_length / field_charset->mbmaxlen; + size_t length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); + size_t local_char_length= max_key_length / field_charset->mbmaxlen; local_char_length= my_charpos(field_charset, ptr + length_bytes, ptr + length_bytes + length, local_char_length); @@ -7603,26 +7649,29 @@ int Field_varstring::key_cmp(const uchar *a,const uchar *b) void Field_varstring::sort_string(uchar *to,uint length) { - uint tot_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); + String buf; + + val_str(&buf, &buf); if (field_charset == &my_charset_bin) { /* Store length last in high-byte order to sort longer strings first */ if (length_bytes == 1) - to[length-1]= tot_length; + to[length - 1]= buf.length(); else - mi_int2store(to+length-2, tot_length); + mi_int2store(to + length - 2, buf.length()); length-= length_bytes; } - - tot_length= field_charset->coll->strnxfrm(field_charset, - to, length, - char_length() * - field_charset->strxfrm_multiply, - ptr + length_bytes, tot_length, - MY_STRXFRM_PAD_WITH_SPACE | - MY_STRXFRM_PAD_TO_MAXLEN); - DBUG_ASSERT(tot_length == length); + +#ifndef DBUG_OFF + 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); + DBUG_ASSERT(rc == length); } @@ -7638,16 +7687,22 @@ enum ha_base_keytype Field_varstring::key_type() const } +/* + Compressed columns need one extra byte to store the compression method. + This byte is invisible to the end user, but not for the storage engine. +*/ + void Field_varstring::sql_type(String &res) const { THD *thd= table->in_use; CHARSET_INFO *cs=res.charset(); - ulong length; + size_t length; length= cs->cset->snprintf(cs,(char*) res.ptr(), res.alloced_length(), "%s(%d)", (has_charset() ? "varchar" : "varbinary"), - (int) field_length / charset()->mbmaxlen); + (int) field_length / charset()->mbmaxlen - + MY_TEST(compression_method())); res.length(length); if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) && has_charset() && (charset()->state & MY_CS_BINSORT)) @@ -7749,32 +7804,36 @@ uint Field_varstring::max_packed_col_length(uint max_length) uint Field_varstring::get_key_image(uchar *buff, uint length, imagetype type_arg) { - uint f_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); - uint local_char_length= length / field_charset->mbmaxlen; - uchar *pos= ptr+length_bytes; - local_char_length= my_charpos(field_charset, pos, pos + f_length, - local_char_length); - set_if_smaller(f_length, local_char_length); + String val; + uint local_char_length; + my_bitmap_map *old_map; + + 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); + if (local_char_length < val.length()) + val.length(local_char_length); /* Key is always stored with 2 bytes */ - int2store(buff,f_length); - memcpy(buff+HA_KEY_BLOB_LENGTH, pos, f_length); - if (f_length < length) + int2store(buff, val.length()); + memcpy(buff + HA_KEY_BLOB_LENGTH, val.ptr(), val.length()); + if (val.length() < length) { /* Must clear this as we do a memcmp in opt_range.cc to detect identical keys */ - bzero(buff+HA_KEY_BLOB_LENGTH+f_length, (length-f_length)); + memset(buff + HA_KEY_BLOB_LENGTH + val.length(), 0, length - val.length()); } - return HA_KEY_BLOB_LENGTH+f_length; + return HA_KEY_BLOB_LENGTH + val.length(); } void Field_varstring::set_key_image(const uchar *buff,uint length) { length= uint2korr(buff); // Real length is here - (void) Field_varstring::store((const char*) buff+HA_KEY_BLOB_LENGTH, length, - field_charset); + (void) store((const char*) buff + HA_KEY_BLOB_LENGTH, length, field_charset); } @@ -7831,13 +7890,14 @@ Field *Field_varstring::new_key_field(MEM_ROOT *root, TABLE *new_table, uint Field_varstring::is_equal(Create_field *new_field) { if (new_field->type_handler() == type_handler() && - new_field->charset == field_charset) + new_field->charset == field_charset && + !new_field->compression_method() == !compression_method()) { - if (new_field->length == max_display_length()) + if (new_field->length == field_length) return IS_EQUAL_YES; - if (new_field->length > max_display_length() && - ((new_field->length <= 255 && max_display_length() <= 255) || - (new_field->length > 255 && max_display_length() > 255))) + if (new_field->length > field_length && + ((new_field->length <= 255 && field_length <= 255) || + (new_field->length > 255 && field_length > 255))) return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer variable length } return IS_EQUAL_NO; @@ -7859,6 +7919,201 @@ void Field_varstring::hash(ulong *nr, ulong *nr2) } +/** + Compress field + + @param[out] to destination buffer for compressed data + @param[in,out] to_length in: size of to, out: compressed data length + @param[in] from data to compress + @param[in] length from length + @param[in] cs from character set + + In worst case (no compression performed) storage requirement is increased by + 1 byte to store header. If it exceeds field length, normal data truncation is + performed. + + Generic compressed header format (1 byte): + + Bits 1-4: method specific bits + Bits 5-8: compression method + + If compression method is 0 then header is immediately followed by + uncompressed data. + + If compression method is zlib: + + Bits 1-3: number of bytes occupied by original data length + Bits 4: true if zlib wrapper not present + Bits 5-8: store 8 (zlib) + + Header is immediately followed by original data length, + followed by compressed data. +*/ + +int Field_longstr::compress(char *to, uint *to_length, + const char *from, uint length, + CHARSET_INFO *cs) +{ + THD *thd= get_thd(); + char *buf= 0; + int rc= 0; + + if (length == 0) + { + *to_length= 0; + return 0; + } + + if (String::needs_conversion_on_storage(length, cs, field_charset) || + *to_length <= length) + { + String_copier copier; + const char *end= from + length; + + if (!(buf= (char*) my_malloc(*to_length - 1, MYF(MY_WME)))) + { + *to_length= 0; + return -1; + } + + length= copier.well_formed_copy(field_charset, buf, *to_length - 1, + cs, from, length, + (*to_length - 1) / field_charset->mbmaxlen); + rc= check_conversion_status(&copier, end, cs, true); + from= buf; + DBUG_ASSERT(length > 0); + } + + if (length >= thd->variables.column_compression_threshold && + (*to_length= compression_method()->compress(thd, to, from, length))) + status_var_increment(thd->status_var.column_compressions); + else + { + /* Store uncompressed */ + to[0]= 0; + memcpy(to + 1, from, length); + *to_length= length + 1; + } + + if (buf) + my_free(buf); + return rc; +} + + +/* + Memory is allocated only when original data was actually compressed. + Otherwise val_ptr points at data located immediately after header. + + Data can be stored uncompressed if data was shorter than threshold + or compressed data was longer than original data. +*/ + +String *Field_longstr::uncompress(String *val_buffer, String *val_ptr, + const uchar *from, uint from_length) +{ + if (from_length) + { + uchar method= (*from & 0xF0) >> 4; + + /* Uncompressed data */ + if (!method) + { + val_ptr->set((const char*) from + 1, from_length - 1, field_charset); + return val_ptr; + } + + if (compression_methods[method].uncompress) + { + if (!compression_methods[method].uncompress(val_buffer, from, from_length, + field_length)) + { + val_buffer->set_charset(field_charset); + status_var_increment(get_thd()->status_var.column_decompressions); + return val_buffer; + } + } + } + + /* + It would be better to return 0 in case of errors, but to take the + safer route, let's return a zero string and let the general + handler catch the error. + */ + val_ptr->set("", 0, field_charset); + return val_ptr; +} + + +int Field_varstring_compressed::store(const char *from, size_t length, + CHARSET_INFO *cs) +{ + ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + uint to_length= (uint)MY_MIN(field_length, field_charset->mbmaxlen * length + 1); + int rc= compress((char*) get_data(), &to_length, from, (uint)length, cs); + store_length(to_length); + return rc; +} + + +String *Field_varstring_compressed::val_str(String *val_buffer, String *val_ptr) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + return uncompress(val_buffer, val_ptr, get_data(), get_length()); +} + + +double Field_varstring_compressed::val_real(void) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + THD *thd= get_thd(); + String buf; + val_str(&buf, &buf); + return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset, + buf.ptr(), buf.length()).result(); +} + + +longlong Field_varstring_compressed::val_int(void) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + THD *thd= get_thd(); + String buf; + val_str(&buf, &buf); + return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset, + buf.ptr(), buf.length()).result(); +} + + +int Field_varstring_compressed::cmp_max(const uchar *a_ptr, const uchar *b_ptr, + uint max_len) +{ + String a, b; + uint a_length, b_length; + + if (length_bytes == 1) + { + a_length= (uint) *a_ptr; + b_length= (uint) *b_ptr; + } + else + { + a_length= uint2korr(a_ptr); + b_length= uint2korr(b_ptr); + } + + uncompress(&a, &a, a_ptr + length_bytes, a_length); + uncompress(&b, &b, b_ptr + length_bytes, b_length); + + if (a.length() > max_len) + a.length(max_len); + if (b.length() > max_len) + b.length(max_len); + + return sortcmp(&a, &b, field_charset); +} + + /**************************************************************************** ** blob type ** A blob is saved as a length and a pointer. The length is stored in the @@ -7901,6 +8156,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(!compression_method() == !from->compression_method()); int rc= 0; uint32 length= from->get_length(); uchar *data= from->get_ptr(); @@ -7919,10 +8175,10 @@ int Field_blob::copy_value(Field_blob *from) } -int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) +int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; - uint copy_length, new_length; + size_t copy_length, new_length; String_copier copier; char *tmp; char buff[STRING_BUFFER_USUAL_SIZE]; @@ -7941,7 +8197,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) DBUG_ASSERT(length <= max_data_length()); new_length= length; - copy_length= (uint)MY_MIN(UINT_MAX,table->in_use->variables.group_concat_max_len); + copy_length= (size_t)MY_MIN(UINT_MAX,table->in_use->variables.group_concat_max_len); if (new_length > copy_length) { new_length= Well_formed_prefix(cs, @@ -7994,7 +8250,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) return 0; } copy_length= copier.well_formed_copy(field_charset, - (char*) value.ptr(), new_length, + (char*) value.ptr(), (uint)new_length, cs, from, length); Field_blob::store_length(copy_length); bmove(ptr+packlength,(uchar*) &tmp,sizeof(char*)); @@ -8008,22 +8264,6 @@ oom_error: } -int Field_blob::store(double nr) -{ - CHARSET_INFO *cs=charset(); - value.set_real(nr, NOT_FIXED_DEC, cs); - return Field_blob::store(value.ptr(),(uint) value.length(), cs); -} - - -int Field_blob::store(longlong nr, bool unsigned_val) -{ - CHARSET_INFO *cs=charset(); - value.set_int(nr, unsigned_val, cs); - return Field_blob::store(value.ptr(), (uint) value.length(), cs); -} - - double Field_blob::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; @@ -8133,7 +8373,7 @@ int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr, uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg) { - uint32 blob_length= get_length(ptr); + size_t blob_length= get_length(ptr); uchar *blob; #ifdef HAVE_SPATIAL @@ -8151,7 +8391,7 @@ uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg) return image_length; } blob= get_ptr(); - gobj= Geometry::construct(&buffer, (char*) blob, blob_length); + gobj= Geometry::construct(&buffer, (char*) blob, (uint32)blob_length); if (!gobj || gobj->get_mbr(&mbr, &dummy)) bzero(buff, image_length); else @@ -8166,12 +8406,12 @@ uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg) #endif /*HAVE_SPATIAL*/ blob= get_ptr(); - uint local_char_length= length / field_charset->mbmaxlen; + size_t local_char_length= length / field_charset->mbmaxlen; local_char_length= my_charpos(field_charset, blob, blob + blob_length, local_char_length); set_if_smaller(blob_length, local_char_length); - if ((uint32) length > blob_length) + if (length > blob_length) { /* Must clear this as we do a memcmp in opt_range.cc to detect @@ -8197,14 +8437,14 @@ void Field_blob::set_key_image(const uchar *buff,uint length) int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length) { uchar *blob1; - uint blob_length=get_length(ptr); + size_t blob_length=get_length(ptr); memcpy(&blob1, ptr+packlength, sizeof(char*)); CHARSET_INFO *cs= charset(); - uint local_char_length= max_key_length / cs->mbmaxlen; + size_t local_char_length= max_key_length / cs->mbmaxlen; local_char_length= my_charpos(cs, blob1, blob1+blob_length, local_char_length); set_if_smaller(blob_length, local_char_length); - return Field_blob::cmp(blob1, blob_length, + return Field_blob::cmp(blob1, (uint32)blob_length, key_ptr+HA_KEY_BLOB_LENGTH, uint2korr(key_ptr)); } @@ -8240,9 +8480,9 @@ Field *Field_blob::new_key_field(MEM_ROOT *root, TABLE *new_table, @returns number of bytes written to metadata_ptr */ -int Field_blob::do_save_field_metadata(uchar *metadata_ptr) +int Field_blob::save_field_metadata(uchar *metadata_ptr) { - DBUG_ENTER("Field_blob::do_save_field_metadata"); + 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); @@ -8258,33 +8498,30 @@ uint32 Field_blob::sort_length() const void Field_blob::sort_string(uchar *to,uint length) { - uchar *blob; - uint blob_length=get_length(); + String buf; - if (!blob_length && field_charset->pad_char == 0) + val_str(&buf, &buf); + if (!buf.length() && field_charset->pad_char == 0) bzero(to,length); else { if (field_charset == &my_charset_bin) { - uchar *pos; - /* Store length of blob last in blob to shorter blobs before longer blobs */ length-= packlength; - pos= to+length; - - store_bigendian(blob_length, pos, packlength); + store_bigendian(buf.length(), to + length, packlength); } - memcpy(&blob, ptr+packlength, sizeof(char*)); - - blob_length= field_charset->coll->strnxfrm(field_charset, - to, length, length, - blob, blob_length, - MY_STRXFRM_PAD_WITH_SPACE | - MY_STRXFRM_PAD_TO_MAXLEN); - DBUG_ASSERT(blob_length == length); + +#ifndef DBUG_OFF + 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); + DBUG_ASSERT(rc == length); } } @@ -8380,11 +8617,9 @@ const uchar *Field_blob::unpack(uchar *to, const uchar *from, DBUG_RETURN(0); // Error in data uint32 const length= get_length(from, master_packlength); DBUG_DUMP("packed", from, length + master_packlength); - bitmap_set_bit(table->write_set, field_index); if (from + master_packlength + length > from_end) DBUG_RETURN(0); - store(reinterpret_cast<const char*>(from) + master_packlength, - length, field_charset); + set_ptr(length, const_cast<uchar*> (from) + master_packlength); DBUG_RETURN(from + master_packlength + length); } @@ -8403,11 +8638,68 @@ uint Field_blob::max_packed_col_length(uint max_length) } +/* + Blob fields are regarded equal if they have same character set, + same blob store length and if either both are compressed or both are + uncompressed. + The logic for compression is that we don't have to uncompress and compress + again an already compressed field just because compression method changes. +*/ + uint Field_blob::is_equal(Create_field *new_field) { return new_field->type_handler() == type_handler() && new_field->charset == field_charset && - new_field->pack_length == pack_length(); + new_field->pack_length == pack_length() && + !new_field->compression_method() == !compression_method(); +} + + +int Field_blob_compressed::store(const char *from, size_t length, + CHARSET_INFO *cs) +{ + ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + uint to_length= (uint)MY_MIN(max_data_length(), field_charset->mbmaxlen * length + 1); + int rc; + + if (value.alloc(to_length)) + { + set_ptr((uint32) 0, NULL); + return -1; + } + + rc= compress((char*) value.ptr(), &to_length, from, (uint)length, cs); + set_ptr(to_length, (uchar*) value.ptr()); + return rc; +} + + +String *Field_blob_compressed::val_str(String *val_buffer, String *val_ptr) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + return uncompress(val_buffer, val_ptr, get_ptr(), get_length()); +} + + +double Field_blob_compressed::val_real(void) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + THD *thd= get_thd(); + String buf; + val_str(&buf, &buf); + return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset, + buf.ptr(), buf.length()).result(); +} + + +longlong Field_blob_compressed::val_int(void) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + THD *thd= get_thd(); + String buf; + val_str(&buf, &buf); + return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset, + buf.ptr(), buf.length()).result(); } @@ -8461,7 +8753,7 @@ uint gis_field_options_image(uchar *buff, List<Create_field> &create_fields) } -uint gis_field_options_read(const uchar *buf, uint buf_len, +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; @@ -8567,7 +8859,7 @@ int Field_geom::store_decimal(const my_decimal *) } -int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) +int Field_geom::store(const char *from, size_t length, CHARSET_INFO *cs) { if (!length) bzero(ptr, Field_blob::pack_length()); @@ -8584,7 +8876,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) wkb_type > (uint32) Geometry::wkb_last) goto err; - if (geom_type != Field::GEOM_GEOMETRY && + if (geom_type != Field::GEOM_GEOMETRY && geom_type != Field::GEOM_GEOMETRYCOLLECTION && (uint32) geom_type != wkb_type) { @@ -8692,7 +8984,7 @@ void Field_enum::store_type(ulonglong value) (if there isn't a empty value in the enum) */ -int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) +int Field_enum::store(const char *from,size_t length,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; int err= 0; @@ -8709,7 +9001,7 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) } /* Remove end space */ - length= field_charset->cset->lengthsp(field_charset, from, length); + length= (uint)field_charset->cset->lengthsp(field_charset, from, length); uint tmp=find_type2(typelib, from, length, field_charset); if (!tmp) { @@ -8724,7 +9016,7 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) set_warning(WARN_DATA_TRUNCATED, 1); err= 1; } - if (!get_thd()->count_cuted_fields && !length) + if ((get_thd()->count_cuted_fields <= CHECK_FIELD_EXPRESSION) && !length) err= 0; } else @@ -8751,7 +9043,7 @@ int Field_enum::store(longlong nr, bool unsigned_val) if ((ulonglong) nr > typelib->count || nr == 0) { set_warning(WARN_DATA_TRUNCATED, 1); - if (nr != 0 || get_thd()->count_cuted_fields) + if (nr != 0 || get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION) { nr= 0; error= 1; @@ -8786,7 +9078,7 @@ longlong Field_enum::val_int(void) @returns number of bytes written to metadata_ptr */ -int Field_enum::do_save_field_metadata(uchar *metadata_ptr) +int Field_enum::save_field_metadata(uchar *metadata_ptr) { *metadata_ptr= real_type(); *(metadata_ptr + 1)= pack_length(); @@ -8875,7 +9167,7 @@ Field *Field_enum::make_new_field(MEM_ROOT *root, TABLE *new_table, */ -int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) +int Field_set::store(const char *from,size_t length,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; bool got_warning= 0; @@ -9294,14 +9586,14 @@ uint Field_bit::is_equal(Create_field *new_field) } -int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs) +int Field_bit::store(const char *from, size_t length, CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; int delta; for (; length && !*from; from++, length--) // skip left 0's ; - delta= bytes_in_rec - length; + delta= (int)(bytes_in_rec - length); if (delta < -1 || (delta == -1 && (uchar) *from > ((1 << bit_len) - 1)) || @@ -9505,9 +9797,9 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg) @returns number of bytes written to metadata_ptr */ -int Field_bit::do_save_field_metadata(uchar *metadata_ptr) +int Field_bit::save_field_metadata(uchar *metadata_ptr) { - DBUG_ENTER("Field_bit::do_save_field_metadata"); + DBUG_ENTER("Field_bit::save_field_metadata"); DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d", bit_len, bytes_in_rec)); /* @@ -9577,9 +9869,9 @@ Field_bit::compatible_field_size(uint field_metadata, void Field_bit::sql_type(String &res) const { CHARSET_INFO *cs= res.charset(); - ulong length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(), + size_t length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(), "bit(%d)", (int) field_length); - res.length((uint) length); + res.length(length); } @@ -9730,7 +10022,7 @@ Field_bit_as_char::Field_bit_as_char(uchar *ptr_arg, uint32 len_arg, } -int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs) +int Field_bit_as_char::store(const char *from, size_t length, CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; int delta; @@ -9738,7 +10030,7 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs) for (; length && !*from; from++, length--) // skip left 0's ; - delta= bytes_in_rec - length; + delta= (int)(bytes_in_rec - length); if (delta < 0 || (delta == 0 && bits && (uint) (uchar) *from >= (uint) (1 << bits))) @@ -9761,9 +10053,9 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs) void Field_bit_as_char::sql_type(String &res) const { CHARSET_INFO *cs= res.charset(); - ulong length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(), + size_t length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(), "bit(%d)", (int) field_length); - res.length((uint) length); + res.length(length); } @@ -9839,7 +10131,7 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root, } } interval->type_names[i]= value.str; - interval->type_lengths[i]= value.length; + interval->type_lengths[i]= (uint)value.length; } interval->type_names[interval->count]= 0; // End marker interval->type_lengths[interval->count]= 0; @@ -9977,6 +10269,8 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name, uint filter= VCOL_IMPOSSIBLE; if (type != VCOL_GENERATED_VIRTUAL && type != VCOL_DEFAULT) filter|= VCOL_NOT_STRICTLY_DETERMINISTIC; + if (type == VCOL_GENERATED_VIRTUAL) + filter|= VCOL_NOT_VIRTUAL; if (ret || (res.errors & filter)) { @@ -10178,8 +10472,8 @@ 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 || - !is_timestamp_type()) + if ((opt_explicit_defaults_for_timestamp || + !is_timestamp_type()) && !vers_sys_field()) { flags|= NO_DEFAULT_VALUE_FLAG; } @@ -10234,7 +10528,8 @@ Field *make_field(TABLE_SHARE *share, Field::geometry_type geom_type, uint srid, Field::utype unireg_check, TYPELIB *interval, - const LEX_CSTRING *field_name) + const LEX_CSTRING *field_name, + uint32 flags) { uchar *UNINIT_VAR(bit_ptr); uchar UNINIT_VAR(bit_offset); @@ -10289,6 +10584,16 @@ Field *make_field(TABLE_SHARE *share, unireg_check, field_name, field_charset); if (field_type == MYSQL_TYPE_VARCHAR) + { + if (unireg_check == Field::TMYSQL_COMPRESSED) + return new (mem_root) + Field_varstring_compressed( + ptr, field_length, + HA_VARCHAR_PACKLENGTH(field_length), + null_pos, null_bit, + unireg_check, field_name, + share, field_charset, zlib_compression_method); + return new (mem_root) Field_varstring(ptr,field_length, HA_VARCHAR_PACKLENGTH(field_length), @@ -10296,6 +10601,7 @@ Field *make_field(TABLE_SHARE *share, unireg_check, field_name, share, field_charset); + } return 0; // Error } @@ -10317,10 +10623,18 @@ Field *make_field(TABLE_SHARE *share, } #endif if (f_is_blob(pack_flag)) + { + if (unireg_check == Field::TMYSQL_COMPRESSED) + return new (mem_root) + Field_blob_compressed(ptr, null_pos, null_bit, + unireg_check, field_name, share, + pack_length, field_charset, zlib_compression_method); + return new (mem_root) Field_blob(ptr,null_pos,null_bit, unireg_check, field_name, share, pack_length, field_charset); + } if (interval) { if (f_is_enum(pack_flag)) @@ -10400,11 +10714,22 @@ Field *make_field(TABLE_SHARE *share, f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); case MYSQL_TYPE_LONGLONG: - return new (mem_root) - Field_longlong(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, - f_is_zerofill(pack_flag) != 0, - f_is_dec(pack_flag) == 0); + if (flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG)) + { + return new (mem_root) + Field_vers_trx_id(ptr, field_length, null_pos, null_bit, + unireg_check, field_name, + f_is_zerofill(pack_flag) != 0, + f_is_dec(pack_flag) == 0); + } + else + { + return new (mem_root) + Field_longlong(ptr,field_length,null_pos,null_bit, + unireg_check, field_name, + f_is_zerofill(pack_flag) != 0, + f_is_dec(pack_flag) == 0); + } case MYSQL_TYPE_TIMESTAMP: { uint dec= field_length > MAX_DATETIME_WIDTH ? @@ -10481,6 +10806,11 @@ Field *make_field(TABLE_SHARE *share, return 0; } +bool Field_vers_trx_id::test_if_equality_guarantees_uniqueness(const Item* item) const +{ + return item->type() == Item::DATE_ITEM; +} + /** Create a field suitable for create of table. */ @@ -10499,10 +10829,27 @@ Column_definition::Column_definition(THD *thd, Field *old_field, comment= old_field->comment; decimals= old_field->decimals(); vcol_info= old_field->vcol_info; - default_value= orig_field ? orig_field->default_value : 0; - check_constraint= orig_field ? orig_field->check_constraint : 0; option_list= old_field->option_list; pack_flag= 0; + compression_method_ptr= 0; + versioning= VERSIONING_NOT_SET; + invisible= old_field->invisible; + + if (orig_field) + { + default_value= orig_field->default_value; + check_constraint= orig_field->check_constraint; + if (orig_field->unireg_check == Field::TMYSQL_COMPRESSED) + { + unireg_check= Field::TMYSQL_COMPRESSED; + compression_method_ptr= zlib_compression_method; + } + } + else + { + default_value= 0; + check_constraint= 0; + } switch (real_field_type()) { case MYSQL_TYPE_TINY_BLOB: @@ -10523,7 +10870,8 @@ Column_definition::Column_definition(THD *thd, Field *old_field, case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VAR_STRING: /* This is corrected in create_length_to_internal_length */ - length= (length+charset->mbmaxlen-1) / charset->mbmaxlen; + length= (length+charset->mbmaxlen-1) / charset->mbmaxlen - + MY_TEST(old_field->compression_method()); break; #ifdef HAVE_SPATIAL case MYSQL_TYPE_GEOMETRY: @@ -10623,6 +10971,7 @@ Column_definition::redefine_stage1_common(const Column_definition *dup_field, flags= dup_field->flags; interval= dup_field->interval; vcol_info= dup_field->vcol_info; + invisible= dup_field->invisible; } @@ -10687,6 +11036,29 @@ bool Column_definition::has_default_expression() (flags & BLOB_FLAG))); } + +bool Column_definition::set_compressed(const char *method) +{ + enum enum_field_types sql_type= real_field_type(); + /* We can't use f_is_blob here as pack_flag is not yet set */ + if (sql_type == MYSQL_TYPE_VARCHAR || sql_type == MYSQL_TYPE_TINY_BLOB || + sql_type == MYSQL_TYPE_BLOB || sql_type == MYSQL_TYPE_MEDIUM_BLOB || + sql_type == MYSQL_TYPE_LONG_BLOB) + { + if (!method || !strcmp(method, zlib_compression_method->name)) + { + unireg_check= Field::TMYSQL_COMPRESSED; + compression_method_ptr= zlib_compression_method; + return false; + } + my_error(ER_UNKNOWN_COMPRESSION_METHOD, MYF(0), method); + } + else + my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name.str); + return true; +} + + /** maximum possible display length for blob. @@ -10725,11 +11097,12 @@ uint32 Field_blob::max_display_length() @param cut_increment - whenever we should increase cut fields count @note - This function won't produce warning and increase cut fields counter - if count_cuted_fields == CHECK_FIELD_IGNORE for current thread. + This function won't produce warning or notes or increase cut fields counter + if count_cuted_fields == CHECK_FIELD_IGNORE or CHECK_FIELD_EXPRESSION + for the current thread. - if count_cuted_fields == CHECK_FIELD_IGNORE then we ignore notes. - This allows us to avoid notes in optimisation, like convert_constant_item(). + This allows us to avoid notes in optimisation, like + convert_constant_item(). @retval 1 if count_cuted_fields == CHECK_FIELD_IGNORE and error level is not NOTE @@ -10746,7 +11119,7 @@ Field::set_warning(Sql_condition::enum_warning_level level, uint code, will have table == NULL. */ THD *thd= get_thd(); - if (thd->count_cuted_fields) + if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION) { thd->cuted_fields+= cut_increment; push_warning_printf(thd, level, code, ER_THD(thd, code), field_name.str, |