Commit 1018c901 authored by Igor Babaev's avatar Igor Babaev

Fixed LP bug #784281.

When a view is merged into a select all the depended_from fields
pointing to the select of the view should have been corrected to
point to the select where the view is used. It was not done yet.
This could lead to wrong results returned by queries such as
one from the test case for bug 33389.
Correction of outer references required walking through all items
of the proccesed qurery. To avoid this the following solution was
implemented.
Each select now contains a pointer to the select it is merged into
(if there is any). Such pointers allow to get the corrected value
of depended_from on the fly. The function Item_ident::get_depended_from
was introduced for this purpose.
parent 704f9703
...@@ -3601,6 +3601,12 @@ create view v2 as select 1 a from t2, v1 where c in ...@@ -3601,6 +3601,12 @@ create view v2 as select 1 a from t2, v1 where c in
insert into t1 values (1), (1); insert into t1 values (1), (1);
insert into t2 values (1), (1); insert into t2 values (1), (1);
prepare stmt from "select * from v2 where a = 1"; prepare stmt from "select * from v2 where a = 1";
execute stmt;
a
1
1
1
1
drop view v1, v2; drop view v1, v2;
drop table t1, t2; drop table t1, t2;
CREATE TABLE t1 (a INT); CREATE TABLE t1 (a INT);
......
...@@ -3574,9 +3574,7 @@ insert into t1 values (1), (1); ...@@ -3574,9 +3574,7 @@ insert into t1 values (1), (1);
insert into t2 values (1), (1); insert into t2 values (1), (1);
prepare stmt from "select * from v2 where a = 1"; prepare stmt from "select * from v2 where a = 1";
# !!! This command returns a wrong result due to a bug in the code of mwl106 execute stmt;
# !!! Unocomment it when the bug is fixed
# execute stmt;
drop view v1, v2; drop view v1, v2;
drop table t1, t2; drop table t1, t2;
......
...@@ -652,7 +652,7 @@ void Item_ident::cleanup() ...@@ -652,7 +652,7 @@ void Item_ident::cleanup()
bool Item_ident::remove_dependence_processor(uchar * arg) bool Item_ident::remove_dependence_processor(uchar * arg)
{ {
DBUG_ENTER("Item_ident::remove_dependence_processor"); DBUG_ENTER("Item_ident::remove_dependence_processor");
if (depended_from == (st_select_lex *) arg) if (get_depended_from() == (st_select_lex *) arg)
depended_from= 0; depended_from= 0;
context= &((st_select_lex *) arg)->context; context= &((st_select_lex *) arg)->context;
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -2292,17 +2292,17 @@ table_map Item_field::used_tables() const ...@@ -2292,17 +2292,17 @@ table_map Item_field::used_tables() const
{ {
if (field->table->const_table) if (field->table->const_table)
return 0; // const item return 0; // const item
return (depended_from ? OUTER_REF_TABLE_BIT : field->table->map); return (get_depended_from() ? OUTER_REF_TABLE_BIT : field->table->map);
} }
table_map Item_field::all_used_tables() const table_map Item_field::all_used_tables() const
{ {
return (depended_from ? OUTER_REF_TABLE_BIT : field->table->map); return (get_depended_from() ? OUTER_REF_TABLE_BIT : field->table->map);
} }
void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref) void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref)
{ {
if (new_parent == depended_from) if (new_parent == get_depended_from())
depended_from= NULL; depended_from= NULL;
Name_resolution_context *ctx= new Name_resolution_context(); Name_resolution_context *ctx= new Name_resolution_context();
ctx->outer_context= NULL; // We don't build a complete name resolver ctx->outer_context= NULL; // We don't build a complete name resolver
...@@ -6299,8 +6299,9 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) ...@@ -6299,8 +6299,9 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
{ {
if (depended_from && reference) if (depended_from && reference)
{ {
DBUG_ASSERT(context->select_lex != depended_from); DBUG_ASSERT(context->select_lex != get_depended_from());
context->select_lex->register_dependency_item(depended_from, reference); context->select_lex->register_dependency_item(get_depended_from(),
reference);
} }
/* /*
It could be that we're referring to something that's in ancestor selects. It could be that we're referring to something that's in ancestor selects.
...@@ -7260,7 +7261,7 @@ bool Item_outer_ref::fix_fields(THD *thd, Item **reference) ...@@ -7260,7 +7261,7 @@ bool Item_outer_ref::fix_fields(THD *thd, Item **reference)
void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref) void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref)
{ {
if (depended_from == new_parent) if (get_depended_from() == new_parent)
{ {
*ref= outer_ref; *ref= outer_ref;
(*ref)->fix_after_pullout(new_parent, ref); (*ref)->fix_after_pullout(new_parent, ref);
...@@ -7270,7 +7271,7 @@ void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref) ...@@ -7270,7 +7271,7 @@ void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref)
void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr) void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr)
{ {
(*ref)->fix_after_pullout(new_parent, ref); (*ref)->fix_after_pullout(new_parent, ref);
if (depended_from == new_parent) if (get_depended_from() == new_parent)
depended_from= NULL; depended_from= NULL;
} }
...@@ -8860,6 +8861,49 @@ void view_error_processor(THD *thd, void *data) ...@@ -8860,6 +8861,49 @@ void view_error_processor(THD *thd, void *data)
((TABLE_LIST *)data)->hide_view_error(thd); ((TABLE_LIST *)data)->hide_view_error(thd);
} }
inline struct st_select_lex *Item_ident::get_depended_from() const
{
st_select_lex *dep;
if ((dep= depended_from))
for ( ; dep->merged_into; dep= dep->merged_into);
return dep;
}
table_map Item_ref::used_tables() const
{
return get_depended_from() ? OUTER_REF_TABLE_BIT : (*ref)->used_tables();
}
void Item_ref::update_used_tables()
{
if (!get_depended_from())
(*ref)->update_used_tables();
}
table_map Item_direct_view_ref::used_tables() const
{
return get_depended_from() ?
OUTER_REF_TABLE_BIT :
(view->merged ? (*ref)->used_tables() : view->table->map);
}
/*
we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE
*/
table_map Item_ref_null_helper::used_tables() const
{
return (get_depended_from() ?
OUTER_REF_TABLE_BIT :
(*ref)->used_tables() | RAND_TABLE_BIT);
}
/***************************************************************************** /*****************************************************************************
** Instantiate templates ** Instantiate templates
*****************************************************************************/ *****************************************************************************/
......
...@@ -1637,6 +1637,7 @@ public: ...@@ -1637,6 +1637,7 @@ public:
Item_ident(TABLE_LIST *view_arg, const char *field_name_arg); Item_ident(TABLE_LIST *view_arg, const char *field_name_arg);
const char *full_name() const; const char *full_name() const;
void cleanup(); void cleanup();
struct st_select_lex *get_depended_from() const;
bool remove_dependence_processor(uchar * arg); bool remove_dependence_processor(uchar * arg);
virtual void print(String *str, enum_query_type query_type); virtual void print(String *str, enum_query_type query_type);
virtual bool change_context_processor(uchar *cntx) virtual bool change_context_processor(uchar *cntx)
...@@ -2524,15 +2525,8 @@ public: ...@@ -2524,15 +2525,8 @@ public:
Field *get_tmp_table_field() Field *get_tmp_table_field()
{ return result_field ? result_field : (*ref)->get_tmp_table_field(); } { return result_field ? result_field : (*ref)->get_tmp_table_field(); }
Item *get_tmp_table_item(THD *thd); Item *get_tmp_table_item(THD *thd);
table_map used_tables() const inline table_map used_tables() const;
{ inline void update_used_tables();
return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables();
}
void update_used_tables()
{
if (!depended_from)
(*ref)->update_used_tables();
}
bool const_item() const bool const_item() const
{ {
return (*ref)->const_item(); return (*ref)->const_item();
...@@ -2852,12 +2846,7 @@ public: ...@@ -2852,12 +2846,7 @@ public:
bool subst_argument_checker(uchar **arg); bool subst_argument_checker(uchar **arg);
Item *equal_fields_propagator(uchar *arg); Item *equal_fields_propagator(uchar *arg);
Item *replace_equal_field(uchar *arg); Item *replace_equal_field(uchar *arg);
table_map used_tables() const table_map used_tables() const;
{
return depended_from ?
OUTER_REF_TABLE_BIT :
(view->merged ? (*ref)->used_tables() : view->table->map);
}
bool walk(Item_processor processor, bool walk_subquery, uchar *arg) bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
{ {
return (*ref)->walk(processor, walk_subquery, arg) || return (*ref)->walk(processor, walk_subquery, arg) ||
...@@ -2960,15 +2949,7 @@ public: ...@@ -2960,15 +2949,7 @@ public:
bool val_bool(); bool val_bool();
bool get_date(MYSQL_TIME *ltime, uint fuzzydate); bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
virtual void print(String *str, enum_query_type query_type); virtual void print(String *str, enum_query_type query_type);
/* table_map used_tables() const;
we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE
*/
table_map used_tables() const
{
return (depended_from ?
OUTER_REF_TABLE_BIT :
(*ref)->used_tables() | RAND_TABLE_BIT);
}
}; };
/* /*
......
...@@ -426,7 +426,7 @@ static bool convert_constant_item(THD *thd, Item_field *field_item, ...@@ -426,7 +426,7 @@ static bool convert_constant_item(THD *thd, Item_field *field_item,
Don't save field value if no data has been read yet. Don't save field value if no data has been read yet.
Outer constant values are always saved. Outer constant values are always saved.
*/ */
bool save_field_value= (field_item->depended_from && bool save_field_value= (field_item->get_depended_from() &&
(field_item->const_item() || (field_item->const_item() ||
!(field->table->status & STATUS_NO_RECORD))); !(field->table->status & STATUS_NO_RECORD)));
if (save_field_value) if (save_field_value)
......
...@@ -1669,6 +1669,7 @@ void st_select_lex::init_select() ...@@ -1669,6 +1669,7 @@ void st_select_lex::init_select()
cond_value= having_value= Item::COND_UNDEF; cond_value= having_value= Item::COND_UNDEF;
inner_refs_list.empty(); inner_refs_list.empty();
full_group_by_flag= 0; full_group_by_flag= 0;
merged_into= 0;
} }
/* /*
...@@ -3393,6 +3394,7 @@ bool SELECT_LEX::merge_subquery(TABLE_LIST *derived, SELECT_LEX *subq_select, ...@@ -3393,6 +3394,7 @@ bool SELECT_LEX::merge_subquery(TABLE_LIST *derived, SELECT_LEX *subq_select,
/* Walk through child's tables and adjust table map, tablenr, /* Walk through child's tables and adjust table map, tablenr,
* parent_lex */ * parent_lex */
subq_select->remap_tables(derived, map, table_no, this); subq_select->remap_tables(derived, map, table_no, this);
subq_select->merged_into= this;
return FALSE; return FALSE;
} }
......
...@@ -638,6 +638,8 @@ public: ...@@ -638,6 +638,8 @@ public:
List<TABLE_LIST> leaf_tables; List<TABLE_LIST> leaf_tables;
List<TABLE_LIST> leaf_tables_exec; List<TABLE_LIST> leaf_tables_exec;
uint insert_tables; uint insert_tables;
st_select_lex *merged_into; /* select which this select is merged into */
/* (not 0 only for views/derived tables) */
const char *type; /* type of select for EXPLAIN */ const char *type; /* type of select for EXPLAIN */
......
...@@ -3903,7 +3903,7 @@ is_local_field (Item *field) ...@@ -3903,7 +3903,7 @@ is_local_field (Item *field)
{ {
return field->real_item()->type() == Item::FIELD_ITEM return field->real_item()->type() == Item::FIELD_ITEM
&& !(field->used_tables() & OUTER_REF_TABLE_BIT) && !(field->used_tables() & OUTER_REF_TABLE_BIT)
&& !((Item_field *)field->real_item())->depended_from; && !((Item_field *)field->real_item())->get_depended_from();
} }
...@@ -9586,21 +9586,21 @@ static bool check_simple_equality(Item *left_item, Item *right_item, ...@@ -9586,21 +9586,21 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
if (left_item->type() == Item::REF_ITEM && if (left_item->type() == Item::REF_ITEM &&
((Item_ref*)left_item)->ref_type() == Item_ref::VIEW_REF) ((Item_ref*)left_item)->ref_type() == Item_ref::VIEW_REF)
{ {
if (((Item_ref*)left_item)->depended_from) if (((Item_ref*)left_item)->get_depended_from())
return FALSE; return FALSE;
left_item= left_item->real_item(); left_item= left_item->real_item();
} }
if (right_item->type() == Item::REF_ITEM && if (right_item->type() == Item::REF_ITEM &&
((Item_ref*)right_item)->ref_type() == Item_ref::VIEW_REF) ((Item_ref*)right_item)->ref_type() == Item_ref::VIEW_REF)
{ {
if (((Item_ref*)right_item)->depended_from) if (((Item_ref*)right_item)->get_depended_from())
return FALSE; return FALSE;
right_item= right_item->real_item(); right_item= right_item->real_item();
} }
if (left_item->type() == Item::FIELD_ITEM && if (left_item->type() == Item::FIELD_ITEM &&
right_item->type() == Item::FIELD_ITEM && right_item->type() == Item::FIELD_ITEM &&
!((Item_field*)left_item)->depended_from && !((Item_field*)left_item)->get_depended_from() &&
!((Item_field*)right_item)->depended_from) !((Item_field*)right_item)->get_depended_from())
{ {
/* The predicate the form field1=field2 is processed */ /* The predicate the form field1=field2 is processed */
...@@ -9683,7 +9683,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item, ...@@ -9683,7 +9683,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
Item_field *field_item= 0; Item_field *field_item= 0;
Item *orig_field_item= 0; Item *orig_field_item= 0;
if (left_item->type() == Item::FIELD_ITEM && if (left_item->type() == Item::FIELD_ITEM &&
!((Item_field*)left_item)->depended_from && !((Item_field*)left_item)->get_depended_from() &&
right_item->const_item()) right_item->const_item())
{ {
orig_field_item= left_item; orig_field_item= left_item;
...@@ -9691,7 +9691,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item, ...@@ -9691,7 +9691,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
const_item= right_item; const_item= right_item;
} }
else if (right_item->type() == Item::FIELD_ITEM && else if (right_item->type() == Item::FIELD_ITEM &&
!((Item_field*)right_item)->depended_from && !((Item_field*)right_item)->get_depended_from() &&
left_item->const_item()) left_item->const_item())
{ {
orig_field_item= right_item; orig_field_item= right_item;
......
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