Commit f4019f5b authored by Alexander Barkov's avatar Alexander Barkov

Backporting from 10.4 to 10.3: MDEV-17325 NULL-ability problems with LEAST()...

Backporting from 10.4 to 10.3: MDEV-17325 NULL-ability problems with LEAST() in combination with NO_ZERO_DATE and NO_ZERO_IN_DATE

This also fixes:
MDEV-17299 Assertion `maybe_null' failed in make_sortkey

Note, during merge of the 10.1 version of MDEV-17299,
please use the 10.3 version of the code (i.e. null merge the 10.1 version).
parent 42c58b87
......@@ -3771,5 +3771,119 @@ t2 CREATE TABLE `t2` (
DROP TABLE t1, t2;
SET sql_mode=DEFAULT;
#
# MDEV-17325 NULL-ability problems with LEAST() in combination with NO_ZERO_DATE and NO_ZERO_IN_DATE
#
SET sql_mode='NO_ZERO_DATE,NO_ZERO_IN_DATE';
SELECT
LEAST('0000-00-00',DATE'2001-01-01') AS s1,
LEAST('0001-00-01',DATE'2001-01-01') AS s2,
LEAST('0000-00-00',TIMESTAMP'2001-01-01 00:00:00') AS s3,
LEAST('0001-00-01',TIMESTAMP'2001-01-01 00:00:00') AS s4,
LEAST(0,DATE'2001-01-01') AS i1,
LEAST(20010001,DATE'2001-01-01') AS i2,
LEAST(0,TIMESTAMP'2001-01-01 00:00:00') AS i3,
LEAST(20010001,TIMESTAMP'2001-01-01 00:00:00') AS i4;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def s1 10 10 0 Y 128 0 63
def s2 10 10 0 Y 128 0 63
def s3 12 26 0 Y 128 6 63
def s4 12 26 0 Y 128 6 63
def i1 10 10 0 Y 128 0 63
def i2 10 10 0 Y 128 0 63
def i3 12 19 0 Y 128 0 63
def i4 12 19 0 Y 128 0 63
s1 s2 s3 s4 i1 i2 i3 i4
NULL NULL NULL NULL NULL NULL NULL NULL
Warnings:
Warning 1292 Incorrect datetime value: '0000-00-00'
Warning 1292 Incorrect datetime value: '0001-00-01'
Warning 1292 Incorrect datetime value: '0000-00-00 00:00:00'
Warning 1292 Incorrect datetime value: '0001-00-01 00:00:00'
Warning 1292 Incorrect datetime value: '0000-00-00'
Warning 1292 Incorrect datetime value: '2001-00-01'
Warning 1292 Incorrect datetime value: '0000-00-00 00:00:00'
Warning 1292 Incorrect datetime value: '2001-00-01 00:00:00'
SET sql_mode='NO_ZERO_DATE,NO_ZERO_IN_DATE';
CREATE TABLE t1 AS SELECT
LEAST('0000-00-00',DATE'2001-01-01') AS s1,
LEAST('0001-00-01',DATE'2001-01-01') AS s2,
LEAST('0000-00-00',TIMESTAMP'2001-01-01 00:00:00') AS s3,
LEAST('0001-00-01',TIMESTAMP'2001-01-01 00:00:00') AS s4,
LEAST(0,DATE'2001-01-01') AS i1,
LEAST(20010001,DATE'2001-01-01') AS i2,
LEAST(0,TIMESTAMP'2001-01-01 00:00:00') AS i3,
LEAST(20010001,TIMESTAMP'2001-01-01 00:00:00') AS i4;
Warnings:
Warning 1292 Incorrect datetime value: '0000-00-00'
Warning 1292 Incorrect datetime value: '0001-00-01'
Warning 1292 Incorrect datetime value: '0000-00-00 00:00:00'
Warning 1292 Incorrect datetime value: '0001-00-01 00:00:00'
Warning 1292 Incorrect datetime value: '0000-00-00'
Warning 1292 Incorrect datetime value: '2001-00-01'
Warning 1292 Incorrect datetime value: '0000-00-00 00:00:00'
Warning 1292 Incorrect datetime value: '2001-00-01 00:00:00'
SELECT * FROM t1;
s1 s2 s3 s4 i1 i2 i3 i4
NULL NULL NULL NULL NULL NULL NULL NULL
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`s1` date DEFAULT NULL,
`s2` date DEFAULT NULL,
`s3` datetime(6) DEFAULT NULL,
`s4` datetime(6) DEFAULT NULL,
`i1` date DEFAULT NULL,
`i2` date DEFAULT NULL,
`i3` datetime DEFAULT NULL,
`i4` datetime DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
SET timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30');
CREATE TABLE t1 AS SELECT LEAST(CURRENT_DATE,CURRENT_TIME) AS c1;
SELECT * FROM t1;
c1
2001-01-01 00:00:00
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` datetime NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
SET old_mode=ZERO_DATE_TIME_CAST;
CREATE TABLE t1 AS SELECT LEAST(CURRENT_DATE,CURRENT_TIME) AS c1;
Warnings:
Warning 1292 Incorrect datetime value: '0000-00-00 10:20:30'
SELECT * FROM t1;
c1
NULL
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` datetime DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
SET old_mode=DEFAULT;
SET timestamp=DEFAULT;
SET sql_mode=DEFAULT;
SET sql_mode='';
SELECT LEAST(999,TIME'10:20:30') AS c1;
c1
NULL
Warnings:
Warning 1292 Incorrect datetime value: '999'
CREATE TABLE t1 AS SELECT LEAST(999,TIME'10:20:30') AS c1;
Warnings:
Warning 1292 Incorrect datetime value: '999'
SELECT * FROM t1;
c1
NULL
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` time DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
SET sql_mode=DEFAULT;
#
# End of 10.3 tests
#
......@@ -628,6 +628,68 @@ SET sql_mode=DEFAULT;
--echo #
--echo # End of 10.3 tests
--echo # MDEV-17325 NULL-ability problems with LEAST() in combination with NO_ZERO_DATE and NO_ZERO_IN_DATE
--echo #
SET sql_mode='NO_ZERO_DATE,NO_ZERO_IN_DATE';
--disable_ps_protocol
--enable_metadata
SELECT
LEAST('0000-00-00',DATE'2001-01-01') AS s1,
LEAST('0001-00-01',DATE'2001-01-01') AS s2,
LEAST('0000-00-00',TIMESTAMP'2001-01-01 00:00:00') AS s3,
LEAST('0001-00-01',TIMESTAMP'2001-01-01 00:00:00') AS s4,
LEAST(0,DATE'2001-01-01') AS i1,
LEAST(20010001,DATE'2001-01-01') AS i2,
LEAST(0,TIMESTAMP'2001-01-01 00:00:00') AS i3,
LEAST(20010001,TIMESTAMP'2001-01-01 00:00:00') AS i4;
--disable_metadata
--enable_ps_protocol
SET sql_mode='NO_ZERO_DATE,NO_ZERO_IN_DATE';
CREATE TABLE t1 AS SELECT
LEAST('0000-00-00',DATE'2001-01-01') AS s1,
LEAST('0001-00-01',DATE'2001-01-01') AS s2,
LEAST('0000-00-00',TIMESTAMP'2001-01-01 00:00:00') AS s3,
LEAST('0001-00-01',TIMESTAMP'2001-01-01 00:00:00') AS s4,
LEAST(0,DATE'2001-01-01') AS i1,
LEAST(20010001,DATE'2001-01-01') AS i2,
LEAST(0,TIMESTAMP'2001-01-01 00:00:00') AS i3,
LEAST(20010001,TIMESTAMP'2001-01-01 00:00:00') AS i4;
SELECT * FROM t1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
SET timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30');
# A TIME always converts to a non-NULL DATETIME with the new CAST style
# Expect a NOT NULL column
CREATE TABLE t1 AS SELECT LEAST(CURRENT_DATE,CURRENT_TIME) AS c1;
SELECT * FROM t1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
# A TIME can convert to a NULL DATETIME with old CAST style
# Expect a NULL-able column
SET old_mode=ZERO_DATE_TIME_CAST;
CREATE TABLE t1 AS SELECT LEAST(CURRENT_DATE,CURRENT_TIME) AS c1;
SELECT * FROM t1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
SET old_mode=DEFAULT;
SET timestamp=DEFAULT;
SET sql_mode=DEFAULT;
SET sql_mode='';
SELECT LEAST(999,TIME'10:20:30') AS c1;
CREATE TABLE t1 AS SELECT LEAST(999,TIME'10:20:30') AS c1;
SELECT * FROM t1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
SET sql_mode=DEFAULT;
--echo #
--echo # End of 10.3 tests
--echo #
......@@ -863,6 +863,31 @@ d COUNT(*)
NULL 2
DROP TABLE t1;
#
# MDEV-17299 Assertion `maybe_null' failed in make_sortkey
#
CREATE TABLE t1 (pk int NOT NULL, d1 date, d2 date NOT NULL);
INSERT INTO t1 values (1,'2018-06-22','2018-06-22'),(2,'2018-07-11','2018-07-11');
CREATE VIEW v1 AS SELECT * FROM t1;
SELECT group_concat(d1/(CASE 'b' WHEN 'j' THEN 'c' END))
FROM v1 GROUP BY greatest(pk, 0, d2);
group_concat(d1/(CASE 'b' WHEN 'j' THEN 'c' END))
NULL
Warnings:
Warning 1292 Incorrect datetime value: '1' for column `test`.`t1`.`pk` at row 1
Warning 1292 Incorrect datetime value: '2' for column `test`.`t1`.`pk` at row 1
Warning 1292 Incorrect datetime value: '1' for column `test`.`t1`.`pk` at row 1
Warning 1292 Incorrect datetime value: '1' for column `test`.`t1`.`pk` at row 1
Warning 1292 Incorrect datetime value: '2' for column `test`.`t1`.`pk` at row 2
CREATE TABLE t2 AS SELECT greatest(pk, 0, d2) AS c1 FROM t1 LIMIT 0;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`c1` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
DROP VIEW v1;
DROP TABLE t1;
#
# End of 10.1 tests
#
#
......
......@@ -591,6 +591,20 @@ INSERT INTO t1 VALUES ('1985-05-13'),('1989-12-24');
SELECT d, COUNT(*) FROM t1 GROUP BY d WITH ROLLUP HAVING CASE d WHEN '2017-05-25' THEN 0 ELSE 1 END;
DROP TABLE t1;
--echo #
--echo # MDEV-17299 Assertion `maybe_null' failed in make_sortkey
--echo #
CREATE TABLE t1 (pk int NOT NULL, d1 date, d2 date NOT NULL);
INSERT INTO t1 values (1,'2018-06-22','2018-06-22'),(2,'2018-07-11','2018-07-11');
CREATE VIEW v1 AS SELECT * FROM t1;
SELECT group_concat(d1/(CASE 'b' WHEN 'j' THEN 'c' END))
FROM v1 GROUP BY greatest(pk, 0, d2);
CREATE TABLE t2 AS SELECT greatest(pk, 0, d2) AS c1 FROM t1 LIMIT 0;
SHOW CREATE TABLE t2;
DROP TABLE t2;
DROP VIEW v1;
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests
......
......@@ -2933,6 +2933,97 @@ bool Type_handler::
}
bool Type_handler_temporal_result::
Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
Item **items, uint nitems) const
{
bool rc= Type_handler::Item_func_min_max_fix_attributes(thd, func,
items, nitems);
if (rc || func->maybe_null)
return rc;
/*
LEAST/GREATES(non-temporal, temporal) can return NULL.
CAST functions Item_{time|datetime|date}_typecast always set maybe_full
to true. Here we try to detect nullability more thoroughly.
Perhaps CAST functions should also reuse this idea eventually.
*/
const Type_handler *hf= func->type_handler();
for (uint i= 0; i < nitems; i++)
{
/*
If items[i] does not need conversion to the current temporal data
type, then we trust items[i]->maybe_null, which was already ORred
to func->maybe_null in the argument loop in fix_fields().
If items[i] requires conversion to the current temporal data type,
then conversion can fail and return NULL even for NOT NULL items.
*/
const Type_handler *ha= items[i]->type_handler();
if (hf == ha)
continue; // No conversion.
if (ha->cmp_type() != TIME_RESULT)
{
func->maybe_null= true; // Conversion from non-temporal is not safe
break;
}
timestamp_type tf= hf->mysql_timestamp_type();
timestamp_type ta= ha->mysql_timestamp_type();
if (tf == ta ||
(tf == MYSQL_TIMESTAMP_DATETIME && ta == MYSQL_TIMESTAMP_DATE))
{
/*
If handlers have the same mysql_timestamp_type(),
then conversion is NULL safe. Conversion from DATE to DATETIME
is also safe. This branch includes data type pairs:
Function return type Argument type Comment
-------------------- ------------- -------------
TIMESTAMP TIMESTAMP no conversion
TIMESTAMP DATETIME not possible
TIMESTAMP DATE not possible
DATETIME DATETIME no conversion
DATETIME TIMESTAMP safe conversion
DATETIME DATE safe conversion
DATE DATE no conversion
TIME TIME no conversion
Note, a function cannot return TIMESTAMP if it has non-TIMESTAMP
arguments (it would return DATETIME in such case).
*/
DBUG_ASSERT(hf->field_type() != MYSQL_TYPE_TIMESTAMP || tf == ta);
continue;
}
/*
Here we have the following data type pairs that did not match
the condition above:
Function return type Argument type Comment
-------------------- ------------- -------
TIMESTAMP TIME Not possible
DATETIME TIME depends on OLD_MODE_ZERO_DATE_TIME_CAST
DATE TIMESTAMP Not possible
DATE DATETIME Not possible
DATE TIME Not possible
TIME TIMESTAMP Not possible
TIME DATETIME Not possible
TIME DATE Not possible
Most pairs are not possible, because the function data type
would be DATETIME (according to LEAST/GREATEST aggregation rules).
Conversion to DATETIME from TIME is not safe when
OLD_MODE_ZERO_DATE_TIME_CAST is set:
- negative TIME values cannot be converted to not-NULL DATETIME values
- TIME values can produce DATETIME values that do not pass
NO_ZERO_DATE and NO_ZERO_IN_DATE tests.
*/
DBUG_ASSERT(hf->field_type() == MYSQL_TYPE_DATETIME);
if (!(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST))
continue;
func->maybe_null= true;
break;
}
return rc;
}
bool Type_handler_real_result::
Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
Item **items, uint nitems) const
......
......@@ -2138,6 +2138,8 @@ class Type_handler_temporal_result: public Type_handler
Item *source_expr, Item *source_const) const;
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const;
bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
Item **items, uint nitems) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment