From 20109712aeb3d23e5e975780897ad236cbcd2ddc Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Tue, 14 Apr 2015 23:18:54 +0200 Subject: [PATCH] MDEV-6892: WHERE does not apply Taking into account implicit dependence of constant view field from nullable table of left join added. Fixed finding real table to check if it turned to NULL (materialized view & derived taken into account) Removed incorrect uninitialization. --- mysql-test/r/derived.result | 12 +++++++++++ mysql-test/t/derived.test | 14 ++++++++++++- sql/item.cc | 26 ++++++++++++++++++----- sql/item.h | 24 ++++++++++++++------- sql/table.cc | 42 ++++++++++++++++++------------------- 5 files changed, 83 insertions(+), 35 deletions(-) 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; } } }