1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-32148 Inefficient WHERE timestamp_column=datetime_const_expr

Changing the way how a the following conditions are evaluated:

    WHERE timestamp_column=datetime_const_expr

(for all comparison operators: =, <=>, <, >, <=, >=, <> and for NULLIF)

Before the change it was always performed as DATETIME.
That was not efficient, as involved per-row TIMESTAMP->DATETIME conversion
for timestamp_column. For example, in case of the SYSTEM time zone
it involved a localtime_r() call, which is known to be slow.

After the change it's performed as TIMESTAMP in many cases.
This allows to avoid per-row conversion, as it works the other way around:
datetime_const_expr is converted to TIMESTAMP once before the execution stage.

Note, datetime_const_expr must be inside monotone continuous periods of
the current time zone, i.e. not near these anomalies:
- DST changes (spring forward, fall back)
- leap seconds
This commit is contained in:
Alexander Barkov
2023-09-12 11:27:54 +04:00
parent af4f9daeb8
commit 351a8eecf0
23 changed files with 1543 additions and 24 deletions

View File

@@ -2917,7 +2917,7 @@ ORDER BY timestamp DESC;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL ixEventWhoisDomainDomain,ixEventWhoisDomainTimestamp NULL NULL NULL 60 22.22 Using where; Using filesort
Warnings:
Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`domain` AS `domain`,`test`.`t1`.`registrant_name` AS `registrant_name`,`test`.`t1`.`registrant_organization` AS `registrant_organization`,`test`.`t1`.`registrant_street1` AS `registrant_street1`,`test`.`t1`.`registrant_street2` AS `registrant_street2`,`test`.`t1`.`registrant_street3` AS `registrant_street3`,`test`.`t1`.`registrant_street4` AS `registrant_street4`,`test`.`t1`.`registrant_street5` AS `registrant_street5`,`test`.`t1`.`registrant_city` AS `registrant_city`,`test`.`t1`.`registrant_postal_code` AS `registrant_postal_code`,`test`.`t1`.`registrant_country` AS `registrant_country`,`test`.`t1`.`registrant_email` AS `registrant_email`,`test`.`t1`.`registrant_telephone` AS `registrant_telephone`,`test`.`t1`.`administrative_name` AS `administrative_name`,`test`.`t1`.`administrative_organization` AS `administrative_organization`,`test`.`t1`.`administrative_street1` AS `administrative_street1`,`test`.`t1`.`administrative_street2` AS `administrative_street2`,`test`.`t1`.`administrative_street3` AS `administrative_street3`,`test`.`t1`.`administrative_street4` AS `administrative_street4`,`test`.`t1`.`administrative_street5` AS `administrative_street5`,`test`.`t1`.`administrative_city` AS `administrative_city`,`test`.`t1`.`administrative_postal_code` AS `administrative_postal_code`,`test`.`t1`.`administrative_country` AS `administrative_country`,`test`.`t1`.`administrative_email` AS `administrative_email`,`test`.`t1`.`administrative_telephone` AS `administrative_telephone`,`test`.`t1`.`technical_name` AS `technical_name`,`test`.`t1`.`technical_organization` AS `technical_organization`,`test`.`t1`.`technical_street1` AS `technical_street1`,`test`.`t1`.`technical_street2` AS `technical_street2`,`test`.`t1`.`technical_street3` AS `technical_street3`,`test`.`t1`.`technical_street4` AS `technical_street4`,`test`.`t1`.`technical_street5` AS `technical_street5`,`test`.`t1`.`technical_city` AS `technical_city`,`test`.`t1`.`technical_postal_code` AS `technical_postal_code`,`test`.`t1`.`technical_country` AS `technical_country`,`test`.`t1`.`technical_email` AS `technical_email`,`test`.`t1`.`technical_telephone` AS `technical_telephone`,`test`.`t1`.`json` AS `json`,`test`.`t1`.`timestamp` AS `timestamp` from `test`.`t1` where `test`.`t1`.`domain` = 'www.mailhost.i-dev.fr' and `test`.`t1`.`timestamp` >= <cache>('2017-01-30 08:24:51' + interval -1 month) order by `test`.`t1`.`timestamp` desc
Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`domain` AS `domain`,`test`.`t1`.`registrant_name` AS `registrant_name`,`test`.`t1`.`registrant_organization` AS `registrant_organization`,`test`.`t1`.`registrant_street1` AS `registrant_street1`,`test`.`t1`.`registrant_street2` AS `registrant_street2`,`test`.`t1`.`registrant_street3` AS `registrant_street3`,`test`.`t1`.`registrant_street4` AS `registrant_street4`,`test`.`t1`.`registrant_street5` AS `registrant_street5`,`test`.`t1`.`registrant_city` AS `registrant_city`,`test`.`t1`.`registrant_postal_code` AS `registrant_postal_code`,`test`.`t1`.`registrant_country` AS `registrant_country`,`test`.`t1`.`registrant_email` AS `registrant_email`,`test`.`t1`.`registrant_telephone` AS `registrant_telephone`,`test`.`t1`.`administrative_name` AS `administrative_name`,`test`.`t1`.`administrative_organization` AS `administrative_organization`,`test`.`t1`.`administrative_street1` AS `administrative_street1`,`test`.`t1`.`administrative_street2` AS `administrative_street2`,`test`.`t1`.`administrative_street3` AS `administrative_street3`,`test`.`t1`.`administrative_street4` AS `administrative_street4`,`test`.`t1`.`administrative_street5` AS `administrative_street5`,`test`.`t1`.`administrative_city` AS `administrative_city`,`test`.`t1`.`administrative_postal_code` AS `administrative_postal_code`,`test`.`t1`.`administrative_country` AS `administrative_country`,`test`.`t1`.`administrative_email` AS `administrative_email`,`test`.`t1`.`administrative_telephone` AS `administrative_telephone`,`test`.`t1`.`technical_name` AS `technical_name`,`test`.`t1`.`technical_organization` AS `technical_organization`,`test`.`t1`.`technical_street1` AS `technical_street1`,`test`.`t1`.`technical_street2` AS `technical_street2`,`test`.`t1`.`technical_street3` AS `technical_street3`,`test`.`t1`.`technical_street4` AS `technical_street4`,`test`.`t1`.`technical_street5` AS `technical_street5`,`test`.`t1`.`technical_city` AS `technical_city`,`test`.`t1`.`technical_postal_code` AS `technical_postal_code`,`test`.`t1`.`technical_country` AS `technical_country`,`test`.`t1`.`technical_email` AS `technical_email`,`test`.`t1`.`technical_telephone` AS `technical_telephone`,`test`.`t1`.`json` AS `json`,`test`.`t1`.`timestamp` AS `timestamp` from `test`.`t1` where `test`.`t1`.`domain` = 'www.mailhost.i-dev.fr' and `test`.`t1`.`timestamp` >= TIMESTAMP/*WITH LOCAL TIME ZONE*/'2016-12-30 08:24:51' order by `test`.`t1`.`timestamp` desc
SET optimizer_switch=@save_optimizer_switch;
DROP TABLE t1;
#

View File

