mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
MDEV-7759 NULLIF(x,y) is not equal to CASE WHEN x=y THEN NULL ELSE x END
This commit is contained in:
parent
80f03abcca
commit
e91bc2e91d
5 changed files with 93 additions and 32 deletions
|
@ -502,6 +502,10 @@ NULLIF(TIMESTAMP'2001-01-01 00:00:00',1.0),
|
||||||
NULLIF(TIMESTAMP'2001-01-01 00:00:00',1e0),
|
NULLIF(TIMESTAMP'2001-01-01 00:00:00',1e0),
|
||||||
NULLIF(TIMESTAMP'2001-01-01 00:00:00','2001-01-01'),
|
NULLIF(TIMESTAMP'2001-01-01 00:00:00','2001-01-01'),
|
||||||
NULLIF(TIMESTAMP'2001-01-01 00:00:00',TIME'00:00:00');
|
NULLIF(TIMESTAMP'2001-01-01 00:00:00',TIME'00:00:00');
|
||||||
|
Warnings:
|
||||||
|
Warning 1292 Incorrect datetime value: '1'
|
||||||
|
Warning 1292 Incorrect datetime value: '1.0'
|
||||||
|
Warning 1292 Incorrect datetime value: '1'
|
||||||
SHOW CREATE TABLE t1;
|
SHOW CREATE TABLE t1;
|
||||||
Table Create Table
|
Table Create Table
|
||||||
t1 CREATE TABLE `t1` (
|
t1 CREATE TABLE `t1` (
|
||||||
|
@ -518,6 +522,10 @@ NULLIF(DATE'2001-01-01',1.0),
|
||||||
NULLIF(DATE'2001-01-01',1e0),
|
NULLIF(DATE'2001-01-01',1e0),
|
||||||
NULLIF(DATE'2001-01-01','2001-01-01'),
|
NULLIF(DATE'2001-01-01','2001-01-01'),
|
||||||
NULLIF(DATE'2001-01-01',TIME'00:00:00');
|
NULLIF(DATE'2001-01-01',TIME'00:00:00');
|
||||||
|
Warnings:
|
||||||
|
Warning 1292 Incorrect datetime value: '1'
|
||||||
|
Warning 1292 Incorrect datetime value: '1.0'
|
||||||
|
Warning 1292 Incorrect datetime value: '1'
|
||||||
SHOW CREATE TABLE t1;
|
SHOW CREATE TABLE t1;
|
||||||
Table Create Table
|
Table Create Table
|
||||||
t1 CREATE TABLE `t1` (
|
t1 CREATE TABLE `t1` (
|
||||||
|
@ -1350,5 +1358,37 @@ t2 CREATE TABLE `t2` (
|
||||||
DROP TABLE t2;
|
DROP TABLE t2;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
#
|
#
|
||||||
|
# MDEV-7759 NULLIF(x,y) is not equal to CASE WHEN x=y THEN NULL ELSE x END
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a YEAR);
|
||||||
|
INSERT INTO t1 VALUES (2010),(2020);
|
||||||
|
SELECT * FROM t1 WHERE a=2010 AND NULLIF(10.1,a) IS NULL;
|
||||||
|
a
|
||||||
|
2010
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND NULLIF(10.1,a) IS NULL;
|
||||||
|
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` = 2010) and 1)
|
||||||
|
SELECT * FROM t1 WHERE a=2010 AND CASE WHEN 10.1=a THEN NULL ELSE 10.1 END IS NULL;
|
||||||
|
a
|
||||||
|
2010
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND CASE WHEN 10.1=a THEN NULL ELSE 10.1 END IS NULL;
|
||||||
|
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` = 2010) and 1)
|
||||||
|
DROP TABLE t1;
|
||||||
|
# Two warnings expected
|
||||||
|
CREATE TABLE t1 AS SELECT
|
||||||
|
NULLIF(TIMESTAMP'2001-01-01 00:00:00',1) AS a,
|
||||||
|
CASE WHEN TIMESTAMP'2001-01-01 00:00:00'=1 THEN NULL
|
||||||
|
ELSE TIMESTAMP'2001-01-01 00:00:00'
|
||||||
|
END AS b;
|
||||||
|
Warnings:
|
||||||
|
Warning 1292 Incorrect datetime value: '1'
|
||||||
|
Warning 1292 Incorrect datetime value: '1'
|
||||||
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
# End of 10.1 tests
|
# End of 10.1 tests
|
||||||
#
|
#
|
||||||
|
|
|
@ -849,6 +849,26 @@ DROP TABLE t2;
|
||||||
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-7759 NULLIF(x,y) is not equal to CASE WHEN x=y THEN NULL ELSE x END
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (a YEAR);
|
||||||
|
INSERT INTO t1 VALUES (2010),(2020);
|
||||||
|
SELECT * FROM t1 WHERE a=2010 AND NULLIF(10.1,a) IS NULL;
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND NULLIF(10.1,a) IS NULL;
|
||||||
|
SELECT * FROM t1 WHERE a=2010 AND CASE WHEN 10.1=a THEN NULL ELSE 10.1 END IS NULL;
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=2010 AND CASE WHEN 10.1=a THEN NULL ELSE 10.1 END IS NULL;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo # Two warnings expected
|
||||||
|
CREATE TABLE t1 AS SELECT
|
||||||
|
NULLIF(TIMESTAMP'2001-01-01 00:00:00',1) AS a,
|
||||||
|
CASE WHEN TIMESTAMP'2001-01-01 00:00:00'=1 THEN NULL
|
||||||
|
ELSE TIMESTAMP'2001-01-01 00:00:00'
|
||||||
|
END AS b;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.1 tests
|
--echo # End of 10.1 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
|
|
@ -552,6 +552,26 @@ void Item_func::convert_const_compared_to_int_field(THD *thd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Item_func::setup_args_and_comparator(THD *thd, Arg_comparator *cmp)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(arg_count == 2);
|
||||||
|
|
||||||
|
if (args[0]->cmp_type() == STRING_RESULT &&
|
||||||
|
args[1]->cmp_type() == STRING_RESULT &&
|
||||||
|
agg_arg_charsets_for_comparison(cmp->cmp_collation, args, 2))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
args[0]->cmp_context= args[1]->cmp_context=
|
||||||
|
item_cmp_type(args[0]->result_type(), args[1]->result_type());
|
||||||
|
|
||||||
|
// Convert constants when compared to int/year field, unless this is LIKE
|
||||||
|
if (functype() != LIKE_FUNC)
|
||||||
|
convert_const_compared_to_int_field(thd);
|
||||||
|
|
||||||
|
return cmp->set_cmp_func(this, tmp_arg, tmp_arg + 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_bool_func2::fix_length_and_dec()
|
void Item_bool_func2::fix_length_and_dec()
|
||||||
{
|
{
|
||||||
max_length= 1; // Function returns 0 or 1
|
max_length= 1; // Function returns 0 or 1
|
||||||
|
@ -562,32 +582,7 @@ void Item_bool_func2::fix_length_and_dec()
|
||||||
*/
|
*/
|
||||||
if (!args[0] || !args[1])
|
if (!args[0] || !args[1])
|
||||||
return;
|
return;
|
||||||
|
setup_args_and_comparator(current_thd, &cmp);
|
||||||
/*
|
|
||||||
We allow to convert to Unicode character sets in some cases.
|
|
||||||
The conditions when conversion is possible are:
|
|
||||||
- arguments A and B have different charsets
|
|
||||||
- A wins according to coercibility rules
|
|
||||||
- character set of A is superset for character set of B
|
|
||||||
|
|
||||||
If all of the above is true, then it's possible to convert
|
|
||||||
B into the character set of A, and then compare according
|
|
||||||
to the collation of A.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DTCollation coll;
|
|
||||||
if (args[0]->cmp_type() == STRING_RESULT &&
|
|
||||||
args[1]->cmp_type() == STRING_RESULT &&
|
|
||||||
agg_arg_charsets_for_comparison(coll, args, 2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
args[0]->cmp_context= args[1]->cmp_context=
|
|
||||||
item_cmp_type(args[0]->result_type(), args[1]->result_type());
|
|
||||||
|
|
||||||
// Convert constants when compared to int/year field, unless this is LIKE
|
|
||||||
if (functype() != LIKE_FUNC)
|
|
||||||
convert_const_compared_to_int_field(current_thd);
|
|
||||||
set_cmp_func();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2760,12 +2755,8 @@ Item_func_nullif::fix_length_and_dec()
|
||||||
decimals= m_args0_copy->decimals;
|
decimals= m_args0_copy->decimals;
|
||||||
unsigned_flag= m_args0_copy->unsigned_flag;
|
unsigned_flag= m_args0_copy->unsigned_flag;
|
||||||
fix_char_length(m_args0_copy->max_char_length());
|
fix_char_length(m_args0_copy->max_char_length());
|
||||||
|
|
||||||
convert_const_compared_to_int_field(current_thd);
|
|
||||||
m_args0_copy->cmp_context= args[1]->cmp_context=
|
|
||||||
item_cmp_type(m_args0_copy->result_type(), args[1]->result_type());
|
|
||||||
cmp.set_cmp_func(this, tmp_arg, tmp_arg + 1, m_args0_copy->cmp_context);
|
|
||||||
maybe_null=1;
|
maybe_null=1;
|
||||||
|
setup_args_and_comparator(current_thd, &cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -66,10 +66,11 @@ public:
|
||||||
Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), set_null(TRUE),
|
Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), set_null(TRUE),
|
||||||
comparators(0), thd(0), a_cache(0), b_cache(0) {};
|
comparators(0), thd(0), a_cache(0), b_cache(0) {};
|
||||||
|
|
||||||
|
private:
|
||||||
int set_cmp_func(Item_result_field *owner_arg,
|
int set_cmp_func(Item_result_field *owner_arg,
|
||||||
Item **a1, Item **a2,
|
Item **a1, Item **a2,
|
||||||
Item_result type);
|
Item_result type);
|
||||||
|
public:
|
||||||
inline int set_cmp_func(Item_result_field *owner_arg,
|
inline int set_cmp_func(Item_result_field *owner_arg,
|
||||||
Item **a1, Item **a2, bool set_null_arg)
|
Item **a1, Item **a2, bool set_null_arg)
|
||||||
{
|
{
|
||||||
|
|
|
@ -398,6 +398,15 @@ public:
|
||||||
walk(&Item::call_bool_func_processor, FALSE, (uchar*) &info);
|
walk(&Item::call_bool_func_processor, FALSE, (uchar*) &info);
|
||||||
}
|
}
|
||||||
void convert_const_compared_to_int_field(THD *thd);
|
void convert_const_compared_to_int_field(THD *thd);
|
||||||
|
/**
|
||||||
|
Prepare arguments and setup a comparator.
|
||||||
|
Used in Item_func_xxx with two arguments and a comparator,
|
||||||
|
e.g. Item_bool_func2 and Item_func_nullif.
|
||||||
|
args[0] or args[1] can be modified:
|
||||||
|
- converted to character set and collation of the operation
|
||||||
|
- or replaced to an Item_int_with_ref
|
||||||
|
*/
|
||||||
|
bool setup_args_and_comparator(THD *thd, Arg_comparator *cmp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue