[MDEV-3708] LP:928048 - Query containing IN subquery with OR in the where clause returns a wrong result Created: 2012-02-07 Updated: 2015-02-02 Resolved: 2012-10-04 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Bug | Priority: | Critical |
| Reporter: | Igor Babaev | Assignee: | Sergei Petrunia |
| Resolution: | Fixed | Votes: | 0 |
| Labels: | Launchpad | ||
| Attachments: |
|
| Description |
|
A query with IN subquery that can be converted to a semi-join may return a wrong result in maridb-5.3 if the where clause of the subquery contains OR condition. The following test case provides such a query. create table t1 (a int, b int); create table t2 (a int, b int, index i_a(a)); insert into t2 values set optimizer_switch='semijoin=on,materialization=on'; The query in from the test case returns a wrong result if the optimizer switch flags 'semijoin' and 'materialization' are set to 'on', a it returns the correct answer if these flags are set to 'off'. MariaDB [test]> set optimizer_switch='semijoin=on,materialization=on'; MariaDB [test]> select * from t1 where t1.a in (select a from t2 where t2.a=7 or t2.b<=1);
-----
----- MariaDB [test]> set optimizer_switch='semijoin=off,materialization=off'; MariaDB [test]> select * from t1 where t1.a in (select a from t2 where t2.a=7 or t2.b<=1);
-----
----- The warning returned by EXPLAIN EXTENDED executed for the query with MariaDB [test]> set optimizer_switch='semijoin=on,materialization=on'; MariaDB [test]> explain extended
---
--- MariaDB [test]> show warnings;
------
------ |
| Comments |
| Comment by Sergei Petrunia [ 2012-02-08 ] |
|
Re: Query containing IN subquery with OR in the where clause returns a wrong result Equality propagation converts the WHERE clause into this: (multiple equal(7, t1.a, t2.a) or (t2.b <= 1)) This is ok. Then, equality substitution produces this WHERE clause: (t1.a = 7) or (t2.b <= 1) we dont expect this kind of WHERE clauses to be produced when With that strategy, we expect that the WHERE clause can be broken into two
The only thing joining the two parts is the IN-equality. IN-equality is not However, make_join_select() gets this clause: (t1.a = 7) or (t2.b <= 1) which can only be checked when one has both t1.a and t2.b. This never happens, |
| Comment by Igor Babaev [ 2012-02-08 ] |
|
Re: Query containing IN subquery with OR in the where clause returns a wrong result |
| Comment by Sergei Petrunia [ 2012-02-13 ] |
|
Re: Query containing IN subquery with OR in the where clause returns a wrong result Equality propagation assumes certain ordering of tables, and tries to Graphically, if we draw join order like this: equality propagation will try pushing conditions to the left. The problem If we take a query select * from ot1,ot2,ot3,ot4... where col in (select ... from it1, it2) and its SJM query plan: then one can push the condition left along the top line through tables otX, or What equality substitution currently does is to assume the ordering of This almost works, because materialization is only applied to un- otX.col=itY.col presense of equalities of this form changes a lot. |
| Comment by Sergei Petrunia [ 2012-02-13 ] |
|
Re: Query containing IN subquery with OR in the where clause returns a wrong result First, the approach "move each condition as much as possible to the left" Consider the queries: Q1 select * from t1 where t1.col in (select t2.col from t2 where cond(t2.col)) Suppose they both are executed with this query plan: id select_type table type it is apparent that, for both queries 1. cond(t1.col) should be attached to table t1 yet, current equality propagation/substituion scheme will not do that, at least Fixing this is a non-trivial though, because the fix will need to change the walk through the WHERE clause and substitute certain occurences of to something else. (the above definition doesn't cover substitution of |
| Comment by Sergei Petrunia [ 2012-02-13 ] |
|
Re: Query containing IN subquery with OR in the where clause returns a wrong result Let's set a more modest goal of
The idea is that given this chart we "must not attempt to move a condition from one line to another" e.g. don't move the condition from the top line into the bottom or vice The implementation of
if (equality has a const item) { for each equality member tblX.colY produce "tblX.colY=const_item" } else { FIRST= first member in X; for each other element OTHER produce "FIRST=OTHER" } } As for not producing equalities that were "fixed on the upper level": |
| Comment by Rasmus Johansson (Inactive) [ 2012-02-20 ] |
|
Launchpad bug id: 928048 |