diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index c62601946c2..1366a8fe97a 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1239,3 +1239,18 @@ Handler_read_prev 0 Handler_read_rnd 0 Handler_read_rnd_next 6 DROP TABLE t1,t2; +CREATE TABLE t1 (c int PRIMARY KEY, e int NOT NULL); +INSERT INTO t1 VALUES (1,0), (2,1); +CREATE TABLE t2 (d int PRIMARY KEY); +INSERT INTO t2 VALUES (1), (2), (3); +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON e<>0 WHERE c=1 AND d IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t2 index NULL PRIMARY 4 NULL 3 Using where; Using index; Not exists +SELECT * FROM t1 LEFT JOIN t2 ON e<>0 WHERE c=1 AND d IS NULL; +c e d +1 0 NULL +SELECT * FROM t1 LEFT JOIN t2 ON e<>0 WHERE c=1 AND d<=>NULL; +c e d +1 0 NULL +DROP TABLE t1,t2; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 51e79a20d65..1a59dbf8fc2 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -845,3 +845,19 @@ SELECT t1.id, a FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.b IS NULL; show status like 'Handler_read%'; DROP TABLE t1,t2; + +# +# Bug 28571: outer join with false on condition over constant tables +# + +CREATE TABLE t1 (c int PRIMARY KEY, e int NOT NULL); +INSERT INTO t1 VALUES (1,0), (2,1); +CREATE TABLE t2 (d int PRIMARY KEY); +INSERT INTO t2 VALUES (1), (2), (3); + +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON e<>0 WHERE c=1 AND d IS NULL; +SELECT * FROM t1 LEFT JOIN t2 ON e<>0 WHERE c=1 AND d IS NULL; +SELECT * FROM t1 LEFT JOIN t2 ON e<>0 WHERE c=1 AND d<=>NULL; + +DROP TABLE t1,t2; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index db6c134b203..ecdb727bcb4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5666,28 +5666,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) join->const_table_map, (table_map) 0); DBUG_EXECUTE("where",print_where(const_cond,"constants");); - for (JOIN_TAB *tab= join->join_tab+join->const_tables; - tab < join->join_tab+join->tables ; tab++) - { - if (*tab->on_expr_ref) - { - JOIN_TAB *cond_tab= tab->first_inner; - COND *tmp= make_cond_for_table(*tab->on_expr_ref, - join->const_table_map, - ( table_map) 0); - if (!tmp) - continue; - tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl); - if (!tmp) - DBUG_RETURN(1); - tmp->quick_fix_field(); - cond_tab->select_cond= !cond_tab->select_cond ? tmp : - new Item_cond_and(cond_tab->select_cond,tmp); - if (!cond_tab->select_cond) - DBUG_RETURN(1); - cond_tab->select_cond->quick_fix_field(); - } - } if (const_cond && !const_cond->val_int()) { DBUG_PRINT("info",("Found impossible WHERE condition")); @@ -5918,13 +5896,39 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) } /* - Push down all predicates from on expressions. - Each of these predicated are guarded by a variable + Push down conditions from all on expressions. + Each of these conditions are guarded by a variable that turns if off just before null complemented row for - outer joins is formed. Thus, the predicates from an + outer joins is formed. Thus, the condition from an 'on expression' are guaranteed not to be checked for the null complemented row. */ + + /* First push down constant conditions from on expressions */ + for (JOIN_TAB *tab= join->join_tab+join->const_tables; + tab < join->join_tab+join->tables ; tab++) + { + if (*tab->on_expr_ref) + { + JOIN_TAB *cond_tab= tab->first_inner; + COND *tmp= make_cond_for_table(*tab->on_expr_ref, + join->const_table_map, + (table_map) 0); + if (!tmp) + continue; + tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl); + if (!tmp) + DBUG_RETURN(1); + tmp->quick_fix_field(); + cond_tab->select_cond= !cond_tab->select_cond ? tmp : + new Item_cond_and(cond_tab->select_cond,tmp); + if (!cond_tab->select_cond) + DBUG_RETURN(1); + cond_tab->select_cond->quick_fix_field(); + } + } + + /* Push down non-constant conditions from on expressions */ JOIN_TAB *last_tab= tab; while (first_inner_tab && first_inner_tab->last_inner == last_tab) {