Commit da561a80 authored by unknown's avatar unknown
Browse files

Fixed bug #24653.

The bug report has demonstrated the following two problems.
1. If an ORDER/GROUP BY list includes a constant expression being 
optimized away and, at the same time, containing single-row
subselects that return more that one row, no error is reported.
Strictly speaking the standard allows to ignore error in this case.
Yet, now a corresponding fatal error is reported in this case.
2. If a query requires sorting by expressions containing single-row
subselects that, however, return more than one row, then the execution
of the query may cause a server crash. 
To fix this some code has been added that blocks execution of a subselect
item in case of a fatal error in the method Item_subselect::exec.


mysql-test/r/subselect.result:
  Added a test cases for bug #24653.
mysql-test/t/subselect.test:
  Added a test cases for bug #24653.
sql/filesort.cc:
  Fixed bug #24653.
  Added a check for fatal error after reading the next row from the table
  in the function find_all_keys.
sql/item.cc:
  Fixed bug #24653.
  Down-ported calculation of the attribute with_subselect of for Item objects.
sql/item.h:
  Fixed bug #24653.
  Down-ported calculation of the attribute with_subselect of for Item objects.
sql/item_cmpfunc.cc:
  Fixed bug #24653.
  Down-ported calculation of the attribute with_subselect of for Item objects.
sql/item_cmpfunc.h:
  Fixed bug #24653.
  Down-ported calculation of the attribute with_subselect of for Item objects.
sql/item_func.cc:
  Fixed bug #24653.
  Down-ported calculation of the attribute with_subselect of for Item objects.
sql/item_subselect.cc:
  Fixed bug #24653.
  Added a check for fatal error in the method Item_subselect::exec
  to block evaluation of subselects in erroneous situations.
  Down-ported calculation of the attribute with_subselect of for Item objects.
sql/sql_select.cc:
  Fixed bug #24653.
  Added a check to verify that any constant expression used
  in ORDER BY and/or GROUP BY lists which is optimized away
  does not contain subselects returning more than one row.
  If it does a fatal error is reported.
parent 6d04643a
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -3026,3 +3026,77 @@ id select_type table type possible_keys key key_len ref rows Extra
1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	
2	SUBQUERY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE
DROP TABLE t1;
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (2), (4), (1), (3);
CREATE TABLE t2 (b int, c int);
INSERT INTO t2 VALUES
(2,1), (1,3), (2,1), (4,4), (2,2), (1,4);
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 2 );
a
2
4
1
3
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 1);
ERROR 21000: Subquery returns more than 1 row
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 2), a;
a
1
2
3
4
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 1), a;
ERROR 21000: Subquery returns more than 1 row
SELECT b, MAX(c) FROM t2 GROUP BY b, (SELECT c FROM t2 WHERE b > 2);
b	MAX(c)
1	4
2	2
4	4
SELECT b, MAX(c) FROM t2 GROUP BY b, (SELECT c FROM t2 WHERE b > 1);
ERROR 21000: Subquery returns more than 1 row
SELECT a FROM t1 GROUP BY a
HAVING IFNULL((SELECT b FROM t2 WHERE b > 2),
(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3;
a
1
2
3
4
SELECT a FROM t1 GROUP BY a
HAVING IFNULL((SELECT b FROM t2 WHERE b > 1),
(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3;
ERROR 21000: Subquery returns more than 1 row
SELECT a FROM t1 GROUP BY a
HAVING IFNULL((SELECT b FROM t2 WHERE b > 4),
(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3;
a
4
SELECT a FROM t1 GROUP BY a
HAVING IFNULL((SELECT b FROM t2 WHERE b > 4),
(SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b)) > 3;
ERROR 21000: Subquery returns more than 1 row
SELECT a FROM t1 
ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 2),
(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b));
a
2
4
1
3
SELECT a FROM t1 
ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 1),
(SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b));
ERROR 21000: Subquery returns more than 1 row
SELECT a FROM t1 
ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 4),
(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b));
a
2
1
3
4
SELECT a FROM t1 
ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 4),
(SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b));
ERROR 21000: Subquery returns more than 1 row
DROP TABLE t1,t2;
+59 −0
Original line number Diff line number Diff line
@@ -1993,4 +1993,63 @@ SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) IS NULL;
EXPLAIN SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) IS NULL;

DROP TABLE t1;

#
# Bug 24653: sorting by expressions containing subselects 
#            that return more than one row
#

CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (2), (4), (1), (3);

CREATE TABLE t2 (b int, c int);
INSERT INTO t2 VALUES
  (2,1), (1,3), (2,1), (4,4), (2,2), (1,4);

SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 2 );
--error 1242   
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 1);  
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 2), a;  
--error 1242   
SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 1), a;
 
SELECT b, MAX(c) FROM t2 GROUP BY b, (SELECT c FROM t2 WHERE b > 2);
--error 1242
SELECT b, MAX(c) FROM t2 GROUP BY b, (SELECT c FROM t2 WHERE b > 1);


SELECT a FROM t1 GROUP BY a
  HAVING IFNULL((SELECT b FROM t2 WHERE b > 2),
                (SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3;
--error 1242
SELECT a FROM t1 GROUP BY a
  HAVING IFNULL((SELECT b FROM t2 WHERE b > 1),
                (SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3;

SELECT a FROM t1 GROUP BY a
  HAVING IFNULL((SELECT b FROM t2 WHERE b > 4),
                (SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3;
--error 1242 
SELECT a FROM t1 GROUP BY a
  HAVING IFNULL((SELECT b FROM t2 WHERE b > 4),
                (SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b)) > 3;

SELECT a FROM t1 
  ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 2),
                  (SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b));
--error 1242
SELECT a FROM t1 
  ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 1),
                  (SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b));

SELECT a FROM t1 
  ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 4),
                  (SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b));
--error 1242
SELECT a FROM t1 
  ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 4),
                  (SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b));

DROP TABLE t1,t2; 

# End of 4.1 tests
+5 −1
Original line number Diff line number Diff line
@@ -387,7 +387,8 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
  byte *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
  my_off_t record;
  TABLE *sort_form;
  volatile my_bool *killed= &current_thd->killed;
  THD *thd= current_thd;
  volatile my_bool *killed= &thd->killed;
  handler *file;
  DBUG_ENTER("find_all_keys");
  DBUG_PRINT("info",("using: %s",(select?select->quick?"ranges":"where":"every row")));
@@ -474,6 +475,9 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
    }
    else
      file->unlock_row();
    /* It does not make sense to read more keys in case of a fatal error */
    if (thd->net.report_error)
      DBUG_RETURN(HA_POS_ERROR);
  }
  (void) file->extra(HA_EXTRA_NO_CACHE);	/* End cacheing of records */
  if (!next_pos)
+1 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ Item::Item():
  collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
  name= 0;
  decimals= 0; max_length= 0;
  with_subselect= 0;

  /* Put item in free list so that we can free all items at end */
  THD *thd= current_thd;
+3 −0
Original line number Diff line number Diff line
@@ -142,6 +142,9 @@ class Item {
  my_bool with_sum_func;
  my_bool fixed;                        /* If item fixed with fix_fields */
  DTCollation collation;
  my_bool with_subselect;               /* If this item is a subselect or some
                                           of its arguments is or contains a
                                           subselect */

  // alloc & destruct is done as start of select using sql_alloc
  Item();
Loading