@@ -678,3 +678,188 @@ SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a >= ALL (SELECT * FROM t1);
a UNIX_TIMESTAMP(a)
2010-10-31 02:25:25 1288481125
DROP TABLE t1;
#
# MDEV-32148 Inefficient WHERE timestamp_column=datetime_expr
#
#
# Testing a DST change (fall back)
#
SET time_zone='Europe/Moscow';
SET @first_second_after_dst_fall_back=1288479600;
CREATE TABLE t1 (a TIMESTAMP NULL);
INSERT INTO t1 VALUES ('2001-01-01 10:20:30'),('2001-01-01 10:20:31');
#
# Optimized (more than 24 hours before the DST fall back)
#
SET timestamp=@first_second_after_dst_fall_back-24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
1288393199 2010-10-30 02:59:59
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2010-10-30 02:59:59'
#
# Not optimized (24 hours before the DST fall back)
#
SET timestamp=@first_second_after_dst_fall_back-24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
1288393200 2010-10-30 03:00:00
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = <cache>(current_timestamp())
#
# Not optimized (less than 24 hours after the DST fall back)
#
SET timestamp=@first_second_after_dst_fall_back+24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
1288565999 2010-11-01 01:59:59
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = <cache>(current_timestamp())
#
# Optimized (24 hours after the DST fall back)
#
SET timestamp=@first_second_after_dst_fall_back+24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
1288566000 2010-11-01 02:00:00
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2010-11-01 02:00:00'
DROP TABLE t1;
SET time_zone=DEFAULT;
#
# Testing a DST change (spring forward)
#
SET time_zone='Europe/Moscow';
SET @first_second_after_dst_spring_forward=1301180400;
CREATE TABLE t1 (a TIMESTAMP NULL);
INSERT INTO t1 VALUES ('2001-01-01 10:20:30'),('2001-01-01 10:20:31');
#
# Optimized (more than 24 hours before the DST sprint forward)
#
SET timestamp=@first_second_after_dst_spring_forward-24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
1301093999 2011-03-26 01:59:59
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2011-03-26 01:59:59'
#
# Not optimized (24 hours before the DST sprint forward)
#
SET timestamp=@first_second_after_dst_spring_forward-24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
1301094000 2011-03-26 02:00:00
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = <cache>(current_timestamp())
#
# Not optimized (less than 24 hours after the DST sprint forward)
#
SET timestamp=@first_second_after_dst_spring_forward+24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
1301266799 2011-03-28 02:59:59
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = <cache>(current_timestamp())
#
# Optimized (24 hours after the DST sprint forward)
#
SET timestamp=@first_second_after_dst_spring_forward+24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
1301266800 2011-03-28 03:00:00
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2011-03-28 03:00:00'
DROP TABLE t1;
#
# Testing a leap second
#
SET time_zone='leap/Europe/Moscow';
SET @leap_second=362793609;
/*The 60th leap second*/
CREATE TABLE t1 (a TIMESTAMP);
SET timestamp=@leap_second-1;
INSERT INTO t1 VALUES (NOW());
SET timestamp=@leap_second;
INSERT INTO t1 VALUES (NOW());
SET timestamp=@leap_second+1;
INSERT INTO t1 VALUES (NOW());
SELECT UNIX_TIMESTAMP(a), a FROM t1 ORDER BY UNIX_TIMESTAMP(a);
UNIX_TIMESTAMP(a) a
362793608 1981-07-01 03:59:59
362793609 1981-07-01 03:59:59
362793610 1981-07-01 04:00:00
INSERT INTO t1 VALUES ('2001-01-01 10:20:30');
#
# Optimized (more than 24 hours before the leap second)
#
SET timestamp=@leap_second-24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
362707208 1981-06-30 03:59:59
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'1981-06-30 03:59:59'
#
# Not optimized (24 hours before the leap second)
#
SET timestamp=@leap_second-24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
362707209 1981-06-30 04:00:00
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = <cache>(current_timestamp())
#
# Not optimized (less than 24 hours after the leap second)
#
SET timestamp=@leap_second+24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
362880008 1981-07-02 03:59:58
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = <cache>(current_timestamp())
#
# Not optimized (24 hours after the leap second)
#
SET timestamp=@leap_second+24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
UNIX_TIMESTAMP() NOW()
362880009 1981-07-02 03:59:59
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'1981-07-02 03:59:59'
DROP TABLE t1;
SET time_zone=DEFAULT;

View File

@@ -630,3 +630,155 @@ SELECT a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a;
SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a <= ALL (SELECT * FROM t1);
SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a >= ALL (SELECT * FROM t1);
DROP TABLE t1;
--echo #
--echo # MDEV-32148 Inefficient WHERE timestamp_column=datetime_expr
--echo #
--echo #
--echo # Testing a DST change (fall back)
--echo #
SET time_zone='Europe/Moscow';
# '2010-10-31 02:59:59' (1288479599)
# '2010-10-31 02:00:00' (1288479600)
SET @first_second_after_dst_fall_back=1288479600;
CREATE TABLE t1 (a TIMESTAMP NULL);
INSERT INTO t1 VALUES ('2001-01-01 10:20:30'),('2001-01-01 10:20:31');
--echo #
--echo # Optimized (more than 24 hours before the DST fall back)
--echo #
SET timestamp=@first_second_after_dst_fall_back-24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (24 hours before the DST fall back)
--echo #
SET timestamp=@first_second_after_dst_fall_back-24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (less than 24 hours after the DST fall back)
--echo #
SET timestamp=@first_second_after_dst_fall_back+24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Optimized (24 hours after the DST fall back)
--echo #
SET timestamp=@first_second_after_dst_fall_back+24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
DROP TABLE t1;
SET time_zone=DEFAULT;
--echo #
--echo # Testing a DST change (spring forward)
--echo #
SET time_zone='Europe/Moscow';
# '2011-03-27 01:59:59' (1301180399)
# '2011-03-27 03:00:00' (1301180400)
SET @first_second_after_dst_spring_forward=1301180400;
CREATE TABLE t1 (a TIMESTAMP NULL);
INSERT INTO t1 VALUES ('2001-01-01 10:20:30'),('2001-01-01 10:20:31');
--echo #
--echo # Optimized (more than 24 hours before the DST sprint forward)
--echo #
SET timestamp=@first_second_after_dst_spring_forward-24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (24 hours before the DST sprint forward)
--echo #
SET timestamp=@first_second_after_dst_spring_forward-24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (less than 24 hours after the DST sprint forward)
--echo #
SET timestamp=@first_second_after_dst_spring_forward+24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Optimized (24 hours after the DST sprint forward)
--echo #
SET timestamp=@first_second_after_dst_spring_forward+24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
DROP TABLE t1;
--echo #
--echo # Testing a leap second
--echo #
SET time_zone='leap/Europe/Moscow';
SET @leap_second=362793609; /*The 60th leap second*/
CREATE TABLE t1 (a TIMESTAMP);
SET timestamp=@leap_second-1;
INSERT INTO t1 VALUES (NOW());
SET timestamp=@leap_second;
INSERT INTO t1 VALUES (NOW());
SET timestamp=@leap_second+1;
INSERT INTO t1 VALUES (NOW());
SELECT UNIX_TIMESTAMP(a), a FROM t1 ORDER BY UNIX_TIMESTAMP(a);
INSERT INTO t1 VALUES ('2001-01-01 10:20:30');
--echo #
--echo # Optimized (more than 24 hours before the leap second)
--echo #
SET timestamp=@leap_second-24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (24 hours before the leap second)
--echo #
SET timestamp=@leap_second-24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (less than 24 hours after the leap second)
--echo #
SET timestamp=@leap_second+24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (24 hours after the leap second)
--echo #
SET timestamp=@leap_second+24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
DROP TABLE t1;
SET time_zone=DEFAULT;

