mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-17325 NULL-ability problems with LEAST() in combination with NO_ZERO_DATE and NO_ZERO_IN_DATE
This commit is contained in:
@ -3755,3 +3755,123 @@ DROP TABLE t1;
|
||||
#
|
||||
# End of 10.3 tests
|
||||
#
|
||||
#
|
||||
# Start of 10.4 tests
|
||||
#
|
||||
#
|
||||
# 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 time value: '999'
|
||||
CREATE TABLE t1 AS SELECT LEAST(999,TIME'10:20:30') AS c1;
|
||||
Warnings:
|
||||
Warning 1292 Incorrect time 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.4 tests
|
||||
#
|
||||
|
@ -615,3 +615,74 @@ DROP TABLE t1;
|
||||
--echo # End of 10.3 tests
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # Start of 10.4 tests
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--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.4 tests
|
||||
--echo #
|
||||
|
@ -3480,6 +3480,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
|
||||
|
@ -3283,6 +3283,8 @@ public:
|
||||
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;
|
||||
|
Reference in New Issue
Block a user