Commit 3c209bfc authored by Sergei Petrunia's avatar Sergei Petrunia

MDEV-25994: Crash with union of my_decimal type in ORDER BY clause

When single-row subquery fails with "Subquery reutrns more than 1 row"
error, it will raise an error and return NULL.

On the other hand, Item_singlerow_subselect sets item->maybe_null=0
for table-less subqueries like "(SELECT not_null_value)"  (*)

This discrepancy (item with maybe_null=0 returning NULL) causes the
code in Type_handler_decimal_result::make_sort_key_part() to crash.

Fixed this by allowing inference (*) only when the subquery is NOT a
UNION.
parent 2be617d8
...@@ -3508,4 +3508,24 @@ DELETE FROM t1 ORDER BY c; ...@@ -3508,4 +3508,24 @@ DELETE FROM t1 ORDER BY c;
DROP TABLE t1; DROP TABLE t1;
SET @@SESSION.max_sort_length=DEFAULT; SET @@SESSION.max_sort_length=DEFAULT;
SET sql_mode=DEFAULT; SET sql_mode=DEFAULT;
#
# MDEV-25994 Crash with union of my_decimal type in ORDER BY clause
#
CREATE TABLE t1 (v1 INTEGER) ;
INSERT INTO t1 (v1) VALUES (8);
UPDATE t1 SET v1 = 1 ORDER BY (SELECT 1.1 UNION SELECT -1);
ERROR 21000: Subquery returns more than 1 row
# This one must be successful
UPDATE t1 SET v1 = 2 ORDER BY (SELECT 1 UNION SELECT 1);
UPDATE t1 SET v1 = 3 ORDER BY (SELECT 'a' UNION SELECT 'b');
ERROR 21000: Subquery returns more than 1 row
# Insert some more data
INSERT INTO t1 (v1) VALUES (8),(9),(100),(-234),(46584),(0);
UPDATE t1 SET v1 = v1+1 ORDER BY (SELECT 100.122 UNION SELECT -189.2);
ERROR 21000: Subquery returns more than 1 row
# This one must be successful
UPDATE t1 SET v1 = v1-200 ORDER BY (SELECT 1 UNION SELECT 1);
UPDATE t1 SET v1 = v1 ORDER BY (SELECT 'abc' UNION SELECT 'bbb');
ERROR 21000: Subquery returns more than 1 row
DROP TABLE t1;
# End of 10.2 tests # End of 10.2 tests
...@@ -1261,7 +1261,7 @@ a ...@@ -1261,7 +1261,7 @@ a
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL `a` bigint(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
create table t1 (a int); create table t1 (a int);
......
...@@ -1265,7 +1265,7 @@ a ...@@ -1265,7 +1265,7 @@ a
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL `a` bigint(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
create table t1 (a int); create table t1 (a int);
......
...@@ -1268,7 +1268,7 @@ a ...@@ -1268,7 +1268,7 @@ a
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL `a` bigint(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
create table t1 (a int); create table t1 (a int);
......
...@@ -1264,7 +1264,7 @@ a ...@@ -1264,7 +1264,7 @@ a
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL `a` bigint(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
create table t1 (a int); create table t1 (a int);
......
...@@ -1267,7 +1267,7 @@ a ...@@ -1267,7 +1267,7 @@ a
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL `a` bigint(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
create table t1 (a int); create table t1 (a int);
......
...@@ -1264,7 +1264,7 @@ a ...@@ -1264,7 +1264,7 @@ a
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`a` bigint(20) NOT NULL `a` bigint(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
create table t1 (a int); create table t1 (a int);
......
...@@ -2331,5 +2331,30 @@ DROP TABLE t1; ...@@ -2331,5 +2331,30 @@ DROP TABLE t1;
SET @@SESSION.max_sort_length=DEFAULT; SET @@SESSION.max_sort_length=DEFAULT;
SET sql_mode=DEFAULT; SET sql_mode=DEFAULT;
--echo #
--echo # MDEV-25994 Crash with union of my_decimal type in ORDER BY clause
--echo #
CREATE TABLE t1 (v1 INTEGER) ;
INSERT INTO t1 (v1) VALUES (8);
--error ER_SUBQUERY_NO_1_ROW
UPDATE t1 SET v1 = 1 ORDER BY (SELECT 1.1 UNION SELECT -1);
--echo # This one must be successful
UPDATE t1 SET v1 = 2 ORDER BY (SELECT 1 UNION SELECT 1);
--error ER_SUBQUERY_NO_1_ROW
UPDATE t1 SET v1 = 3 ORDER BY (SELECT 'a' UNION SELECT 'b');
-- echo # Insert some more data
INSERT INTO t1 (v1) VALUES (8),(9),(100),(-234),(46584),(0);
--error ER_SUBQUERY_NO_1_ROW
UPDATE t1 SET v1 = v1+1 ORDER BY (SELECT 100.122 UNION SELECT -189.2);
--echo # This one must be successful
UPDATE t1 SET v1 = v1-200 ORDER BY (SELECT 1 UNION SELECT 1);
--error ER_SUBQUERY_NO_1_ROW
UPDATE t1 SET v1 = v1 ORDER BY (SELECT 'abc' UNION SELECT 'bbb');
DROP TABLE t1;
--echo # End of 10.2 tests --echo # End of 10.2 tests
...@@ -1266,11 +1266,18 @@ bool Item_singlerow_subselect::fix_length_and_dec() ...@@ -1266,11 +1266,18 @@ bool Item_singlerow_subselect::fix_length_and_dec()
} }
unsigned_flag= value->unsigned_flag; unsigned_flag= value->unsigned_flag;
/* /*
If there are not tables in subquery then ability to have NULL value If the subquery has no tables (1) and is not a UNION (2), like:
depends on SELECT list (if single row subquery have tables then it
always can be NULL if there are not records fetched). (SELECT subq_value)
then its NULLability is the same as subq_value's NULLability.
(1): A subquery that uses a table will return NULL when the table is empty.
(2): A UNION subquery will return NULL if it produces a "Subquery returns
more than one row" error.
*/ */
if (engine->no_tables()) if (engine->no_tables() &&
engine->engine_type() != subselect_engine::UNION_ENGINE)
maybe_null= engine->may_be_null(); maybe_null= engine->may_be_null();
else else
{ {
......
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