Commit cf31ccc3 authored by unknown's avatar unknown

Fix for LP BUG#908269 Wrong result with subquery in select list, EXISTS,...

Fix for LP BUG#908269 Wrong result with subquery in select list, EXISTS, constant MyISAM/Aria table.

Problem: When building the condition for JOIN::outer_ref_cond the optimizer forgot to take into account
that this condition could depend on constant tables as well.
parent d21189d7
...@@ -5908,5 +5908,29 @@ a ...@@ -5908,5 +5908,29 @@ a
2009-02-02 2009-02-02
set @@optimizer_switch=@old_optimizer_switch; set @@optimizer_switch=@old_optimizer_switch;
drop table t1; drop table t1;
#
# LP BUG#908269 incorrect condition in case of subqueries depending
# on constant tables
#
CREATE TABLE t1 ( a INT );
INSERT INTO t1 VALUES (1),(5);
CREATE TABLE t2 ( b INT ) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1);
CREATE TABLE t3 ( c INT );
INSERT INTO t3 VALUES (4),(5);
SET optimizer_switch='subquery_cache=off';
SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1;
( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) )
1
NULL
SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1;
( SELECT b FROM t2 WHERE b = a OR b * 0)
1
NULL
SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1;
( SELECT b FROM t2 WHERE b = a OR rand() * 0)
1
NULL
drop table t1,t2,t3;
# return optimizer switch changed in the beginning of this test # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
...@@ -5909,6 +5909,30 @@ a ...@@ -5909,6 +5909,30 @@ a
2009-02-02 2009-02-02
set @@optimizer_switch=@old_optimizer_switch; set @@optimizer_switch=@old_optimizer_switch;
drop table t1; drop table t1;
#
# LP BUG#908269 incorrect condition in case of subqueries depending
# on constant tables
#
CREATE TABLE t1 ( a INT );
INSERT INTO t1 VALUES (1),(5);
CREATE TABLE t2 ( b INT ) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1);
CREATE TABLE t3 ( c INT );
INSERT INTO t3 VALUES (4),(5);
SET optimizer_switch='subquery_cache=off';
SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1;
( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) )
1
NULL
SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1;
( SELECT b FROM t2 WHERE b = a OR b * 0)
1
NULL
SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1;
( SELECT b FROM t2 WHERE b = a OR rand() * 0)
1
NULL
drop table t1,t2,t3;
# return optimizer switch changed in the beginning of this test # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
set optimizer_switch=default; set optimizer_switch=default;
......
...@@ -5905,6 +5905,30 @@ a ...@@ -5905,6 +5905,30 @@ a
2009-02-02 2009-02-02
set @@optimizer_switch=@old_optimizer_switch; set @@optimizer_switch=@old_optimizer_switch;
drop table t1; drop table t1;
#
# LP BUG#908269 incorrect condition in case of subqueries depending
# on constant tables
#
CREATE TABLE t1 ( a INT );
INSERT INTO t1 VALUES (1),(5);
CREATE TABLE t2 ( b INT ) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1);
CREATE TABLE t3 ( c INT );
INSERT INTO t3 VALUES (4),(5);
SET optimizer_switch='subquery_cache=off';
SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1;
( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) )
1
NULL
SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1;
( SELECT b FROM t2 WHERE b = a OR b * 0)
1
NULL
SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1;
( SELECT b FROM t2 WHERE b = a OR rand() * 0)
1
NULL
drop table t1,t2,t3;
# return optimizer switch changed in the beginning of this test # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
set @optimizer_switch_for_subselect_test=null; set @optimizer_switch_for_subselect_test=null;
...@@ -5914,6 +5914,30 @@ a ...@@ -5914,6 +5914,30 @@ a
2009-02-02 2009-02-02
set @@optimizer_switch=@old_optimizer_switch; set @@optimizer_switch=@old_optimizer_switch;
drop table t1; drop table t1;
#
# LP BUG#908269 incorrect condition in case of subqueries depending
# on constant tables
#
CREATE TABLE t1 ( a INT );
INSERT INTO t1 VALUES (1),(5);
CREATE TABLE t2 ( b INT ) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1);
CREATE TABLE t3 ( c INT );
INSERT INTO t3 VALUES (4),(5);
SET optimizer_switch='subquery_cache=off';
SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1;
( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) )
1
NULL
SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1;
( SELECT b FROM t2 WHERE b = a OR b * 0)
1
NULL
SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1;
( SELECT b FROM t2 WHERE b = a OR rand() * 0)
1
NULL
drop table t1,t2,t3;
# return optimizer switch changed in the beginning of this test # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
set optimizer_switch=default; set optimizer_switch=default;
......
...@@ -5905,6 +5905,30 @@ a ...@@ -5905,6 +5905,30 @@ a
2009-02-02 2009-02-02
set @@optimizer_switch=@old_optimizer_switch; set @@optimizer_switch=@old_optimizer_switch;
drop table t1; drop table t1;
#
# LP BUG#908269 incorrect condition in case of subqueries depending
# on constant tables
#
CREATE TABLE t1 ( a INT );
INSERT INTO t1 VALUES (1),(5);
CREATE TABLE t2 ( b INT ) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1);
CREATE TABLE t3 ( c INT );
INSERT INTO t3 VALUES (4),(5);
SET optimizer_switch='subquery_cache=off';
SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1;
( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) )
1
NULL
SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1;
( SELECT b FROM t2 WHERE b = a OR b * 0)
1
NULL
SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1;
( SELECT b FROM t2 WHERE b = a OR rand() * 0)
1
NULL
drop table t1,t2,t3;
# return optimizer switch changed in the beginning of this test # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
set @optimizer_switch_for_subselect_test=null; set @optimizer_switch_for_subselect_test=null;
......
...@@ -4990,5 +4990,33 @@ SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1); ...@@ -4990,5 +4990,33 @@ SELECT * FROM t1 WHERE a IN (SELECT a AS field1 FROM t1 GROUP BY field1);
set @@optimizer_switch=@old_optimizer_switch; set @@optimizer_switch=@old_optimizer_switch;
drop table t1; drop table t1;
--echo #
--echo # LP BUG#908269 incorrect condition in case of subqueries depending
--echo # on constant tables
--echo #
CREATE TABLE t1 ( a INT );
INSERT INTO t1 VALUES (1),(5);
# t2 must be MyISAM or Aria and contain 1 row
CREATE TABLE t2 ( b INT ) ENGINE=MyISAM;
INSERT INTO t2 VALUES (1);
CREATE TABLE t3 ( c INT );
INSERT INTO t3 VALUES (4),(5);
SET optimizer_switch='subquery_cache=off';
SELECT ( SELECT b FROM t2 WHERE b = a OR EXISTS ( SELECT c FROM t3 WHERE c = b ) ) FROM t1;
# This query just for example, it should return the same as above (1 and NULL)
SELECT ( SELECT b FROM t2 WHERE b = a OR b * 0) FROM t1;
# example with "random"
SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1;
drop table t1,t2,t3;
--echo # return optimizer switch changed in the beginning of this test --echo # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
...@@ -8033,14 +8033,33 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -8033,14 +8033,33 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
DBUG_RETURN(1); // Impossible const condition DBUG_RETURN(1); // Impossible const condition
} }
COND *outer_ref_cond= make_cond_for_table(thd, cond, if (join->table_count != join->const_tables)
OUTER_REF_TABLE_BIT, {
OUTER_REF_TABLE_BIT, COND *outer_ref_cond= make_cond_for_table(thd, cond,
-1, FALSE, FALSE); join->const_table_map |
if (outer_ref_cond) OUTER_REF_TABLE_BIT,
{ OUTER_REF_TABLE_BIT,
add_cond_and_fix(thd, &outer_ref_cond, join->outer_ref_cond); -1, FALSE, FALSE);
join->outer_ref_cond= outer_ref_cond; if (outer_ref_cond)
{
add_cond_and_fix(thd, &outer_ref_cond, join->outer_ref_cond);
join->outer_ref_cond= outer_ref_cond;
}
}
else
{
COND *pseudo_bits_cond=
make_cond_for_table(thd, cond,
join->const_table_map |
PSEUDO_TABLE_BITS,
PSEUDO_TABLE_BITS,
-1, FALSE, FALSE);
if (pseudo_bits_cond)
{
add_cond_and_fix(thd, &pseudo_bits_cond,
join->pseudo_bits_cond);
join->pseudo_bits_cond= pseudo_bits_cond;
}
} }
} }
} }
...@@ -14927,14 +14946,15 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) ...@@ -14927,14 +14946,15 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
/* /*
HAVING will be checked after processing aggregate functions, HAVING will be checked after processing aggregate functions,
But WHERE should checked here (we alredy have read tables). But WHERE should checked here (we alredy have read tables).
Notice that make_join_select() splits all conditions into three groups - Notice that make_join_select() splits all conditions in this case
exec_const_cond, outer_ref_cond, and conditions attached to non-constant into two groups exec_const_cond and outer_ref_cond.
tables. Within this IF the latter do not exist. At the same time Within this other conditions are not exists. At the same time
exec_const_cond is already checked either by make_join_select or in the exec_const_cond is already checked either by make_join_select or in the
beginning of JOIN::exec. Therefore here it is sufficient to check only beginning of JOIN::exec. Therefore here it is sufficient to check only
outer_ref_cond. pseudo_bits_cond.
*/ */
if (!join->outer_ref_cond || join->outer_ref_cond->val_int()) DBUG_ASSERT(join->outer_ref_cond == NULL);
if (!join->pseudo_bits_cond || join->pseudo_bits_cond->val_int())
{ {
error= (*end_select)(join, 0, 0); error= (*end_select)(join, 0, 0);
if (error == NESTED_LOOP_OK || error == NESTED_LOOP_QUERY_LIMIT) if (error == NESTED_LOOP_OK || error == NESTED_LOOP_QUERY_LIMIT)
......
...@@ -1111,6 +1111,7 @@ public: ...@@ -1111,6 +1111,7 @@ public:
COND *conds; // ---"--- COND *conds; // ---"---
Item *conds_history; // store WHERE for explain Item *conds_history; // store WHERE for explain
COND *outer_ref_cond; ///<part of conds containing only outer references COND *outer_ref_cond; ///<part of conds containing only outer references
COND *pseudo_bits_cond; // part of conds containing special bita
TABLE_LIST *tables_list; ///<hold 'tables' parameter of mysql_select TABLE_LIST *tables_list; ///<hold 'tables' parameter of mysql_select
List<TABLE_LIST> *join_list; ///< list of joined tables in reverse order List<TABLE_LIST> *join_list; ///< list of joined tables in reverse order
COND_EQUAL *cond_equal; COND_EQUAL *cond_equal;
...@@ -1237,7 +1238,7 @@ public: ...@@ -1237,7 +1238,7 @@ public:
rollup.state= ROLLUP::STATE_NONE; rollup.state= ROLLUP::STATE_NONE;
no_const_tables= FALSE; no_const_tables= FALSE;
outer_ref_cond= 0; outer_ref_cond= pseudo_bits_cond= NULL;
in_to_exists_where= NULL; in_to_exists_where= NULL;
in_to_exists_having= NULL; in_to_exists_having= NULL;
} }
......
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