View File

@@ -872,13 +872,13 @@ SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=' 2001-01-01 00:00:00';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00'
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=' 2001-01-01 00:00:00';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and <cache>(octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 19 + rand()
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00' and <cache>(octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00')) = 19 + rand()
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=' garbage ';
id select_type table type possible_keys key key_len ref rows filtered Extra
@@ -905,13 +905,13 @@ SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=TIMESTAMP'2001-01-01 00:00:00.000000';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00.000000'
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE LENGTH(a)=30+RAND() AND a=TIMESTAMP'2001-01-01 00:00:00.000000';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and <cache>(octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 30 + rand()
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00.000000' and <cache>(octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 30 + rand()
DROP TABLE t1;
CREATE TABLE t1 (a TIMESTAMP(6));;
INSERT INTO t1 VALUES ('2001-01-01 00:00:00.000000'),('2001-01-01 00:00:01.000000');
@@ -930,13 +930,13 @@ SELECT * FROM t1 WHERE LENGTH(a)=26 AND a=TIMESTAMP'2001-01-01 00:00:00.000000';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00.000000'
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE LENGTH(a)=40+RAND() AND a=TIMESTAMP'2001-01-01 00:00:00.000000';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00.000000' and <cache>(octet_length(TIMESTAMP'2001-01-01 00:00:00.000000')) = 40 + rand()
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00.000000' and <cache>(octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00.000000')) = 40 + rand()
DROP TABLE t1;
SET timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30');
CREATE TABLE t1 (a TIMESTAMP);;
@@ -956,13 +956,13 @@ SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=TIME'00:00:00';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00'
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE LENGTH(a)=40+RAND() AND a=TIME'00:00:00';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-01 00:00:00' and <cache>(octet_length(TIMESTAMP'2001-01-01 00:00:00')) = 40 + rand()
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00' and <cache>(octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00')) = 40 + rand()
DROP TABLE t1;
#
# End of 10.1 tests
@@ -1347,6 +1347,540 @@ SET time_zone=DEFAULT;
# End of 10.4 tests
#
#
# Start of 10.6 tests
#
#
# MDEV-32148 Inefficient WHERE timestamp_column=datetime_expr
#
SET time_zone='+00:00';
CREATE TABLE t1 (a TIMESTAMP);
INSERT INTO t1 VALUES ('0000-00-00 00:00:00');
INSERT INTO t1 VALUES ('2001-01-01 10:20:30'), ('2001-01-01 10:20:31');
#
# Comparison predicates: Bad TIMESTAMP values preserve DATETIME comparison
#
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1001-01-01 10:20:30';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1001-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2001-01-00 00:00:00';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2001-01-00 00:00:00'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2040-01-01 10:20:30';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2040-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='1001-01-01 10:20:30';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1001-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-00 00:00:00';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Warning 1292 Incorrect datetime value: '2001-01-00 00:00:00'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = '2001-01-00 00:00:00'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2040-01-01 10:20:30';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2040-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 10010101102030
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20010100000000
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20400101102030
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030e0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 10010101102030e0
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000e0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20010100000000e0
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030e0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20400101102030e0
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030.0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 10010101102030.0
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000.0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20010100000000.0
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030.0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 20400101102030.0
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=DATE_ADD('2020-01-01 10:20:30', INTERVAL 30 YEAR);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2050-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE COALESCE(NULL, a)=DATE_ADD('2020-01-01 10:20:30', INTERVAL 30 YEAR);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where coalesce(NULL,`test`.`t1`.`a`) = <cache>('2020-01-01 10:20:30' + interval 30 year)
#
# Comparison predicates: Good TIMESTAMP values switch to TIMESTAMP comparison
#
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-00 00:00:00';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2001-01-01 10:20:30';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-00 00:00:00';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01 10:20:30';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0e0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00.000000'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030e0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.000000'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0.0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00.0'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030.0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.0'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=DATE_ADD('2001-01-01 10:20:00', INTERVAL 30 SECOND);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE COALESCE(NULL, a)=DATE_ADD('2001-01-01 10:20:00', INTERVAL 30 SECOND);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where coalesce(NULL,`test`.`t1`.`a`) = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30'
#
# Corner cases: DATETIME values before the supported optimization range
# FROM_UNIXTIME(0)..FROM_UNIXTIME(24*3600-1)
#
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 00:00:00';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1970-01-01 00:00:00'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1970-01-01 23:59:59'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.999999';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1970-01-01 23:59:59.999999'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.9999999';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1292 Truncated incorrect DATETIME value: '1970-01-01 23:59:59.9999999'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1970-01-01 23:59:59.999999'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(24*3600-1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = <cache>(from_unixtime(24 * 3600 - 1))
#
# Corner cases: DATETIME values inside the supported optimization range:
# FROM_UNIXTIME(24*3600) .. FROM_UNIXTIME(0x7FFFFFFF-24*3600)
#
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(24*3600);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'1970-01-02 00:00:00'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-02 00:00:00';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'1970-01-02 00:00:00'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2038-01-18 03:14:07'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF-24*3600);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2038-01-18 03:14:07'
#
# Corner cases: DATETIME values after the supported optimization range
# FROM_UNIXTIME(0x7FFFFFFF-24*3600+1) .. FROM_UNIXTIME(0x7FFFFFFF)
#
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF-24*3600+1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = <cache>(from_unixtime(0x7fffffff - 24 * 3600 + 1))
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:08';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2038-01-18 03:14:08'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-19 03:14:07';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2038-01-19 03:14:07'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = <cache>(from_unixtime(0x7fffffff))
#
# Corner cases: rounding
#
SET sql_mode=TIME_ROUND_FRACTIONAL;
#
# Not optimized (before the supported range)
#
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.999999';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'1970-01-01 23:59:59.999999'
#
# Optimized
#
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.9999999';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1292 Truncated incorrect DATETIME value: '1970-01-01 23:59:59.9999999'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'1970-01-02 00:00:00.000000'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07.999999';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2038-01-18 03:14:07.999999'
#
# Not optimized (after the supported range)
#
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07.9999999';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1292 Truncated incorrect DATETIME value: '2038-01-18 03:14:07.9999999'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP'2038-01-18 03:14:08.000000'
SET sql_mode=DEFAULT;
#
# NULLIF: Bad TIMESTAMP values preserve DATETIME comparison
#
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'1001-01-01 10:20:30');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP'1001-01-01 10:20:30')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2001-01-00 00:00:00');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP'2001-01-00 00:00:00')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2040-01-01 10:20:30');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP'2040-01-01 10:20:30')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'1001-01-01 10:20:30');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,'1001-01-01 10:20:30')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2001-01-00 00:00:00');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,'2001-01-00 00:00:00')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2040-01-01 10:20:30');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,'2040-01-01 10:20:30')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,10010101102030)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20010100000000)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20400101102030)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030e0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,10010101102030e0)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000e0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20010100000000e0)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030e0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20400101102030e0)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030.0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,10010101102030.0)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000.0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20010100000000.0)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030.0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,20400101102030.0)
#
# NULLIF: Good TIMESTAMP values switch to TIMESTAMP comparison
#
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'0000-00-00 00:00:00');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2001-01-01 10:20:30');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'0000-00-00 00:00:00');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2001-01-01 10:20:30');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0e0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00.000000')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030e0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.000000')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0.0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'0000-00-00 00:00:00.0')
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030.0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where nullif(`test`.`t1`.`a`,TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.0')
#
# Subqueries with bad TIMESTAMP values
# It's not clear from the output if the comparison is done as DATETIME or TIMESTAMP
#
CREATE TABLE t2 (a DATETIME);
INSERT INTO t2 VALUES ('1001-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 1 100.00
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (/* select#2 */ select max('1001-01-01 10:20:30') from dual)
DROP TABLE t2;
CREATE TABLE t2 (a DATETIME);
INSERT INTO t2 VALUES ('2001-00-00 00:00:00');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 1 100.00
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (/* select#2 */ select max('2001-00-00 00:00:00') from dual)
DROP TABLE t2;
CREATE TABLE t2 (a DATETIME);
INSERT INTO t2 VALUES ('2040-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 1 100.00
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (/* select#2 */ select max('2040-01-01 10:20:30') from dual)
DROP TABLE t2;
#
# Subqueries with good TIMESTAMP values
# It's not clear from the output if the comparison is done as DATETIME or TIMESTAMP
#
CREATE TABLE t2 (a DATETIME);
INSERT INTO t2 VALUES ('0000-00-00 00:00:00');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 1 100.00
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (/* select#2 */ select max('0000-00-00 00:00:00') from dual)
DROP TABLE t2;
CREATE TABLE t2 (a DATETIME);
INSERT INTO t2 VALUES ('2001-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 1 100.00
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = (/* select#2 */ select max('2001-01-01 10:20:30') from dual)
DROP TABLE t2;
#
# Trivial equality elimination
# Covers Type_handler_timestamp_common::Item_const_eq()
#
EXPLAIN EXTENDED SELECT * FROM t1
WHERE IF(a='2001-01-01 00:00:00',1,0)=IF(a='2001-01-01 00:00:00',1,0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where if(`test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00',1,0) = if(`test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 00:00:00',1,0)
EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE (a<=>?)=(a<=>?)'
USING '2001-01-01 00:00:00', '2001-01-01 00:00:00';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where 1
#
# Equal field propagation: Good TIMESTAMP values switch to TIMESTAMP comparison
#
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=TIMESTAMP'2001-01-01 10:20:30';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a='2001-01-01 10:20:30';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030e0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.000000'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030.0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.0'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=TIMESTAMP'2001-01-01 10:20:30';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' and <cache>(octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30')) = 19 + rand()
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a='2001-01-01 10:20:30';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' and <cache>(octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30')) = 19 + rand()
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30' and <cache>(octet_length(TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30')) = 19 + rand()
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030e0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.000000' and <cache>(octet_length(TIMESTAMP'2001-01-01 10:20:30')) = 19 + rand()
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030.0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIMESTAMP/*WITH LOCAL TIME ZONE*/'2001-01-01 10:20:30.0' and <cache>(octet_length(TIMESTAMP'2001-01-01 10:20:30')) = 19 + rand()
DROP TABLE t1;
SET time_zone=DEFAULT;
#
# End of 10.6 tests
#
#
# MDEV-29225 make explicit_defaults_for_timestamps SESSION variable
#
set explicit_defaults_for_timestamp=OFF;

