diff --git a/sql/field.cc b/sql/field.cc index bac5dd95b5a..4a82eae6a0e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5818,9 +5818,7 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd, See comments about truncation in the same place in Field_time::get_equal_const_item(). */ - return new (thd->mem_root) Item_datetime_literal(thd, - dt.get_mysql_time(), - decimals()); + return new (thd->mem_root) Item_datetime_literal(thd, &dt, decimals()); } break; case ANY_SUBST: @@ -5832,7 +5830,7 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd, if (!dt.is_valid_datetime()) return NULL; return new (thd->mem_root) - Item_datetime_literal_for_invalid_dates(thd, dt.get_mysql_time(), + Item_datetime_literal_for_invalid_dates(thd, &dt, dt.get_mysql_time()-> second_part ? TIME_SECOND_PART_DIGITS : 0); @@ -6183,7 +6181,7 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx, (assuming CURRENT_DATE is '2015-08-30' */ - return new (thd->mem_root) Item_time_literal(thd, tm.get_mysql_time(), + return new (thd->mem_root) Item_time_literal(thd, &tm, tm.get_mysql_time()-> second_part ? TIME_SECOND_PART_DIGITS : @@ -6212,8 +6210,7 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx, decimals()); if (!tm.is_valid_time()) return NULL; - return new (thd->mem_root) Item_time_literal(thd, tm.get_mysql_time(), - decimals()); + return new (thd->mem_root) Item_time_literal(thd, &tm, decimals()); } break; } @@ -6772,12 +6769,12 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx, */ if (!dt.hhmmssff_is_zero()) return new (thd->mem_root) - Item_datetime_literal_for_invalid_dates(thd, dt.get_mysql_time(), + Item_datetime_literal_for_invalid_dates(thd, &dt, dt.get_mysql_time()-> second_part ? TIME_SECOND_PART_DIGITS : 0); - return new (thd->mem_root) - Item_date_literal_for_invalid_dates(thd, Date(&dt).get_mysql_time()); + Date d(&dt); + return new (thd->mem_root) Item_date_literal_for_invalid_dates(thd, &d); } break; case IDENTITY_SUBST: @@ -6792,8 +6789,8 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx, Datetime dt(thd, const_item, Datetime::Options(TIME_CONV_NONE, thd)); if (!dt.is_valid_datetime()) return NULL; - return new (thd->mem_root) - Item_date_literal(thd, Date(&dt).get_mysql_time()); + Date d(&dt); + return new (thd->mem_root) Item_date_literal(thd, &d); } break; } diff --git a/sql/item.cc b/sql/item.cc index 22a8cb169b3..d8074dbb013 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6998,7 +6998,7 @@ void Item_date_literal::print(String *str, enum_query_type query_type) { str->append("DATE'"); char buf[MAX_DATE_STRING_REP_LENGTH]; - my_date_to_str(&cached_time, buf); + my_date_to_str(cached_time.get_mysql_time(), buf); str->append(buf); str->append('\''); } @@ -7013,7 +7013,7 @@ Item *Item_date_literal::clone_item(THD *thd) bool Item_date_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { fuzzydate |= sql_mode_for_dates(thd); - *ltime= cached_time; + cached_time.copy_to_mysql_time(ltime); return (null_value= check_date_with_warn(thd, ltime, fuzzydate, MYSQL_TIMESTAMP_ERROR)); } @@ -7023,7 +7023,7 @@ void Item_datetime_literal::print(String *str, enum_query_type query_type) { str->append("TIMESTAMP'"); char buf[MAX_DATE_STRING_REP_LENGTH]; - my_datetime_to_str(&cached_time, buf, decimals); + my_datetime_to_str(cached_time.get_mysql_time(), buf, decimals); str->append(buf); str->append('\''); } @@ -7038,7 +7038,7 @@ Item *Item_datetime_literal::clone_item(THD *thd) bool Item_datetime_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { fuzzydate |= sql_mode_for_dates(thd); - *ltime= cached_time; + cached_time.copy_to_mysql_time(ltime); return (null_value= check_date_with_warn(thd, ltime, fuzzydate, MYSQL_TIMESTAMP_ERROR)); } @@ -7048,7 +7048,7 @@ void Item_time_literal::print(String *str, enum_query_type query_type) { str->append("TIME'"); char buf[MAX_DATE_STRING_REP_LENGTH]; - my_time_to_str(&cached_time, buf, decimals); + my_time_to_str(cached_time.get_mysql_time(), buf, decimals); str->append(buf); str->append('\''); } @@ -7062,7 +7062,7 @@ Item *Item_time_literal::clone_item(THD *thd) bool Item_time_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - *ltime= cached_time; + cached_time.copy_to_mysql_time(ltime); if (fuzzydate & TIME_TIME_ONLY) return (null_value= false); return (null_value= check_date_with_warn(thd, ltime, fuzzydate, @@ -9922,23 +9922,20 @@ Item *Item_cache_temporal::convert_to_basic_const_item(THD *thd) Item *Item_cache_datetime::make_literal(THD *thd) { - MYSQL_TIME ltime; - unpack_time(val_datetime_packed(thd), <ime, MYSQL_TIMESTAMP_DATETIME); - return new (thd->mem_root) Item_datetime_literal(thd, <ime, decimals); + Datetime dt(thd, this, TIME_CONV_NONE | TIME_FRAC_NONE); + return new (thd->mem_root) Item_datetime_literal(thd, &dt, decimals); } Item *Item_cache_date::make_literal(THD *thd) { - MYSQL_TIME ltime; - unpack_time(val_datetime_packed(thd), <ime, MYSQL_TIMESTAMP_DATE); - return new (thd->mem_root) Item_date_literal(thd, <ime); + Date d(thd, this, TIME_CONV_NONE | TIME_FRAC_NONE); + return new (thd->mem_root) Item_date_literal(thd, &d); } Item *Item_cache_time::make_literal(THD *thd) { - MYSQL_TIME ltime; - unpack_time(val_time_packed(thd), <ime, MYSQL_TIMESTAMP_TIME); - return new (thd->mem_root) Item_time_literal(thd, <ime, decimals); + Time t(thd, this); + return new (thd->mem_root) Item_time_literal(thd, &t, decimals); } diff --git a/sql/item.h b/sql/item.h index 95ca06ac211..bff60d60506 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4820,29 +4820,20 @@ public: class Item_temporal_literal :public Item_literal { -protected: - MYSQL_TIME cached_time; public: - /** - Constructor for Item_date_literal. - @param ltime DATE value. - */ - Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime) + Item_temporal_literal(THD *thd) :Item_literal(thd) { collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII); decimals= 0; - cached_time= *ltime; } - Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime, uint dec_arg): + Item_temporal_literal(THD *thd, uint dec_arg): Item_literal(thd) { collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII); decimals= dec_arg; - cached_time= *ltime; } - const MYSQL_TIME *const_ptr_mysql_time() const { return &cached_time; } int save_in_field(Field *field, bool no_conversions) { return save_date_in_field(field, no_conversions); } }; @@ -4853,27 +4844,62 @@ public: */ class Item_date_literal: public Item_temporal_literal { -public: - Item_date_literal(THD *thd, const MYSQL_TIME *ltime) - :Item_temporal_literal(thd, ltime) +protected: + Date cached_time; + bool update_null() { + return maybe_null && + (null_value= cached_time.check_date_with_warn(current_thd)); + } +public: + Item_date_literal(THD *thd, const Date *ltime) + :Item_temporal_literal(thd), + cached_time(*ltime) + { + DBUG_ASSERT(cached_time.is_valid_date()); max_length= MAX_DATE_WIDTH; /* If date has zero month or day, it can return NULL in case of NO_ZERO_DATE or NO_ZERO_IN_DATE. - We can't just check the current sql_mode here in constructor, + If date is `February 30`, it can return NULL in case if + no ALLOW_INVALID_DATES is set. + We can't set null_value using the current sql_mode here in constructor, because sql_mode can change in case of prepared statements between PREPARE and EXECUTE. + Here we only set maybe_null to true if the value has such anomalies. + Later (during execution time), if maybe_null is true, then the value + will be checked per row, according to the execution time sql_mode. + The check_date() below call should cover all cases mentioned. */ - maybe_null= !ltime->month || !ltime->day; + maybe_null= cached_time.check_date(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE); } const Type_handler *type_handler() const { return &type_handler_newdate; } void print(String *str, enum_query_type query_type); + const MYSQL_TIME *const_ptr_mysql_time() const + { + return cached_time.get_mysql_time(); + } Item *clone_item(THD *thd); - longlong val_int() { return Date(this).to_longlong(); } - double val_real() { return Date(this).to_double(); } - String *val_str(String *to) { return Date(this).to_string(to); } - my_decimal *val_decimal(my_decimal *to) { return Date(this).to_decimal(to); } + longlong val_int() + { + return update_null() ? 0 : cached_time.to_longlong(); + } + double val_real() + { + return update_null() ? 0 : cached_time.to_double(); + } + String *val_str(String *to) + { + return update_null() ? 0 : cached_time.to_string(to); + } + my_decimal *val_decimal(my_decimal *to) + { + return update_null() ? 0 : cached_time.to_decimal(to); + } + longlong val_datetime_packed(THD *thd) + { + return update_null() ? 0 : cached_time.valid_date_to_packed(); + } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate); Item *get_copy(THD *thd) { return get_item_copy(thd, this); } @@ -4885,19 +4911,31 @@ public: */ class Item_time_literal: public Item_temporal_literal { +protected: + Time cached_time; public: - Item_time_literal(THD *thd, const MYSQL_TIME *ltime, uint dec_arg): - Item_temporal_literal(thd, ltime, dec_arg) + Item_time_literal(THD *thd, const Time *ltime, uint dec_arg): + Item_temporal_literal(thd, dec_arg), + cached_time(*ltime) { + DBUG_ASSERT(cached_time.is_valid_time()); max_length= MIN_TIME_WIDTH + (decimals ? decimals + 1 : 0); } const Type_handler *type_handler() const { return &type_handler_time2; } void print(String *str, enum_query_type query_type); + const MYSQL_TIME *const_ptr_mysql_time() const + { + return cached_time.get_mysql_time(); + } Item *clone_item(THD *thd); - longlong val_int() { return Time(this).to_longlong(); } - double val_real() { return Time(this).to_double(); } - String *val_str(String *to) { return Time(this).to_string(to, decimals); } - my_decimal *val_decimal(my_decimal *to) { return Time(this).to_decimal(to); } + longlong val_int() { return cached_time.to_longlong(); } + double val_real() { return cached_time.to_double(); } + String *val_str(String *to) { return cached_time.to_string(to, decimals); } + my_decimal *val_decimal(my_decimal *to) { return cached_time.to_decimal(to); } + longlong val_time_packed(THD *thd) + { + return cached_time.valid_time_to_packed(); + } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate); bool val_native(THD *thd, Native *to) { @@ -4913,26 +4951,49 @@ public: */ class Item_datetime_literal: public Item_temporal_literal { -public: - Item_datetime_literal(THD *thd, const MYSQL_TIME *ltime, uint dec_arg): - Item_temporal_literal(thd, ltime, dec_arg) +protected: + Datetime cached_time; + bool update_null() { + return maybe_null && + (null_value= cached_time.check_date_with_warn(current_thd)); + } +public: + Item_datetime_literal(THD *thd, const Datetime *ltime, uint dec_arg): + Item_temporal_literal(thd, dec_arg), + cached_time(*ltime) + { + DBUG_ASSERT(cached_time.is_valid_datetime()); max_length= MAX_DATETIME_WIDTH + (decimals ? decimals + 1 : 0); // See the comment on maybe_null in Item_date_literal - maybe_null= !ltime->month || !ltime->day; + maybe_null= cached_time.check_date(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE); } const Type_handler *type_handler() const { return &type_handler_datetime2; } void print(String *str, enum_query_type query_type); + const MYSQL_TIME *const_ptr_mysql_time() const + { + return cached_time.get_mysql_time(); + } Item *clone_item(THD *thd); - longlong val_int() { return Datetime(this).to_longlong(); } - double val_real() { return Datetime(this).to_double(); } + longlong val_int() + { + return update_null() ? 0 : cached_time.to_longlong(); + } + double val_real() + { + return update_null() ? 0 : cached_time.to_double(); + } String *val_str(String *to) { - return Datetime(this).to_string(to, decimals); + return update_null() ? NULL : cached_time.to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) { - return Datetime(this).to_decimal(to); + return update_null() ? NULL : cached_time.to_decimal(to); + } + longlong val_datetime_packed(THD *thd) + { + return update_null() ? 0 : cached_time.valid_datetime_to_packed(); } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate); Item *get_copy(THD *thd) @@ -4969,11 +5030,14 @@ class Item_date_literal_for_invalid_dates: public Item_date_literal in sql_mode=TRADITIONAL. */ public: - Item_date_literal_for_invalid_dates(THD *thd, const MYSQL_TIME *ltime) - :Item_date_literal(thd, ltime) { } + Item_date_literal_for_invalid_dates(THD *thd, const Date *ltime) + :Item_date_literal(thd, ltime) + { + maybe_null= false; + } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - *ltime= cached_time; + cached_time.copy_to_mysql_time(ltime); return (null_value= false); } }; @@ -4987,11 +5051,14 @@ class Item_datetime_literal_for_invalid_dates: public Item_datetime_literal { public: Item_datetime_literal_for_invalid_dates(THD *thd, - const MYSQL_TIME *ltime, uint dec_arg) - :Item_datetime_literal(thd, ltime, dec_arg) { } + const Datetime *ltime, uint dec_arg) + :Item_datetime_literal(thd, ltime, dec_arg) + { + maybe_null= false; + } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - *ltime= cached_time; + cached_time.copy_to_mysql_time(ltime); return (null_value= false); } }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 19e36632f0c..7091ffc2c58 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -722,8 +722,9 @@ bool vers_select_conds_t::init_from_sysvar(THD *thd) if (type != SYSTEM_TIME_UNSPECIFIED && type != SYSTEM_TIME_ALL) { DBUG_ASSERT(type == SYSTEM_TIME_AS_OF); + Datetime dt(&in.ltime); start.item= new (thd->mem_root) - Item_datetime_literal(thd, &in.ltime, TIME_SECOND_PART_DIGITS); + Item_datetime_literal(thd, &dt, TIME_SECOND_PART_DIGITS); if (!start.item) return true; } @@ -787,15 +788,17 @@ Item* period_get_condition(THD *thd, TABLE_LIST *table, SELECT_LEX *select, { case SYSTEM_TIME_UNSPECIFIED: case SYSTEM_TIME_HISTORY: + { thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE); max_time.second_part= TIME_MAX_SECOND_PART; - curr= newx Item_datetime_literal(thd, &max_time, TIME_SECOND_PART_DIGITS); + Datetime dt(&max_time); + curr= newx Item_datetime_literal(thd, &dt, TIME_SECOND_PART_DIGITS); if (conds->type == SYSTEM_TIME_UNSPECIFIED) cond1= newx Item_func_eq(thd, conds->field_end, curr); else cond1= newx Item_func_lt(thd, conds->field_end, curr); break; - break; + } case SYSTEM_TIME_AS_OF: cond1= newx Item_func_le(thd, conds->field_start, conds->start.item); cond2= newx Item_func_gt(thd, conds->field_end, conds->start.item); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2f8de331d30..3ffb5338053 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -10082,11 +10082,6 @@ int finalize_schema_table(st_plugin_int *plugin) DBUG_RETURN(0); } -/* - This is used to create a timestamp field -*/ - -MYSQL_TIME zero_time={ 0,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_TIME }; /** Output trigger information (SHOW CREATE TRIGGER) to the client. @@ -10171,8 +10166,9 @@ static bool show_create_trigger_impl(THD *thd, Trigger *trigger) MY_CS_NAME_SIZE), mem_root); + static const Datetime zero_datetime(Datetime::zero()); Item_datetime_literal *tmp= (new (mem_root) - Item_datetime_literal(thd, &zero_time, 2)); + Item_datetime_literal(thd, &zero_datetime, 2)); tmp->set_name(thd, STRING_WITH_LEN("Created"), system_charset_info); fields.push_back(tmp, mem_root); diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 85052a1c1bc..0c26e947789 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -8391,7 +8391,10 @@ Type_handler_date_common::create_literal_item(THD *thd, if (tmp.is_valid_temporal() && tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATE && !have_important_literal_warnings(&st)) - item= new (thd->mem_root) Item_date_literal(thd, tmp.get_mysql_time()); + { + Date d(&tmp); + item= new (thd->mem_root) Item_date_literal(thd, &d); + } literal_warn(thd, item, str, length, cs, &st, "DATE", send_error); return item; } @@ -8410,8 +8413,10 @@ Type_handler_temporal_with_date::create_literal_item(THD *thd, if (tmp.is_valid_temporal() && tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATETIME && !have_important_literal_warnings(&st)) - item= new (thd->mem_root) Item_datetime_literal(thd, tmp.get_mysql_time(), - st.precision); + { + Datetime dt(&tmp); + item= new (thd->mem_root) Item_datetime_literal(thd, &dt, st.precision); + } literal_warn(thd, item, str, length, cs, &st, "DATETIME", send_error); return item; } @@ -8430,8 +8435,7 @@ Type_handler_time_common::create_literal_item(THD *thd, Time tmp(thd, &st, str, length, cs, opt); if (tmp.is_valid_time() && !have_important_literal_warnings(&st)) - item= new (thd->mem_root) Item_time_literal(thd, tmp.get_mysql_time(), - st.precision); + item= new (thd->mem_root) Item_time_literal(thd, &tmp, st.precision); literal_warn(thd, item, str, length, cs, &st, "TIME", send_error); return item; } diff --git a/sql/sql_type.h b/sql/sql_type.h index 8726208b788..2064a55dc14 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -1722,6 +1722,11 @@ public: { return is_valid_time() ? Temporal::to_packed() : 0; } + longlong valid_time_to_packed() const + { + DBUG_ASSERT(is_valid_time_slow()); + return Temporal::to_packed(); + } long fraction_remainder(uint dec) const { DBUG_ASSERT(is_valid_time()); @@ -1896,6 +1901,11 @@ public: { return ::check_date_with_warn(thd, this, flags, MYSQL_TIMESTAMP_ERROR); } + bool check_date_with_warn(THD *thd) + { + return ::check_date_with_warn(thd, this, Temporal::sql_mode_for_dates(thd), + MYSQL_TIMESTAMP_ERROR); + } static date_conv_mode_t comparison_flags_for_get_date() { return TIME_INVALID_DATES | TIME_FUZZY_DATES; } }; @@ -1964,11 +1974,37 @@ public: datetime_to_date(this); DBUG_ASSERT(is_valid_date_slow()); } + explicit Date(const Temporal_hybrid *from) + { + *(static_cast(this))= *from; + DBUG_ASSERT(is_valid_date_slow()); + } bool is_valid_date() const { DBUG_ASSERT(is_valid_value_slow()); return time_type == MYSQL_TIMESTAMP_DATE; } + bool check_date(date_conv_mode_t flags, int *warnings) const + { + DBUG_ASSERT(is_valid_date_slow()); + return ::check_date(this, (year || month || day), + ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), + warnings); + } + bool check_date(THD *thd, int *warnings) const + { + return check_date(Temporal::sql_mode_for_dates(thd), warnings); + } + bool check_date(date_conv_mode_t flags) const + { + int dummy; /* unused */ + return check_date(flags, &dummy); + } + bool check_date(THD *thd) const + { + int dummy; + return check_date(Temporal::sql_mode_for_dates(thd), &dummy); + } const MYSQL_TIME *get_mysql_time() const { DBUG_ASSERT(is_valid_date_slow()); @@ -2011,6 +2047,11 @@ public: return Temporal_with_date::yearweek(week_behaviour); } + longlong valid_date_to_packed() const + { + DBUG_ASSERT(is_valid_date_slow()); + return Temporal::to_packed(); + } longlong to_longlong() const { return is_valid_date() ? (longlong) TIME_to_ulonglong_date(this) : 0LL; @@ -2197,6 +2238,16 @@ public: { round(thd, dec, time_round_mode_t(fuzzydate), warn); } + explicit Datetime(const Temporal_hybrid *from) + { + *(static_cast(this))= *from; + DBUG_ASSERT(is_valid_datetime_slow()); + } + explicit Datetime(const MYSQL_TIME *from) + { + *(static_cast(this))= *from; + DBUG_ASSERT(is_valid_datetime_slow()); + } bool is_valid_datetime() const { @@ -2219,6 +2270,10 @@ public: int dummy; /* unused */ return check_date(flags, &dummy); } + bool check_date(THD *thd) const + { + return check_date(Temporal::sql_mode_for_dates(thd)); + } bool hhmmssff_is_zero() const { DBUG_ASSERT(is_valid_datetime_slow()); @@ -2327,6 +2382,11 @@ public: { return is_valid_datetime() ? Temporal::to_packed() : 0; } + longlong valid_datetime_to_packed() const + { + DBUG_ASSERT(is_valid_datetime_slow()); + return Temporal::to_packed(); + } long fraction_remainder(uint dec) const { DBUG_ASSERT(is_valid_datetime()); diff --git a/sql/table.cc b/sql/table.cc index ca0af28a79d..6fa2ef51f89 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -9365,7 +9365,8 @@ bool TR_table::query(MYSQL_TIME &commit_time, bool backwards) SELECT_LEX &slex= *(thd->lex->first_select_lex()); Name_resolution_context_backup backup(slex.context, *this); Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_COMMIT_TS]); - Item *value= newx Item_datetime_literal(thd, &commit_time, 6); + Datetime dt(&commit_time); + Item *value= newx Item_datetime_literal(thd, &dt, 6); COND *conds; if (backwards) conds= newx Item_func_ge(thd, field, value);