Commit 78794f32 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 c8611b6e
......@@ -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 t2 values (1), (1);
prepare stmt from "select * from v2 where a = 1";
execute stmt;
a
1
1
1
1
drop view v1, v2;
drop table t1, t2;
CREATE TABLE t1 (a INT);
......
......@@ -3574,9 +3574,7 @@ insert into t1 values (1), (1);
insert into t2 values (1), (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
# !!! Unocomment it when the bug is fixed
# execute stmt;
execute stmt;
drop view v1, v2;
drop table t1, t2;
......
......@@ -652,7 +652,7 @@ void Item_ident::cleanup()
bool Item_ident::remove_dependence_processor(uchar * arg)
{
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;
context= &((st_select_lex *) arg)->context;
DBUG_RETURN(0);
......@@ -2292,17 +2292,17 @@ table_map Item_field::used_tables() const
{
if (field->table->const_table)
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
{
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)
{
if (new_parent == depended_from)
if (new_parent == get_depended_from())
depended_from= NULL;
Name_resolution_context *ctx= new Name_resolution_context();
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)
{
if (depended_from && reference)
{
DBUG_ASSERT(context->select_lex != depended_from);
context->select_lex->register_dependency_item(depended_from, reference);
DBUG_ASSERT(context->select_lex != get_depended_from());
context->select_lex->register_dependency_item(get_depended_from(),
reference);
}
/*
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)
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)->fix_after_pullout(new_parent, 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)
{
(*ref)->fix_after_pullout(new_parent, ref);
if (depended_from == new_parent)
if (get_depended_from() == new_parent)
depended_from= NULL;
}
......@@ -8860,6 +8861,49 @@ void view_error_processor(THD *thd, void *data)
((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
*****************************************************************************/
......
......@@ -1637,6 +1637,7 @@ class Item_ident :public Item
Item_ident(TABLE_LIST *view_arg, const char *field_name_arg);
const char *full_name() const;
void cleanup();
struct st_select_lex *get_depended_from() const;
bool remove_dependence_processor(uchar * arg);
virtual void print(String *str, enum_query_type query_type);
virtual bool change_context_processor(uchar *cntx)
......@@ -2524,15 +2525,8 @@ class Item_ref :public Item_ident
Field *get_tmp_table_field()
{ return result_field ? result_field : (*ref)->get_tmp_table_field(); }
Item *get_tmp_table_item(THD *thd);
table_map used_tables() const
{
return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables();
}
void update_used_tables()
{
if (!depended_from)
(*ref)->update_used_tables();
}
inline table_map used_tables() const;
inline void update_used_tables();
bool const_item() const
{
return (*ref)->const_item();
......@@ -2852,12 +2846,7 @@ class Item_direct_view_ref :public Item_direct_ref
bool subst_argument_checker(uchar **arg);
Item *equal_fields_propagator(uchar *arg);
Item *replace_equal_field(uchar *arg);
table_map used_tables() const
{
return depended_from ?
OUTER_REF_TABLE_BIT :
(view->merged ? (*ref)->used_tables() : view->table->map);
}
table_map used_tables() const;
bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
return (*ref)->walk(processor, walk_subquery, arg) ||
......@@ -2960,15 +2949,7 @@ class Item_ref_null_helper: public Item_ref
bool val_bool();
bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
virtual void print(String *str, enum_query_type query_type);
/*
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);
}
table_map used_tables() const;
};
/*
......
......@@ -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.
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->table->status & STATUS_NO_RECORD)));
if (save_field_value)
......
......@@ -1669,6 +1669,7 @@ void st_select_lex::init_select()
cond_value= having_value= Item::COND_UNDEF;
inner_refs_list.empty();
full_group_by_flag= 0;
merged_into= 0;
}
/*
......@@ -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,
* parent_lex */
subq_select->remap_tables(derived, map, table_no, this);
subq_select->merged_into= this;
return FALSE;
}
......
......@@ -638,6 +638,8 @@ class st_select_lex: public st_select_lex_node
List<TABLE_LIST> leaf_tables;
List<TABLE_LIST> leaf_tables_exec;
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 */
......
......@@ -3903,7 +3903,7 @@ is_local_field (Item *field)
{
return field->real_item()->type() == Item::FIELD_ITEM
&& !(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,
if (left_item->type() == Item::REF_ITEM &&
((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;
left_item= left_item->real_item();
}
if (right_item->type() == Item::REF_ITEM &&
((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;
right_item= right_item->real_item();
}
if (left_item->type() == Item::FIELD_ITEM &&
right_item->type() == Item::FIELD_ITEM &&
!((Item_field*)left_item)->depended_from &&
!((Item_field*)right_item)->depended_from)
!((Item_field*)left_item)->get_depended_from() &&
!((Item_field*)right_item)->get_depended_from())
{
/* The predicate the form field1=field2 is processed */
......@@ -9683,7 +9683,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
Item_field *field_item= 0;
Item *orig_field_item= 0;
if (left_item->type() == Item::FIELD_ITEM &&
!((Item_field*)left_item)->depended_from &&
!((Item_field*)left_item)->get_depended_from() &&
right_item->const_item())
{
orig_field_item= left_item;
......@@ -9691,7 +9691,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
const_item= right_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())
{
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