View File

@@ -907,6 +907,246 @@ SET time_zone=DEFAULT;
--echo # End of 10.4 tests
--echo #
--echo #
--echo # Start of 10.6 tests
--echo #
--echo #
--echo # MDEV-32148 Inefficient WHERE timestamp_column=datetime_expr
--echo #
SET time_zone='+00:00';
CREATE TABLE t1 (a TIMESTAMP);
INSERT INTO t1 VALUES ('0000-00-00 00:00:00');
INSERT INTO t1 VALUES ('2001-01-01 10:20:30'), ('2001-01-01 10:20:31');
--echo #
--echo # Comparison predicates: Bad TIMESTAMP values preserve DATETIME comparison
--echo #
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1001-01-01 10:20:30';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2001-01-00 00:00:00';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2040-01-01 10:20:30';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='1001-01-01 10:20:30';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-00 00:00:00';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2040-01-01 10:20:30';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030e0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000e0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030e0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10010101102030.0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010100000000.0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20400101102030.0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=DATE_ADD('2020-01-01 10:20:30', INTERVAL 30 YEAR);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE COALESCE(NULL, a)=DATE_ADD('2020-01-01 10:20:30', INTERVAL 30 YEAR);
--echo #
--echo # Comparison predicates: Good TIMESTAMP values switch to TIMESTAMP comparison
--echo #
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-00 00:00:00';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2001-01-01 10:20:30';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-00 00:00:00';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01 10:20:30';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0e0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030e0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=0.0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=20010101102030.0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=DATE_ADD('2001-01-01 10:20:00', INTERVAL 30 SECOND);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE COALESCE(NULL, a)=DATE_ADD('2001-01-01 10:20:00', INTERVAL 30 SECOND);
--echo #
--echo # Corner cases: DATETIME values before the supported optimization range
--echo # FROM_UNIXTIME(0)..FROM_UNIXTIME(24*3600-1)
--echo #
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 00:00:00';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.999999';
# Truncation of the 7th flactional digit produces a NOTE only without --ps
--disable_ps_protocol
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.9999999';
--enable_ps_protocol
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(24*3600-1);
--echo #
--echo # Corner cases: DATETIME values inside the supported optimization range:
--echo # FROM_UNIXTIME(24*3600) .. FROM_UNIXTIME(0x7FFFFFFF-24*3600)
--echo #
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(24*3600);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-02 00:00:00';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF-24*3600);
--echo #
--echo # Corner cases: DATETIME values after the supported optimization range
--echo # FROM_UNIXTIME(0x7FFFFFFF-24*3600+1) .. FROM_UNIXTIME(0x7FFFFFFF)
--echo #
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF-24*3600+1);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:08';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-19 03:14:07';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=FROM_UNIXTIME(0x7FFFFFFF);
--echo #
--echo # Corner cases: rounding
--echo #
SET sql_mode=TIME_ROUND_FRACTIONAL;
--echo #
--echo # Not optimized (before the supported range)
--echo #
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.999999';
--echo #
--echo # Optimized
--echo #
--disable_ps_protocol
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'1970-01-01 23:59:59.9999999';
--enable_ps_protocol
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07.999999';
--echo #
--echo # Not optimized (after the supported range)
--echo #
--disable_ps_protocol
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'2038-01-18 03:14:07.9999999';
--enable_ps_protocol
SET sql_mode=DEFAULT;
--echo #
--echo # NULLIF: Bad TIMESTAMP values preserve DATETIME comparison
--echo #
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'1001-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2001-01-00 00:00:00');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2040-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'1001-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2001-01-00 00:00:00');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2040-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030e0);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000e0);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030e0);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,10010101102030.0);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010100000000.0);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20400101102030.0);
--echo #
--echo # NULLIF: Good TIMESTAMP values switch to TIMESTAMP comparison
--echo #
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'0000-00-00 00:00:00');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,TIMESTAMP'2001-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'0000-00-00 00:00:00');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,'2001-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0e0);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030e0);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,0.0);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NULLIF(a,20010101102030.0);
--echo #
--echo # Subqueries with bad TIMESTAMP values
--echo # It's not clear from the output if the comparison is done as DATETIME or TIMESTAMP
--echo #
CREATE TABLE t2 (a DATETIME);
INSERT INTO t2 VALUES ('1001-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2);
DROP TABLE t2;
CREATE TABLE t2 (a DATETIME);
INSERT INTO t2 VALUES ('2001-00-00 00:00:00');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2);
DROP TABLE t2;
CREATE TABLE t2 (a DATETIME);
INSERT INTO t2 VALUES ('2040-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2);
DROP TABLE t2;
--echo #
--echo # Subqueries with good TIMESTAMP values
--echo # It's not clear from the output if the comparison is done as DATETIME or TIMESTAMP
--echo #
CREATE TABLE t2 (a DATETIME);
INSERT INTO t2 VALUES ('0000-00-00 00:00:00');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2);
DROP TABLE t2;
CREATE TABLE t2 (a DATETIME);
INSERT INTO t2 VALUES ('2001-01-01 10:20:30');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t2);
DROP TABLE t2;
--echo #
--echo # Trivial equality elimination
--echo # Covers Type_handler_timestamp_common::Item_const_eq()
--echo #
EXPLAIN EXTENDED SELECT * FROM t1
WHERE IF(a='2001-01-01 00:00:00',1,0)=IF(a='2001-01-01 00:00:00',1,0);
EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE (a<=>?)=(a<=>?)'
USING '2001-01-01 00:00:00', '2001-01-01 00:00:00';
--echo #
--echo # Equal field propagation: Good TIMESTAMP values switch to TIMESTAMP comparison
--echo #
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=TIMESTAMP'2001-01-01 10:20:30';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a='2001-01-01 10:20:30';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030e0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19 AND a=20010101102030.0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=TIMESTAMP'2001-01-01 10:20:30';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a='2001-01-01 10:20:30';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030e0;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(a)=19+RAND() AND a=20010101102030.0;
DROP TABLE t1;
SET time_zone=DEFAULT;
--echo #
--echo # End of 10.6 tests
--echo #
--echo #
--echo # MDEV-29225 make explicit_defaults_for_timestamps SESSION variable
--echo #

