diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 54da823c43947..a05c6a78cdbf4 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -3210,3 +3210,48 @@ DROP TABLE t1,t2; # # End of 10.1 tests # +# +# Start of 10.3 tests +# +# +# MDEV-12515 Wrong value when storing DATE_ADD() and ADDTIME() to a numeric field +# +SET sql_mode=''; +CREATE TABLE t1 AS SELECT +DATE_ADD('2001-01-01',INTERVAL 1 DAY) AS c1, +ADDTIME('10:20:30',1) AS c2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varchar(19) DEFAULT NULL, + `c2` varchar(26) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +2001-01-02 10:20:31 +DROP TABLE t1; +CREATE TABLE t2 (c INT); +INSERT INTO t2 SELECT DATE_ADD('2001-01-01',INTERVAL 1 DAY); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +INSERT INTO t2 VALUES ('2001-01-02'); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +SELECT * FROM t2; +c +2001 +2001 +DROP TABLE t2; +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES (ADDTIME('10:20:30',1)); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +INSERT INTO t2 VALUES ('10:20:31'); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +SELECT * FROM t2; +a +10 +10 +DROP TABLE t2; +SET sql_mode=DEFAULT; diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index e713233180603..6a7b7e7b8bfb8 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -3902,5 +3902,36 @@ SELECT 1 MOD COALESCE(a) FROM t1; ERROR HY000: Illegal parameter data types bigint and geometry for operation '%' DROP TABLE t1; # +# MDEV-12514 Split Item_temporal_func::fix_length_and_dec() +# +SELECT DATE_ADD(POINT(1,1), INTERVAL 10 DAY); +ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval' +SELECT DATE_SUB(POINT(1,1), INTERVAL 10 DAY); +ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval' +SELECT POINT(1,1) + INTERVAL 10 DAY; +ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval' +SELECT POINT(1,1) - INTERVAL 10 DAY; +ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval' +SELECT INTERVAL 10 DAY + POINT(1,1); +ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval' +SELECT INTERVAL 10 DAY + POINT(1,1); +ERROR HY000: Illegal parameter data types geometry and interval for operation 'date_add_interval' +SELECT ADDTIME(POINT(1,1), '10:10:10'); +ERROR HY000: Illegal parameter data types geometry and varchar for operation 'add_time' +SELECT ADDTIME('10:10:10', POINT(1,1)); +ERROR HY000: Illegal parameter data types varchar and geometry for operation 'add_time' +SELECT ADDTIME(POINT(1,1), TIME'10:10:10'); +ERROR HY000: Illegal parameter data types geometry and time for operation 'add_time' +SELECT ADDTIME(TIME'10:10:10', POINT(1,1)); +ERROR HY000: Illegal parameter data types time and geometry for operation 'add_time' +SELECT ADDTIME(POINT(1,1), TIMESTAMP'2001-01-01 10:10:10'); +ERROR HY000: Illegal parameter data types geometry and datetime for operation 'add_time' +SELECT ADDTIME(TIMESTAMP'2001-01-01 10:10:10', POINT(1,1)); +ERROR HY000: Illegal parameter data types datetime and geometry for operation 'add_time' +SELECT STR_TO_DATE(POINT(1,1),'%M %d,%Y'); +ERROR HY000: Illegal parameter data types geometry and varchar for operation 'str_to_date' +SELECT STR_TO_DATE('2001-01-01', POINT(1,1)); +ERROR HY000: Illegal parameter data types varchar and geometry for operation 'str_to_date' +# # End of 10.3 tests # diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 6e0169d97caf5..e8d1d4e79e3e0 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -1817,3 +1817,35 @@ DROP TABLE t1,t2; --echo # --echo # End of 10.1 tests --echo # + + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-12515 Wrong value when storing DATE_ADD() and ADDTIME() to a numeric field +--echo # + +SET sql_mode=''; + +CREATE TABLE t1 AS SELECT + DATE_ADD('2001-01-01',INTERVAL 1 DAY) AS c1, + ADDTIME('10:20:30',1) AS c2; +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t2 (c INT); +INSERT INTO t2 SELECT DATE_ADD('2001-01-01',INTERVAL 1 DAY); +INSERT INTO t2 VALUES ('2001-01-02'); +SELECT * FROM t2; +DROP TABLE t2; + +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES (ADDTIME('10:20:30',1)); +INSERT INTO t2 VALUES ('10:20:31'); +SELECT * FROM t2; +DROP TABLE t2; + +SET sql_mode=DEFAULT; diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index a19de83f0466b..1b355b70bc628 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -2090,6 +2090,40 @@ SELECT 1 MOD COALESCE(a) FROM t1; DROP TABLE t1; +--echo # +--echo # MDEV-12514 Split Item_temporal_func::fix_length_and_dec() +--echo # + +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT DATE_ADD(POINT(1,1), INTERVAL 10 DAY); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT DATE_SUB(POINT(1,1), INTERVAL 10 DAY); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT POINT(1,1) + INTERVAL 10 DAY; +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT POINT(1,1) - INTERVAL 10 DAY; +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT INTERVAL 10 DAY + POINT(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT INTERVAL 10 DAY + POINT(1,1); + +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ADDTIME(POINT(1,1), '10:10:10'); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ADDTIME('10:10:10', POINT(1,1)); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ADDTIME(POINT(1,1), TIME'10:10:10'); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ADDTIME(TIME'10:10:10', POINT(1,1)); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ADDTIME(POINT(1,1), TIMESTAMP'2001-01-01 10:10:10'); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT ADDTIME(TIMESTAMP'2001-01-01 10:10:10', POINT(1,1)); + +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT STR_TO_DATE(POINT(1,1),'%M %d,%Y'); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT STR_TO_DATE('2001-01-01', POINT(1,1)); --echo # --echo # End of 10.3 tests diff --git a/sql/item_func.h b/sql/item_func.h index 7f9321f017d21..a367a0d74c42f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -75,18 +75,10 @@ class Item_func :public Item_func_or_sum { return count_string_length(item, nitems); } - void set_attributes_temporal(uint int_part_length, uint dec) - { - collation.set_numeric(); - unsigned_flag= 0; - decimals= MY_MIN(dec, TIME_SECOND_PART_DIGITS); - uint length= decimals + int_part_length + (dec ? 1 : 0); - fix_char_length(length); - } void aggregate_attributes_temporal(uint int_part_length, Item **item, uint nitems) { - set_attributes_temporal(int_part_length, count_max_decimals(item, nitems)); + fix_attributes_temporal(int_part_length, count_max_decimals(item, nitems)); } table_map not_null_tables_cache; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 174f8ffb9fa29..a4a1f900fce45 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1458,34 +1458,6 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval) } -void Item_temporal_func::fix_length_and_dec() -{ - uint char_length= mysql_temporal_int_part_length(field_type()); - /* - We set maybe_null to 1 as default as any bad argument with date or - time can get us to return NULL. - */ - maybe_null= (arg_count > 0); - if (decimals) - { - if (decimals == NOT_FIXED_DEC) - char_length+= TIME_SECOND_PART_DIGITS + 1; - else - { - set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); - char_length+= decimals + 1; - } - } - sql_mode= current_thd->variables.sql_mode & - (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE); - collation.set(field_type() == MYSQL_TYPE_STRING ? - default_charset() : &my_charset_numeric, - field_type() == MYSQL_TYPE_STRING ? - DERIVATION_COERCIBLE : DERIVATION_NUMERIC, - MY_REPERTOIRE_ASCII); - fix_char_length(char_length); -} - String *Item_temporal_func::val_str(String *str) { DBUG_ASSERT(fixed == 1); @@ -2009,8 +1981,8 @@ void Item_func_from_unixtime::fix_length_and_dec() THD *thd= current_thd; thd->time_zone_used= 1; tz= thd->variables.time_zone; - decimals= args[0]->decimals; - Item_temporal_func::fix_length_and_dec(); + fix_attributes_datetime_not_fixed_dec(args[0]->decimals); + maybe_null= true; } @@ -2039,8 +2011,8 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime, void Item_func_convert_tz::fix_length_and_dec() { - decimals= args[0]->temporal_precision(MYSQL_TYPE_DATETIME); - Item_temporal_func::fix_length_and_dec(); + fix_attributes_datetime(args[0]->temporal_precision(MYSQL_TYPE_DATETIME)); + maybe_null= true; } @@ -2093,6 +2065,13 @@ void Item_date_add_interval::fix_length_and_dec() { enum_field_types arg0_field_type; + if (!args[0]->type_handler()->is_traditional_type()) + { + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), + args[0]->type_handler()->name().ptr(), + "interval", func_name()); + return; + } /* The field type for the result of an Item_datefunc is defined as follows: @@ -2108,7 +2087,6 @@ void Item_date_add_interval::fix_length_and_dec() (This is because you can't know if the string contains a DATE, MYSQL_TIME or DATETIME argument) */ - set_handler_by_field_type(MYSQL_TYPE_STRING); arg0_field_type= args[0]->field_type(); uint interval_dec= 0; if (int_type == INTERVAL_MICROSECOND || @@ -2121,30 +2099,47 @@ void Item_date_add_interval::fix_length_and_dec() if (arg0_field_type == MYSQL_TYPE_DATETIME || arg0_field_type == MYSQL_TYPE_TIMESTAMP) { - decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME), interval_dec); - set_handler_by_field_type(MYSQL_TYPE_DATETIME); + uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME), + interval_dec); + set_handler(&type_handler_datetime); + fix_attributes_datetime(dec); } else if (arg0_field_type == MYSQL_TYPE_DATE) { if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH) - set_handler_by_field_type(arg0_field_type); + { + set_handler(&type_handler_newdate); + fix_attributes_date(); + } else { - decimals= interval_dec; - set_handler_by_field_type(MYSQL_TYPE_DATETIME); + set_handler(&type_handler_datetime2); + fix_attributes_datetime(interval_dec); } } else if (arg0_field_type == MYSQL_TYPE_TIME) { - decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME), interval_dec); + uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME), interval_dec); if (int_type >= INTERVAL_DAY && int_type != INTERVAL_YEAR_MONTH) - set_handler_by_field_type(arg0_field_type); + { + set_handler(&type_handler_time2); + fix_attributes_time(dec); + } else - set_handler_by_field_type(MYSQL_TYPE_DATETIME); + { + set_handler(&type_handler_datetime2); + fix_attributes_datetime(dec); + } } else - decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME), interval_dec); - Item_temporal_func::fix_length_and_dec(); + { + uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME), + interval_dec); + set_handler(&type_handler_string); + collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); + fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec); + } + maybe_null= true; } @@ -2649,8 +2644,15 @@ bool Item_func_makedate::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) void Item_func_add_time::fix_length_and_dec() { enum_field_types arg0_field_type; - decimals= MY_MAX(args[0]->decimals, args[1]->decimals); + if (!args[0]->type_handler()->is_traditional_type() || + !args[1]->type_handler()->is_traditional_type()) + { + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), + args[0]->type_handler()->name().ptr(), + args[1]->type_handler()->name().ptr(), func_name()); + return; + } /* The field type for the result of an Item_func_add_time function is defined as follows: @@ -2661,24 +2663,32 @@ void Item_func_add_time::fix_length_and_dec() - Otherwise the result is MYSQL_TYPE_STRING */ - set_handler_by_field_type(MYSQL_TYPE_STRING); arg0_field_type= args[0]->field_type(); if (arg0_field_type == MYSQL_TYPE_DATE || arg0_field_type == MYSQL_TYPE_DATETIME || arg0_field_type == MYSQL_TYPE_TIMESTAMP || is_date) { - set_handler_by_field_type(MYSQL_TYPE_DATETIME); - decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME), + uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME), args[1]->temporal_precision(MYSQL_TYPE_TIME)); + set_handler(&type_handler_datetime2); + fix_attributes_datetime(dec); } else if (arg0_field_type == MYSQL_TYPE_TIME) { - set_handler_by_field_type(MYSQL_TYPE_TIME); - decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME), + uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME), args[1]->temporal_precision(MYSQL_TYPE_TIME)); + set_handler(&type_handler_time2); + fix_attributes_time(dec); + } + else + { + uint dec= MY_MAX(args[0]->decimals, args[1]->decimals); + set_handler(&type_handler_string); + collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); + fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec); } - Item_temporal_func::fix_length_and_dec(); + maybe_null= true; } /** @@ -3169,6 +3179,14 @@ get_date_time_result_type(const char *format, uint length) void Item_func_str_to_date::fix_length_and_dec() { + if (!args[0]->type_handler()->is_traditional_type() || + !args[1]->type_handler()->is_traditional_type()) + { + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), + args[0]->type_handler()->name().ptr(), + args[1]->type_handler()->name().ptr(), func_name()); + return; + } if (agg_arg_charsets(collation, args, 2, MY_COLL_ALLOW_CONV, 1)) return; if (collation.collation->mbminlen > 1) @@ -3180,8 +3198,10 @@ void Item_func_str_to_date::fix_length_and_dec() #endif } - set_handler_by_field_type(MYSQL_TYPE_DATETIME); - decimals= TIME_SECOND_PART_DIGITS; + maybe_null= true; + set_handler(&type_handler_datetime2); + fix_attributes_datetime(TIME_SECOND_PART_DIGITS); + if ((const_item= args[1]->const_item())) { char format_buff[64]; @@ -3195,25 +3215,29 @@ void Item_func_str_to_date::fix_length_and_dec() get_date_time_result_type(format->ptr(), format->length()); switch (cached_format_type) { case DATE_ONLY: - set_handler_by_field_type(MYSQL_TYPE_DATE); + set_handler(&type_handler_newdate); + fix_attributes_date(); break; case TIME_MICROSECOND: - decimals= 6; - /* fall through */ + set_handler(&type_handler_time2); + fix_attributes_time(TIME_SECOND_PART_DIGITS); + break; case TIME_ONLY: - set_handler_by_field_type(MYSQL_TYPE_TIME); + set_handler(&type_handler_time2); + fix_attributes_time(0); break; case DATE_TIME_MICROSECOND: - decimals= 6; - /* fall through */ + set_handler(&type_handler_datetime2); + fix_attributes_datetime(TIME_SECOND_PART_DIGITS); + break; case DATE_TIME: - set_handler_by_field_type(MYSQL_TYPE_DATETIME); + set_handler(&type_handler_datetime2); + fix_attributes_datetime(0); break; } } } cached_timestamp_type= mysql_type_to_time_type(field_type()); - Item_temporal_func::fix_length_and_dec(); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index f66c57e2fb53a..40b8c169c802a 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -31,16 +31,6 @@ enum date_time_format_types }; -static inline uint -mysql_temporal_int_part_length(enum enum_field_types mysql_type) -{ - static uint max_time_type_width[5]= - { MAX_DATETIME_WIDTH, MAX_DATETIME_WIDTH, MAX_DATE_WIDTH, - MAX_DATETIME_WIDTH, MIN_TIME_WIDTH }; - return max_time_type_width[mysql_type_to_time_type(mysql_type)+2]; -} - - bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval); class Item_func_period_add :public Item_int_func @@ -531,7 +521,6 @@ class Item_func_time_to_sec :public Item_func_seconds_hybrid class Item_temporal_func: public Item_func { - sql_mode_t sql_mode; public: Item_temporal_func(THD *thd): Item_func(thd) {} Item_temporal_func(THD *thd, Item *a): Item_func(thd, a) {} @@ -549,7 +538,6 @@ class Item_temporal_func: public Item_func { return tmp_table_field_from_field_type(table, false, false); } int save_in_field(Field *field, bool no_conversions) { return save_date_in_field(field, no_conversions); } - void fix_length_and_dec(); }; @@ -557,22 +545,20 @@ class Item_temporal_func: public Item_func Abstract class for functions returning TIME, DATE, DATETIME or string values, whose data type depends on parameters and is set at fix_fields time. */ -class Item_temporal_hybrid_func: public Item_temporal_func, - public Type_handler_hybrid_field_type +class Item_temporal_hybrid_func: public Item_hybrid_func { protected: String ascii_buf; // Conversion buffer public: Item_temporal_hybrid_func(THD *thd, Item *a, Item *b): - Item_temporal_func(thd, a, b) {} - const Type_handler *type_handler() const - { return Type_handler_hybrid_field_type::type_handler(); } - enum_field_types field_type() const - { return Type_handler_hybrid_field_type::field_type(); } - enum Item_result result_type () const - { return Type_handler_hybrid_field_type::result_type(); } - enum Item_result cmp_type () const - { return Type_handler_hybrid_field_type::cmp_type(); } + Item_hybrid_func(thd, a, b) {} + + longlong val_int() { return val_int_from_date(); } + double val_real() { return val_real_from_date(); } + bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date)= 0; + my_decimal *val_decimal(my_decimal *decimal_value) + { return val_decimal_from_date(decimal_value); } + /** Fix the returned timestamp to match field_type(), which is important for val_str(). @@ -599,6 +585,11 @@ class Item_datefunc :public Item_temporal_func Item_datefunc(THD *thd, Item *a): Item_temporal_func(thd, a) { } Item_datefunc(THD *thd, Item *a, Item *b): Item_temporal_func(thd, a, b) { } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } + void fix_length_and_dec() + { + fix_attributes_date(); + maybe_null= (arg_count > 0); + } }; @@ -635,6 +626,7 @@ class Item_func_curtime :public Item_timefunc Item_func_curtime(THD *thd, uint dec): Item_timefunc(thd), last_query_id(0) { decimals= dec; } bool fix_fields(THD *, Item **); + void fix_length_and_dec() { fix_attributes_time(decimals); } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); /* Abstract method that defines which time zone is used for conversion. @@ -722,6 +714,7 @@ class Item_func_now :public Item_datetimefunc Item_func_now(THD *thd, uint dec): Item_datetimefunc(thd), last_query_id(0) { decimals= dec; } bool fix_fields(THD *, Item **); + void fix_length_and_dec() { fix_attributes_datetime(decimals); } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0; bool check_vcol_func_processor(void *arg) @@ -886,8 +879,8 @@ class Item_func_sec_to_time :public Item_timefunc bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); void fix_length_and_dec() { - decimals= MY_MIN(args[0]->decimals, TIME_SECOND_PART_DIGITS); - Item_timefunc::fix_length_and_dec(); + fix_attributes_time(args[0]->decimals); + maybe_null= true; } const char *func_name() const { return "sec_to_time"; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) @@ -1066,11 +1059,12 @@ class Item_temporal_typecast: public Item_temporal_func Item_temporal_typecast(THD *thd, Item *a): Item_temporal_func(thd, a) {} virtual const char *cast_type() const = 0; void print(String *str, enum_query_type query_type); - void fix_length_and_dec_generic() + void fix_length_and_dec_generic(uint int_part_len) { if (decimals == NOT_FIXED_DEC) decimals= args[0]->temporal_precision(field_type()); - Item_temporal_func::fix_length_and_dec(); + fix_attributes_temporal(int_part_len, decimals); + maybe_null= true; } }; @@ -1163,9 +1157,10 @@ class Item_func_timediff :public Item_timefunc const char *func_name() const { return "timediff"; } void fix_length_and_dec() { - decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME), + uint dec= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME), args[1]->temporal_precision(MYSQL_TYPE_TIME)); - Item_timefunc::fix_length_and_dec(); + fix_attributes_time(dec); + maybe_null= true; } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); Item *get_copy(THD *thd, MEM_ROOT *mem_root) @@ -1180,8 +1175,8 @@ class Item_func_maketime :public Item_timefunc {} void fix_length_and_dec() { - decimals= MY_MIN(args[2]->decimals, TIME_SECOND_PART_DIGITS); - Item_timefunc::fix_length_and_dec(); + fix_attributes_time(args[2]->decimals); + maybe_null= true; } const char *func_name() const { return "maketime"; } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 337111f6e535e..cf5e4e4640048 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -26,14 +26,10 @@ static Type_handler_long type_handler_long; static Type_handler_int24 type_handler_int24; static Type_handler_year type_handler_year; static Type_handler_time type_handler_time; -static Type_handler_time2 type_handler_time2; static Type_handler_date type_handler_date; -static Type_handler_newdate type_handler_newdate; -static Type_handler_datetime2 type_handler_datetime2; static Type_handler_timestamp type_handler_timestamp; static Type_handler_timestamp2 type_handler_timestamp2; static Type_handler_olddecimal type_handler_olddecimal; -static Type_handler_string type_handler_string; static Type_handler_tiny_blob type_handler_tiny_blob; static Type_handler_medium_blob type_handler_medium_blob; static Type_handler_long_blob type_handler_long_blob; @@ -42,6 +38,7 @@ static Type_handler_blob type_handler_blob; Type_handler_null type_handler_null; Type_handler_row type_handler_row; +Type_handler_string type_handler_string; Type_handler_varchar type_handler_varchar; Type_handler_longlong type_handler_longlong; Type_handler_float type_handler_float; @@ -52,6 +49,10 @@ Type_handler_bit type_handler_bit; Type_handler_enum type_handler_enum; Type_handler_set type_handler_set; +Type_handler_time2 type_handler_time2; +Type_handler_newdate type_handler_newdate; +Type_handler_datetime2 type_handler_datetime2; + #ifdef HAVE_SPATIAL Type_handler_geometry type_handler_geometry; #endif @@ -1346,7 +1347,7 @@ bool Type_handler_date_common:: Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const { - func->set_attributes_temporal(MAX_DATE_WIDTH, 0); + func->fix_attributes_date(); return false; } @@ -2688,7 +2689,7 @@ bool Type_handler_numeric:: bool Type_handler:: Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const { - item->fix_length_and_dec_generic(); + item->fix_length_and_dec_generic(MIN_TIME_WIDTH); return false; } @@ -2696,7 +2697,7 @@ bool Type_handler:: bool Type_handler:: Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const { - item->fix_length_and_dec_generic(); + item->fix_length_and_dec_generic(MAX_DATE_WIDTH); return false; } @@ -2705,7 +2706,7 @@ bool Type_handler:: Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item) const { - item->fix_length_and_dec_generic(); + item->fix_length_and_dec_generic(MAX_DATETIME_WIDTH); return false; } diff --git a/sql/sql_type.h b/sql/sql_type.h index 891c785fef20e..bd5290ad1fe54 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -23,6 +23,8 @@ #include "mysqld.h" #include "sql_array.h" +#include "sql_const.h" +#include "my_time.h" class Field; class Item; @@ -261,6 +263,54 @@ class Type_std_attributes max_length= char_to_byte_length_safe(max_char_length_arg, collation.collation->mbmaxlen); } + void fix_char_length_temporal_not_fixed_dec(uint int_part_length, uint dec) + { + uint char_length= int_part_length; + if ((decimals= dec)) + { + if (decimals == NOT_FIXED_DEC) + char_length+= TIME_SECOND_PART_DIGITS + 1; + else + { + set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); + char_length+= decimals + 1; + } + } + fix_char_length(char_length); + } + void fix_attributes_temporal_not_fixed_dec(uint int_part_length, uint dec) + { + collation.set_numeric(); + unsigned_flag= 0; + fix_char_length_temporal_not_fixed_dec(int_part_length, dec); + } + void fix_attributes_time_not_fixed_dec(uint dec) + { + fix_attributes_temporal_not_fixed_dec(MIN_TIME_WIDTH, dec); + } + void fix_attributes_datetime_not_fixed_dec(uint dec) + { + fix_attributes_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec); + } + void fix_attributes_temporal(uint int_part_length, uint dec) + { + collation.set_numeric(); + unsigned_flag= 0; + decimals= MY_MIN(dec, TIME_SECOND_PART_DIGITS); + max_length= decimals + int_part_length + (dec ? 1 : 0); + } + void fix_attributes_date() + { + fix_attributes_temporal(MAX_DATE_WIDTH, 0); + } + void fix_attributes_time(uint dec) + { + fix_attributes_temporal(MIN_TIME_WIDTH, dec); + } + void fix_attributes_datetime(uint dec) + { + fix_attributes_temporal(MAX_DATETIME_WIDTH, dec); + } }; @@ -1585,6 +1635,7 @@ class Type_handler_hybrid_field_type extern Type_handler_row type_handler_row; extern Type_handler_null type_handler_null; +extern Type_handler_string type_handler_string; extern Type_handler_varchar type_handler_varchar; extern Type_handler_longlong type_handler_longlong; extern Type_handler_float type_handler_float; @@ -1596,6 +1647,10 @@ extern Type_handler_bit type_handler_bit; extern Type_handler_enum type_handler_enum; extern Type_handler_set type_handler_set; +extern Type_handler_time2 type_handler_time2; +extern Type_handler_newdate type_handler_newdate; +extern Type_handler_datetime2 type_handler_datetime2; + class Type_aggregator {