From fba7fbbc5c7bb1d05488108a29b854ee8ef0066a Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 17 May 2017 12:21:39 +0400 Subject: [PATCH] MDEV-9397 Split field.cc:calc_pack_length() into virtual methods in Type_handler - Adding new virtual methods in Type_handler: * Column_definition_prepare_stage1() * Column_definition_prepare_stage2() * calc_pack_length() - Using new methods to remove type specific code in: * Global function calc_pack_length() * Column_definition::prepare_create_field() * The loop body mysql_prepare_create_table() * Column_definition::sp_prepare_create_field() --- sql/field.cc | 176 +++++++----------- sql/field.h | 52 +++++- sql/sql_lex.cc | 9 +- sql/sql_table.cc | 474 ++++++++++++++++++++++------------------------- sql/sql_table.h | 2 +- sql/sql_type.cc | 301 ++++++++++++++++++++++++++++++ sql/sql_type.h | 215 +++++++++++++++++++++ 7 files changed, 849 insertions(+), 380 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index b17198b3a1e..577b09e948d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -53,15 +53,6 @@ static const char *zero_timestamp="0000-00-00 00:00:00.000000"; LEX_CSTRING temp_lex_str= {"temp", 4}; -/* number of bytes to store second_part part of the TIMESTAMP(N) */ -static uint sec_part_bytes[MAX_DATETIME_PRECISION+1]= { 0, 1, 1, 2, 2, 3, 3 }; - -/* number of bytes to store DATETIME(N) */ -static uint datetime_hires_bytes[MAX_DATETIME_PRECISION+1]= { 5, 6, 6, 7, 7, 7, 8 }; - -/* number of bytes to store TIME(N) */ -static uint time_hires_bytes[MAX_DATETIME_PRECISION+1]= { 3, 4, 4, 5, 5, 5, 6 }; - uchar Field_null::null[1]={1}; const char field_separator=','; @@ -5226,14 +5217,14 @@ static longlong read_bigendian(const uchar *from, uint bytes) void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) { mi_int4store(ptr, timestamp); - store_bigendian(sec_part_shift(sec_part, dec), ptr+4, sec_part_bytes[dec]); + store_bigendian(sec_part_shift(sec_part, dec), ptr+4, sec_part_bytes(dec)); } my_time_t Field_timestamp_hires::get_timestamp(const uchar *pos, ulong *sec_part) const { ASSERT_COLUMN_MARKED_FOR_READ; - *sec_part= (long)sec_part_unshift(read_bigendian(pos+4, sec_part_bytes[dec]), dec); + *sec_part= (long)sec_part_unshift(read_bigendian(pos+4, sec_part_bytes(dec)), dec); return mi_uint4korr(pos); } @@ -5300,19 +5291,14 @@ int Field_timestamp_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) int32 a,b; ulong a_sec_part, b_sec_part; a= mi_uint4korr(a_ptr); - a_sec_part= (ulong)read_bigendian(a_ptr+4, sec_part_bytes[dec]); + a_sec_part= (ulong)read_bigendian(a_ptr+4, sec_part_bytes(dec)); b= mi_uint4korr(b_ptr); - b_sec_part= (ulong)read_bigendian(b_ptr+4, sec_part_bytes[dec]); + b_sec_part= (ulong)read_bigendian(b_ptr+4, sec_part_bytes(dec)); return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : a_sec_part < b_sec_part ? -1 : a_sec_part > b_sec_part ? 1 : 0; } -uint32 Field_timestamp_hires::pack_length() const -{ - return 4 + sec_part_bytes[dec]; -} - void Field_timestamp_with_dec::make_field(Send_field *field) { Field::make_field(field); @@ -5951,11 +5937,6 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx, } -uint32 Field_time_hires::pack_length() const -{ - return time_hires_bytes[dec]; -} - longlong Field_time_with_dec::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; @@ -6658,11 +6639,6 @@ bool Field_datetime_hires::get_TIME(MYSQL_TIME *ltime, const uchar *pos, } -uint32 Field_datetime_hires::pack_length() const -{ - return datetime_hires_bytes[dec]; -} - int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) { ulonglong a=read_bigendian(a_ptr, Field_datetime_hires::pack_length()); @@ -9803,6 +9779,32 @@ void Column_definition::set_attributes(const Lex_field_type_st &type, } +void Column_definition::create_length_to_internal_length_bit() +{ + if (f_bit_as_char(pack_flag)) + { + key_length= pack_length= ((length + 7) & ~7) / 8; + } + else + { + pack_length= length / 8; + /* We need one extra byte to store the bits we save among the null bits */ + key_length= pack_length + MY_TEST(length & 7); + } +} + + +void Column_definition::create_length_to_internal_length_newdecimal() +{ + key_length= pack_length= + my_decimal_get_binary_size(my_decimal_length_to_precision(length, + decimals, + flags & + UNSIGNED_FLAG), + decimals); +} + + /** Convert create_field::length from number of characters to number of bytes. */ @@ -9818,38 +9820,41 @@ void Column_definition::create_length_to_internal_length(void) case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: case MYSQL_TYPE_VARCHAR: - length*= charset->mbmaxlen; - key_length= length; - pack_length= calc_pack_length(real_field_type(), length); + create_length_to_internal_length_string(); break; case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: - /* Pack_length already calculated in sql_parse.cc */ - length*= charset->mbmaxlen; - key_length= pack_length; + create_length_to_internal_length_typelib(); break; case MYSQL_TYPE_BIT: - if (f_bit_as_char(pack_flag)) - { - key_length= pack_length= ((length + 7) & ~7) / 8; - } - else - { - pack_length= length / 8; - /* We need one extra byte to store the bits we save among the null bits */ - key_length= pack_length + MY_TEST(length & 7); - } + create_length_to_internal_length_bit(); break; case MYSQL_TYPE_NEWDECIMAL: - key_length= pack_length= - my_decimal_get_binary_size(my_decimal_length_to_precision(length, - decimals, - flags & - UNSIGNED_FLAG), - decimals); + create_length_to_internal_length_newdecimal(); break; - default: - key_length= pack_length= calc_pack_length(real_field_type(), length); + + case MYSQL_TYPE_NULL: + create_length_to_internal_length_null(); + break; + + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_TIME2: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_DATETIME2: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_TIMESTAMP2: + create_length_to_internal_length_simple(); break; } } @@ -10110,64 +10115,6 @@ enum_field_types get_blob_type_from_length(ulong length) } -/* - Make a field from the .frm file info -*/ - -uint32 calc_pack_length(enum_field_types type,uint32 length) -{ - switch (type) { - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_DECIMAL: return (length); - case MYSQL_TYPE_VARCHAR: return (length + (length < 256 ? 1: 2)); - case MYSQL_TYPE_YEAR: - case MYSQL_TYPE_TINY : return 1; - case MYSQL_TYPE_SHORT : return 2; - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_NEWDATE: return 3; - case MYSQL_TYPE_TIME: return length > MIN_TIME_WIDTH - ? time_hires_bytes[length - 1 - MIN_TIME_WIDTH] - : 3; - case MYSQL_TYPE_TIME2: - return length > MIN_TIME_WIDTH ? - my_time_binary_length(length - MIN_TIME_WIDTH - 1) : 3; - case MYSQL_TYPE_TIMESTAMP: - return length > MAX_DATETIME_WIDTH - ? 4 + sec_part_bytes[length - 1 - MAX_DATETIME_WIDTH] - : 4; - case MYSQL_TYPE_TIMESTAMP2: - return length > MAX_DATETIME_WIDTH ? - my_timestamp_binary_length(length - MAX_DATETIME_WIDTH - 1) : 4; - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_LONG : return 4; - case MYSQL_TYPE_FLOAT : return sizeof(float); - case MYSQL_TYPE_DOUBLE: return sizeof(double); - case MYSQL_TYPE_DATETIME: - return length > MAX_DATETIME_WIDTH - ? datetime_hires_bytes[length - 1 - MAX_DATETIME_WIDTH] - : 8; - case MYSQL_TYPE_DATETIME2: - return length > MAX_DATETIME_WIDTH ? - my_datetime_binary_length(length - MAX_DATETIME_WIDTH - 1) : 5; - case MYSQL_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */ - case MYSQL_TYPE_NULL : return 0; - case MYSQL_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr; - case MYSQL_TYPE_BLOB: return 2+portable_sizeof_char_ptr; - case MYSQL_TYPE_MEDIUM_BLOB: return 3+portable_sizeof_char_ptr; - case MYSQL_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr; - case MYSQL_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr; - case MYSQL_TYPE_SET: - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_NEWDECIMAL: - abort(); return 0; // This shouldn't happen - case MYSQL_TYPE_BIT: return length / 8; - default: - return 0; - } -} - - uint pack_length_to_packflag(uint type) { switch (type) { @@ -10248,9 +10195,12 @@ Field *make_field(TABLE_SHARE *share, return 0; // Error } - uint pack_length=calc_pack_length((enum_field_types) - f_packtype(pack_flag), - field_length); + // MYSQL_TYPE_VAR_STRING is handled above + DBUG_ASSERT(f_packtype(pack_flag) != MYSQL_TYPE_VAR_STRING); + const Type_handler *tmp; + tmp= Type_handler::get_handler_by_real_type((enum_field_types) + f_packtype(pack_flag)); + uint pack_length= tmp->calc_pack_length(field_length); #ifdef HAVE_SPATIAL if (f_is_geom(pack_flag)) diff --git a/sql/field.h b/sql/field.h index 093fcce6fac..10363fd855b 100644 --- a/sql/field.h +++ b/sql/field.h @@ -2454,6 +2454,10 @@ public: class Field_timestamp_hires :public Field_timestamp_with_dec { + uint sec_part_bytes(uint dec) const + { + return Type_handler_timestamp::sec_part_bytes(dec); + } public: Field_timestamp_hires(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, @@ -2468,7 +2472,7 @@ public: my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; void store_TIME(my_time_t timestamp, ulong sec_part); int cmp(const uchar *,const uchar *); - uint32 pack_length() const; + uint32 pack_length() const { return 4 + sec_part_bytes(dec); } uint size_of() const { return sizeof(*this); } }; @@ -2735,7 +2739,7 @@ public: bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); int cmp(const uchar *,const uchar *); void sort_string(uchar *buff,uint length); - uint32 pack_length() const; + uint32 pack_length() const { return Type_handler_time::hires_bytes(dec); } uint size_of() const { return sizeof(*this); } }; @@ -2894,7 +2898,7 @@ public: DBUG_ASSERT(dec); } int cmp(const uchar *,const uchar *); - uint32 pack_length() const; + uint32 pack_length() const { return Type_handler_datetime::hires_bytes(dec); } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) { return Field_datetime_hires::get_TIME(ltime, ptr, fuzzydate); } uint size_of() const { return sizeof(*this); } @@ -3831,6 +3835,8 @@ class Column_definition: public Sql_alloc, set_if_bigger(*max_length, (uint32)length); } } + bool prepare_stage1_check_typelib_default(); + bool prepare_stage1_convert_default(THD *, MEM_ROOT *, CHARSET_INFO *to); const Type_handler *field_type() const; // Prevent using this public: LEX_CSTRING field_name; @@ -3882,6 +3888,29 @@ public: Column_definition(THD *thd, Field *field, Field *orig_field); void set_attributes(const Lex_field_type_st &type, CHARSET_INFO *cs); void create_length_to_internal_length(void); + void create_length_to_internal_length_null() + { + DBUG_ASSERT(length == 0); + key_length= pack_length= 0; + } + void create_length_to_internal_length_simple() + { + key_length= pack_length= type_handler()->calc_pack_length(length); + } + void create_length_to_internal_length_string() + { + length*= charset->mbmaxlen; + key_length= length; + pack_length= type_handler()->calc_pack_length(length); + } + void create_length_to_internal_length_typelib() + { + /* Pack_length already calculated in sql_parse.cc */ + length*= charset->mbmaxlen; + key_length= pack_length; + } + void create_length_to_internal_length_bit(); + void create_length_to_internal_length_newdecimal(); /** Prepare a SET/ENUM field. @@ -3917,8 +3946,22 @@ public: bool sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root); - bool prepare_create_field(uint *blob_columns, ulonglong table_flags); + bool prepare_stage1(THD *thd, MEM_ROOT *mem_root, + handler *file, ulonglong table_flags); + bool prepare_stage1_typelib(THD *thd, MEM_ROOT *mem_root, + handler *file, ulonglong table_flags); + bool prepare_stage1_string(THD *thd, MEM_ROOT *mem_root, + handler *file, ulonglong table_flags); + bool prepare_stage1_bit(THD *thd, MEM_ROOT *mem_root, + handler *file, ulonglong table_flags); + bool prepare_stage2(handler *handler, ulonglong table_flags); + bool prepare_stage2_blob(handler *handler, + ulonglong table_flags, uint field_flags); + bool prepare_stage2_varchar(ulonglong table_flags); + bool prepare_stage2_typelib(const char *type_name, uint field_flags, + uint *dup_val_count); + uint pack_flag_numeric(uint dec) const; uint sign_length() const { return flags & UNSIGNED_FLAG ? 0 : 1; } bool check_length(uint mysql_errno, uint max_allowed_length) const; bool fix_attributes_real(uint default_length); @@ -4212,7 +4255,6 @@ public: uint pack_length_to_packflag(uint type); enum_field_types get_blob_type_from_length(ulong length); -uint32 calc_pack_length(enum_field_types type,uint32 length); int set_field_to_null(Field *field); int set_field_to_null_with_conversions(Field *field, bool no_conversions); int convert_null_to_field_value_or_error(Field *field); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 8cabe795d21..febd0931e48 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -5407,13 +5407,8 @@ sp_variable *LEX::sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name, spcont->declare_var_boundary(1); spvar->field_def.field_name= spvar->name; spvar->field_def.set_handler(&type_handler_longlong); - /* - The below is a simplified version of what - Column_definition::prepare_create_field() does for a LONGLONG field. - */ - spvar->field_def.pack_flag= (FIELDFLAG_NUMBER | - f_settype((uint) MYSQL_TYPE_LONGLONG)); - + type_handler_longlong.Column_definition_prepare_stage2(&spvar->field_def, + NULL, HA_CAN_GEOMETRY); if (!value && !(value= new (thd->mem_root) Item_null(thd))) return NULL; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f985f6e73fc..e202552ac8a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2845,23 +2845,82 @@ bool check_duplicates_in_interval(const char *set_or_name, } +bool Column_definition::prepare_stage2_blob(handler *file, + ulonglong table_flags, + uint field_flags) +{ + if (table_flags & HA_NO_BLOBS) + { + my_error(ER_TABLE_CANT_HANDLE_BLOB, MYF(0), file->table_type()); + return true; + } + pack_flag= field_flags | + pack_length_to_packflag(pack_length - portable_sizeof_char_ptr); + if (charset->state & MY_CS_BINSORT) + pack_flag|= FIELDFLAG_BINARY; + length= 8; // Unireg field length + return false; +} + + +bool Column_definition::prepare_stage2_typelib(const char *type_name, + uint field_flags, + uint *dup_val_count) +{ + pack_flag= pack_length_to_packflag(pack_length) | field_flags; + if (charset->state & MY_CS_BINSORT) + pack_flag|= FIELDFLAG_BINARY; + return check_duplicates_in_interval(type_name, field_name.str, interval, + charset, dup_val_count); +} + + +uint Column_definition::pack_flag_numeric(uint dec) const +{ + return (FIELDFLAG_NUMBER | + (flags & UNSIGNED_FLAG ? 0 : FIELDFLAG_DECIMAL) | + (flags & ZEROFILL_FLAG ? FIELDFLAG_ZEROFILL : 0) | + (dec << FIELDFLAG_DEC_SHIFT)); +} + + +bool Column_definition::prepare_stage2_varchar(ulonglong table_flags) +{ +#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR + if (table_flags & HA_NO_VARCHAR) + { + /* convert VARCHAR to CHAR because handler is not yet up to date */ + set_handler(&type_handler_var_string); + pack_length= type_handler()->calc_pack_length((uint) length); + if ((length / charset->mbmaxlen) > MAX_FIELD_CHARLENGTH) + { + my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name.str, + static_cast(MAX_FIELD_CHARLENGTH)); + return true; + } + } +#endif + pack_flag= (charset->state & MY_CS_BINSORT) ? FIELDFLAG_BINARY : 0; + return false; +} + + /* Prepare a Column_definition instance for packing Members such as pack_flag are valid after this call. - @param IN/OUT blob_columns - count for BLOBs + @param IN handler - storage engine handler, + or NULL if preparing for an SP variable @param IN table_flags - table flags @retval false - ok @retval true - error (not supported type, bad definition, etc) */ -bool Column_definition::prepare_create_field(uint *blob_columns, - ulonglong table_flags) +bool Column_definition::prepare_stage2(handler *file, + ulonglong table_flags) { - uint dup_val_count; - uint decimals_orig= decimals; - DBUG_ENTER("Column_definition::prepare_create_field"); + DBUG_ENTER("Column_definition::prepare_stage2"); /* This code came from mysql_prepare_create_table. @@ -2869,122 +2928,9 @@ bool Column_definition::prepare_create_field(uint *blob_columns, */ DBUG_ASSERT(charset); - switch (real_field_type()) { - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_LONG_BLOB: - pack_flag= FIELDFLAG_BLOB | - pack_length_to_packflag(pack_length - portable_sizeof_char_ptr); - if (charset->state & MY_CS_BINSORT) - pack_flag|= FIELDFLAG_BINARY; - length= 8; // Unireg field length - (*blob_columns)++; - break; - case MYSQL_TYPE_GEOMETRY: -#ifdef HAVE_SPATIAL - if (!(table_flags & HA_CAN_GEOMETRY)) - { - my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY"); - DBUG_RETURN(1); - } - pack_flag= FIELDFLAG_GEOM | - pack_length_to_packflag(pack_length - portable_sizeof_char_ptr); - if (charset->state & MY_CS_BINSORT) - pack_flag|= FIELDFLAG_BINARY; - length= 8; // Unireg field length - (*blob_columns)++; - break; -#else - my_error(ER_FEATURE_DISABLED, MYF(0), - sym_group_geom.name, sym_group_geom.needed_define); + if (type_handler()->Column_definition_prepare_stage2(this, file, table_flags)) DBUG_RETURN(true); -#endif /*HAVE_SPATIAL*/ - case MYSQL_TYPE_VARCHAR: -#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR - if (table_flags & HA_NO_VARCHAR) - { - /* convert VARCHAR to CHAR because handler is not yet up to date */ - set_handler(&type_handler_var_string); - pack_length= calc_pack_length(real_field_type(), (uint) length); - if ((length / charset->mbmaxlen) > MAX_FIELD_CHARLENGTH) - { - my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name.str, - static_cast(MAX_FIELD_CHARLENGTH)); - DBUG_RETURN(true); - } - } -#endif - /* fall through */ - case MYSQL_TYPE_STRING: - pack_flag= 0; - if (charset->state & MY_CS_BINSORT) - pack_flag|= FIELDFLAG_BINARY; - break; - case MYSQL_TYPE_ENUM: - pack_flag= pack_length_to_packflag(pack_length) | FIELDFLAG_INTERVAL; - if (charset->state & MY_CS_BINSORT) - pack_flag|= FIELDFLAG_BINARY; - if (check_duplicates_in_interval("ENUM", field_name.str, interval, - charset, &dup_val_count)) - DBUG_RETURN(true); - break; - case MYSQL_TYPE_SET: - pack_flag= pack_length_to_packflag(pack_length) | FIELDFLAG_BITFIELD; - if (charset->state & MY_CS_BINSORT) - pack_flag|= FIELDFLAG_BINARY; - if (check_duplicates_in_interval("SET", field_name.str, interval, - charset, &dup_val_count)) - DBUG_RETURN(true); - /* Check that count of unique members is not more then 64 */ - if (interval->count - dup_val_count > sizeof(longlong)*8) - { - my_error(ER_TOO_BIG_SET, MYF(0), field_name.str); - DBUG_RETURN(true); - } - break; - case MYSQL_TYPE_DATE: // Rest of string types - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIME2: - case MYSQL_TYPE_DATETIME2: - case MYSQL_TYPE_NULL: - pack_flag= f_settype((uint) real_field_type()); - break; - case MYSQL_TYPE_BIT: - /* - We have sql_field->pack_flag already set here, see - mysql_prepare_create_table(). - */ - break; - case MYSQL_TYPE_NEWDECIMAL: - pack_flag= (FIELDFLAG_NUMBER | - (flags & UNSIGNED_FLAG ? 0 : FIELDFLAG_DECIMAL) | - (flags & ZEROFILL_FLAG ? FIELDFLAG_ZEROFILL : 0) | - (decimals_orig << FIELDFLAG_DEC_SHIFT)); - break; - case MYSQL_TYPE_FLOAT: - case MYSQL_TYPE_DOUBLE: - /* - User specified FLOAT() or DOUBLE() without precision. Change to - FLOATING_POINT_DECIMALS to keep things compatible with earlier MariaDB - versions. - */ - if (decimals_orig >= FLOATING_POINT_DECIMALS) - decimals_orig= FLOATING_POINT_DECIMALS; - /* fall-trough */ - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_TIMESTAMP2: - /* fall-through */ - default: - pack_flag= (FIELDFLAG_NUMBER | - (flags & UNSIGNED_FLAG ? 0 : FIELDFLAG_DECIMAL) | - (flags & ZEROFILL_FLAG ? FIELDFLAG_ZEROFILL : 0) | - f_settype((uint) real_field_type()) | - (decimals_orig << FIELDFLAG_DEC_SHIFT)); - break; - } + if (!(flags & NOT_NULL_FLAG) || (vcol_info)) /* Make virtual columns allow NULL values */ pack_flag|= FIELDFLAG_MAYBE_NULL; @@ -3007,7 +2953,7 @@ bool Column_definition::prepare_create_field(uint *blob_columns, cs Character set */ -CHARSET_INFO* get_sql_field_charset(Create_field *sql_field, +CHARSET_INFO* get_sql_field_charset(Column_definition *sql_field, HA_CREATE_INFO *create_info) { CHARSET_INFO *cs= sql_field->charset; @@ -3146,6 +3092,143 @@ static void check_duplicate_key(THD *thd, Key *key, KEY *key_info, } +bool Column_definition::prepare_stage1_typelib(THD *thd, + MEM_ROOT *mem_root, + handler *file, + ulonglong table_flags) +{ + /* + Pass the last parameter to prepare_interval_field() as follows: + - If we are preparing for an SP variable (file is NULL), we pass "false", + to force allocation and full copying of TYPELIB values on the given + mem_root, even if no character set conversion is needed. This is needed + because a life cycle of an SP variable is longer than the current query. + + - If we are preparing for a CREATE TABLE, (file != NULL), we pass "true". + This will create the typelib in runtime memory - we will free the + occupied memory at the same time when we free this + sql_field -- at the end of execution. + Pass "true" as the last argument to reuse "interval_list" + values in "interval" in cases when no character conversion is needed, + to avoid extra copying. + */ + if (prepare_interval_field(mem_root, file != NULL)) + return true; // E.g. wrong values with commas: SET('a,b') + create_length_to_internal_length_typelib(); + + DBUG_ASSERT(file || !default_value); // SP variables have no default_value + if (default_value && default_value->expr->basic_const_item()) + { + if ((charset != default_value->expr->collation.collation && + prepare_stage1_convert_default(thd, mem_root, charset)) || + prepare_stage1_check_typelib_default()) + return true; + } + return false; +} + + +bool Column_definition::prepare_stage1_string(THD *thd, + MEM_ROOT *mem_root, + handler *file, + ulonglong table_flags) +{ + create_length_to_internal_length_string(); + if (prepare_blob_field(thd)) + return true; + DBUG_ASSERT(file || !default_value); // SP variables have no default_value + /* + Convert the default value from client character + set into the column character set if necessary. + We can only do this for constants as we have not yet run fix_fields. + */ + if (default_value && + default_value->expr->basic_const_item() && + charset != default_value->expr->collation.collation) + { + if (prepare_stage1_convert_default(thd, mem_root, charset)) + return true; + } + return false; +} + + +bool Column_definition::prepare_stage1_bit(THD *thd, + MEM_ROOT *mem_root, + handler *file, + ulonglong table_flags) +{ + pack_flag= FIELDFLAG_NUMBER; + if (!(table_flags & HA_CAN_BIT_FIELD)) + pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR; + create_length_to_internal_length_bit(); + return false; +} + + +bool Column_definition::prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + handler *file, + ulonglong table_flags) +{ + return type_handler()->Column_definition_prepare_stage1(thd, mem_root, + this, file, + table_flags); +} + + +bool Column_definition::prepare_stage1_convert_default(THD *thd, + MEM_ROOT *mem_root, + CHARSET_INFO *cs) +{ + DBUG_ASSERT(thd->mem_root == mem_root); + Item *item; + if (!(item= default_value->expr->safe_charset_converter(thd, cs))) + { + my_error(ER_INVALID_DEFAULT, MYF(0), field_name.str); + return true; // Could not convert + } + /* Fix for prepare statement */ + thd->change_item_tree(&default_value->expr, item); + return false; +} + + +bool Column_definition::prepare_stage1_check_typelib_default() +{ + StringBuffer str; + String *def= default_value->expr->val_str(&str); + bool not_found; + if (def == NULL) /* SQL "NULL" maps to NULL */ + { + not_found= flags & NOT_NULL_FLAG; + } + else + { + not_found= false; + if (real_field_type() == MYSQL_TYPE_SET) + { + char *not_used; + uint not_used2; + find_set(interval, def->ptr(), def->length(), + charset, ¬_used, ¬_used2, ¬_found); + } + else /* MYSQL_TYPE_ENUM */ + { + def->length(charset->cset->lengthsp(charset, + def->ptr(), def->length())); + not_found= !find_type2(interval, def->ptr(), def->length(), charset); + } + } + if (not_found) + { + my_error(ER_INVALID_DEFAULT, MYF(0), field_name.str); + return true; + } + return false; +} + + /* Preparation for table creation @@ -3180,7 +3263,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, { const char *key_name; Create_field *sql_field,*dup_field; - uint field,null_fields,blob_columns,max_key_length; + uint field,null_fields,max_key_length; ulong record_offset= 0; KEY *key_info; KEY_PART_INFO *key_part_info; @@ -3193,7 +3276,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, bool tmp_table= create_table_mode == C_ALTER_TABLE; DBUG_ENTER("mysql_prepare_create_table"); - null_fields=blob_columns=0; + null_fields= 0; create_info->varchar= 0; max_key_length= file->max_key_length(); @@ -3215,8 +3298,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, select_field_pos= alter_info->create_list.elements - select_field_count; for (field_no=0; (sql_field=it++) ; field_no++) { - CHARSET_INFO *save_cs; - /* Initialize length from its original value (number of characters), which was set in the parser. This is necessary if we're @@ -3224,105 +3305,18 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, */ sql_field->length= sql_field->char_length; /* Set field charset. */ - save_cs= sql_field->charset= get_sql_field_charset(sql_field, create_info); + sql_field->charset= get_sql_field_charset(sql_field, create_info); if ((sql_field->flags & BINCMP_FLAG) && - !(sql_field->charset= find_bin_collation(sql_field->charset))) - DBUG_RETURN(TRUE); + !(sql_field->charset= find_bin_collation(sql_field->charset))) + DBUG_RETURN(true); - if (sql_field->real_field_type() == MYSQL_TYPE_SET || - sql_field->real_field_type() == MYSQL_TYPE_ENUM) - { - /* - Create the typelib in runtime memory - we will free the - occupied memory at the same time when we free this - sql_field -- at the end of execution. - Pass "true" as the last argument to reuse "interval_list" - values in "interval" in cases when no character conversion is needed, - to avoid extra copying. - */ - if (sql_field->prepare_interval_field(thd->mem_root, true)) - DBUG_RETURN(true); // E.g. wrong values with commas: SET('a,b') - } + if (sql_field->prepare_stage1(thd, thd->mem_root, + file, file->ha_table_flags())) + DBUG_RETURN(true); - if (sql_field->real_field_type() == MYSQL_TYPE_BIT) - { - sql_field->pack_flag= FIELDFLAG_NUMBER; - if (file->ha_table_flags() & HA_CAN_BIT_FIELD) - total_uneven_bit_length+= sql_field->length & 7; - else - sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR; - } - - sql_field->create_length_to_internal_length(); - if (sql_field->prepare_blob_field(thd)) - DBUG_RETURN(TRUE); - - /* - Convert the default value from client character - set into the column character set if necessary. - We can only do this for constants as we have not yet run fix_fields. - */ - if (sql_field->default_value && - sql_field->default_value->expr->basic_const_item() && - save_cs != sql_field->default_value->expr->collation.collation && - (sql_field->real_field_type() == MYSQL_TYPE_VAR_STRING || - sql_field->real_field_type() == MYSQL_TYPE_STRING || - sql_field->real_field_type() == MYSQL_TYPE_SET || - sql_field->real_field_type() == MYSQL_TYPE_TINY_BLOB || - sql_field->real_field_type() == MYSQL_TYPE_MEDIUM_BLOB || - sql_field->real_field_type() == MYSQL_TYPE_LONG_BLOB || - sql_field->real_field_type() == MYSQL_TYPE_BLOB || - sql_field->real_field_type() == MYSQL_TYPE_ENUM)) - { - Item *item; - if (!(item= sql_field->default_value->expr-> - safe_charset_converter(thd, save_cs))) - { - /* Could not convert */ - my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name.str); - DBUG_RETURN(TRUE); - } - /* Fix for prepare statement */ - thd->change_item_tree(&sql_field->default_value->expr, item); - } - - if (sql_field->default_value && - sql_field->default_value->expr->basic_const_item() && - (sql_field->real_field_type() == MYSQL_TYPE_SET || - sql_field->real_field_type() == MYSQL_TYPE_ENUM)) - { - StringBuffer str; - String *def= sql_field->default_value->expr->val_str(&str); - bool not_found; - if (def == NULL) /* SQL "NULL" maps to NULL */ - { - not_found= sql_field->flags & NOT_NULL_FLAG; - } - else - { - not_found= false; - if (sql_field->real_field_type() == MYSQL_TYPE_SET) - { - char *not_used; - uint not_used2; - find_set(sql_field->interval, def->ptr(), def->length(), - sql_field->charset, ¬_used, ¬_used2, ¬_found); - } - else /* MYSQL_TYPE_ENUM */ - { - def->length(sql_field->charset->cset->lengthsp(sql_field->charset, - def->ptr(), def->length())); - not_found= !find_type2(sql_field->interval, def->ptr(), - def->length(), sql_field->charset); - } - } - - if (not_found) - { - my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name.str); - DBUG_RETURN(TRUE); - } - } + if (sql_field->real_field_type() == MYSQL_TYPE_BIT && + file->ha_table_flags() & HA_CAN_BIT_FIELD) + total_uneven_bit_length+= sql_field->length & 7; if (!(sql_field->flags & NOT_NULL_FLAG)) null_fields++; @@ -3419,7 +3413,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, { DBUG_ASSERT(sql_field->charset != 0); - if (sql_field->prepare_create_field(&blob_columns, file->ha_table_flags())) + if (sql_field->prepare_stage2(file, file->ha_table_flags())) DBUG_RETURN(TRUE); if (sql_field->real_field_type() == MYSQL_TYPE_VARCHAR) create_info->varchar= TRUE; @@ -3461,12 +3455,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(TRUE); } - if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS)) - { - my_error(ER_TABLE_CANT_HANDLE_BLOB, MYF(0), file->table_type()); - DBUG_RETURN(TRUE); - } - /* CREATE TABLE[with auto_increment column] SELECT is unsafe as the rows inserted in the created table depends on the order of the rows fetched @@ -4237,7 +4225,7 @@ bool Column_definition::prepare_blob_field(THD *thd) { /* The user has given a length to the blob column */ set_handler(Type_handler::blob_type_handler(length)); - pack_length= calc_pack_length(real_field_type(), 0); + pack_length= type_handler()->calc_pack_length(0); } length= 0; } @@ -4262,30 +4250,8 @@ bool Column_definition::prepare_blob_field(THD *thd) bool Column_definition::sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root) { - if (real_field_type() == MYSQL_TYPE_SET || - real_field_type() == MYSQL_TYPE_ENUM) - { - /* - Pass "false" as the last argument to allocate TYPELIB values on mem_root, - even if no character set conversion is needed. - */ - if (prepare_interval_field(mem_root, false)) - return true; // E.g. wrong values with commas: SET('a,b') - } - - if (real_field_type() == MYSQL_TYPE_BIT) - pack_flag= FIELDFLAG_NUMBER | FIELDFLAG_TREAT_BIT_AS_CHAR; - create_length_to_internal_length(); - DBUG_ASSERT(default_value == 0); - /* - prepare_blob_field() can return an error on attempt to create a too long - VARCHAR/VARBINARY field when the current sql_mode does not allow automatic - conversion to TEXT/BLOB. - */ - if (prepare_blob_field(thd)) - return true; - uint unused1; - return prepare_create_field(&unused1, HA_CAN_GEOMETRY); + return prepare_stage1(thd, mem_root, NULL, HA_CAN_GEOMETRY) || + prepare_stage2(NULL, HA_CAN_GEOMETRY); } diff --git a/sql/sql_table.h b/sql/sql_table.h index 4fb6135e9cc..2e080462deb 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -253,7 +253,7 @@ bool quick_rm_table(THD *thd, handlerton *base, const char *db, const char *table_path=0); void close_cached_table(THD *thd, TABLE *table); void sp_prepare_create_field(THD *thd, Column_definition *sql_field); -CHARSET_INFO* get_sql_field_charset(Create_field *sql_field, +CHARSET_INFO* get_sql_field_charset(Column_definition *sql_field, HA_CREATE_INFO *create_info); bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); int write_bin_log(THD *thd, bool clear_error, diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 5e08a616d9f..90f8d674e67 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -379,6 +379,20 @@ Type_handler_hybrid_field_type::Type_handler_hybrid_field_type() } +/***************************************************************************/ + +/* number of bytes to store second_part part of the TIMESTAMP(N) */ +uint Type_handler_timestamp::m_sec_part_bytes[MAX_DATETIME_PRECISION + 1]= + { 0, 1, 1, 2, 2, 3, 3 }; + +/* number of bytes to store DATETIME(N) */ +uint Type_handler_datetime::m_hires_bytes[MAX_DATETIME_PRECISION + 1]= + { 5, 6, 6, 7, 7, 7, 8 }; + +/* number of bytes to store TIME(N) */ +uint Type_handler_time::m_hires_bytes[MAX_DATETIME_PRECISION + 1]= + { 3, 4, 4, 5, 5, 5, 6 }; + /***************************************************************************/ const Name Type_handler_row::m_name_row(C_STRING_WITH_LEN("row")); @@ -1539,6 +1553,293 @@ bool Type_handler_bit:: return def->fix_attributes_bit(); } +/*************************************************************************/ + +bool Type_handler:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->create_length_to_internal_length_simple(); + return false; +} + +bool Type_handler_null:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->create_length_to_internal_length_null(); + return false; +} + +bool Type_handler_newdecimal:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->create_length_to_internal_length_newdecimal(); + return false; +} + +bool Type_handler_bit:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + return def->prepare_stage1_bit(thd, mem_root, file, table_flags); +} + +bool Type_handler_typelib:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + return def->prepare_stage1_typelib(thd, mem_root, file, table_flags); +} + + +bool Type_handler_string_result:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + return def->prepare_stage1_string(thd, mem_root, file, table_flags); +} + + +#ifdef HAVE_SPATIAL +bool Type_handler_geometry:: + Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->create_length_to_internal_length_string(); + return def->prepare_blob_field(thd); +} +#endif + + +/*************************************************************************/ + +bool Type_handler:: + Column_definition_prepare_stage2_legacy(Column_definition *def, + enum_field_types type) const +{ + def->pack_flag= f_settype((uint) type); + return false; +} + +bool Type_handler:: + Column_definition_prepare_stage2_legacy_num(Column_definition *def, + enum_field_types type) const +{ + def->pack_flag= def->pack_flag_numeric(def->decimals) | + f_settype((uint) type); + return false; +} + +bool Type_handler:: + Column_definition_prepare_stage2_legacy_real(Column_definition *def, + enum_field_types type) const +{ + uint dec= def->decimals; + /* + User specified FLOAT() or DOUBLE() without precision. Change to + FLOATING_POINT_DECIMALS to keep things compatible with earlier MariaDB + versions. + */ + if (dec >= FLOATING_POINT_DECIMALS) + dec= FLOATING_POINT_DECIMALS; + def->pack_flag= def->pack_flag_numeric(dec) | f_settype((uint) type); + return false; +} + +bool Type_handler_newdecimal:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->pack_flag= def->pack_flag_numeric(def->decimals); + return false; +} + +bool Type_handler_blob_common:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_BLOB); +} + +#ifdef HAVE_SPATIAL +bool Type_handler_geometry:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + if (!(table_flags & HA_CAN_GEOMETRY)) + { + my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY"); + return true; + } + return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_GEOM); +} +#endif + +bool Type_handler_varchar:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + return def->prepare_stage2_varchar(table_flags); +} + +bool Type_handler_string:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + def->pack_flag= (def->charset->state & MY_CS_BINSORT) ? FIELDFLAG_BINARY : 0; + return false; +} + +bool Type_handler_enum:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + uint dummy; + return def->prepare_stage2_typelib("ENUM", FIELDFLAG_INTERVAL, &dummy); +} + +bool Type_handler_set:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + uint dup_count; + if (def->prepare_stage2_typelib("SET", FIELDFLAG_BITFIELD, &dup_count)) + return true; + /* Check that count of unique members is not more then 64 */ + if (def->interval->count - dup_count > sizeof(longlong)*8) + { + my_error(ER_TOO_BIG_SET, MYF(0), def->field_name.str); + return true; + } + return false; +} + +bool Type_handler_bit:: + Column_definition_prepare_stage2(Column_definition *def, + handler *file, + ulonglong table_flags) const +{ + /* + We have sql_field->pack_flag already set here, see + mysql_prepare_create_table(). + */ + return false; +} + +/*************************************************************************/ + +uint32 Type_handler_time::calc_pack_length(uint32 length) const +{ + return length > MIN_TIME_WIDTH ? + hires_bytes(length - 1 - MIN_TIME_WIDTH) : 3; +} + +uint32 Type_handler_time2::calc_pack_length(uint32 length) const +{ + return length > MIN_TIME_WIDTH ? + my_time_binary_length(length - MIN_TIME_WIDTH - 1) : 3; +} + +uint32 Type_handler_timestamp::calc_pack_length(uint32 length) const +{ + return length > MAX_DATETIME_WIDTH ? + 4 + sec_part_bytes(length - 1 - MAX_DATETIME_WIDTH) : 4; +} + +uint32 Type_handler_timestamp2::calc_pack_length(uint32 length) const +{ + return length > MAX_DATETIME_WIDTH ? + my_timestamp_binary_length(length - MAX_DATETIME_WIDTH - 1) : 4; +} + +uint32 Type_handler_datetime::calc_pack_length(uint32 length) const +{ + return length > MAX_DATETIME_WIDTH ? + hires_bytes(length - 1 - MAX_DATETIME_WIDTH) : 8; +} + +uint32 Type_handler_datetime2::calc_pack_length(uint32 length) const +{ + return length > MAX_DATETIME_WIDTH ? + my_datetime_binary_length(length - MAX_DATETIME_WIDTH - 1) : 5; +} + +uint32 Type_handler_tiny_blob::calc_pack_length(uint32 length) const +{ + return 1 + portable_sizeof_char_ptr; +} + +uint32 Type_handler_blob::calc_pack_length(uint32 length) const +{ + return 2 + portable_sizeof_char_ptr; +} + +uint32 Type_handler_medium_blob::calc_pack_length(uint32 length) const +{ + return 3 + portable_sizeof_char_ptr; +} + +uint32 Type_handler_long_blob::calc_pack_length(uint32 length) const +{ + return 4 + portable_sizeof_char_ptr; +} + +#ifdef HAVE_SPATIAL +uint32 Type_handler_geometry::calc_pack_length(uint32 length) const +{ + return 4 + portable_sizeof_char_ptr; +} +#endif + +uint32 Type_handler_newdecimal::calc_pack_length(uint32 length) const +{ + abort(); // This shouldn't happen + return 0; +} + +uint32 Type_handler_set::calc_pack_length(uint32 length) const +{ + abort(); // This shouldn't happen + return 0; +} + +uint32 Type_handler_enum::calc_pack_length(uint32 length) const +{ + abort(); // This shouldn't happen + return 0; +} + + /*************************************************************************/ Field *Type_handler::make_and_init_table_field(const LEX_CSTRING *name, const Record_addr &addr, diff --git a/sql/sql_type.h b/sql/sql_type.h index 7acab7078e1..28bb2a2edc9 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -67,6 +67,7 @@ class Sort_param; class Arg_comparator; struct st_value; class Protocol; +class handler; struct TABLE; struct SORT_FIELD_ATTR; @@ -549,6 +550,15 @@ protected: bool Item_send_time(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_date(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_datetime(Item *item, Protocol *protocol, st_value *buf) const; + bool Column_definition_prepare_stage2_legacy(Column_definition *c, + enum_field_types type) + const; + bool Column_definition_prepare_stage2_legacy_num(Column_definition *c, + enum_field_types type) + const; + bool Column_definition_prepare_stage2_legacy_real(Column_definition *c, + enum_field_types type) + const; public: static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length); @@ -692,6 +702,14 @@ public: uint metadata, const Field *target) const= 0; virtual bool Column_definition_fix_attributes(Column_definition *c) const= 0; + virtual bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; + virtual bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const= 0; virtual Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -708,6 +726,7 @@ public: SORT_FIELD_ATTR *attr) const= 0; virtual uint32 max_display_length(const Item *item) const= 0; + virtual uint32 calc_pack_length(uint32 length) const= 0; virtual bool Item_save_in_value(Item *item, st_value *value) const= 0; virtual bool Item_param_set_from_value(THD *thd, Item_param *param, @@ -935,6 +954,22 @@ public: DBUG_ASSERT(0); return true; } + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const + { + DBUG_ASSERT(0); + return true; + } + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { + DBUG_ASSERT(0); + return true; + } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -959,6 +994,11 @@ public: DBUG_ASSERT(0); return 0; } + uint32 calc_pack_length(uint32 length) const + { + DBUG_ASSERT(0); + return 0; + } uint Item_decimal_precision(const Item *item) const { DBUG_ASSERT(0); @@ -1470,6 +1510,11 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; uint32 max_display_length(const Item *item) const; uint Item_time_precision(Item *item) const { @@ -1578,6 +1623,7 @@ public: const Name name() const { return m_name_tiny; } enum_field_types field_type() const { return MYSQL_TYPE_TINY; } uint32 max_display_length(const Item *item) const { return 4; } + uint32 calc_pack_length(uint32 length) const { return 1; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_tiny(item, protocol, buf); @@ -1585,6 +1631,10 @@ public: Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TINY); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1604,9 +1654,14 @@ public: return Item_send_short(item, protocol, buf); } uint32 max_display_length(const Item *item) const { return 6; } + uint32 calc_pack_length(uint32 length) const { return 2; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_SHORT); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1625,6 +1680,7 @@ public: { return MY_INT32_NUM_DECIMAL_DIGITS; } + uint32 calc_pack_length(uint32 length) const { return 4; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_long(item, protocol, buf); @@ -1632,6 +1688,10 @@ public: Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_LONG); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1647,6 +1707,7 @@ public: const Name name() const { return m_name_longlong; } enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } uint32 max_display_length(const Item *item) const { return 20; } + uint32 calc_pack_length(uint32 length) const { return 8; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_longlong(item, protocol, buf); @@ -1654,6 +1715,12 @@ public: Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { + return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_LONGLONG); + } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1673,9 +1740,14 @@ public: return Item_send_long(item, protocol, buf); } uint32 max_display_length(const Item *item) const { return 8; } + uint32 calc_pack_length(uint32 length) const { return 3; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_INT24); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1691,6 +1763,7 @@ public: const Name name() const { return m_name_year; } enum_field_types field_type() const { return MYSQL_TYPE_YEAR; } uint32 max_display_length(const Item *item) const; + uint32 calc_pack_length(uint32 length) const { return 1; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_short(item, protocol, buf); @@ -1698,6 +1771,10 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_YEAR); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1713,6 +1790,7 @@ public: const Name name() const { return m_name_bit; } enum_field_types field_type() const { return MYSQL_TYPE_BIT; } uint32 max_display_length(const Item *item) const; + uint32 calc_pack_length(uint32 length) const { return length / 8; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_str(item, protocol, buf); @@ -1724,6 +1802,14 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1740,6 +1826,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_FLOAT; } bool type_can_have_auto_increment_attribute() const { return true; } uint32 max_display_length(const Item *item) const { return 25; } + uint32 calc_pack_length(uint32 length) const { return sizeof(float); } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_float(item, protocol, buf); @@ -1748,6 +1835,10 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_real(c, MYSQL_TYPE_FLOAT); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1764,6 +1855,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } bool type_can_have_auto_increment_attribute() const { return true; } uint32 max_display_length(const Item *item) const { return 53; } + uint32 calc_pack_length(uint32 length) const { return sizeof(double); } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const { return Item_send_double(item, protocol, buf); @@ -1771,6 +1863,10 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_real(c, MYSQL_TYPE_DOUBLE); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1821,10 +1917,18 @@ public: class Type_handler_time: public Type_handler_time_common { + /* number of bytes to store TIME(N) */ + static uint m_hires_bytes[MAX_DATETIME_PRECISION+1]; public: + static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; } virtual ~Type_handler_time() {} + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_TIME); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1837,8 +1941,13 @@ class Type_handler_time2: public Type_handler_time_common public: virtual ~Type_handler_time2() {} enum_field_types real_field_type() const { return MYSQL_TYPE_TIME2; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_TIME2); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1889,8 +1998,13 @@ class Type_handler_date: public Type_handler_date_common { public: virtual ~Type_handler_date() {} + uint32 calc_pack_length(uint32 length) const { return 4; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATE); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1903,8 +2017,13 @@ class Type_handler_newdate: public Type_handler_date_common public: virtual ~Type_handler_newdate() {} enum_field_types real_field_type() const { return MYSQL_TYPE_NEWDATE; } + uint32 calc_pack_length(uint32 length) const { return 3; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_NEWDATE); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1949,10 +2068,18 @@ public: class Type_handler_datetime: public Type_handler_datetime_common { + /* number of bytes to store DATETIME(N) */ + static uint m_hires_bytes[MAX_DATETIME_PRECISION + 1]; public: + static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; } virtual ~Type_handler_datetime() {} + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATETIME); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -1965,8 +2092,13 @@ class Type_handler_datetime2: public Type_handler_datetime_common public: virtual ~Type_handler_datetime2() {} enum_field_types real_field_type() const { return MYSQL_TYPE_DATETIME2; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATETIME2); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2015,10 +2147,18 @@ public: class Type_handler_timestamp: public Type_handler_timestamp_common { + /* number of bytes to store second_part part of the TIMESTAMP(N) */ + static uint m_sec_part_bytes[MAX_DATETIME_PRECISION + 1]; public: + static uint sec_part_bytes(uint dec) { return m_sec_part_bytes[dec]; } virtual ~Type_handler_timestamp() {} + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TIMESTAMP); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2031,8 +2171,15 @@ class Type_handler_timestamp2: public Type_handler_timestamp_common public: virtual ~Type_handler_timestamp2() {} enum_field_types real_field_type() const { return MYSQL_TYPE_TIMESTAMP2; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { + return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TIMESTAMP2); + } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2047,11 +2194,16 @@ public: virtual ~Type_handler_olddecimal() {} const Name name() const { return m_name_decimal; } enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; } + uint32 calc_pack_length(uint32 length) const { return length; } const Type_handler *type_handler_for_tmp_table(const Item *item) const; const Type_handler *type_handler_for_union(const Item *item) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_DECIMAL); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2066,9 +2218,18 @@ public: virtual ~Type_handler_newdecimal() {} const Name name() const { return m_name_decimal; } enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2087,11 +2248,21 @@ public: const Type_handler *type_handler_for_tmp_table(const Item *item) const; const Type_handler *type_handler_for_union(const Item *) const; uint32 max_display_length(const Item *item) const { return 0; } + uint32 calc_pack_length(uint32 length) const { return 0; } bool Item_save_in_value(Item *item, st_value *value) const; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_NULL); } Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2117,6 +2288,7 @@ public: const Name name() const { return m_name_char; } enum_field_types field_type() const { return MYSQL_TYPE_STRING; } bool is_param_long_data_type() const { return true; } + uint32 calc_pack_length(uint32 length) const { return length; } const Type_handler *type_handler_for_tmp_table(const Item *item) const { return varstring_type_handler(item); @@ -2124,6 +2296,9 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2145,6 +2320,10 @@ public: return varstring_type_handler(item); } bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const + { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_STRING); } const Type_handler *type_handler_for_union(const Item *item) const { return varstring_type_handler(item); @@ -2159,6 +2338,10 @@ public: virtual ~Type_handler_varchar() {} const Name name() const { return m_name_varchar; } enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } + uint32 calc_pack_length(uint32 length) const + { + return (length + (length < 256 ? 1: 2)); + } const Type_handler *type_handler_for_tmp_table(const Item *item) const { return varstring_type_handler(item); @@ -2171,6 +2354,9 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2197,6 +2383,9 @@ public: } bool is_param_long_data_type() const { return true; } bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, Type_handler_hybrid_field_type *, @@ -2212,6 +2401,7 @@ public: virtual ~Type_handler_tiny_blob() {} const Name name() const { return m_name_tinyblob; } enum_field_types field_type() const { return MYSQL_TYPE_TINY_BLOB; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -2228,6 +2418,7 @@ public: virtual ~Type_handler_medium_blob() {} const Name name() const { return m_name_mediumblob; } enum_field_types field_type() const { return MYSQL_TYPE_MEDIUM_BLOB; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -2244,6 +2435,7 @@ public: virtual ~Type_handler_long_blob() {} const Name name() const { return m_name_longblob; } enum_field_types field_type() const { return MYSQL_TYPE_LONG_BLOB; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -2260,6 +2452,7 @@ public: virtual ~Type_handler_blob() {} const Name name() const { return m_name_blob; } enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -2278,6 +2471,7 @@ public: const Name name() const { return m_name_geometry; } enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; } bool is_param_long_data_type() const { return true; } + uint32 calc_pack_length(uint32 length) const; const Type_handler *type_handler_for_comparison() const; bool type_can_have_key_part() const { @@ -2295,6 +2489,14 @@ public: Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2343,6 +2545,11 @@ public: Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const; + bool Column_definition_prepare_stage1(THD *thd, + MEM_ROOT *mem_root, + Column_definition *c, + handler *file, + ulonglong table_flags) const; }; @@ -2353,9 +2560,13 @@ public: virtual ~Type_handler_enum() {} const Name name() const { return m_name_enum; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, @@ -2370,9 +2581,13 @@ public: virtual ~Type_handler_set() {} const Name name() const { return m_name_set; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; } + uint32 calc_pack_length(uint32 length) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool Column_definition_fix_attributes(Column_definition *c) const; + bool Column_definition_prepare_stage2(Column_definition *c, + handler *file, + ulonglong table_flags) const; Field *make_table_field(const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr,