diff options
author | Alexander Barkov <bar@mariadb.com> | 2023-02-14 13:27:46 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2023-02-14 18:36:40 +0400 |
commit | fec3696fef6fb5a0be5f78632c056382f227e778 (patch) | |
tree | d869e7cbd8e48c2778b2b236b291caebe45383c2 | |
parent | 8c1ad2a9fe940376d7cb79515685138e3591e5b7 (diff) | |
download | mariadb-git-bb-11.0-bar-MDEV-15751.tar.gz |
MDEV-15751 CURRENT_TIMESTAMP should return a TIMESTAMP [WITH TIME ZONE?]bb-11.0-bar-MDEV-15751
-rw-r--r-- | mysql-test/main/create.result | 2 | ||||
-rw-r--r-- | mysql-test/main/func_group.result | 4 | ||||
-rw-r--r-- | mysql-test/main/func_time.result | 82 | ||||
-rw-r--r-- | mysql-test/main/func_time.test | 48 | ||||
-rw-r--r-- | mysql-test/main/func_time_hires.result | 8 | ||||
-rw-r--r-- | mysql-test/main/ps.result | 6 | ||||
-rw-r--r-- | sql/field.cc | 6 | ||||
-rw-r--r-- | sql/field.h | 2 | ||||
-rw-r--r-- | sql/item.cc | 19 | ||||
-rw-r--r-- | sql/item.h | 2 | ||||
-rw-r--r-- | sql/item_func.h | 2 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 77 | ||||
-rw-r--r-- | sql/item_timefunc.h | 111 | ||||
-rw-r--r-- | sql/sql_class.cc | 5 | ||||
-rw-r--r-- | sql/sql_class.h | 3 | ||||
-rw-r--r-- | sql/sql_lex.cc | 2 | ||||
-rw-r--r-- | sql/sql_type.cc | 6 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 6 |
18 files changed, 299 insertions, 92 deletions
diff --git a/mysql-test/main/create.result b/mysql-test/main/create.result index 79c86c0ed61..c557b8bf890 100644 --- a/mysql-test/main/create.result +++ b/mysql-test/main/create.result @@ -128,7 +128,7 @@ drop table t2; create table t2 select now() as a , curtime() as b, curdate() as c , 1+1 as d , 1.0 + 1 as e , 33333333333333333 + 3 as f; describe t2; Field Type Null Key Default Extra -a datetime NO NULL +a timestamp NO NULL b time NO NULL c date NO NULL d int(3) NO NULL diff --git a/mysql-test/main/func_group.result b/mysql-test/main/func_group.result index 8f9c27eeb86..9173bbcacfb 100644 --- a/mysql-test/main/func_group.result +++ b/mysql-test/main/func_group.result @@ -781,12 +781,12 @@ insert into t1 values (now()); create table t2 select f2 from (select max(now()) f2 from t1) a; show columns from t2; Field Type Null Key Default Extra -f2 datetime YES NULL +f2 timestamp YES NULL drop table t2; create table t2 select f2 from (select now() f2 from t1) a; show columns from t2; Field Type Null Key Default Extra -f2 datetime NO NULL +f2 timestamp NO NULL drop table t2, t1; CREATE TABLE t1( id int PRIMARY KEY, diff --git a/mysql-test/main/func_time.result b/mysql-test/main/func_time.result index e10d4e0e02b..5aaa5a65425 100644 --- a/mysql-test/main/func_time.result +++ b/mysql-test/main/func_time.result @@ -6380,3 +6380,85 @@ NULL SELECT FROM_UNIXTIME(LEAST(3696610869, NULL)); FROM_UNIXTIME(LEAST(3696610869, NULL)) NULL +# +# MDEV-15751 CURRENT_TIMESTAMP should return a TIMESTAMP [WITH TIME ZONE?] +# +CREATE TABLE t1 AS +SELECT +current_timestamp(), +current_timestamp(0), +current_timestamp(1), +current_timestamp(2), +current_timestamp(3), +current_timestamp(4), +current_timestamp(5), +current_timestamp(6); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `current_timestamp()` timestamp NOT NULL, + `current_timestamp(0)` timestamp NOT NULL, + `current_timestamp(1)` timestamp(1) NOT NULL, + `current_timestamp(2)` timestamp(2) NOT NULL, + `current_timestamp(3)` timestamp(3) NOT NULL, + `current_timestamp(4)` timestamp(4) NOT NULL, + `current_timestamp(5)` timestamp(5) NOT NULL, + `current_timestamp(6)` timestamp(6) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +DROP TABLE t1; +CREATE TABLE t1 AS +SELECT +sysdate(), +sysdate(0), +sysdate(1), +sysdate(2), +sysdate(3), +sysdate(4), +sysdate(5), +sysdate(6); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `sysdate()` timestamp NOT NULL, + `sysdate(0)` timestamp NOT NULL, + `sysdate(1)` timestamp(1) NOT NULL, + `sysdate(2)` timestamp(2) NOT NULL, + `sysdate(3)` timestamp(3) NOT NULL, + `sysdate(4)` timestamp(4) NOT NULL, + `sysdate(5)` timestamp(5) NOT NULL, + `sysdate(6)` timestamp(6) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +DROP TABLE t1; +CREATE TABLE t1 AS +SELECT +from_unixtime(1000000e0), +from_unixtime(1000000), +from_unixtime(1000000.1), +from_unixtime(1000000.12), +from_unixtime(1000000.123), +from_unixtime(1000000.1234), +from_unixtime(1000000.12345), +from_unixtime(1000000.123456), +from_unixtime(1000000.1234567), +from_unixtime(1000000.12345678), +from_unixtime(1000000.123456789), +from_unixtime(1000000.1234567891), +from_unixtime(1000000.12345678912); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `from_unixtime(1000000e0)` timestamp(6) NULL DEFAULT NULL, + `from_unixtime(1000000)` timestamp NULL DEFAULT NULL, + `from_unixtime(1000000.1)` timestamp(1) NULL DEFAULT NULL, + `from_unixtime(1000000.12)` timestamp(2) NULL DEFAULT NULL, + `from_unixtime(1000000.123)` timestamp(3) NULL DEFAULT NULL, + `from_unixtime(1000000.1234)` timestamp(4) NULL DEFAULT NULL, + `from_unixtime(1000000.12345)` timestamp(5) NULL DEFAULT NULL, + `from_unixtime(1000000.123456)` timestamp(6) NULL DEFAULT NULL, + `from_unixtime(1000000.1234567)` timestamp(6) NULL DEFAULT NULL, + `from_unixtime(1000000.12345678)` timestamp(6) NULL DEFAULT NULL, + `from_unixtime(1000000.123456789)` timestamp(6) NULL DEFAULT NULL, + `from_unixtime(1000000.1234567891)` timestamp(6) NULL DEFAULT NULL, + `from_unixtime(1000000.12345678912)` timestamp(6) NULL DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +DROP TABLE t1; diff --git a/mysql-test/main/func_time.test b/mysql-test/main/func_time.test index b0b9eb5c63c..9f214037347 100644 --- a/mysql-test/main/func_time.test +++ b/mysql-test/main/func_time.test @@ -3254,3 +3254,51 @@ SELECT CONCAT(MAKETIME('01', '01', LEAST( -100, NULL ))); --echo # SELECT FROM_UNIXTIME(LEAST(3696610869, NULL)); + +--echo # +--echo # MDEV-15751 CURRENT_TIMESTAMP should return a TIMESTAMP [WITH TIME ZONE?] +--echo # + +CREATE TABLE t1 AS +SELECT + current_timestamp(), + current_timestamp(0), + current_timestamp(1), + current_timestamp(2), + current_timestamp(3), + current_timestamp(4), + current_timestamp(5), + current_timestamp(6); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 AS +SELECT + sysdate(), + sysdate(0), + sysdate(1), + sysdate(2), + sysdate(3), + sysdate(4), + sysdate(5), + sysdate(6); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 AS +SELECT + from_unixtime(1000000e0), + from_unixtime(1000000), + from_unixtime(1000000.1), + from_unixtime(1000000.12), + from_unixtime(1000000.123), + from_unixtime(1000000.1234), + from_unixtime(1000000.12345), + from_unixtime(1000000.123456), + from_unixtime(1000000.1234567), + from_unixtime(1000000.12345678), + from_unixtime(1000000.123456789), + from_unixtime(1000000.1234567891), + from_unixtime(1000000.12345678912); +SHOW CREATE TABLE t1; +DROP TABLE t1; diff --git a/mysql-test/main/func_time_hires.result b/mysql-test/main/func_time_hires.result index 24221eeed16..1af5cd28fc0 100644 --- a/mysql-test/main/func_time_hires.result +++ b/mysql-test/main/func_time_hires.result @@ -39,14 +39,14 @@ t1 CREATE TABLE `t1` ( `sec_to_time(12345)` time DEFAULT NULL, `sec_to_time(12345.6789)` time(4) DEFAULT NULL, `sec_to_time(1234567e-2)` time(6) DEFAULT NULL, - `now()` datetime NOT NULL, + `now()` timestamp NOT NULL, `curtime(0)` time NOT NULL, `utc_timestamp(1)` datetime(1) NOT NULL, `utc_time(2)` time(2) NOT NULL, `current_time(3)` time(3) NOT NULL, - `current_timestamp(4)` datetime(4) NOT NULL, - `localtime(5)` datetime(5) NOT NULL, - `localtimestamp(6)` datetime(6) NOT NULL, + `current_timestamp(4)` timestamp(4) NOT NULL, + `localtime(5)` timestamp(5) NOT NULL, + `localtimestamp(6)` timestamp(6) NOT NULL, `time_to_sec(123456)` bigint(17) DEFAULT NULL, `time_to_sec('12:34:56.789')` decimal(19,3) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci diff --git a/mysql-test/main/ps.result b/mysql-test/main/ps.result index d5e501b06ef..2f90a64cdd4 100644 --- a/mysql-test/main/ps.result +++ b/mysql-test/main/ps.result @@ -4592,21 +4592,21 @@ EXECUTE stmt USING CURRENT_TIMESTAMP; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `c1` datetime NOT NULL + `c1` timestamp NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; EXECUTE stmt USING CURRENT_TIMESTAMP(3); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `c1` datetime(3) NOT NULL + `c1` timestamp(3) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; EXECUTE stmt USING CURRENT_TIMESTAMP(6); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `c1` datetime(6) NOT NULL + `c1` timestamp(6) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; EXECUTE stmt USING CURRENT_TIME; diff --git a/sql/field.cc b/sql/field.cc index 6b782f79d3a..4e26e16bd97 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5524,7 +5524,11 @@ bool Field_timestamp::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) { ulong sec_part; my_time_t ts= get_timestamp(&sec_part); - return get_thd()->timestamp_to_TIME(ltime, ts, sec_part, fuzzydate); + /* + Zero timestamp means zero datetime here. + Hence "true" in the last argument. + */ + return get_thd()->timestamp_to_TIME(ltime, ts, sec_part, fuzzydate, true); } diff --git a/sql/field.h b/sql/field.h index 4036f032257..09357eed7a0 100644 --- a/sql/field.h +++ b/sql/field.h @@ -3204,7 +3204,7 @@ public: bool zero_pack() const override { return false; } /* This method is used by storage/perfschema and - Item_func_now_local::save_in_field(). + thd_get_query_start_data(). */ void store_TIME(my_time_t ts, ulong sec_part) { diff --git a/sql/item.cc b/sql/item.cc index 5bcddb5cd67..b5998c58b44 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2689,6 +2689,25 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, } +bool +Item_func_or_sum + ::check_decimal_scale_or_error(decimal_digits_t max_allowed_decimals) const +{ + if (decimals > max_allowed_decimals) + { + /* + Historically MariaDB raises ER_TOO_BIG_PRECISION + instead of ER_TOO_BIG_SCALE when checking fractional digits + of an SQL function. Perhaps should be fixed eventually. + */ + my_error(ER_TOO_BIG_PRECISION, MYF(0), func_name(), max_allowed_decimals); + return true; + } + return false; +} + + + /** @brief Building clone for Item_func_or_sum diff --git a/sql/item.h b/sql/item.h index 706360c48f1..15016f25781 100644 --- a/sql/item.h +++ b/sql/item.h @@ -5381,6 +5381,8 @@ class Item_func_or_sum: public Item_result_field, public Used_tables_and_const_cache { protected: + bool check_decimal_scale_or_error(decimal_digits_t max_allowed_scale) const; + bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems, uint flags, int item_sep) { diff --git a/sql/item_func.h b/sql/item_func.h index 520dbdc90c7..7b12062a92b 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -745,6 +745,8 @@ public: protected: const Handler *m_func_handler; public: + Item_handled_func(THD *thd) + :Item_func(thd), m_func_handler(NULL) { } Item_handled_func(THD *thd, Item *a) :Item_func(thd, a), m_func_handler(NULL) { } Item_handled_func(THD *thd, Item *a, Item *b) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 52b9ae7a682..3e224e3e6f7 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1547,13 +1547,8 @@ bool Item_func_curdate::get_date(THD *thd, MYSQL_TIME *res, bool Item_func_curtime::fix_fields(THD *thd, Item **items) { - if (decimals > TIME_SECOND_PART_DIGITS) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), - func_name(), TIME_SECOND_PART_DIGITS); - return 1; - } - return Item_timefunc::fix_fields(thd, items); + return check_decimal_scale_or_error(TIME_SECOND_PART_DIGITS) || + Item_timefunc::fix_fields(thd, items); } bool Item_func_curtime::get_date(THD *thd, MYSQL_TIME *res, @@ -1623,12 +1618,8 @@ void Item_func_curtime_utc::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) bool Item_func_now::fix_fields(THD *thd, Item **items) { - if (decimals > TIME_SECOND_PART_DIGITS) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), - func_name(), TIME_SECOND_PART_DIGITS); - return 1; - } + if (check_decimal_scale_or_error(TIME_SECOND_PART_DIGITS)) + return true; return Item_datetimefunc::fix_fields(thd, items); } @@ -1642,32 +1633,10 @@ void Item_func_now::print(String *str, enum_query_type query_type) } -int Item_func_now_local::save_in_field(Field *field, bool no_conversions) +bool Item_func_current_timestamp::val_native(THD *thd, Native *to) { - if (field->type() == MYSQL_TYPE_TIMESTAMP) - { - THD *thd= field->get_thd(); - my_time_t ts= thd->query_start(); - ulong sec_part= decimals ? thd->query_start_sec_part() : 0; - sec_part-= my_time_fraction_remainder(sec_part, decimals); - field->set_notnull(); - field->store_timestamp(ts, sec_part); - return 0; - } - else - return Item_datetimefunc::save_in_field(field, no_conversions); -} - - -/** - Converts current time in my_time_t to MYSQL_TIME representation for local - time zone. Defines time zone (local) used for whole NOW function. -*/ -void Item_func_now_local::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) -{ - thd->variables.time_zone->gmt_sec_to_TIME(now_time, thd->query_start()); - set_sec_part(thd->query_start_sec_part(), now_time, this); - thd->used|= THD::TIME_ZONE_USED; + Timestamp ts(Timeval(thd->query_start(), thd->query_start_sec_part())); + return null_value= ts.trunc(decimals).to_native(to, decimals); } @@ -1705,22 +1674,14 @@ bool Item_func_now::get_date(THD *thd, MYSQL_TIME *res, Converts current time in my_time_t to MYSQL_TIME representation for local time zone. Defines time zone (local) used for whole SYSDATE function. */ -void Item_func_sysdate_local::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) +bool Item_func_sysdate_local::val_native(THD *thd, Native *to) { my_hrtime_t now= my_hrtime(); - thd->variables.time_zone->gmt_sec_to_TIME(now_time, hrtime_to_my_time(now)); - set_sec_part(hrtime_sec_part(now), now_time, this); - thd->used|= THD::TIME_ZONE_USED; + Timestamp ts(Timeval(hrtime_to_my_time(now), hrtime_sec_part(now))); + return null_value= ts.trunc(decimals).to_native(to, decimals); } -bool Item_func_sysdate_local::get_date(THD *thd, MYSQL_TIME *res, - date_mode_t fuzzydate __attribute__((unused))) -{ - store_now_in_TIME(thd, res); - return 0; -} - bool Item_func_sec_to_time::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { DBUG_ASSERT(fixed()); @@ -2732,7 +2693,6 @@ null_date: bool Item_func_from_unixtime::fix_length_and_dec(THD *thd) { - thd->used|= THD::TIME_ZONE_USED; tz= thd->variables.time_zone; Type_std_attributes::set( Type_temporal_attributes_not_fixed_dec(MAX_DATETIME_WIDTH, @@ -2743,26 +2703,23 @@ bool Item_func_from_unixtime::fix_length_and_dec(THD *thd) } -bool Item_func_from_unixtime::get_date(THD *thd, MYSQL_TIME *ltime, - date_mode_t fuzzydate __attribute__((unused))) +bool Item_func_from_unixtime::val_native(THD *thd, Native *to) { - bzero((char *)ltime, sizeof(*ltime)); - ltime->time_type= MYSQL_TIMESTAMP_TIME; - VSec9 sec(thd, args[0], "unixtime", TIMESTAMP_MAX_VALUE); DBUG_ASSERT(sec.is_null() || sec.sec() <= TIMESTAMP_MAX_VALUE); if (sec.is_null() || sec.truncated() || sec.neg()) return (null_value= 1); - sec.round(MY_MIN(decimals, TIME_SECOND_PART_DIGITS), thd->temporal_round_mode()); + // decimals can be NOT_FIXED_DEC + decimal_digits_t fixed_decimals= MY_MIN(decimals, TIME_SECOND_PART_DIGITS); + + sec.round(fixed_decimals, thd->temporal_round_mode()); if (sec.sec() > TIMESTAMP_MAX_VALUE) return (null_value= true); // Went out of range after rounding - tz->gmt_sec_to_TIME(ltime, (my_time_t) sec.sec()); - ltime->second_part= sec.usec(); - - return (null_value= 0); + Timestamp ts(Timeval(sec.sec(), sec.usec())); + return null_value= ts.to_native(to, fixed_decimals); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a5f6d9307c6..1c463c8a332 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -707,6 +707,49 @@ public: }; +class Item_timestampfunc: public Item_func +{ +protected: + Datetime to_datetime(THD *thd) + { + return Timestamp_or_zero_datetime_native_null(thd, this).to_datetime(thd); + } +public: + Item_timestampfunc(THD *thd): Item_func(thd) {} + Item_timestampfunc(THD *thd, Item *a): Item_func(thd, a) {} + const Type_handler *type_handler() const override + { return &type_handler_timestamp2; } + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override + { + return null_value= to_datetime(thd).copy_to_mysql_time(ltime); + } + double val_real() override + { + Datetime dt= to_datetime(current_thd); + null_value= !dt.is_valid_datetime(); + return dt.to_double(); + } + longlong val_int() override + { + Datetime dt= to_datetime(current_thd); + null_value= !dt.is_valid_datetime(); + return dt.to_longlong(); + } + my_decimal *val_decimal(my_decimal *to) override + { + Datetime dt= to_datetime(current_thd); + null_value= !dt.is_valid_datetime(); + return dt.to_decimal(to); + } + String *val_str(String *to) override + { + Datetime dt= to_datetime(current_thd); + null_value= !dt.is_valid_datetime(); + return dt.to_string(to, decimals); + } +}; + + /* Abstract CURTIME function. Children should define what time zone is used */ class Item_func_curtime :public Item_timefunc @@ -837,20 +880,48 @@ public: }; -class Item_func_now_local :public Item_func_now +/* + This is a replacement for Item_func_now_local, + returning TIMESTAMP instead of DATETIME. +*/ +class Item_func_current_timestamp: public Item_timestampfunc { public: - Item_func_now_local(THD *thd, uint dec): Item_func_now(thd, dec) {} + Item_func_current_timestamp(THD *thd, uint dec) + :Item_timestampfunc(thd) + { decimals= dec; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("current_timestamp") }; return name; } - int save_in_field(Field *field, bool no_conversions) override; - void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) override; + void print(String *str, enum_query_type query_type) override + { + str->append(func_name_cstring()); + str->append('('); + if (decimals) + str->append_ulonglong(decimals); + str->append(')'); + } + bool fix_length_and_dec(THD *thd) override + { + if (check_decimal_scale_or_error(TIME_SECOND_PART_DIGITS)) + return true; + fix_attributes_datetime(decimals); + return false; + } + bool val_native(THD *thd, Native *to) override; + bool check_vcol_func_processor(void *arg) override + { + /* + NOW is safe for replication as slaves will run with same time as + master + */ + return mark_unsupported_function(func_name(), "()", arg, VCOL_TIME_FUNC); + } enum Functype functype() const override { return NOW_FUNC; } Item *get_copy(THD *thd) override - { return get_item_copy<Item_func_now_local>(thd, this); } + { return get_item_copy<Item_func_current_timestamp>(thd, this); } }; @@ -879,18 +950,34 @@ public: This is like NOW(), but always uses the real current time, not the query_start(). This matches the Oracle behavior. */ -class Item_func_sysdate_local :public Item_func_now +class Item_func_sysdate_local :public Item_timestampfunc { public: - Item_func_sysdate_local(THD *thd, uint dec): Item_func_now(thd, dec) {} + Item_func_sysdate_local(THD *thd, uint dec) + :Item_timestampfunc(thd) + { decimals= dec; } bool const_item() const override { return 0; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("sysdate") }; return name; } - void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) override; - bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; + void print(String *str, enum_query_type query_type) override + { + str->append(func_name_cstring()); + str->append('('); + if (decimals) + str->append_ulonglong(decimals); + str->append(')'); + } + bool fix_length_and_dec(THD *thd) override + { + if (check_decimal_scale_or_error(TIME_SECOND_PART_DIGITS)) + return true; + fix_attributes_datetime(decimals); + return false; + } + bool val_native(THD *thd, Native *to) override; table_map used_tables() const override { return RAND_TABLE_BIT; } bool check_vcol_func_processor(void *arg) override { @@ -1029,20 +1116,20 @@ public: }; -class Item_func_from_unixtime :public Item_datetimefunc +class Item_func_from_unixtime :public Item_timestampfunc { bool check_arguments() const override { return args[0]->check_type_can_return_decimal(func_name_cstring()); } Time_zone *tz; public: - Item_func_from_unixtime(THD *thd, Item *a): Item_datetimefunc(thd, a) {} + Item_func_from_unixtime(THD *thd, Item *a): Item_timestampfunc(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("from_unixtime") }; return name; } bool fix_length_and_dec(THD *thd) override; - bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; + bool val_native(THD *thd, Native *to) override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 28119b54ddf..e9336d440c3 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -8319,10 +8319,11 @@ Query_arena_stmt::~Query_arena_stmt() bool THD::timestamp_to_TIME(MYSQL_TIME *ltime, my_time_t ts, - ulong sec_part, date_mode_t fuzzydate) + ulong sec_part, date_mode_t fuzzydate, + bool zero_timestamp_means_zero_datetime) { used|= TIME_ZONE_USED; - if (ts == 0 && sec_part == 0) + if (ts == 0 && sec_part == 0 && zero_timestamp_means_zero_datetime) { if (fuzzydate & TIME_NO_ZERO_DATE) return 1; diff --git a/sql/sql_class.h b/sql/sql_class.h index f0bf695a1c1..7378225eaa2 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3900,7 +3900,8 @@ public: } const Type_handler *type_handler_for_datetime() const; bool timestamp_to_TIME(MYSQL_TIME *ltime, my_time_t ts, - ulong sec_part, date_mode_t fuzzydate); + ulong sec_part, date_mode_t fuzzydate, + bool zero_timesteamp_means_zero_datetime); inline my_time_t query_start() { return start_time; } inline ulong query_start_sec_part() { used|= QUERY_START_SEC_PART_USED; return start_time_sec_part; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index e3f486486d7..b686aee4f7c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -9425,7 +9425,7 @@ Item *LEX::make_item_func_sysdate(THD *thd, uint fsp) set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); Item *item= global_system_variables.sysdate_is_now == 0 ? (Item *) new (thd->mem_root) Item_func_sysdate_local(thd, fsp) : - (Item *) new (thd->mem_root) Item_func_now_local(thd, fsp); + (Item *) new (thd->mem_root) Item_func_current_timestamp(thd, fsp); if (unlikely(item == NULL)) return NULL; safe_to_cache_query=0; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 5d109309d85..916a4f336e0 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -397,7 +397,11 @@ bool Timestamp::to_native(Native *to, uint decimals) const bool Timestamp::to_TIME(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) const { - return thd->timestamp_to_TIME(to, tv_sec, tv_usec, fuzzydate); + /* + Zero timestamp with sec=0, usec=0 means a normal timestamp here, + it is not a zero datetime. Hence "false" in the last argument. + */ + return thd->timestamp_to_TIME(to, tv_sec, tv_usec, fuzzydate, false); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f0ed46646ae..e59d2feeee7 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2845,7 +2845,7 @@ opt_ev_status: ev_starts: /* empty */ { - Item *item= new (thd->mem_root) Item_func_now_local(thd, 0); + Item *item= new (thd->mem_root) Item_func_current_timestamp(thd, 0); if (unlikely(item == NULL)) MYSQL_YYABORT; Lex->event_parse_data->item_starts= item; @@ -6338,7 +6338,7 @@ attribute: } | ON UPDATE_SYM NOW_SYM opt_default_time_precision { - Item *item= new (thd->mem_root) Item_func_now_local(thd, $4); + Item *item= new (thd->mem_root) Item_func_current_timestamp(thd, $4); if (unlikely(item == NULL)) MYSQL_YYABORT; Lex->last_field->on_update= item; @@ -10077,7 +10077,7 @@ function_call_nonkeyword: } | NOW_SYM opt_time_precision { - $$= new (thd->mem_root) Item_func_now_local(thd, $2); + $$= new (thd->mem_root) Item_func_current_timestamp(thd, $2); if (unlikely($$ == NULL)) MYSQL_YYABORT; Lex->safe_to_cache_query=0; |