diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 17 | ||||
-rw-r--r-- | sql/field.h | 8 | ||||
-rw-r--r-- | sql/item.cc | 59 | ||||
-rw-r--r-- | sql/item.h | 31 | ||||
-rw-r--r-- | sql/item_func.cc | 35 | ||||
-rw-r--r-- | sql/item_func.h | 37 | ||||
-rw-r--r-- | sql/item_sum.h | 6 | ||||
-rw-r--r-- | sql/item_timefunc.h | 2 | ||||
-rw-r--r-- | sql/my_decimal.h | 2 | ||||
-rw-r--r-- | sql/procedure.h | 2 | ||||
-rw-r--r-- | sql/sql_error.h | 55 | ||||
-rw-r--r-- | sql/sql_time.cc | 83 | ||||
-rw-r--r-- | sql/sql_type.cc | 203 | ||||
-rw-r--r-- | sql/sql_type.h | 306 | ||||
-rw-r--r-- | sql/sql_type_int.h | 12 |
15 files changed, 510 insertions, 348 deletions
diff --git a/sql/field.cc b/sql/field.cc index d7214687e2d..7e27ed1bfc3 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2253,16 +2253,13 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) } -bool Field::get_date(MYSQL_TIME *ltime,date_mode_t fuzzydate) -{ - char buff[40]; - String tmp(buff,sizeof(buff),&my_charset_bin),*res; - if (!(res=val_str(&tmp)) || - str_to_datetime_with_warn(get_thd(), - res->charset(), res->ptr(), res->length(), - ltime, fuzzydate)) - return 1; - return 0; +bool Field::get_date(MYSQL_TIME *to, date_mode_t mode) +{ + StringBuffer<40> tmp; + Temporal::Warn_push warn(get_thd(), NullS, to, mode); + Temporal_hybrid *t= new(to) Temporal_hybrid(get_thd(), &warn, + val_str(&tmp), mode); + return !t->is_valid_temporal(); } /** diff --git a/sql/field.h b/sql/field.h index d5b2a621d48..eb39b6bcec9 100644 --- a/sql/field.h +++ b/sql/field.h @@ -2077,8 +2077,9 @@ public: } bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return my_decimal(ptr, precision, dec). - to_datetime_with_warn(get_thd(), ltime, fuzzydate, field_name.str); + my_decimal nr(ptr, precision, dec); + return decimal_to_datetime_with_warn(get_thd(), &nr, ltime, + fuzzydate, field_name.str); } bool val_bool() { @@ -2612,9 +2613,10 @@ protected: int store_invalid_with_warning(const ErrConv *str, int was_cut, timestamp_type ts_type) { + DBUG_ASSERT(was_cut); reset(); Sql_condition::enum_warning_level level= Sql_condition::WARN_LEVEL_WARN; - if (was_cut == 0) // special case: zero date + if (was_cut & MYSQL_TIME_WARN_ZERO_DATE) { DBUG_ASSERT(ts_type != MYSQL_TIMESTAMP_TIME); set_warnings(level, str, MYSQL_TIME_WARN_OUT_OF_RANGE, ts_type); diff --git a/sql/item.cc b/sql/item.cc index 88bb929fc05..d4cfa790986 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1277,60 +1277,27 @@ Item *Item_param::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) bool Item::get_date_from_int(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { Longlong_hybrid value(val_int(), unsigned_flag); - if (null_value || int_to_datetime_with_warn(thd, value, - ltime, fuzzydate, - field_name_or_null())) - return null_value|= make_zero_date(ltime, fuzzydate); - return null_value= false; + return null_value || int_to_datetime_with_warn(thd, value, + ltime, fuzzydate, + field_name_or_null()); } bool Item::get_date_from_real(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { double value= val_real(); - if (null_value || double_to_datetime_with_warn(thd, value, ltime, fuzzydate, - field_name_or_null())) - return null_value|= make_zero_date(ltime, fuzzydate); - return null_value= false; + return null_value || double_to_datetime_with_warn(thd, value, + ltime, fuzzydate, + field_name_or_null()); } -bool Item::get_date_from_string(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) +bool Item::get_date_from_string(THD *thd, MYSQL_TIME *to, date_mode_t mode) { - char buff[40]; - String tmp(buff,sizeof(buff), &my_charset_bin),*res; - if (!(res=val_str(&tmp)) || - str_to_datetime_with_warn(thd, res->charset(), res->ptr(), res->length(), - ltime, fuzzydate)) - return null_value|= make_zero_date(ltime, fuzzydate); - return null_value= false; -} - - -bool Item::make_zero_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) -{ - /* - if the item was not null and convertion failed, we return a zero date - if allowed, otherwise - null. - */ - bzero((char*) ltime,sizeof(*ltime)); - if (fuzzydate & TIME_TIME_ONLY) - { - /* - In the following scenario: - - The caller expected to get a TIME value - - Item returned a not NULL string or numeric value - - But then conversion from string or number to TIME failed - we need to change the default time_type from MYSQL_TIMESTAMP_DATE - (which was set in bzero) to MYSQL_TIMESTAMP_TIME and therefore - return TIME'00:00:00' rather than DATE'0000-00-00'. - If we don't do this, methods like Item::get_time_with_conversion() - will erroneously subtract CURRENT_DATE from '0000-00-00 00:00:00' - and return TIME'-838:59:59' instead of TIME'00:00:00' as a result. - */ - ltime->time_type= MYSQL_TIMESTAMP_TIME; - } - return !(fuzzydate & TIME_FUZZY_DATES); + StringBuffer<40> tmp; + Temporal::Warn_push warn(thd, field_name_or_null(), to, mode); + Temporal_hybrid *t= new(to) Temporal_hybrid(thd, &warn, val_str(&tmp), mode); + return !t->is_valid_temporal(); } @@ -3735,7 +3702,7 @@ my_decimal *Item_null::val_decimal(my_decimal *decimal_value) bool Item_null::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - make_zero_date(ltime, fuzzydate); + set_zero_time(ltime, MYSQL_TIMESTAMP_NONE); return (null_value= true); } @@ -4261,7 +4228,7 @@ bool Item_param::get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) *res= value.time; return 0; } - return type_handler()->Item_get_date(thd, this, res, fuzzydate); + return type_handler()->Item_get_date_with_warn(thd, this, res, fuzzydate); } diff --git a/sql/item.h b/sql/item.h index d15dbade60f..c2666c35c67 100644 --- a/sql/item.h +++ b/sql/item.h @@ -870,12 +870,6 @@ protected: return rc; } public: - /* - This method is used if the item was not null but convertion to - TIME/DATE/DATETIME failed. We return a zero date if allowed, - otherwise - null. - */ - bool make_zero_date(MYSQL_TIME *ltime, date_mode_t fuzzydate); /* Cache val_str() into the own buffer, e.g. to evaluate constant @@ -1172,6 +1166,12 @@ public: If value is not null null_value flag will be reset to FALSE. */ virtual double val_real()=0; + Double_null to_double_null() + { + // val_real() must be caleed on a separate line. See to_longlong_null() + double nr= val_real(); + return Double_null(nr, null_value); + } /* Return integer representation of item. @@ -1193,6 +1193,10 @@ public: */ return Longlong_null(nr, null_value); } + Longlong_hybrid_null to_longlong_hybrid_null() + { + return Longlong_hybrid_null(to_longlong_null(), unsigned_flag); + } /** Get a value for CAST(x AS SIGNED). Too large positive unsigned integer values are converted @@ -3031,7 +3035,7 @@ public: Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return type_handler()->Item_get_date(thd, this, ltime, fuzzydate); + return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } }; @@ -4516,7 +4520,7 @@ public: String *val_str(String*) { return &str_value; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return type_handler()->Item_get_date(thd, this, ltime, fuzzydate); + return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } }; @@ -6389,10 +6393,9 @@ class Item_cache_year: public Item_cache_int public: Item_cache_year(THD *thd, const Type_handler *handler) :Item_cache_int(thd, handler) { } - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode) { - return null_value= - VYear(this).to_mysql_time_with_warn(thd, ltime, fuzzydate, NULL); + return type_handler_year.Item_get_date_with_warn(thd, this, to, mode); } }; @@ -6549,8 +6552,10 @@ public: longlong val_int(); String* val_str(String *str); my_decimal *val_decimal(my_decimal *); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) - { return VDec(this).to_datetime_with_warn(thd, ltime, fuzzydate, this); } + bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode) + { + return decimal_to_datetime_with_warn(thd, VDec(this).ptr(), to, mode, NULL); + } bool cache_value(); Item *convert_to_basic_const_item(THD *thd); Item *get_copy(THD *thd) diff --git a/sql/item_func.cc b/sql/item_func.cc index 20c0a2564bb..c176a7e43a7 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -831,17 +831,6 @@ Item_func_hybrid_field_type::val_decimal_from_int_op(my_decimal *dec) return dec; } -bool Item_func_hybrid_field_type::get_date_from_int_op(THD *thd, - MYSQL_TIME *ltime, - date_mode_t fuzzydate) -{ - Longlong_hybrid value(int_op(), unsigned_flag); - if (null_value || int_to_datetime_with_warn(thd, value, - ltime, fuzzydate, NULL)) - return make_zero_mysql_time(ltime, fuzzydate); - return (null_value= 0); -} - String *Item_func_hybrid_field_type::val_str_from_real_op(String *str) { @@ -867,17 +856,6 @@ Item_func_hybrid_field_type::val_decimal_from_real_op(my_decimal *dec) return dec; } -bool Item_func_hybrid_field_type::get_date_from_real_op(THD *thd, - MYSQL_TIME *ltime, - date_mode_t fuzzydate) -{ - double value= real_op(); - if (null_value || - double_to_datetime_with_warn(thd, value, ltime, fuzzydate, NULL)) - return make_zero_mysql_time(ltime, fuzzydate); - return (null_value= 0); -} - String *Item_func_hybrid_field_type::val_str_from_date_op(String *str) { @@ -975,19 +953,6 @@ Item_func_hybrid_field_type::val_decimal_from_str_op(my_decimal *decimal_value) return res ? decimal_from_string_with_check(decimal_value, res) : 0; } -bool Item_func_hybrid_field_type::get_date_from_str_op(THD *thd, - MYSQL_TIME *ltime, - date_mode_t fuzzydate) -{ - StringBuffer<40> tmp; - String *res; - if (!(res= str_op_with_null_check(&tmp)) || - str_to_datetime_with_warn(thd, res->charset(), res->ptr(), res->length(), - ltime, fuzzydate)) - return make_zero_mysql_time(ltime, fuzzydate); - return (null_value= 0); -} - void Item_func_signed::print(String *str, enum_query_type query_type) { diff --git a/sql/item_func.h b/sql/item_func.h index 602b13fad7a..660d39f48ea 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -680,11 +680,6 @@ class Item_func_hybrid_field_type: public Item_hybrid_func DBUG_ASSERT((res != NULL) ^ null_value); return res; } - bool make_zero_mysql_time(MYSQL_TIME *ltime, date_mode_t fuzzydate) - { - bzero(ltime, sizeof(*ltime)); - return null_value|= !(fuzzydate & TIME_FUZZY_DATES); - } public: // Value methods that involve no conversion @@ -723,10 +718,6 @@ public: double val_real_from_time_op(); double val_real_from_int_op(); - bool get_date_from_str_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - bool get_date_from_real_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - bool get_date_from_int_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - public: Item_func_hybrid_field_type(THD *thd): Item_hybrid_func(thd) @@ -770,11 +761,11 @@ public: DBUG_ASSERT(null_value == (res == NULL)); return res; } - bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) + bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode) { DBUG_ASSERT(fixed); return Item_func_hybrid_field_type::type_handler()-> - Item_func_hybrid_field_type_get_date(thd, this, res, fuzzydate); + Item_func_hybrid_field_type_get_date_with_warn(thd, this, to, mode); } /** @@ -794,6 +785,10 @@ public: */ return Longlong_null(nr, null_value); } + Longlong_hybrid_null to_longlong_hybrid_null_op() + { + return Longlong_hybrid_null(to_longlong_null_op(), unsigned_flag); + } /** @brief Performs the operation that this functions implements when the @@ -802,6 +797,12 @@ public: @return The result of the operation. */ virtual double real_op()= 0; + Double_null to_double_null_op() + { + // val_real() must be caleed on a separate line. See to_longlong_null() + double nr= real_op(); + return Double_null(nr, null_value); + } /** @brief Performs the operation that this functions implements when the @@ -1180,8 +1181,10 @@ public: double val_real() { return VDec(this).to_double(); } longlong val_int() { return VDec(this).to_longlong(unsigned_flag); } my_decimal *val_decimal(my_decimal*); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) - { return VDec(this).to_datetime_with_warn(thd, ltime, fuzzydate, this); } + bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode) + { + return decimal_to_datetime_with_warn(thd, VDec(this).ptr(), to, mode, NULL); + } const Type_handler *type_handler() const { return &type_handler_newdecimal; } void fix_length_and_dec_generic() {} bool fix_length_and_dec() @@ -2292,7 +2295,7 @@ public: } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return type_handler()->Item_get_date(thd, this, ltime, fuzzydate); + return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } }; @@ -2602,7 +2605,9 @@ public: { return create_table_field_from_handler(table); } bool check_vcol_func_processor(void *arg); bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) - { return type_handler()->Item_get_date(thd, this, ltime, fuzzydate); } + { + return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); + } }; @@ -2832,7 +2837,7 @@ public: { return val_decimal_from_real(dec_buf); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return type_handler()->Item_get_date(thd, this, ltime, fuzzydate); + return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } /* TODO: fix to support views */ const char *func_name() const { return "get_system_var"; } diff --git a/sql/item_sum.h b/sql/item_sum.h index c88a850c241..1a21c257221 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -744,7 +744,7 @@ public: my_decimal *val_decimal(my_decimal *); bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return type_handler()->Item_get_date(thd, this, ltime, fuzzydate); + return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } void reset_field(); }; @@ -1405,7 +1405,7 @@ public: } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return type_handler()->Item_get_date(thd, this, ltime, fuzzydate); + return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } }; @@ -1567,7 +1567,7 @@ public: virtual void print(String *str, enum_query_type query_type); bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return type_handler()->Item_get_date(thd, this, ltime, fuzzydate); + return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } }; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index de5ba8df2fe..d2a4e87a3d1 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -457,7 +457,7 @@ public: } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return type_handler()->Item_get_date(thd, this, ltime, fuzzydate); + return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } const Type_handler *type_handler() const { return &type_handler_long; } bool fix_length_and_dec() diff --git a/sql/my_decimal.h b/sql/my_decimal.h index f0bb69c60c8..b22c686cc90 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -217,8 +217,6 @@ public: { return check_result(mask, decimal_round(this, to, (int) scale, mode)); } - bool to_datetime_with_warn(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate, - const char *field_name); int to_binary(uchar *bin, int prec, int scale, uint mask= E_DEC_FATAL_ERROR) const; #endif diff --git a/sql/procedure.h b/sql/procedure.h index 2169091c0a6..050cc3817c0 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -71,7 +71,7 @@ public: } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return type_handler()->Item_get_date(thd, this, ltime, fuzzydate); + return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } Item* get_copy(THD *thd) { return 0; } }; diff --git a/sql/sql_error.h b/sql/sql_error.h index b783d527cb3..6586c49a125 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -814,11 +814,48 @@ private: extern char *err_conv(char *buff, uint to_length, const char *from, uint from_length, CHARSET_INFO *from_cs); -class ErrConv +class ErrBuff { protected: mutable char err_buffer[MYSQL_ERRMSG_SIZE]; public: + ErrBuff() + { + err_buffer[0]= '\0'; + } + const char *ptr() const { return err_buffer; } + const char *set_longlong(const Longlong_hybrid &nr) const + { + return nr.is_unsigned() ? ullstr(nr.value(), err_buffer) : + llstr(nr.value(), err_buffer); + } + const char *set_double(double nr) const + { + my_gcvt(nr, MY_GCVT_ARG_DOUBLE, sizeof(err_buffer), err_buffer, 0); + return err_buffer; + } + const char *set_decimal(const decimal_t *d) const + { + int len= sizeof(err_buffer); + decimal2string(d, err_buffer, &len, 0, 0, ' '); + return err_buffer; + } + const char *set_str(const char *str, size_t len, CHARSET_INFO *cs) const + { + DBUG_ASSERT(len < UINT_MAX32); + return err_conv(err_buffer, (uint) sizeof(err_buffer), str, (uint) len, cs); + } + const char *set_mysql_time(const MYSQL_TIME *ltime) const + { + my_TIME_to_str(ltime, err_buffer, AUTO_SEC_PART_DIGITS); + return err_buffer; + } +}; + + +class ErrConv: public ErrBuff +{ +public: ErrConv() {} virtual ~ErrConv() {} virtual const char *ptr() const = 0; @@ -838,8 +875,7 @@ public: : ErrConv(), str(s->ptr()), len(s->length()), cs(s->charset()) {} const char *ptr() const { - DBUG_ASSERT(len < UINT_MAX32); - return err_conv(err_buffer, (uint) sizeof(err_buffer), str, (uint) len, cs); + return set_str(str, len, cs); } }; @@ -850,8 +886,7 @@ public: : ErrConv(), Longlong_hybrid(nr) { } const char *ptr() const { - return m_unsigned ? ullstr(m_value, err_buffer) : - llstr(m_value, err_buffer); + return set_longlong(static_cast<Longlong_hybrid>(*this)); } }; @@ -862,8 +897,7 @@ public: ErrConvDouble(double num_arg) : ErrConv(), num(num_arg) {} const char *ptr() const { - my_gcvt(num, MY_GCVT_ARG_DOUBLE, sizeof(err_buffer), err_buffer, 0); - return err_buffer; + return set_double(num); } }; @@ -874,8 +908,7 @@ public: ErrConvTime(const MYSQL_TIME *ltime_arg) : ErrConv(), ltime(ltime_arg) {} const char *ptr() const { - my_TIME_to_str(ltime, err_buffer, AUTO_SEC_PART_DIGITS); - return err_buffer; + return set_mysql_time(ltime); } }; @@ -886,9 +919,7 @@ public: ErrConvDecimal(const decimal_t *d_arg) : ErrConv(), d(d_arg) {} const char *ptr() const { - int len= sizeof(err_buffer); - decimal2string(d, err_buffer, &len, 0, 0, ' '); - return err_buffer; + return set_decimal(d); } }; diff --git a/sql/sql_time.cc b/sql/sql_time.cc index 630d150be77..9562394f11e 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -377,9 +377,11 @@ bool Temporal::str_to_time(MYSQL_TIME_STATUS *status, date_mode_t fuzzydate) { TemporalAsciiBuffer tmp(str, length, cs); - return ::str_to_time(tmp.str, tmp.length, this, + bool rc= ::str_to_time(tmp.str, tmp.length, this, ulonglong(fuzzydate & TIME_MODE_FOR_XXX_TO_DATE), status); + DBUG_ASSERT(status->warnings || !rc); + return rc; } @@ -389,9 +391,11 @@ bool Temporal::str_to_datetime(MYSQL_TIME_STATUS *status, date_mode_t flags) { TemporalAsciiBuffer tmp(str, length, cs); - return ::str_to_datetime(tmp.str, tmp.length, this, + bool rc= ::str_to_datetime(tmp.str, tmp.length, this, ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), status); + DBUG_ASSERT(status->warnings || !rc); + return rc; } @@ -401,7 +405,9 @@ bool Interval_DDhhmmssff::str_to_DDhhmmssff(MYSQL_TIME_STATUS *status, CHARSET_INFO *cs, ulong max_hour) { TemporalAsciiBuffer tmp(str, length, cs); - return ::str_to_DDhhmmssff(tmp.str, tmp.length, this, UINT_MAX32, status); + bool rc= ::str_to_DDhhmmssff(tmp.str, tmp.length, this, UINT_MAX32, status); + DBUG_ASSERT(status->warnings || !rc); + return rc; } @@ -413,45 +419,22 @@ bool Interval_DDhhmmssff::str_to_DDhhmmssff(MYSQL_TIME_STATUS *status, See description of str_to_datetime() for more information. */ -static bool -str_to_datetime_with_warn(THD *thd, CHARSET_INFO *cs, - const char *str, size_t length, MYSQL_TIME *l_time, - date_mode_t flags, MYSQL_TIME_STATUS *status) -{ - Temporal_hybrid *t= new(l_time) Temporal_hybrid(status, str, length, cs, flags); - if (!t->is_valid_temporal() || status->warnings) - { - const ErrConvString err(str, length, &my_charset_bin); - make_truncated_value_warning(thd, - !t->is_valid_temporal() ? - Sql_condition::WARN_LEVEL_WARN : - Sql_condition::time_warn_level(status->warnings), - &err, flags & TIME_TIME_ONLY ? - MYSQL_TIMESTAMP_TIME : l_time->time_type, NullS); - } - DBUG_EXECUTE_IF("str_to_datetime_warn", - push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, - ER_YES, str);); - return !t->is_valid_temporal(); -} - - bool str_to_datetime_with_warn(THD *thd, CHARSET_INFO *cs, - const char *str, size_t length, MYSQL_TIME *l_time, - date_mode_t flags) + const char *str, size_t length, MYSQL_TIME *to, + date_mode_t mode) { - MYSQL_TIME_STATUS status; - return str_to_datetime_with_warn(thd, cs, str, length, l_time, flags, &status); + Temporal::Warn_push warn(thd, NullS, to, mode); + Temporal_hybrid *t= new(to) Temporal_hybrid(thd, &warn, str, length, cs, mode); + return !t->is_valid_temporal(); } bool double_to_datetime_with_warn(THD *thd, double value, MYSQL_TIME *ltime, date_mode_t fuzzydate, const char *field_name) { - const ErrConvDouble str(value); - Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, Sec6(value), fuzzydate, - &str, field_name); + Temporal::Warn_push warn(thd, field_name, ltime, fuzzydate); + Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, value, fuzzydate); return !t->is_valid_temporal(); } @@ -460,9 +443,8 @@ bool decimal_to_datetime_with_warn(THD *thd, const my_decimal *value, MYSQL_TIME *ltime, date_mode_t fuzzydate, const char *field_name) { - const ErrConvDecimal str(value); - Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, Sec6(value), fuzzydate, - &str, field_name); + Temporal::Warn_push warn(thd, field_name, ltime, fuzzydate); + Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, value, fuzzydate); return !t->is_valid_temporal(); } @@ -471,14 +453,12 @@ bool int_to_datetime_with_warn(THD *thd, const Longlong_hybrid &nr, MYSQL_TIME *ltime, date_mode_t fuzzydate, const char *field_name) { - const ErrConvInteger str(nr); /* Note: conversion from an integer to TIME can overflow to '838:59:59.999999', so the conversion result can have fractional digits. */ - Temporal_hybrid *t= new (ltime) - Temporal_hybrid(thd, Sec6(nr), - fuzzydate, &str, field_name); + Temporal::Warn_push warn(thd, field_name, ltime, fuzzydate); + Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, nr, fuzzydate); return !t->is_valid_temporal(); } @@ -909,20 +889,7 @@ void make_truncated_value_warning(THD *thd, timestamp_type time_type, const char *field_name) { - const char *type_str; - - switch (time_type) { - case MYSQL_TIMESTAMP_DATE: - type_str= "date"; - break; - case MYSQL_TIMESTAMP_TIME: - type_str= "time"; - break; - case MYSQL_TIMESTAMP_DATETIME: // FALLTHROUGH - default: - type_str= "datetime"; - break; - } + const char *type_str= Temporal::type_name_by_timestamp_type(time_type); return thd->push_warning_wrong_or_truncated_value(level, time_type <= MYSQL_TIMESTAMP_ERROR, type_str, sval->ptr(), field_name); @@ -1400,11 +1367,3 @@ void unpack_time(longlong packed, MYSQL_TIME *my_time, break; } } - - -bool my_decimal::to_datetime_with_warn(THD *thd, MYSQL_TIME *to, - date_mode_t fuzzydate, - const char *field_name) -{ - return decimal_to_datetime_with_warn(thd, this, to, fuzzydate, field_name); -} diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 23fa678e7cf..a432f37b580 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -160,15 +160,6 @@ date_mode_t Temporal::sql_mode_for_dates(THD *thd) } -bool Dec_ptr::to_datetime_with_warn(THD *thd, MYSQL_TIME *to, - date_mode_t fuzzydate, Item *item) -{ - if (to_datetime_with_warn(thd, to, fuzzydate, item->field_name_or_null())) - return item->null_value|= item->make_zero_date(to, fuzzydate); - return item->null_value= false; -} - - my_decimal *Temporal::to_decimal(my_decimal *to) const { return date2my_decimal(this, to); @@ -182,6 +173,20 @@ my_decimal *Temporal::bad_to_decimal(my_decimal *to) const } +void Temporal::make_from_str(THD *thd, Warn *warn, + const char *str, size_t length, + CHARSET_INFO *cs, date_mode_t fuzzydate) +{ + DBUG_EXECUTE_IF("str_to_datetime_warn", + push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_YES, ErrConvString(str, length,cs).ptr());); + if (str_to_datetime(warn, str, length, cs, fuzzydate)) + make_fuzzy_date(&warn->warnings, fuzzydate); + if (warn->warnings) + warn->set_str(str, length, &my_charset_bin); +} + + Temporal_hybrid::Temporal_hybrid(THD *thd, Item *item, date_mode_t fuzzydate) { if (item->get_date(thd, this, fuzzydate)) @@ -221,31 +226,30 @@ void Sec6::make_truncated_warning(THD *thd, const char *type_str) const } -bool Sec6::convert_to_mysql_time(THD *thd, MYSQL_TIME *ltime, - date_mode_t fuzzydate, const ErrConv *str, - const char *field_name) const +bool Sec6::convert_to_mysql_time(THD *thd, int *warn, MYSQL_TIME *ltime, + date_mode_t fuzzydate) const { - int warn; bool is_time= bool(fuzzydate & TIME_TIME_ONLY); - const char *typestr= is_time ? "time" : "datetime"; - bool rc= is_time ? to_time(ltime, &warn) : - to_datetime(ltime, fuzzydate, &warn); + bool rc= is_time ? to_time(ltime, warn) : to_datetime(ltime, fuzzydate, warn); + DBUG_ASSERT(*warn || !rc); if (truncated()) - { - // The value was already truncated at the constructor call time - thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN, - !is_time, typestr, - str->ptr(), field_name); - } - else if (rc || MYSQL_TIME_WARN_HAVE_WARNINGS(warn)) + *warn|= MYSQL_TIME_WARN_TRUNCATED; + return rc; +} + + +void Temporal::push_conversion_warnings(THD *thd, bool totally_useless_value, int warn, + const char *typestr, + const char *field_name, + const char *value) +{ + if (MYSQL_TIME_WARN_HAVE_WARNINGS(warn)) thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN, - rc, typestr, str->ptr(), - field_name); + totally_useless_value, + typestr, value, field_name); else if (MYSQL_TIME_WARN_HAVE_NOTES(warn)) thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_NOTE, - rc, typestr, str->ptr(), - field_name); - return rc; + false, typestr, value, field_name); } @@ -340,11 +344,10 @@ const LEX_CSTRING Interval_DDhhmmssff::m_type_name= {STRING_WITH_LEN("INTERVAL DAY TO SECOND")}; -Interval_DDhhmmssff::Interval_DDhhmmssff(THD *thd, MYSQL_TIME_STATUS *st, +Interval_DDhhmmssff::Interval_DDhhmmssff(THD *thd, Status *st, bool push_warnings, Item *item, ulong max_hour) { - my_time_status_init(st); switch (item->cmp_type()) { case ROW_RESULT: DBUG_ASSERT(0); @@ -425,7 +428,6 @@ Interval_DDhhmmssff::push_warning_wrong_or_truncated_value(THD *thd, uint Interval_DDhhmmssff::fsp(THD *thd, Item *item) { - MYSQL_TIME_STATUS st; switch (item->cmp_type()) { case INT_RESULT: case TIME_RESULT: @@ -441,6 +443,7 @@ uint Interval_DDhhmmssff::fsp(THD *thd, Item *item) } if (!item->const_item() || item->is_expensive()) return TIME_SECOND_PART_DIGITS; + Status st; Interval_DDhhmmssff it(thd, &st, false/*no warnings*/, item, UINT_MAX32); return it.is_valid_interval_DDhhmmssff() ? st.precision : TIME_SECOND_PART_DIGITS; @@ -3995,47 +3998,87 @@ bool Type_handler_string_result::Item_val_bool(Item *item) const /*************************************************************************/ -bool Type_handler_int_result::Item_get_date(THD *thd, Item *item, - MYSQL_TIME *ltime, - date_mode_t fuzzydate) const + +bool Type_handler::Item_get_date_with_warn(THD *thd, Item *item, + MYSQL_TIME *ltime, + date_mode_t fuzzydate) const { - return item->get_date_from_int(thd, ltime, fuzzydate); + Temporal::Warn_push warn(thd, item->field_name_or_null(), ltime, fuzzydate); + Item_get_date(thd, item, &warn, ltime, fuzzydate); + return ltime->time_type < 0; } -bool Type_handler_year::Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime, +bool Type_handler::Item_func_hybrid_field_type_get_date_with_warn(THD *thd, + Item_func_hybrid_field_type *item, + MYSQL_TIME *ltime, + date_mode_t mode) const +{ + Temporal::Warn_push warn(thd, item->field_name_or_null(), ltime, mode); + Item_func_hybrid_field_type_get_date(thd, item, &warn, ltime, mode); + return ltime->time_type < 0; +} + + +/************************************************************************/ +void Type_handler_decimal_result::Item_get_date(THD *thd, Item *item, + Temporal::Warn *warn, + MYSQL_TIME *ltime, + date_mode_t fuzzydate) const +{ + new(ltime) Temporal_hybrid(thd, warn, VDec(item).ptr(), fuzzydate); +} + + +void Type_handler_int_result::Item_get_date(THD *thd, Item *item, + Temporal::Warn *warn, + MYSQL_TIME *to, + date_mode_t mode) const +{ + new(to) Temporal_hybrid(thd, warn, item->to_longlong_hybrid_null(), mode); +} + + +void Type_handler_year::Item_get_date(THD *thd, Item *item, + Temporal::Warn *warn, + MYSQL_TIME *ltime, date_mode_t fuzzydate) const { - return item->null_value= - VYear(item).to_mysql_time_with_warn(thd, ltime, fuzzydate, - item->field_name_or_null()); + VYear year(item); + DBUG_ASSERT(!year.truncated()); + Longlong_hybrid_null nr(Longlong_null(year.to_YYYYMMDD(), year.is_null()), + item->unsigned_flag); + new(ltime) Temporal_hybrid(thd, warn, nr, fuzzydate); } -bool Type_handler_real_result::Item_get_date(THD *thd, Item *item, +void Type_handler_real_result::Item_get_date(THD *thd, Item *item, + Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const { - return item->get_date_from_real(thd, ltime, fuzzydate); + new(ltime) Temporal_hybrid(thd, warn, item->to_double_null(), fuzzydate); } -bool Type_handler_string_result::Item_get_date(THD *thd, Item *item, +void Type_handler_string_result::Item_get_date(THD *thd, Item *item, + Temporal::Warn *warn, MYSQL_TIME *ltime, - date_mode_t fuzzydate) const + date_mode_t mode) const { - return item->get_date_from_string(thd, ltime, fuzzydate); + StringBuffer<40> tmp; + new(ltime) Temporal_hybrid(thd, warn, item->val_str(&tmp), mode); } -bool Type_handler_temporal_result::Item_get_date(THD *thd, Item *item, +void Type_handler_temporal_result::Item_get_date(THD *thd, Item *item, + Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const { DBUG_ASSERT(0); // Temporal type items must implement native get_date() item->null_value= true; - set_zero_time(ltime, mysql_timestamp_type()); - return true; + set_zero_time(ltime, MYSQL_TIMESTAMP_NONE); } @@ -4176,26 +4219,31 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_decimal( } -bool +void Type_handler_decimal_result::Item_func_hybrid_field_type_get_date( THD *thd, Item_func_hybrid_field_type *item, + Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const { - return VDec_op(item).to_datetime_with_warn(thd, ltime, fuzzydate, item); + new (ltime) Temporal_hybrid(thd, warn, VDec_op(item).ptr(), fuzzydate); } -bool +void Type_handler_year::Item_func_hybrid_field_type_get_date( THD *thd, Item_func_hybrid_field_type *item, + Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const { - return item->null_value= - VYear_op(item).to_mysql_time_with_warn(thd, ltime, fuzzydate, NULL); + VYear_op year(item); + DBUG_ASSERT(!year.truncated()); + Longlong_hybrid_null nr(Longlong_null(year.to_YYYYMMDD(), year.is_null()), + item->unsigned_flag); + new(ltime) Temporal_hybrid(thd, warn, nr, fuzzydate); } @@ -4238,18 +4286,18 @@ Type_handler_int_result::Item_func_hybrid_field_type_val_decimal( } -bool +void Type_handler_int_result::Item_func_hybrid_field_type_get_date( THD *thd, Item_func_hybrid_field_type *item, - MYSQL_TIME *ltime, - date_mode_t fuzzydate) const + Temporal::Warn *warn, + MYSQL_TIME *to, + date_mode_t mode) const { - return item->get_date_from_int_op(thd, ltime, fuzzydate); + new(to) Temporal_hybrid(thd, warn, item->to_longlong_hybrid_null_op(), mode); } - /***************************************************************************/ String * @@ -4288,14 +4336,15 @@ Type_handler_real_result::Item_func_hybrid_field_type_val_decimal( } -bool +void Type_handler_real_result::Item_func_hybrid_field_type_get_date( THD *thd, Item_func_hybrid_field_type *item, - MYSQL_TIME *ltime, - date_mode_t fuzzydate) const + Temporal::Warn *warn, + MYSQL_TIME *to, + date_mode_t mode) const { - return item->get_date_from_real_op(thd, ltime, fuzzydate); + new(to) Temporal_hybrid(thd, warn, item->to_double_null_op(), mode); } @@ -4337,14 +4386,16 @@ Type_handler_temporal_result::Item_func_hybrid_field_type_val_decimal( } -bool +void Type_handler_temporal_result::Item_func_hybrid_field_type_get_date( THD *thd, Item_func_hybrid_field_type *item, + Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const { - return item->date_op(thd, ltime, fuzzydate); + if (item->date_op(thd, ltime, fuzzydate)) + set_zero_time(ltime, MYSQL_TIMESTAMP_NONE); } @@ -4386,14 +4437,16 @@ Type_handler_time_common::Item_func_hybrid_field_type_val_decimal( } -bool +void Type_handler_time_common::Item_func_hybrid_field_type_get_date( THD *thd, Item_func_hybrid_field_type *item, + Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const { - return item->time_op(thd, ltime); + if (item->time_op(thd, ltime)) + set_zero_time(ltime, MYSQL_TIMESTAMP_NONE); } @@ -4435,14 +4488,18 @@ Type_handler_string_result::Item_func_hybrid_field_type_val_decimal( } -bool +void Type_handler_string_result::Item_func_hybrid_field_type_get_date( THD *thd, Item_func_hybrid_field_type *item, + Temporal::Warn *warn, MYSQL_TIME *ltime, - date_mode_t fuzzydate) const + date_mode_t mode) const { - return item->get_date_from_str_op(thd, ltime, fuzzydate); + StringBuffer<40> tmp; + String *res= item->str_op(&tmp); + DBUG_ASSERT((res == NULL) == item->null_value); + new(ltime) Temporal_hybrid(thd, warn, res, mode); } /***************************************************************************/ @@ -4907,7 +4964,7 @@ bool Type_handler_numeric:: Item_func_min_max_get_date(THD *thd, Item_func_min_max *func, MYSQL_TIME *ltime, date_mode_t fuzzydate) const { - return Item_get_date(thd, func, ltime, fuzzydate); + return Item_get_date_with_warn(thd, func, ltime, fuzzydate); } @@ -7508,9 +7565,9 @@ Type_handler_date_common::create_literal_item(THD *thd, CHARSET_INFO *cs, bool send_error) const { - MYSQL_TIME_STATUS st; + Temporal::Warn st; Item_literal *item= NULL; - Temporal_hybrid tmp(&st, str, length, cs, sql_mode_for_dates(thd)); + Temporal_hybrid tmp(thd, &st, str, length, cs, sql_mode_for_dates(thd)); if (tmp.is_valid_temporal() && tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATE && !have_important_literal_warnings(&st)) @@ -7528,9 +7585,9 @@ Type_handler_temporal_with_date::create_literal_item(THD *thd, CHARSET_INFO *cs, bool send_error) const { - MYSQL_TIME_STATUS st; + Temporal::Warn st; Item_literal *item= NULL; - Temporal_hybrid tmp(&st, str, length, cs, sql_mode_for_dates(thd)); + Temporal_hybrid tmp(thd, &st, str, length, cs, sql_mode_for_dates(thd)); if (tmp.is_valid_temporal() && tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATETIME && !have_important_literal_warnings(&st)) diff --git a/sql/sql_type.h b/sql/sql_type.h index 45c98f7b7d3..5de4c8e431a 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -96,6 +96,7 @@ protected: my_decimal *m_ptr; Dec_ptr() { } public: + Dec_ptr(my_decimal *ptr) :m_ptr(ptr) { } bool is_null() const { return m_ptr == NULL; } const my_decimal *ptr() const { return m_ptr; } const my_decimal *ptr_or(const my_decimal *def) const @@ -113,14 +114,6 @@ public: longlong to_longlong(bool unsigned_flag) { return m_ptr ? m_ptr->to_longlong(unsigned_flag) : 0; } bool to_bool() const { return m_ptr ? m_ptr->to_bool() : false; } - bool to_datetime_with_warn(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate, - const char *field_name) - { - return m_ptr ? m_ptr->to_datetime_with_warn(thd, to, fuzzydate, field_name) : - true; - } - bool to_datetime_with_warn(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate, - Item *item); String *to_string(String *to) const { return m_ptr ? m_ptr->to_string(to) : NULL; @@ -260,20 +253,23 @@ public: long usec() const { return m_usec; } /** Converts Sec6 to MYSQL_TIME - - @param ltime converted value will be written here + @param thd current thd + @param [out] warn conversion warnings will be written here + @param [out] ltime converted value will be written here @param fuzzydate conversion flags (TIME_INVALID_DATE, etc) - @param str original number, as an ErrConv. For the warning - @param field_name field name or NULL if not a field. For the warning @returns false for success, true for a failure */ - bool convert_to_mysql_time(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate, - const ErrConv *str, const char *field_name) const; + bool convert_to_mysql_time(THD *thd, + int *warn, + MYSQL_TIME *ltime, + date_mode_t fuzzydate) const; // Convert a number in format hhhmmss.ff to TIME'hhh:mm:ss.ff' bool to_time(MYSQL_TIME *to, int *warn) const { - return number_to_time(m_neg, m_sec, m_usec, to, warn); + bool rc= number_to_time(m_neg, m_sec, m_usec, to, warn); + DBUG_ASSERT(*warn || !rc); + return rc; } /* Convert a number in format YYYYMMDDhhmmss.ff to @@ -286,9 +282,11 @@ public: *warn= MYSQL_TIME_WARN_OUT_OF_RANGE; return true; } - return number_to_datetime(m_sec, m_usec, to, - ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), - warn) == -1; + bool rc= number_to_datetime(m_sec, m_usec, to, + ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), + warn) == -1; + DBUG_ASSERT(*warn || !rc); + return rc; } // Convert elapsed seconds to TIME bool sec_to_time(MYSQL_TIME *ltime, uint dec) const @@ -394,20 +392,12 @@ class Year protected: uint m_year; bool m_truncated; - bool to_mysql_time_with_warn(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate, - const char *field_name) const - { - // Make it YYYYMMDD - Longlong_hybrid value(static_cast<ulonglong>(m_year) * 10000, true); - const ErrConvInteger str(value); - Sec6 sec(value); - return sec.convert_to_mysql_time(thd, to, fuzzydate, &str, field_name); - } uint year_precision(const Item *item) const; public: Year(): m_year(0), m_truncated(false) { } Year(longlong value, bool unsigned_flag, uint length); uint year() const { return m_year; } + uint to_YYYYMMDD() const { return m_year * 10000; } bool truncated() const { return m_truncated; } }; @@ -419,12 +409,6 @@ public: :Year(nr.is_null() ? 0 : nr.value(), unsigned_flag, length), Null_flag(nr.is_null()) { } - bool to_mysql_time_with_warn(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate, - const char *field_name) const - { - return m_is_null ? true : - Year::to_mysql_time_with_warn(thd, to, fuzzydate, field_name); - } }; @@ -442,15 +426,109 @@ public: }; +class Double_null: public Null_flag +{ +protected: + double m_value; +public: + Double_null(double value, bool is_null) + :Null_flag(is_null), m_value(value) + { } + double value() const { return m_value; } +}; + + class Temporal: protected MYSQL_TIME { public: + class Status: public MYSQL_TIME_STATUS + { + public: + Status() { my_time_status_init(this); } + }; + + class Warn: public ErrBuff, + public Status + { + public: + void push_conversion_warnings(THD *thd, bool totally_useless_value, date_mode_t mode, + timestamp_type tstype, const char *name) + { + const char *typestr= tstype >= 0 ? type_name_by_timestamp_type(tstype) : + mode & TIME_TIME_ONLY ? "time" : "datetime"; + Temporal::push_conversion_warnings(thd, totally_useless_value, warnings, typestr, + name, ptr()); + } + }; + + class Warn_push: public Warn + { + THD *m_thd; + const char *m_name; + const MYSQL_TIME *m_ltime; + date_mode_t m_mode; + public: + Warn_push(THD *thd, const char *name, + const MYSQL_TIME *ltime, date_mode_t mode) + :m_thd(thd), m_name(name), m_ltime(ltime), m_mode(mode) + { } + ~Warn_push() + { + if (warnings) + push_conversion_warnings(m_thd, m_ltime->time_type < 0, + m_mode, m_ltime->time_type, m_name); + } + }; + +public: static date_mode_t sql_mode_for_dates(THD *thd); bool is_valid_temporal() const { DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR); return time_type != MYSQL_TIMESTAMP_NONE; } + static const char *type_name_by_timestamp_type(timestamp_type time_type) + { + switch (time_type) { + case MYSQL_TIMESTAMP_DATE: return "date"; + case MYSQL_TIMESTAMP_TIME: return "time"; + case MYSQL_TIMESTAMP_DATETIME: // FALLTHROUGH + default: + break; + } + return "datetime"; + } + static void push_conversion_warnings(THD *thd, bool totally_useless_value, int warn, + const char *type_name, + const char *field_name, + const char *value); + /* + This method is used if the item was not null but convertion to + TIME/DATE/DATETIME failed. We return a zero date if allowed, + otherwise - null. + */ + void make_fuzzy_date(int *warn, date_mode_t fuzzydate) + { + /* + In the following scenario: + - The caller expected to get a TIME value + - Item returned a not NULL string or numeric value + - But then conversion from string or number to TIME failed + we need to change the default time_type from MYSQL_TIMESTAMP_DATE + (which was set in bzero) to MYSQL_TIMESTAMP_TIME and therefore + return TIME'00:00:00' rather than DATE'0000-00-00'. + If we don't do this, methods like Item::get_time_with_conversion() + will erroneously subtract CURRENT_DATE from '0000-00-00 00:00:00' + and return TIME'-838:59:59' instead of TIME'00:00:00' as a result. + */ + timestamp_type tstype= !(fuzzydate & TIME_FUZZY_DATES) ? + MYSQL_TIMESTAMP_NONE : + fuzzydate & TIME_TIME_ONLY ? + MYSQL_TIMESTAMP_TIME : + MYSQL_TIMESTAMP_DATETIME; + set_zero_time(this, tstype); + } + protected: my_decimal *bad_to_decimal(my_decimal *to) const; my_decimal *to_decimal(my_decimal *to) const; @@ -465,6 +543,39 @@ protected: *warn= MYSQL_TIME_WARN_OUT_OF_RANGE; time_type= MYSQL_TIMESTAMP_NONE; } + void make_from_sec6(THD *thd, MYSQL_TIME_STATUS *st, + const Sec6 &nr, date_mode_t mode) + { + if (nr.convert_to_mysql_time(thd, &st->warnings, this, mode)) + make_fuzzy_date(&st->warnings, mode); + } + void make_from_str(THD *thd, Warn *warn, + const char *str, size_t length, CHARSET_INFO *cs, + date_mode_t fuzzydate); + void make_from_double(THD *thd, Warn *warn, double nr, date_mode_t mode) + { + make_from_sec6(thd, warn, Sec6(nr), mode); + if (warn->warnings) + warn->set_double(nr); + } + void make_from_longlong_hybrid(THD *thd, Warn *warn, + const Longlong_hybrid &nr, date_mode_t mode) + { + /* + Note: conversion from an integer to TIME can overflow to + '838:59:59.999999', so the conversion result can have fractional digits. + */ + make_from_sec6(thd, warn, Sec6(nr), mode); + if (warn->warnings) + warn->set_longlong(nr); + } + void make_from_decimal(THD *thd, Warn *warn, + const my_decimal *nr, date_mode_t mode) + { + make_from_sec6(thd, warn, Sec6(nr), mode); + if (warn->warnings) + warn->set_decimal(nr); + } bool str_to_time(MYSQL_TIME_STATUS *st, const char *str, size_t length, CHARSET_INFO *cs, date_mode_t fuzzydate); bool str_to_datetime(MYSQL_TIME_STATUS *st, const char *str, size_t length, @@ -506,6 +617,7 @@ public: class Temporal_hybrid: public Temporal { public: + // Contructors for Item Temporal_hybrid(THD *thd, Item *item, date_mode_t fuzzydate); Temporal_hybrid(THD *thd, Item *item) :Temporal_hybrid(thd, item, sql_mode_for_dates(thd)) @@ -513,18 +625,56 @@ public: Temporal_hybrid(Item *item) :Temporal_hybrid(current_thd, item) { } - Temporal_hybrid(MYSQL_TIME_STATUS *st, const char *str, size_t length, - CHARSET_INFO *cs, date_mode_t fuzzydate) + + // Constructors for non-NULL values + Temporal_hybrid(THD *thd, Warn *warn, + const char *str, size_t length, CHARSET_INFO *cs, + date_mode_t fuzzydate) + { + make_from_str(thd, warn, str, length, cs, fuzzydate); + } + Temporal_hybrid(THD *thd, Warn *warn, + const Longlong_hybrid &nr, date_mode_t fuzzydate) + { + make_from_longlong_hybrid(thd, warn, nr, fuzzydate); + } + Temporal_hybrid(THD *thd, Warn *warn, double nr, date_mode_t fuzzydate) { - if (str_to_datetime(st, str, length, cs, fuzzydate)) + make_from_double(thd, warn, nr, fuzzydate); + } + + // Constructors for nullable values + Temporal_hybrid(THD *thd, Warn *warn, const String *str, date_mode_t mode) + { + if (!str) + time_type= MYSQL_TIMESTAMP_NONE; + else + make_from_str(thd, warn, str->ptr(), str->length(), str->charset(), mode); + } + Temporal_hybrid(THD *thd, Warn *warn, + const Longlong_hybrid_null &nr, date_mode_t fuzzydate) + { + if (nr.is_null()) time_type= MYSQL_TIMESTAMP_NONE; + else + make_from_longlong_hybrid(thd, warn, nr, fuzzydate); } - Temporal_hybrid(THD *thd, const Sec6 &sec, date_mode_t fuzzydate, - const ErrConv *str, const char *field_name) + Temporal_hybrid(THD *thd, Warn *warn, const Double_null &nr, date_mode_t mode) { - if (sec.convert_to_mysql_time(thd, this, fuzzydate, str, field_name)) + if (nr.is_null()) time_type= MYSQL_TIMESTAMP_NONE; + else + make_from_double(thd, warn, nr.value(), mode); } + Temporal_hybrid(THD *thd, Warn *warn, const my_decimal *nr, date_mode_t mode) + { + if (!nr) + time_type= MYSQL_TIMESTAMP_NONE; + else + make_from_decimal(thd, warn, nr, mode); + } + // End of constuctors + longlong to_longlong() const { if (!is_valid_temporal()) @@ -705,11 +855,11 @@ public: return 87649415; } public: - Interval_DDhhmmssff(THD *thd, MYSQL_TIME_STATUS *st, bool push_warnings, + Interval_DDhhmmssff(THD *thd, Status *st, bool push_warnings, Item *item, ulong max_hour); Interval_DDhhmmssff(THD *thd, Item *item) { - MYSQL_TIME_STATUS st; + Status st; new(this) Interval_DDhhmmssff(thd, &st, true, item, max_useful_hour()); } const MYSQL_TIME *get_mysql_time() const @@ -2549,8 +2699,11 @@ public: bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const= 0; virtual bool Item_val_bool(Item *item) const= 0; - virtual bool Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime, + virtual void Item_get_date(THD *thd, Item *item, + Temporal::Warn *buff, MYSQL_TIME *ltime, date_mode_t fuzzydate) const= 0; + bool Item_get_date_with_warn(THD *thd, Item *item, MYSQL_TIME *ltime, + date_mode_t fuzzydate) const; virtual longlong Item_val_int_signed_typecast(Item *item) const= 0; virtual longlong Item_val_int_unsigned_typecast(Item *item) const= 0; @@ -2571,10 +2724,15 @@ public: Item_func_hybrid_field_type *, my_decimal *) const= 0; virtual - bool Item_func_hybrid_field_type_get_date(THD *, + void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, + Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const= 0; + bool Item_func_hybrid_field_type_get_date_with_warn(THD *thd, + Item_func_hybrid_field_type *, + MYSQL_TIME *, + date_mode_t) const; virtual String *Item_func_min_max_val_str(Item_func_min_max *, String *) const= 0; virtual @@ -2836,11 +2994,12 @@ public: DBUG_ASSERT(0); return false; } - bool Item_get_date(THD *thd, Item *item, - MYSQL_TIME *ltime, date_mode_t fuzzydate) const + void Item_get_date(THD *thd, Item *item, + Temporal::Warn *warn, MYSQL_TIME *ltime, + date_mode_t fuzzydate) const { DBUG_ASSERT(0); - return true; + set_zero_time(ltime, MYSQL_TIMESTAMP_NONE); } longlong Item_val_int_signed_typecast(Item *item) const { @@ -2882,13 +3041,14 @@ public: DBUG_ASSERT(0); return NULL; } - bool Item_func_hybrid_field_type_get_date(THD *, + void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, - MYSQL_TIME *, + Temporal::Warn *, + MYSQL_TIME *ltime, date_mode_t fuzzydate) const { DBUG_ASSERT(0); - return true; + set_zero_time(ltime, MYSQL_TIMESTAMP_NONE); } String *Item_func_min_max_val_str(Item_func_min_max *, String *) const @@ -3058,8 +3218,8 @@ public: bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const; bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const; bool Item_val_bool(Item *item) const; - bool Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime, - date_mode_t fuzzydate) const; + void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, + MYSQL_TIME *ltime, date_mode_t fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -3072,8 +3232,9 @@ public: my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const; - bool Item_func_hybrid_field_type_get_date(THD *, + void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, + Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const; @@ -3156,11 +3317,8 @@ public: { return VDec(item).to_bool(); } - bool Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime, - date_mode_t fuzzydate) const - { - return VDec(item).to_datetime_with_warn(thd, ltime, fuzzydate, item); - } + void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, + MYSQL_TIME *ltime, date_mode_t fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const { @@ -3176,8 +3334,9 @@ public: my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const; - bool Item_func_hybrid_field_type_get_date(THD *, + void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, + Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const; @@ -3366,8 +3525,8 @@ public: bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; bool Item_val_bool(Item *item) const; - bool Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime, - date_mode_t fuzzydate) const; + void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, + MYSQL_TIME *ltime, date_mode_t fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -3380,8 +3539,9 @@ public: my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const; - bool Item_func_hybrid_field_type_get_date(THD *, + void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, + Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const; @@ -3448,8 +3608,8 @@ public: bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; bool Item_val_bool(Item *item) const; - bool Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime, - date_mode_t fuzzydate) const; + void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, + MYSQL_TIME *ltime, date_mode_t fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -3462,8 +3622,9 @@ public: my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const; - bool Item_func_hybrid_field_type_get_date(THD *, + void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, + Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const; bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, @@ -3565,8 +3726,8 @@ public: bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const; bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const; bool Item_val_bool(Item *item) const; - bool Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime, - date_mode_t fuzzydate) const; + void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, + MYSQL_TIME *ltime, date_mode_t fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -3579,8 +3740,9 @@ public: my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const; - bool Item_func_hybrid_field_type_get_date(THD *, + void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, + Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const; @@ -3901,10 +4063,11 @@ public: const Column_definition_attributes *attr, uint32 flags) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; - bool Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime, - date_mode_t fuzzydate) const; - bool Item_func_hybrid_field_type_get_date(THD *, + void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, + MYSQL_TIME *ltime, date_mode_t fuzzydate) const; + void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *item, + Temporal::Warn *, MYSQL_TIME *to, date_mode_t fuzzydate) const; }; @@ -4088,8 +4251,9 @@ public: my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const; - bool Item_func_hybrid_field_type_get_date(THD *, + void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, + Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const; diff --git a/sql/sql_type_int.h b/sql/sql_type_int.h index 6c88222fed0..1cc93415176 100644 --- a/sql/sql_type_int.h +++ b/sql/sql_type_int.h @@ -67,4 +67,16 @@ public: } }; + +class Longlong_hybrid_null: public Longlong_hybrid, + public Null_flag +{ +public: + Longlong_hybrid_null(const Longlong_null &nr, bool unsigned_flag) + :Longlong_hybrid(nr.value(), unsigned_flag), + Null_flag(nr.is_null()) + { } +}; + + #endif // SQL_TYPE_INT_INCLUDED |