View File

@@ -40,7 +40,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
3 UNION e ALL NULL NULL NULL NULL 4 100.00 Using where
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 with ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors`
Note 1003 with ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors`
select row_start into @ts_2 from emp where name="john";
explain extended /* All report to 'Bill' */
with recursive
@@ -64,7 +64,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
3 RECURSIVE UNION <derived2> ref key0 key0 5 test.e.mgr 1 100.00
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors`
Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors`
/* All report to 'Bill' */
with recursive
ancestors
@@ -105,7 +105,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
3 RECURSIVE UNION <derived2> ref key0 key0 5 test.e.mgr 1 100.00
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors`
Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `ancestors`.`emp_id` AS `emp_id`,`ancestors`.`name` AS `name`,`ancestors`.`mgr` AS `mgr`,`ancestors`.`salary` AS `salary` from `ancestors`
with recursive
ancestors
as
@@ -146,7 +146,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
3 RECURSIVE UNION <derived2> ref key0 key0 5 test.e.mgr 1 100.00
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1` union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > @`ts_1` and `test`.`e`.`row_start` <= @`ts_1`)/* select#1 */ select `test`.`emp`.`name` AS `name` from `test`.`emp` semi join (`ancestors`) where `ancestors`.`emp_id` = `test`.`emp`.`emp_id` and `test`.`emp`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999'
Note 1003 with recursive ancestors as (/* select#2 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` where `test`.`e`.`name` = 'bill' and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' union /* select#3 */ select `test`.`e`.`emp_id` AS `emp_id`,`test`.`e`.`name` AS `name`,`test`.`e`.`mgr` AS `mgr`,`test`.`e`.`salary` AS `salary` from `test`.`emp` FOR SYSTEM_TIME AS OF TIMESTAMP @`ts_1` `e` join `ancestors` `a` where `a`.`emp_id` = `test`.`e`.`mgr` and `test`.`e`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`e`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu')/* select#1 */ select `test`.`emp`.`name` AS `name` from `test`.`emp` semi join (`ancestors`) where `ancestors`.`emp_id` = `test`.`emp`.`emp_id` and `test`.`emp`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999'
with recursive
ancestors
as

View File

@@ -211,12 +211,12 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join)
Query A:
Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > <cache>(current_timestamp(6)) and `test`.`t2`.`row_start` <= <cache>(current_timestamp(6)) and `test`.`t1`.`row_end` > <cache>(current_timestamp(6)) and `test`.`t1`.`row_start` <= <cache>(current_timestamp(6))
Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t2`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu'
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join)
Query B:
Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > <cache>(current_timestamp(6)) and `test`.`t2`.`row_start` <= <cache>(current_timestamp(6)) and `test`.`t1`.`row_end` > <cache>(current_timestamp(6)) and `test`.`t1`.`row_start` <= <cache>(current_timestamp(6))
Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP current_timestamp(6) where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t2`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu'
Fine result: queries A and B are equal.
## LEFT JOIN: t1, t2 versioned
select * from (

View File

@@ -155,21 +155,21 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Note 1003 select `test`.`t1`.`x` AS `IJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0`
Note 1003 select `test`.`t1`.`x` AS `IJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t2`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu'
explain extended select * from (select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x)
for system_time as of timestamp @t0 as t;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Note 1003 select `test`.`t1`.`x` AS `LJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` left join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` on(`test`.`t2`.`x` = `test`.`t1`.`x` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0`) where `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0`
Note 1003 select `test`.`t1`.`x` AS `LJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` left join `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` on(`test`.`t2`.`x` = `test`.`t1`.`x` and `test`.`t2`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t2`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu') where `test`.`t1`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu'
explain extended select * from (select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x)
for system_time as of timestamp @t0 as t;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Note 1003 select `test`.`t1`.`x` AS `RJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` left join `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` on(`test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0`) where `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0`
Note 1003 select `test`.`t1`.`x` AS `RJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t2` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` left join `test`.`t1` FOR SYSTEM_TIME AS OF TIMESTAMP @`t0` on(`test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t1`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu') where `test`.`t2`.`row_end` > TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu' and `test`.`t2`.`row_start` <= TIMESTAMP/*WITH LOCAL TIME ZONE*/'YYYY-MM-DD hh:ss:mm:.uuuuuu'
select * from (select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x)
for system_time as of timestamp @t0 as t;
IJ2_x1 y1 x2 y2

View File

@@ -5,6 +5,8 @@ if (`SELECT $PS_PROTOCOL != 0`)
--source include/have_innodb.inc
--source include/default_optimizer_switch.inc
--let $replace_regex_tsltz6= /TIMESTAMP..WITH LOCAL TIME ZONE..'....-..-.. ..:..:..[.]......'/TIMESTAMP\/*WITH LOCAL TIME ZONE*\/'YYYY-MM-DD hh:ss:mm:.uuuuuu'/
SET @saved_stats_persistent = @@GLOBAL.innodb_stats_persistent;
SET GLOBAL innodb_stats_persistent = OFF;
@@ -42,6 +44,7 @@ select row_start into @ts_1 from emp where name="jane";
update emp set mgr=30 where name ="john";
--replace_regex $replace_regex_tsltz6
explain extended
with ancestors as (
select e.emp_id, e.name, e.mgr, e.salary from emp as e where name = 'bill'
@@ -68,6 +71,7 @@ as
)
select * from ancestors;
--replace_regex $replace_regex_tsltz6
eval explain extended $q;
eval $q;
@@ -86,6 +90,7 @@ as
)
select * from ancestors for system_time as of timestamp @ts_1;
--replace_regex $replace_regex_tsltz6
eval explain extended $q;
eval $q;
@@ -104,6 +109,7 @@ as
)
select name from emp where emp_id in (select emp_id from ancestors for system_time as of timestamp @ts_1);
--replace_regex $replace_regex_tsltz6
eval explain extended $q;
eval $q;

View File

@@ -1,5 +1,7 @@
--source include/default_optimizer_switch.inc
--let $replace_regex_tsltz6= /TIMESTAMP..WITH LOCAL TIME ZONE..'....-..-.. ..:..:..[.]......'/TIMESTAMP\/*WITH LOCAL TIME ZONE*\/'YYYY-MM-DD hh:ss:mm:.uuuuuu'/
create table emp
(
emp_id int,
@@ -164,6 +166,7 @@ select * from (
select t1.x, t1.y as y1, t2.x as x2, t2.y as y2
from t1 join t2 on t1.x = t2.x) for system_time as of now() as t;
--replace_regex $replace_regex_tsltz6
let $a=`show warnings`;
--echo Query A:
echo $a;
@@ -174,6 +177,7 @@ select * from (
from t1 for system_time as of now()
join t2 for system_time as of now() on t1.x = t2.x) as t;
--replace_regex $replace_regex_tsltz6
let $b=`show warnings`;
--echo Query B:
echo $b;

View File

@@ -6,6 +6,8 @@ if (`SELECT $PS_PROTOCOL != 0`)
--source suite/versioning/common.inc
--source include/default_optimizer_switch.inc
--let $replace_regex_tsltz6= /TIMESTAMP..WITH LOCAL TIME ZONE..'....-..-.. ..:..:..[.]......'/TIMESTAMP\/*WITH LOCAL TIME ZONE*\/'YYYY-MM-DD hh:ss:mm:.uuuuuu'/
SET @saved_stats_persistent = @@GLOBAL.innodb_stats_persistent;
SET GLOBAL innodb_stats_persistent = OFF;
@@ -98,11 +100,14 @@ delete from t1;
delete from t2;
#384
--replace_regex $replace_regex_tsltz6
explain extended select * from (select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x)
for system_time as of timestamp @t0 as t;
--replace_regex $replace_regex_tsltz6
explain extended select * from (select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x)
for system_time as of timestamp @t0 as t;
#383
--replace_regex $replace_regex_tsltz6
explain extended select * from (select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x)
for system_time as of timestamp @t0 as t;

View File

@@ -7332,6 +7332,17 @@ void Item_datetime_literal::print(String *str, enum_query_type query_type)
}
void Item_timestamp_literal::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("TIMESTAMP/*WITH LOCAL TIME ZONE*/'"));
char buf[MAX_DATE_STRING_REP_LENGTH];
Datetime dt= m_value.to_datetime(current_thd);
int length= my_datetime_to_str(dt.get_mysql_time(), buf, decimals);
str->append(buf, length);
str->append('\'');
}
Item *Item_datetime_literal::clone_item(THD *thd)
{
return new (thd->mem_root) Item_datetime_literal(thd, &cached_time, decimals);

View File

@@ -5005,9 +5005,21 @@ class Item_timestamp_literal: public Item_literal
public:
Item_timestamp_literal(THD *thd)
:Item_literal(thd)
{ }
{
collation= DTCollation_numeric();
}
Item_timestamp_literal(THD *thd,
const Timestamp_or_zero_datetime &value,
decimal_digits_t dec)
:Item_literal(thd),
m_value(value)
{
collation= DTCollation_numeric();
decimals= dec;
}
const Type_handler *type_handler() const override
{ return &type_handler_timestamp2; }
void print(String *str, enum_query_type query_type) override;
int save_in_field(Field *field, bool) override
{
Timestamp_or_zero_datetime_native native(m_value, decimals);
@@ -5039,6 +5051,10 @@ public:
{
return m_value.to_native(to, decimals);
}
const Timestamp_or_zero_datetime &value() const
{
return m_value;
}
void set_value(const Timestamp_or_zero_datetime &value)
{
m_value= value;

View File

@@ -392,6 +392,9 @@ static bool convert_const_to_int(THD *thd, Item_field *field_item,
This directly contradicts the manual (number and a string should
be compared as doubles), but seems to provide more
"intuitive" behavior in some cases (but less intuitive in others).
This method should be moved to Type_handler::convert_item_for_comparison()
eventually.
*/
void Item_func::convert_const_compared_to_int_field(THD *thd)
{
@@ -412,6 +415,43 @@ void Item_func::convert_const_compared_to_int_field(THD *thd)
}
bool Item_func::aggregate_args2_for_comparison_with_conversion(
THD *thd,
Type_handler_hybrid_field_type *th)
{
DBUG_ASSERT(arg_count >= 2);
for (bool done= false ; !done ; )
{
if (th->aggregate_for_comparison(func_name_cstring(), args, 2, false))
return true;
if (thd->lex->is_ps_or_view_context_analysis())
return false;
done= true;
for (uint subject= 0; subject < 2; subject++)
{
uint other_side= subject == 0 ? 1 : 0;
/* See comment in convert_const_to_int() */
if (!args[subject]->with_sum_func() &&
args[subject]->can_eval_in_optimize())
{
Item *item= th->type_handler()->convert_item_for_comparison(thd,
args[subject],
args[other_side]);
if (!item)
return true; // An error happened, e.g. EOM
if (item != args[subject])
{
thd->change_item_tree(&args[subject], item);
done= false; // Aggregate again, using the replacement item
break;
}
}
}
}
return false;
}
/*
Iterate through arguments and compare them to the original arguments
in "old_args". If some argument was replaced:
@@ -487,7 +527,7 @@ bool Item_bool_rowready_func2::fix_length_and_dec(THD *thd)
Item_args old_args(args[0], args[1]);
convert_const_compared_to_int_field(thd);
Type_handler_hybrid_field_type tmp;
if (tmp.aggregate_for_comparison(func_name_cstring(), args, 2, false) ||
if (aggregate_args2_for_comparison_with_conversion(thd, &tmp) ||
tmp.type_handler()->Item_bool_rowready_func2_fix_length_and_dec(thd,
this))
{
@@ -2804,7 +2844,10 @@ Item_func_nullif::fix_length_and_dec(THD *thd)
set_maybe_null();
m_arg0= args[0];
convert_const_compared_to_int_field(thd);
if (cmp.set_cmp_func(thd, this, &args[0], &args[1], true/*set_null*/))
Type_handler_hybrid_field_type tmp;
if (aggregate_args2_for_comparison_with_conversion(thd, &tmp) ||
cmp.set_cmp_func(thd, this, tmp.type_handler(),
&args[0], &args[1], true/*set_null*/))
return true;
/*
A special code for EXECUTE..PREPARE.

View File

@@ -83,6 +83,8 @@ protected:
return print_sql_mode_qualified_name(to, query_type, func_name_cstring());
}
bool aggregate_args2_for_comparison_with_conversion(THD *thd,
Type_handler_hybrid_field_type *th);
public:
// Print an error message for a builtin-schema qualified function call

View File

@@ -1207,6 +1207,63 @@ void thd_gmt_sec_to_TIME(MYSQL_THD thd, MYSQL_TIME *ltime, my_time_t t)
}
/*
@brief
Convert a non-zero DATETIME to its safe timeval based representation,
which guarantees a safe roundtrip DATETIME->timeval->DATETIME,
e.g. to optimize:
WHERE timestamp_arg0 = datetime_arg1
in the way that we replace "datetime_arg1" to its TIMESTAMP equivalent
"timestamp_arg1" and switch from DATETIME comparison to TIMESTAMP comparison:
WHERE timestamp_arg0 = timestamp_arg1
This helps to avoid slow TIMESTAMP->DATETIME data type conversion
for timestamp_arg0 per row.
@detail
Round trip is possible if the input "YYYY-MM-DD hh:mm:ss" value
satisfies the following conditions:
1. TIME_to_gmt_sec() returns no errors or warnings,
which means the input value
a. has no zeros in YYYYMMDD
b. fits into the TIMESTAMP range
c. does not fall into the spring forward gap
(because values inside gaps get adjusted to the beginning of the gap)
2. The my_time_t value returned by TIME_to_gmt_sec() must not be
near a DST change or near a leap second, to avoid anomalies:
- "YYYY-MM-DD hh:mm:ss" has more than one matching my_time_t values
- "YYYY-MM-DD hh:mm:ss" has no matching my_time_t values
(e.g. fall into the spring forward gap)
@param dt The DATETIME value to convert.
Must not be zero '0000-00-00 00:00:00.000000'.
(The zero value must be handled by the caller).
@return The conversion result
@retval If succeeded, non-NULL Timeval value.
@retval Timeval_null value representing SQL NULL if the argument
does not have a safe replacement.
*/
Timeval_null
THD::safe_timeval_replacement_for_nonzero_datetime(const Datetime &dt)
{
used|= THD::TIME_ZONE_USED;
DBUG_ASSERT(non_zero_date(dt.get_mysql_time()));
uint error= 0;
const MYSQL_TIME *ltime= dt.get_mysql_time();
my_time_t sec= variables.time_zone->TIME_to_gmt_sec(ltime, &error);
if (error /* (1) */ ||
!variables.time_zone->is_monotone_continuous_around(sec) /* (2) */)
return Timeval_null();
return Timeval_null(sec, ltime->second_part);
}
#ifdef _WIN32
extern "C" my_thread_id next_thread_id_noinline()
{

View File

@@ -4283,6 +4283,8 @@ public:
utime_after_query= current_utime();
}
Timeval_null safe_timeval_replacement_for_nonzero_datetime(const Datetime &);
/**
Update server status after execution of a top level statement.
Currently only checks if a query was slow, and assigns

View File

@@ -7686,6 +7686,104 @@ Item *Type_handler_row::
return NULL;
}
/***************************************************************************/
/*
Check if in a predicate like:
WHERE timestamp_arg=datetime_arg
we can replace DATETIME comparison to TIMESTAMP comparison,
to avoid slow TIMESTAMP->DATETIME data type conversion per row.
TIMESTAMP and DATETIME are compared as DATETIME historically.
This may be inefficient, because involves a conversion of
the TIMESTAMP side to DATETIME per row.
The conversion happens in Timezone::gmt_sec_to_TIME().
E.g. in case of the SYSTEM timezone, it calls localtime_r(),
which is known to be slow.
It's generally not possible to compare TIMESTAMP and DATETIME
as TIMESTAMP without behavior change, because:
- DATETIME has a wider range.
- Two different TIMESTAMP values can have the same DATETIME value
near the "fall back" DST change, as well as for leap seconds.
- There are DATETIME gaps during the "spring forward" DST switch.
However, if the DATETIME side is a constant, then we can compare
it to TIMESTAMP as TIMESTAMP in many cases. The DATETIME argument can
be converted once to TIMESTAMP, so no data type conversion will
happen per row. This is faster for big tables.
The comparison predicates must satisfy the following conditions:
1. There must be a proper data type combination:
- other must be of the TIMESTAMP data type
- subject must be of the DATETIME data type,
or can convert to DATETIME.
2. subject must be a constant
3. subject must convert to TIMESTAMP safely
(without time zone anomalies near its value)
*/
Item *
Type_handler_datetime_common::convert_item_for_comparison(
THD *thd,
Item *subject,
const Item *counterpart)
const
{
if (!dynamic_cast<const Type_handler_timestamp_common*>(
counterpart->type_handler()) ||
!subject->type_handler()->can_return_date())
return subject;
struct Count_handler : public Internal_error_handler
{
uint hit= 0;
bool handle_condition(THD *thd,
uint sql_errno,
const char *sqlstate,
Sql_condition::enum_warning_level *level,
const char *msg,
Sql_condition **cond_hdl)
{
hit++;
return *level == Sql_condition::WARN_LEVEL_WARN;
}
} cnt_handler;
// Suppress and count warnings
thd->push_internal_handler(&cnt_handler);
Datetime dt(thd, subject, Timestamp::DatetimeOptions(thd));
thd->pop_internal_handler();
if (!dt.is_valid_datetime() || cnt_handler.hit)
{
/*
SQL NULL DATETIME, or a DATETIME with zeros in YYYYMMDD,
or warnings during DATETIME evaluation.
*/
return subject;
}
// '0000-00-00 00:00:00' is a special valid MariaDB TIMESTAMP value
if (!non_zero_date(dt.get_mysql_time()))
return new (thd->mem_root) Item_timestamp_literal(thd,
Timestamp_or_zero_datetime::zero(),
subject->datetime_precision(thd));
const Timeval_null tv(thd->safe_timeval_replacement_for_nonzero_datetime(dt));
if (tv.is_null())
return subject; // Time zone anomalies found around "dt"
// Should be safe to convert
const Timestamp_or_zero_datetime ts(Timestamp(tv.to_timeval()));
return new (thd->mem_root) Item_timestamp_literal(thd,
ts,
subject->datetime_precision(thd));
}
/***************************************************************************/
static const char* item_name(Item *a, String *str)
@@ -8686,6 +8784,43 @@ Type_handler_temporal_result::Item_const_eq(const Item_const *a,
b->get_type_all_attributes_from_const()->decimals);
}
/*
@brief
Check if two costant timestamp values are identical.
@return
true <=> *a and *b are identical
*/
bool
Type_handler_timestamp_common::Item_const_eq(const Item_const *a,
const Item_const *b,
bool binary_cmp) const
{
/*
In a condition like:
WHERE IF(a='2001-01-01 00:00:00',1,0)=IF(a='2001-01-01 00:00:00',1,0);
Item_func_eq::fix_length_and_dec() calls get_timestamp_item_for_comparison()
which replaces string literals '2001-01-01 00:00:00' with
Item_timestamp_literal instances, which later during remove_eq_conds()
come to here.
Note, Item_param bound to TIMESTAMP is not detected here,
so trivial conditions of this kind do not get eliminated:
DECLARE ts TIMESTAMP DEFAULT (SELECT MAX(ts_col) FROM t1);
EXECUTE IMMEDIATE
'SELECT * FROM t1 WHERE COALESCE(ts_col,?)<=>COALESCE(ts_col,?)'
USING ts, ts;
It should be fixed by MDEV-14271.
*/
const Item_timestamp_literal *ta, *tb;
if (!(ta= dynamic_cast<const Item_timestamp_literal*>(a)) ||
!(tb= dynamic_cast<const Item_timestamp_literal*>(b)))
return false;
return !ta->value().cmp(tb->value());
}
/***************************************************************************/
const Type_handler *

View File

@@ -2837,6 +2837,11 @@ public:
class Timestamp_or_zero_datetime: protected Timestamp
{
bool m_is_zero_datetime;
public:
static Timestamp_or_zero_datetime zero()
{
return Timestamp_or_zero_datetime(Timestamp(0, 0), true);
}
public:
Timestamp_or_zero_datetime()
:Timestamp(0,0), m_is_zero_datetime(true)
@@ -2845,7 +2850,7 @@ public:
:Timestamp(native.length() ? Timestamp(native) : Timestamp(0,0)),
m_is_zero_datetime(native.length() == 0)
{ }
Timestamp_or_zero_datetime(const Timestamp &tm, bool is_zero_datetime)
Timestamp_or_zero_datetime(const Timestamp &tm, bool is_zero_datetime= false)
:Timestamp(tm), m_is_zero_datetime(is_zero_datetime)
{ }
Timestamp_or_zero_datetime(THD *thd, const MYSQL_TIME *ltime, uint *err_code);
@@ -2869,6 +2874,11 @@ public:
return 1;
return Timestamp::cmp(other);
}
const Timestamp &to_timestamp() const
{
DBUG_ASSERT(!is_zero_datetime());
return *this;
}
bool to_TIME(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) const;
/*
Convert to native format:
@@ -4206,6 +4216,33 @@ public:
virtual Item *make_const_item_for_comparison(THD *thd,
Item *src,
const Item *cmp) const= 0;
/**
When aggregating function arguments for comparison
(e.g. for =, <, >, <=, >=, NULLIF), in some cases we rewrite
arguments. For example, if the predicate
timestamp_expr0 = datetime_const_expr1
decides to compare arguments as DATETIME,
we can try to rewrite datetime_const_expr1 to a TIMESTAMP constant
and perform the comparison as TIMESTAMP, which is faster because
does not have to perform TIMESTAMP->DATETIME data type conversion per row.
"this" is the type handler that is used to compare
"subject" and "counterpart" (DATETIME in the above example).
@param thd the current thread
@param subject the comparison side that we want try to rewrite
@param counterpart the other comparison side
@retval subject, if the subject does not need to be rewritten
@retval NULL in case of error (e.g. EOM)
@retval Otherwise, a pointer to a new Item which can
be used as a replacement for the subject.
*/
virtual Item *convert_item_for_comparison(THD *thd,
Item *subject,
const Item *counterpart) const
{
return subject;
}
virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0;
virtual Item *make_constructor_item(THD *thd, List<Item> *args) const
{
@@ -6524,6 +6561,9 @@ public:
}
String *print_item_value(THD *thd, Item *item, String *str) const override;
Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
Item *convert_item_for_comparison(THD *thd,
Item *subject,
const Item *counterpart) const override;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override;
double Item_func_min_max_val_real(Item_func_min_max *) const override;
longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
@@ -6695,6 +6735,8 @@ public:
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
my_decimal *) const override;
bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override;
bool Item_const_eq(const Item_const *a, const Item_const *b,
bool binary_cmp) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const LEX_CSTRING &name,
Type_handler_hybrid_field_type *,

View File

@@ -1035,4 +1035,29 @@ public:
};
/*
A value that's either a Timeval or SQL NULL
*/
class Timeval_null: protected Timeval
{
bool m_is_null;
public:
Timeval_null()
:Timeval(0, 0),
m_is_null(true)
{ }
Timeval_null(const my_time_t sec, ulong usec)
:Timeval(sec, usec),
m_is_null(false)
{ }
const Timeval & to_timeval() const
{
DBUG_ASSERT(!m_is_null);
return *this;
}
bool is_null() const { return m_is_null; }
};
#endif /* STRUCTS_INCLUDED */

