mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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).
This commit is contained in:
@ -3771,5 +3771,119 @@ t2 CREATE TABLE `t2` (
|
|||||||
DROP TABLE t1, t2;
|
DROP TABLE t1, t2;
|
||||||
SET sql_mode=DEFAULT;
|
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
|
# End of 10.3 tests
|
||||||
#
|
#
|
||||||
|
@ -628,6 +628,68 @@ SET sql_mode=DEFAULT;
|
|||||||
|
|
||||||
|
|
||||||
--echo #
|
--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 #
|
--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
|
NULL 2
|
||||||
DROP TABLE t1;
|
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
|
# 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;
|
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;
|
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 #
|
||||||
--echo # End of 10.1 tests
|
--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::
|
bool Type_handler_real_result::
|
||||||
Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
|
Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
|
||||||
Item **items, uint nitems) const
|
Item **items, uint nitems) const
|
||||||
|
@ -2138,6 +2138,8 @@ public:
|
|||||||
Item *source_expr, Item *source_const) const;
|
Item *source_expr, Item *source_const) const;
|
||||||
bool subquery_type_allows_materialization(const Item *inner,
|
bool subquery_type_allows_materialization(const Item *inner,
|
||||||
const Item *outer) const;
|
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_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_sum_fix_length_and_dec(Item_sum_sum *) const;
|
||||||
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
|
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
|
||||||
|
Reference in New Issue
Block a user