diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index d0f42c3d3ec..7c44466ae92 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -568,3 +568,15 @@ update t1 set balance=(select sum(balance) from (SELECT balance FROM t1 where ac set optimizer_switch=@save_derived_optimizer_switch_bug; drop table t1; set optimizer_switch=@save_derived_optimizer_switch; +# +# MDEV-6892: WHERE does not apply +# +create table t1 (id int); +create table t2 (id int); +insert into t1 values(1),(2),(3); +insert into t2 values(4),(5),(6); +select x.id, message from (select id from t1) x left join +(select id, 1 as message from t2) y on x.id=y.id +where coalesce(message,0) <> 0; +id message +drop table t1,t2; diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 61ae3695a1f..ddce7f55292 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -492,5 +492,17 @@ update t1 set balance=(select sum(balance) from (SELECT balance FROM t1 where ac set optimizer_switch=@save_derived_optimizer_switch_bug; drop table t1; - set optimizer_switch=@save_derived_optimizer_switch; + +--echo # +--echo # MDEV-6892: WHERE does not apply +--echo # +create table t1 (id int); +create table t2 (id int); +insert into t1 values(1),(2),(3); +insert into t2 values(4),(5),(6); +#explain extended +select x.id, message from (select id from t1) x left join +(select id, 1 as message from t2) y on x.id=y.id +where coalesce(message,0) <> 0; +drop table t1,t2; diff --git a/sql/item.cc b/sql/item.cc index cfc5f67dc8e..59ec3e69102 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7949,6 +7949,7 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) return TRUE; if (view->table && view->table->maybe_null) maybe_null= TRUE; + set_null_ref_table(); return FALSE; } @@ -9790,13 +9791,28 @@ void Item_ref::update_used_tables() (*ref)->update_used_tables(); } +void Item_direct_view_ref::update_used_tables() +{ + set_null_ref_table(); + Item_direct_ref::update_used_tables(); +} + + table_map Item_direct_view_ref::used_tables() const { - return get_depended_from() ? - OUTER_REF_TABLE_BIT : - ((view->is_merged_derived() || view->merged || !view->table) ? - (*ref)->used_tables() : - view->table->map); + DBUG_ASSERT(null_ref_table); + + if (get_depended_from()) + return OUTER_REF_TABLE_BIT; + + if (view->is_merged_derived() || view->merged || !view->table) + return ((*ref)->used_tables() ? + (*ref)->used_tables() : + ((null_ref_table != NO_NULL_TABLE) ? + null_ref_table->map : + (table_map)0 )); + + return view->table->map; } table_map Item_direct_view_ref::not_null_tables() const diff --git a/sql/item.h b/sql/item.h index ed50605ef7b..2d7236615a8 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3315,13 +3315,16 @@ class Item_direct_view_ref :public Item_direct_ref #define NO_NULL_TABLE (reinterpret_cast(0x1)) + void set_null_ref_table() + { + if (!view->is_inner_table_of_outer_join() || + !(null_ref_table= view->get_real_join_table())) + null_ref_table= NO_NULL_TABLE; + } + bool check_null_ref() { - if (null_ref_table == NULL) - { - if (!(null_ref_table= view->get_real_join_table())) - null_ref_table= NO_NULL_TABLE; - } + DBUG_ASSERT(null_ref_table); if (null_ref_table != NO_NULL_TABLE && null_ref_table->null_row) { null_value= 1; @@ -3329,6 +3332,7 @@ class Item_direct_view_ref :public Item_direct_ref } return FALSE; } + public: Item_direct_view_ref(Name_resolution_context *context_arg, Item **item, const char *table_name_arg, @@ -3336,7 +3340,11 @@ public: TABLE_LIST *view_arg) :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg), item_equal(0), view(view_arg), - null_ref_table(NULL) {} + null_ref_table(NULL) + { + if (fixed) + set_null_ref_table(); + } bool fix_fields(THD *, Item **); bool eq(const Item *item, bool binary_cmp) const; @@ -3353,8 +3361,10 @@ public: bool subst_argument_checker(uchar **arg); Item *equal_fields_propagator(uchar *arg); Item *replace_equal_field(uchar *arg); - table_map used_tables() const; + table_map used_tables() const; + void update_used_tables(); table_map not_null_tables() const; + bool const_item() const { return used_tables() == 0; } bool walk(Item_processor processor, bool walk_subquery, uchar *arg) { return (*ref)->walk(processor, walk_subquery, arg) || diff --git a/sql/table.cc b/sql/table.cc index 7df2ae641ca..e4dee77171d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5034,7 +5034,8 @@ TABLE *TABLE_LIST::get_real_join_table() TABLE_LIST *tbl= this; while (tbl->table == NULL || tbl->table->reginfo.join_tab == NULL) { - if (tbl->view == NULL && tbl->derived == NULL) + if ((tbl->view == NULL && tbl->derived == NULL) || + tbl->is_materialized_derived()) break; /* we do not support merging of union yet */ DBUG_ASSERT(tbl->view == NULL || @@ -5043,28 +5044,25 @@ TABLE *TABLE_LIST::get_real_join_table() tbl->derived->first_select()->next_select() == NULL); { - List_iterator_fast ti; + List_iterator_fast + ti(tbl->view != NULL ? + tbl->view->select_lex.top_join_list : + tbl->derived->first_select()->top_join_list); + for (;;) { - List_iterator_fast - ti(tbl->view != NULL ? - tbl->view->select_lex.top_join_list : - tbl->derived->first_select()->top_join_list); - for (;;) - { - tbl= NULL; - /* - Find left table in outer join on this level - (the list is reverted). - */ - for (TABLE_LIST *t= ti++; t; t= ti++) - tbl= t; - if (!tbl) - return NULL; // view/derived with no tables - if (!tbl->nested_join) - break; - /* go deeper if we've found nested join */ - ti= tbl->nested_join->join_list; - } + tbl= NULL; + /* + Find left table in outer join on this level + (the list is reverted). + */ + for (TABLE_LIST *t= ti++; t; t= ti++) + tbl= t; + if (!tbl) + return NULL; // view/derived with no tables + if (!tbl->nested_join) + break; + /* go deeper if we've found nested join */ + ti= tbl->nested_join->join_list; } } }