View File

@@ -2426,6 +2426,59 @@ void Time_zone::adjust_leap_second(MYSQL_TIME *t)
t->second= 59;
}
/*
@brief
Check if timestamp<->datetime conversion is guaranteed to be reversible
around the given time value.
*/
bool Time_zone::is_monotone_continuous_around(my_time_t sec) const
{
const my_time_t width= 24 * 60 * 60;
/*
Let's check that the TIMESTAMP range [sec - width, sec + width]
converts back to a DATETIME range [dtmin, dtmax], and the difference
(dtmax-dtmin), calculated using DATETIME arithmetics,
is also equal to exactly 2*width.
This should almost guarantee that the TIMESTAMP range around sec
is monotone and continuous and thus has no DST changes or leap seconds.
It's still possible that there are two or more timezone offset changes
in the given range. But there are no such time zones according to
our knowledge.
Note, DST changes and leap seconds do not interfere on a short time_t range:
- Leap seconds happen in winter and summer
- DST changes happen in spring and fall
The largest time zone change that ever happened in a single place
was 24 hours:
- from SST (UTC-11) - the American Samoa Time Zone
- to WST (UTC+13) - the Independent State of Samoa Time Zone
The Independent State of Samoa used SST until it moved across
the International Date Line at the end of 29 December 2011, to WST.
It is now 24 hours ahead of American Samoa
(and 25 hours in Southern hemisphere summer).
Let's use 24 hours as width (48 hours range total).
*/
if (sec < width || sec > TIMESTAMP_MAX_VALUE - width)
return false;
MYSQL_TIME dtmin, dtmax;
gmt_sec_to_TIME(&dtmin, sec - width);
gmt_sec_to_TIME(&dtmax, sec + width);
ulonglong seconds;
ulong useconds;
if (calc_time_diff(&dtmax, &dtmin, 1, &seconds, &useconds))
return false; // dtmax is smaller than dtmin, should not happen.
if (seconds != (ulonglong) width * 2)
return false; // Anomalies found (DST changes or leap seconds)
return true;
}
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */

