diff options
author | Alexander Barkov <bar@mariadb.com> | 2018-08-01 16:14:41 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2018-08-01 16:15:16 +0400 |
commit | 54fc47960dcfca618bd7cc7e5785e3dde09e7121 (patch) | |
tree | 4b2af6c2937c735e5863a59afce615e442c67a96 | |
parent | af46c25760bdc698cf219258f6c42316ed01b924 (diff) | |
download | mariadb-git-54fc47960dcfca618bd7cc7e5785e3dde09e7121.tar.gz |
MDEV-16874 Implement class Item_handled_func
-rw-r--r-- | mysql-test/main/func_time.result | 1 | ||||
-rw-r--r-- | sql/item_func.h | 62 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 278 | ||||
-rw-r--r-- | sql/item_timefunc.h | 459 | ||||
-rw-r--r-- | sql/sql_type.h | 5 |
5 files changed, 547 insertions, 258 deletions
diff --git a/mysql-test/main/func_time.result b/mysql-test/main/func_time.result index f55e0e47eea..58a0897b9d0 100644 --- a/mysql-test/main/func_time.result +++ b/mysql-test/main/func_time.result @@ -1716,7 +1716,6 @@ min(timestampadd(month, 1>'', from_days('%Z'))) NULL Warnings: Warning 1292 Truncated incorrect INTEGER value: '%Z' -Warning 1292 Truncated incorrect DOUBLE value: '' Warning 1292 Incorrect datetime value: '0000-00-00' SET timestamp=UNIX_TIMESTAMP('2001-01-01 00:00:00'); create table t1(a time); diff --git a/sql/item_func.h b/sql/item_func.h index cfc87fb067d..131d038668d 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -40,8 +40,6 @@ class Item_func :public Item_func_or_sum, { void sync_with_sum_func_and_with_field(List<Item> &list); protected: - String *val_str_from_val_str_ascii(String *str, String *str2); - virtual bool check_arguments() const { return check_argument_types_scalar(0, arg_count); @@ -188,6 +186,8 @@ public: update_null_value(); return null_value; } + String *val_str_from_val_str_ascii(String *str, String *str2); + void signal_divide_by_null(); friend class udf_handler; Field *create_field_for_create_select(TABLE *table) @@ -450,6 +450,64 @@ public: }; +class Item_handled_func: public Item_func +{ +public: + class Handler + { + public: + virtual ~Handler() { } + virtual String *val_str(Item_handled_func *, String *) const= 0; + virtual String *val_str_ascii(Item_handled_func *, String *) const= 0; + virtual double val_real(Item_handled_func *) const= 0; + virtual longlong val_int(Item_handled_func *) const= 0; + virtual my_decimal *val_decimal(Item_handled_func *, my_decimal *) const= 0; + virtual bool get_date(Item_handled_func *, MYSQL_TIME *, ulonglong fuzzydate) const= 0; + virtual const Type_handler *return_type_handler() const= 0; + virtual bool fix_length_and_dec(Item_handled_func *) const= 0; + }; +protected: + const Handler *m_func_handler; +public: + Item_handled_func(THD *thd, Item *a) + :Item_func(thd, a), m_func_handler(NULL) { } + Item_handled_func(THD *thd, Item *a, Item *b) + :Item_func(thd, a, b), m_func_handler(NULL) { } + void set_func_handler(const Handler *handler) + { + m_func_handler= handler; + } + const Type_handler *type_handler() const + { + return m_func_handler->return_type_handler(); + } + String *val_str(String *to) + { + return m_func_handler->val_str(this, to); + } + String *val_str_ascii(String *to) + { + return m_func_handler->val_str_ascii(this, to); + } + double val_real() + { + return m_func_handler->val_real(this); + } + longlong val_int() + { + return m_func_handler->val_int(this); + } + my_decimal *val_decimal(my_decimal *to) + { + return m_func_handler->val_decimal(this, to); + } + bool get_date(MYSQL_TIME *to, ulonglong fuzzydate) + { + return m_func_handler->get_date(this, to, fuzzydate); + } +}; + + /** Functions that at fix_fields() time determine the returned field type, trying to preserve the exact data type of the arguments. diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 789297f0c7f..d167fdb0ea5 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -58,6 +58,29 @@ /** Day number for Dec 31st, 9999. */ #define MAX_DAY_NUMBER 3652424L + +Func_handler_date_add_interval_datetime_arg0_time + func_handler_date_add_interval_datetime_arg0_time; + +Func_handler_date_add_interval_datetime func_handler_date_add_interval_datetime; +Func_handler_date_add_interval_date func_handler_date_add_interval_date; +Func_handler_date_add_interval_time func_handler_date_add_interval_time; +Func_handler_date_add_interval_string func_handler_date_add_interval_string; + +Func_handler_add_time_datetime func_handler_add_time_datetime_add(1); +Func_handler_add_time_datetime func_handler_add_time_datetime_sub(-1); +Func_handler_add_time_time func_handler_add_time_time_add(1); +Func_handler_add_time_time func_handler_add_time_time_sub(-1); +Func_handler_add_time_string func_handler_add_time_string_add(1); +Func_handler_add_time_string func_handler_add_time_string_sub(-1); + +Func_handler_str_to_date_datetime_sec func_handler_str_to_date_datetime_sec; +Func_handler_str_to_date_datetime_usec func_handler_str_to_date_datetime_usec; +Func_handler_str_to_date_date func_handler_str_to_date_date; +Func_handler_str_to_date_time_sec func_handler_str_to_date_time_sec; +Func_handler_str_to_date_time_usec func_handler_str_to_date_time_usec; + + /* Date formats corresponding to compound %r and %T conversion specifiers @@ -1482,19 +1505,20 @@ String *Item_temporal_func::val_str(String *str) } -String *Item_temporal_hybrid_func::val_str_ascii(String *str) +String *Func_handler_temporal_hybrid::val_str_ascii(Item_handled_func *item, + String *str) const { - DBUG_ASSERT(fixed == 1); + DBUG_ASSERT(item->is_fixed()); MYSQL_TIME ltime; - if (get_date(<ime, 0) || - (null_value= my_TIME_to_str(<ime, str, decimals))) + if (get_date(item, <ime, 0) || + (item->null_value= my_TIME_to_str(<ime, str, item->decimals))) return (String *) 0; /* Check that the returned timestamp type matches to the function type */ - DBUG_ASSERT(field_type() == MYSQL_TYPE_STRING || + DBUG_ASSERT(item->field_type() == MYSQL_TYPE_STRING || ltime.time_type == MYSQL_TIMESTAMP_NONE || - ltime.time_type == mysql_timestamp_type()); + ltime.time_type == return_type_handler()->mysql_timestamp_type()); return str; } @@ -2088,115 +2112,44 @@ bool Item_date_add_interval::fix_length_and_dec() MYSQL_TIME or DATETIME argument) */ arg0_field_type= args[0]->field_type(); - uint interval_dec= 0; - if (int_type == INTERVAL_MICROSECOND || - (int_type >= INTERVAL_DAY_MICROSECOND && - int_type <= INTERVAL_SECOND_MICROSECOND)) - interval_dec= TIME_SECOND_PART_DIGITS; - else if (int_type == INTERVAL_SECOND && args[1]->decimals > 0) - interval_dec= MY_MIN(args[1]->decimals, TIME_SECOND_PART_DIGITS); if (arg0_field_type == MYSQL_TYPE_DATETIME || arg0_field_type == MYSQL_TYPE_TIMESTAMP) { - uint dec= MY_MAX(args[0]->datetime_precision(), interval_dec); - set_handler(&type_handler_datetime); - fix_attributes_datetime(dec); + set_func_handler(&func_handler_date_add_interval_datetime); } else if (arg0_field_type == MYSQL_TYPE_DATE) { if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH) - { - set_handler(&type_handler_newdate); - fix_attributes_date(); - } + set_func_handler(&func_handler_date_add_interval_date); else - { - set_handler(&type_handler_datetime2); - fix_attributes_datetime(interval_dec); - } + set_func_handler(&func_handler_date_add_interval_datetime); } else if (arg0_field_type == MYSQL_TYPE_TIME) { - uint dec= MY_MAX(args[0]->time_precision(), interval_dec); if (int_type >= INTERVAL_DAY && int_type != INTERVAL_YEAR_MONTH) - { - set_handler(&type_handler_time2); - fix_attributes_time(dec); - } + set_func_handler(&func_handler_date_add_interval_time); else - { - set_handler(&type_handler_datetime2); - fix_attributes_datetime(dec); - } + set_func_handler(&func_handler_date_add_interval_datetime_arg0_time); } else { - uint dec= MY_MAX(args[0]->datetime_precision(), 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); + set_func_handler(&func_handler_date_add_interval_string); } maybe_null= true; - return FALSE; + return m_func_handler->fix_length_and_dec(this); } -bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) +bool Func_handler_date_add_interval_datetime_arg0_time:: + get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const { - INTERVAL interval; - - if (field_type() == MYSQL_TYPE_TIME) - { - Time t(args[0]); - if (!t.is_valid_time()) - return (null_value= true); - t.copy_to_mysql_time(ltime); - } - else if (field_type() == MYSQL_TYPE_DATETIME) - { - THD *thd= current_thd; - if (args[0]->field_type() == MYSQL_TYPE_TIME) - { - // time_expr + INTERVAL {YEAR|QUARTER|MONTH|WEEK|YEAR_MONTH} - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_DATETIME_FUNCTION_OVERFLOW, - ER_THD(thd, ER_DATETIME_FUNCTION_OVERFLOW), - "time"); - return (null_value= true); - } - Datetime dt(thd, args[0], 0); - if (!dt.is_valid_datetime()) - return (null_value= true); - dt.copy_to_mysql_time(ltime); - } - else if (field_type() == MYSQL_TYPE_DATE) - { - Date d(current_thd, args[0], 0); - if (!d.is_valid_date()) - return (null_value= true); - d.copy_to_mysql_time(ltime); - } - else - { - if (args[0]->get_date(ltime, 0)) - return (null_value=true); - } - - if (get_interval_value(args[1], int_type, &interval)) - return (null_value= true); - - if (ltime->time_type != MYSQL_TIMESTAMP_TIME && - check_date_with_warn(ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE, - MYSQL_TIMESTAMP_ERROR)) - return (null_value=1); - - if (date_sub_interval) - interval.neg = !interval.neg; - - if (date_add_interval(ltime, int_type, interval)) - return (null_value=1); - return (null_value= 0); + THD *thd= current_thd; + // time_expr + INTERVAL {YEAR|QUARTER|MONTH|WEEK|YEAR_MONTH} + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_DATETIME_FUNCTION_OVERFLOW, + ER_THD(thd, ER_DATETIME_FUNCTION_OVERFLOW), "time"); + return (item->null_value= true); } @@ -2700,69 +2653,22 @@ bool Item_func_add_time::fix_length_and_dec() arg0_field_type == MYSQL_TYPE_DATETIME || arg0_field_type == MYSQL_TYPE_TIMESTAMP) { - uint dec= MY_MAX(args[0]->datetime_precision(), args[1]->time_precision()); - set_handler(&type_handler_datetime2); - fix_attributes_datetime(dec); + set_func_handler(sign > 0 ? &func_handler_add_time_datetime_add : + &func_handler_add_time_datetime_sub); } else if (arg0_field_type == MYSQL_TYPE_TIME) { - uint dec= MY_MAX(args[0]->time_precision(), args[1]->time_precision()); - set_handler(&type_handler_time2); - fix_attributes_time(dec); + set_func_handler(sign > 0 ? &func_handler_add_time_time_add : + &func_handler_add_time_time_sub); } 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); - } - maybe_null= true; - return FALSE; -} - -/** - ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a - time/datetime value - - t: time_or_datetime_expression - a: time_expression - - Result: Time value or datetime value -*/ - -bool Item_func_add_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME l_time2; - - if (Item_func_add_time::field_type() == MYSQL_TYPE_DATETIME) - { - // TIMESTAMP function OR the first argument is DATE/DATETIME/TIMESTAMP - Datetime dt(current_thd, args[0], 0); - return (null_value= (!dt.is_valid_datetime() || - args[1]->get_time(&l_time2) || - Sec6_add(dt.get_mysql_time(), &l_time2, sign). - to_datetime(ltime))); + set_func_handler(sign > 0 ? &func_handler_add_time_string_add : + &func_handler_add_time_string_sub); } - if (Item_func_add_time::field_type() == MYSQL_TYPE_TIME) - { - // ADDTIME() and the first argument is TIME - Time t(args[0]); - return (null_value= (!t.is_valid_time() || - args[1]->get_time(&l_time2) || - Sec6_add(t.get_mysql_time(), &l_time2, sign). - to_time(ltime, decimals))); - } - - // Detect a proper timestamp type based on the argument values - MYSQL_TIME l_time1; - if (args[0]->get_time(&l_time1) || args[1]->get_time(&l_time2)) - return (null_value= true); - Sec6_add add(&l_time1, &l_time2, sign); - return (null_value= (l_time1.time_type == MYSQL_TIMESTAMP_TIME ? - add.to_time(ltime, decimals) : add.to_datetime(ltime))); + maybe_null= true; + return m_func_handler->fix_length_and_dec(this); } @@ -3102,15 +3008,10 @@ void Item_func_get_format::print(String *str, enum_query_type query_type) specifiers supported by extract_date_time() function. @return - One of date_time_format_types values: - - DATE_TIME_MICROSECOND - - DATE_TIME - - DATE_ONLY - - TIME_MICROSECOND - - TIME_ONLY + A function handler corresponding the given format */ -static date_time_format_types +static const Item_handled_func::Handler * get_date_time_result_type(const char *format, uint length) { const char *time_part_frms= "HISThiklrs"; @@ -3137,21 +3038,21 @@ get_date_time_result_type(const char *format, uint length) frac_second_used implies time_part_used, and thus we already have all types of date-time components and can end our search. */ - return DATE_TIME_MICROSECOND; + return &func_handler_str_to_date_datetime_usec; } } } /* We don't have all three types of date-time components */ if (frac_second_used) - return TIME_MICROSECOND; + return &func_handler_str_to_date_time_usec; if (time_part_used) { if (date_part_used) - return DATE_TIME; - return TIME_ONLY; + return &func_handler_str_to_date_datetime_sec; + return &func_handler_str_to_date_time_sec; } - return DATE_ONLY; + return &func_handler_str_to_date_date; } @@ -3171,56 +3072,27 @@ bool Item_func_str_to_date::fix_length_and_dec() internal_charset= &my_charset_utf8mb4_general_ci; maybe_null= true; - set_handler(&type_handler_datetime2); - fix_attributes_datetime(TIME_SECOND_PART_DIGITS); + set_func_handler(&func_handler_str_to_date_datetime_usec); if ((const_item= args[1]->const_item())) { - char format_buff[64]; - String format_str(format_buff, sizeof(format_buff), &my_charset_bin); + StringBuffer<64> format_str; String *format= args[1]->val_str(&format_str, &format_converter, internal_charset); - decimals= 0; if (!args[1]->null_value) - { - date_time_format_types cached_format_type= - get_date_time_result_type(format->ptr(), format->length()); - switch (cached_format_type) { - case DATE_ONLY: - set_handler(&type_handler_newdate); - fix_attributes_date(); - break; - case TIME_MICROSECOND: - set_handler(&type_handler_time2); - fix_attributes_time(TIME_SECOND_PART_DIGITS); - break; - case TIME_ONLY: - set_handler(&type_handler_time2); - fix_attributes_time(0); - break; - case DATE_TIME_MICROSECOND: - set_handler(&type_handler_datetime2); - fix_attributes_datetime(TIME_SECOND_PART_DIGITS); - break; - case DATE_TIME: - set_handler(&type_handler_datetime2); - fix_attributes_datetime(0); - break; - } - } + set_func_handler(get_date_time_result_type(format->ptr(), format->length())); } - cached_timestamp_type= mysql_timestamp_type(); - return FALSE; + return m_func_handler->fix_length_and_dec(this); } -bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) +bool Item_func_str_to_date::get_date_common(MYSQL_TIME *ltime, + ulonglong fuzzy_date, + timestamp_type tstype) { DATE_TIME_FORMAT date_time_format; - char val_buff[64], format_buff[64]; - String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val; - String format_str(format_buff, sizeof(format_buff), &my_charset_bin), - *format; + StringBuffer<64> val_string, format_str; + String *val, *format; val= args[0]->val_str(&val_string, &subject_converter, internal_charset); format= args[1]->val_str(&format_str, &format_converter, internal_charset); @@ -3230,19 +3102,9 @@ bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) date_time_format.format.str= (char*) format->ptr(); date_time_format.format.length= format->length(); if (extract_date_time(&date_time_format, val->ptr(), val->length(), - ltime, cached_timestamp_type, 0, "datetime", + ltime, tstype, 0, "datetime", fuzzy_date | sql_mode_for_dates(current_thd))) return (null_value=1); - if (cached_timestamp_type == MYSQL_TIMESTAMP_TIME && ltime->day) - { - /* - Day part for time type can be nonzero value and so - we should add hours from day part to hour part to - keep valid time value. - */ - ltime->hour+= ltime->day*24; - ltime->day= 0; - } return (null_value= 0); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a7bdbc8a76b..45d23c13474 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -25,11 +25,6 @@ class MY_LOCALE; -enum date_time_format_types -{ - TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND -}; - bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval); @@ -602,38 +597,6 @@ public: }; -/** - 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_hybrid_func -{ -protected: - String ascii_buf; // Conversion buffer -public: - Item_temporal_hybrid_func(THD *thd, Item *a, Item *b): - 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); } - - /** - Return string value in ASCII character set. - */ - String *val_str_ascii(String *str); - /** - Return string value in @@character_set_connection. - */ - String *val_str(String *str) - { - return val_str_from_val_str_ascii(str, &ascii_buf); - } -}; - - class Item_datefunc :public Item_temporal_func { public: @@ -985,18 +948,17 @@ public: }; -class Item_date_add_interval :public Item_temporal_hybrid_func +class Item_date_add_interval :public Item_handled_func { public: const interval_type int_type; // keep it public const bool date_sub_interval; // keep it public Item_date_add_interval(THD *thd, Item *a, Item *b, interval_type type_arg, bool neg_arg): - Item_temporal_hybrid_func(thd, a, b),int_type(type_arg), + Item_handled_func(thd, a, b), int_type(type_arg), date_sub_interval(neg_arg) {} const char *func_name() const { return "date_add_interval"; } bool fix_length_and_dec(); - bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); bool eq(const Item *item, bool binary_cmp) const; void print(String *str, enum_query_type query_type); enum precedence precedence() const { return ADDINTERVAL_PRECEDENCE; } @@ -1264,20 +1226,30 @@ public: }; -class Item_func_add_time :public Item_temporal_hybrid_func +/** + ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a + time/datetime value + + t: time_or_datetime_expression + a: time_expression + + Result: Time value or datetime value +*/ + +class Item_func_add_time :public Item_handled_func { int sign; public: Item_func_add_time(THD *thd, Item *a, Item *b, bool neg_arg) - :Item_temporal_hybrid_func(thd, a, b), sign(neg_arg ? -1 : 1) + :Item_handled_func(thd, a, b), sign(neg_arg ? -1 : 1) { } bool fix_length_and_dec(); - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); const char *func_name() const { return sign > 0 ? "addtime" : "subtime"; } Item *get_copy(THD *thd) { return get_item_copy<Item_func_add_time>(thd, this); } }; + class Item_func_timediff :public Item_timefunc { bool check_arguments() const @@ -1394,19 +1366,18 @@ public: }; -class Item_func_str_to_date :public Item_temporal_hybrid_func +class Item_func_str_to_date :public Item_handled_func { - timestamp_type cached_timestamp_type; bool const_item; String subject_converter; String format_converter; CHARSET_INFO *internal_charset; public: Item_func_str_to_date(THD *thd, Item *a, Item *b): - Item_temporal_hybrid_func(thd, a, b), const_item(false), + Item_handled_func(thd, a, b), const_item(false), internal_charset(NULL) {} - bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); + bool get_date_common(MYSQL_TIME *ltime, ulonglong fuzzy_date, timestamp_type); const char *func_name() const { return "str_to_date"; } bool fix_length_and_dec(); Item *get_copy(THD *thd) @@ -1426,4 +1397,398 @@ public: { return get_item_copy<Item_func_last_day>(thd, this); } }; + +/*****************************************************************************/ + +/** + 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 Func_handler_temporal_hybrid: public Item_handled_func::Handler +{ +public: + double val_real(Item_handled_func *item) const + { + return item->val_real_from_date(); + } + longlong val_int(Item_handled_func *item) const + { + return item->val_int_from_date(); + } + my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const + { + return item->val_decimal_from_date(to); + } + String *val_str(Item_handled_func *item, String *to) const + { + StringBuffer<MAX_FIELD_WIDTH> ascii_buf; + return item->val_str_from_val_str_ascii(to, &ascii_buf); + } + String *val_str_ascii(Item_handled_func *, String *to) const; +}; + + +class Func_handler_date_add_interval: public Func_handler_temporal_hybrid +{ +protected: + static uint interval_dec(const Item *item, interval_type int_type) + { + if (int_type == INTERVAL_MICROSECOND || + (int_type >= INTERVAL_DAY_MICROSECOND && + int_type <= INTERVAL_SECOND_MICROSECOND)) + return TIME_SECOND_PART_DIGITS; + if (int_type == INTERVAL_SECOND && item->decimals > 0) + return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); + return 0; + } + interval_type int_type(const Item_handled_func *item) const + { + return static_cast<const Item_date_add_interval*>(item)->int_type; + } + bool sub(const Item_handled_func *item) const + { + return static_cast<const Item_date_add_interval*>(item)->date_sub_interval; + } + bool add(Item *item, interval_type type, bool sub, MYSQL_TIME *to) const + { + INTERVAL interval; + if (get_interval_value(item, type, &interval)) + return true; + if (sub) + interval.neg = !interval.neg; + return date_add_interval(to, type, interval); + } +}; + + +class Func_handler_date_add_interval_datetime: + public Func_handler_date_add_interval +{ +public: + const Type_handler *return_type_handler() const + { + return &type_handler_datetime2; + } + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->datetime_precision(), + interval_dec(item->arguments()[1], int_type(item))); + item->fix_attributes_datetime(dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + Datetime dt(current_thd, item->arguments()[0], 0); + if (!dt.is_valid_datetime() || + dt.check_date_with_warn(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)) + return (item->null_value= true); + dt.copy_to_mysql_time(to); + return (item->null_value= add(item->arguments()[1], + int_type(item), sub(item), to)); + } +}; + + +class Func_handler_date_add_interval_datetime_arg0_time: + public Func_handler_date_add_interval_datetime +{ +public: + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const; +}; + + +class Func_handler_date_add_interval_date: public Func_handler_date_add_interval +{ +public: + const Type_handler *return_type_handler() const + { + return &type_handler_newdate; + } + bool fix_length_and_dec(Item_handled_func *item) const + { + item->fix_attributes_date(); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + Date d(current_thd, item->arguments()[0], 0); + if (!d.is_valid_date() || + d.check_date_with_warn(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)) + return (item->null_value= true); + d.copy_to_mysql_time(to); + return (item->null_value= add(item->arguments()[1], + int_type(item), sub(item), to)); + } +}; + + +class Func_handler_date_add_interval_time: public Func_handler_date_add_interval +{ +public: + const Type_handler *return_type_handler() const + { + return &type_handler_time2; + } + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->time_precision(), + interval_dec(item->arguments()[1], int_type(item))); + item->fix_attributes_time(dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + Time t(item->arguments()[0]); + if (!t.is_valid_time()) + return (item->null_value= true); + t.copy_to_mysql_time(to); + return (item->null_value= add(item->arguments()[1], + int_type(item), sub(item), to)); + } +}; + + +class Func_handler_date_add_interval_string: + public Func_handler_date_add_interval +{ +public: + const Type_handler *return_type_handler() const + { + return &type_handler_string; + } + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->datetime_precision(), + interval_dec(item->arguments()[1], int_type(item))); + item->collation.set(item->default_charset(), + DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); + item->fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + if (item->arguments()[0]->get_date(to, 0) || + (to->time_type != MYSQL_TIMESTAMP_TIME && + check_date_with_warn(to, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE, + MYSQL_TIMESTAMP_ERROR))) + return (item->null_value= true); + return (item->null_value= add(item->arguments()[1], + int_type(item), sub(item), to)); + } +}; + + + +class Func_handler_add_time: public Func_handler_temporal_hybrid +{ +protected: + int m_sign; + Func_handler_add_time(int sign) :m_sign(sign) { } +}; + + +class Func_handler_add_time_datetime: public Func_handler_add_time +{ +public: + Func_handler_add_time_datetime(int sign) + :Func_handler_add_time(sign) + { } + const Type_handler *return_type_handler() const + { + return &type_handler_datetime2; + } + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->datetime_precision(), + item->arguments()[1]->time_precision()); + item->fix_attributes_datetime(dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + DBUG_ASSERT(item->is_fixed()); + MYSQL_TIME l_time2; + Datetime dt(current_thd, item->arguments()[0], 0); + return (item->null_value= (!dt.is_valid_datetime() || + item->arguments()[1]->get_time(&l_time2) || + Sec6_add(dt.get_mysql_time(), &l_time2, m_sign). + to_datetime(to))); + } +}; + + +class Func_handler_add_time_time: public Func_handler_add_time +{ +public: + Func_handler_add_time_time(int sign) + :Func_handler_add_time(sign) + { } + const Type_handler *return_type_handler() const + { + return &type_handler_time2; + } + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->time_precision(), + item->arguments()[1]->time_precision()); + item->fix_attributes_time(dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + DBUG_ASSERT(item->is_fixed()); + MYSQL_TIME l_time2; + Time t(item->arguments()[0]); + return (item->null_value= (!t.is_valid_time() || + item->arguments()[1]->get_time(&l_time2) || + Sec6_add(t.get_mysql_time(), &l_time2, m_sign). + to_time(to, item->decimals))); + } +}; + + +class Func_handler_add_time_string: public Func_handler_add_time +{ +public: + Func_handler_add_time_string(int sign) + :Func_handler_add_time(sign) + { } + const Type_handler *return_type_handler() const + { + return &type_handler_string; + } + bool fix_length_and_dec(Item_handled_func *item) const + { + uint dec= MY_MAX(item->arguments()[0]->decimals, + item->arguments()[1]->decimals); + item->collation.set(item->default_charset(), + DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); + item->fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec); + return false; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + DBUG_ASSERT(item->is_fixed()); + // Detect a proper timestamp type based on the argument values + MYSQL_TIME l_time1, l_time2; + if (item->arguments()[0]->get_time(&l_time1) || + item->arguments()[1]->get_time(&l_time2)) + return (item->null_value= true); + Sec6_add add(&l_time1, &l_time2, m_sign); + return (item->null_value= (l_time1.time_type == MYSQL_TIMESTAMP_TIME ? + add.to_time(to, item->decimals) : + add.to_datetime(to))); + + } +}; + + +class Func_handler_str_to_date_datetime: public Func_handler_temporal_hybrid +{ +public: + const Type_handler *return_type_handler() const + { + return &type_handler_datetime2; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + return static_cast<Item_func_str_to_date*>(item)-> + get_date_common(to, fuzzy, MYSQL_TIMESTAMP_DATETIME); + } +}; + + +class Func_handler_str_to_date_datetime_sec: + public Func_handler_str_to_date_datetime +{ +public: + bool fix_length_and_dec(Item_handled_func *item) const + { + item->fix_attributes_datetime(0); + return false; + } +}; + + +class Func_handler_str_to_date_datetime_usec: + public Func_handler_str_to_date_datetime +{ +public: + bool fix_length_and_dec(Item_handled_func *item) const + { + item->fix_attributes_datetime(TIME_SECOND_PART_DIGITS); + return false; + } +}; + + +class Func_handler_str_to_date_date: public Func_handler_temporal_hybrid +{ +public: + const Type_handler *return_type_handler() const + { + return &type_handler_newdate; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + return static_cast<Item_func_str_to_date*>(item)-> + get_date_common(to, fuzzy, MYSQL_TIMESTAMP_DATE); + } + bool fix_length_and_dec(Item_handled_func *item) const + { + item->fix_attributes_date(); + return false; + } +}; + + +class Func_handler_str_to_date_time: public Func_handler_temporal_hybrid +{ +public: + const Type_handler *return_type_handler() const + { + return &type_handler_time2; + } + bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const + { + if (static_cast<Item_func_str_to_date*>(item)-> + get_date_common(to, fuzzy, MYSQL_TIMESTAMP_TIME)) + return true; + if (to->day) + { + /* + Day part for time type can be nonzero value and so + we should add hours from day part to hour part to + keep valid time value. + */ + to->hour+= to->day * 24; + to->day= 0; + } + return false; + } +}; + + +class Func_handler_str_to_date_time_sec: public Func_handler_str_to_date_time +{ +public: + bool fix_length_and_dec(Item_handled_func *item) const + { + item->fix_attributes_time(0); + return false; + } +}; + + +class Func_handler_str_to_date_time_usec: public Func_handler_str_to_date_time +{ +public: + bool fix_length_and_dec(Item_handled_func *item) const + { + item->fix_attributes_time(TIME_SECOND_PART_DIGITS); + return false; + } +}; + + #endif /* ITEM_TIMEFUNC_INCLUDED */ diff --git a/sql/sql_type.h b/sql/sql_type.h index d4e588e244d..e50df06f084 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -367,6 +367,11 @@ protected: { make_from_item(thd, item, flags); } +public: + bool check_date_with_warn(ulonglong flags) + { + return ::check_date_with_warn(this, flags, MYSQL_TIMESTAMP_ERROR); + } }; |