revision-id: ff927d06e89d50f1d9e8e5bbf1798f700dfdd4e6 (mariadb-10.2.31-677-gff927d06e89) parent(s): ab271ee7e22ce1250ec36b09123bfb98bc3f8107 author: Varun Gupta committer: Varun Gupta timestamp: 2021-01-13 17:06:01 +0530 message: MDEV-24519: Server crashes in Charset::set_charset upon SELECT The query causing the issue here has implicit grouping for we have to produce one row with special values for the aggregates (depending on each aggregate function), and NULL values for all non-aggregate fields. The subselect item where implicit grouping was being done, null_value for the subselect item was being reset incorrectly for the case when the implcit grouping produces NULL values for the items in the select list for the subquery. A fix could be that if all the columns of the subquery are nullable then we make sure that the null_value for the subselect is set to TRUE. --- mysql-test/r/subselect4.result | 27 +++++++++++++++++++++++++++ mysql-test/t/subselect4.test | 24 ++++++++++++++++++++++++ sql/item_subselect.cc | 22 +++++++++++++++++++++- sql/item_subselect.h | 1 + 4 files changed, 73 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index c0df4f626b1..a9b89577462 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -2686,4 +2686,31 @@ SELECT * FROM t2; f bar DROP TABLE t1, t2; +# +# MDEV-24519: Server crashes in Charset::set_charset upon SELECT +# +CREATE TABLE t1 (a VARBINARY(8)); +INSERT INTO t1 VALUES ('foo'),('bar'); +CREATE TABLE t2 (b VARBINARY(8)); +EXPLAIN +SELECT a FROM t1 WHERE (a, a) IN (SELECT 'qux', 'qux') AND a = (SELECT MIN(b) FROM t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used +SELECT a FROM t1 WHERE (a, a) IN (SELECT 'qux', 'qux') AND a = (SELECT MIN(b) FROM t2); +a +DROP TABLE t1,t2; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b VARBINARY(8)); +EXPLAIN +SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used +SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2); +a +DROP TABLE t1,t2; # End of 10.2 tests diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index 6eada9b27d9..7c6f294c25e 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -2201,4 +2201,28 @@ SELECT * FROM t2; DROP TABLE t1, t2; +--echo # +--echo # MDEV-24519: Server crashes in Charset::set_charset upon SELECT +--echo # + +CREATE TABLE t1 (a VARBINARY(8)); +INSERT INTO t1 VALUES ('foo'),('bar'); +CREATE TABLE t2 (b VARBINARY(8)); + +EXPLAIN +SELECT a FROM t1 WHERE (a, a) IN (SELECT 'qux', 'qux') AND a = (SELECT MIN(b) FROM t2); +SELECT a FROM t1 WHERE (a, a) IN (SELECT 'qux', 'qux') AND a = (SELECT MIN(b) FROM t2); + +DROP TABLE t1,t2; + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b VARBINARY(8)); + +EXPLAIN +SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2); +SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2); + +DROP TABLE t1,t2; + --echo # End of 10.2 tests diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 802bfca64b7..7d3fcc8d55f 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1296,9 +1296,29 @@ bool Item_singlerow_subselect::null_inside() return 0; } + +/* + @brief + Checks whether all the columns of a subselect are NULL + + @retval + TRUE all columns NULL + FALSE otherwise +*/ +bool Item_singlerow_subselect::all_nulls() +{ + for (uint i= 0; i < max_columns ; i++) + { + if (!row[i]->null_value) + return false; + } + return true; +} + + void Item_singlerow_subselect::bring_value() { - if (!exec() && assigned()) + if (!exec() && assigned() && !all_nulls()) null_value= 0; else reset(); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 2292c22480f..f999e1a5015 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -317,6 +317,7 @@ class Item_singlerow_subselect :public Item_subselect Item** addr(uint i) { return (Item**)row + i; } bool check_cols(uint c); bool null_inside(); + bool all_nulls(); void bring_value(); /**