View File

@@ -80,6 +80,13 @@ public:
*/
virtual ~Time_zone() = default;
/**
Check if the time zone does not have any anomalies around "sec", such as:
- DST changes (spring forward, fall back)
- leap seconds (the 60-th second)
*/
bool is_monotone_continuous_around(my_time_t sec) const;
protected:
static inline void adjust_leap_second(MYSQL_TIME *t);
};

View File

@@ -257,7 +257,7 @@ select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timest
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (_latin1'2018-10-28 01:30:00' > t0.`col_ts`)
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` between _latin1'2018-10-28 00:30:00' and _latin1'2018-10-28 01:30:00')
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where ((t0.`col_ts` >= _latin1'2018-10-28 00:30:00') and (t0.`col_ts` <= _latin1'2018-10-28 01:30:00'))
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '2018-03-25 01:00:00')
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > _latin1'2018-03-25 01:00:00')
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '1970-01-01 00:00:01')
SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'
SELECT col_a, col_dt, col_ts, unix_timestamp(col_ts) FROM tbl_a ORDER BY col_a;
@@ -344,7 +344,7 @@ select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timest
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (_latin1'2018-10-28 01:30:00' > t0.`col_ts`)
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` between _latin1'2018-10-28 00:30:00' and _latin1'2018-10-28 01:30:00')
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where ((t0.`col_ts` >= _latin1'2018-10-28 00:30:00') and (t0.`col_ts` <= _latin1'2018-10-28 01:30:00'))
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '2018-03-25 01:00:00')
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > _latin1'2018-03-25 01:00:00')
select t0.`col_a` `col_a`,t0.`col_dt` `col_dt`,t0.`col_ts` `col_ts`,(unix_timestamp(t0.`col_ts`)) `unix_timestamp(col_ts)` from `ts_test_remote`.`tbl_a` t0 where (t0.`col_ts` > '1970-01-01 00:00:01')
SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%select %'
SELECT col_a, col_dt, col_ts, unix_timestamp(col_ts) FROM tbl_a ORDER BY col_a;