Commit 71c69f42 authored by konstantin@mysql.com's avatar konstantin@mysql.com

Fix for Bug#8801: the bug was in co-operation of Item_ref

with view-merge algorithm and prepared statements: in case when some
Item_ref pointing to a view column was substituted with a reference 
pointing to the view expression for that column
Item_ref::ref member of the original Item_ref was left pointing to 
not_found_item (0x1).
As we currently perform expression substition part of the view-merge 
algorithm per each execution of a prepared statement or stored procedure, 
we need to preserve original Item_ref objects usable.
parent dfba6f4e
...@@ -3513,6 +3513,9 @@ Item_ref::Item_ref(Item **item, const char *table_name_par, ...@@ -3513,6 +3513,9 @@ Item_ref::Item_ref(Item **item, const char *table_name_par,
Item_field::fix_fields, here we first search the SELECT and GROUP BY Item_field::fix_fields, here we first search the SELECT and GROUP BY
clauses, and then we search the FROM clause. clauses, and then we search the FROM clause.
POSTCONDITION
Item_ref::ref is 0 or points to a valid item
RETURN RETURN
TRUE if error TRUE if error
FALSE on success FALSE on success
...@@ -3534,6 +3537,19 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ...@@ -3534,6 +3537,19 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
if (ref == not_found_item) /* This reference was not resolved. */ if (ref == not_found_item) /* This reference was not resolved. */
{ {
TABLE_LIST *table_list;
Field *from_field;
SELECT_LEX *last;
ref= 0;
if (!outer_sel || (current_sel->master_unit()->first_select()->linkage ==
DERIVED_TABLE_TYPE))
{
/* The current reference cannot be resolved in this query. */
my_error(ER_BAD_FIELD_ERROR,MYF(0),
this->full_name(), current_thd->where);
return TRUE;
}
/* /*
If there is an outer select, and it is not a derived table (which do If there is an outer select, and it is not a derived table (which do
not support the use of outer fields for now), try to resolve this not support the use of outer fields for now), try to resolve this
...@@ -3543,13 +3559,10 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ...@@ -3543,13 +3559,10 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
subselects may contain columns with the same names. The subselects are subselects may contain columns with the same names. The subselects are
searched starting from the innermost. searched starting from the innermost.
*/ */
if (outer_sel && (current_sel->master_unit()->first_select()->linkage != from_field= (Field*) not_found_field;
DERIVED_TABLE_TYPE)) last= 0;
{
TABLE_LIST *table_list;
Field *from_field= (Field*) not_found_field;
SELECT_LEX *last= 0;
/* The following loop will always be excuted at least once */
for ( ; outer_sel ; for ( ; outer_sel ;
outer_sel= (prev_unit= outer_sel->master_unit())->outer_select()) outer_sel= (prev_unit= outer_sel->master_unit())->outer_select())
{ {
...@@ -3568,16 +3581,24 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ...@@ -3568,16 +3581,24 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
prev_subselect_item->const_item_cache&= (*ref)->const_item(); prev_subselect_item->const_item_cache&= (*ref)->const_item();
break; break;
} }
/*
Set ref to 0 to ensure that we get an error in case we replaced
this item with another item and still use this item in some
other place of the parse tree.
*/
ref= 0;
} }
/* Search in the tables of the FROM clause of the outer select. */ /* Search in the tables of the FROM clause of the outer select. */
table_list= outer_sel->get_table_list(); table_list= outer_sel->get_table_list();
if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list) if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
{
/* /*
It is a primary INSERT st_select_lex => do not resolve against the It is a primary INSERT st_select_lex => do not resolve against
first table. the first table.
*/ */
table_list= table_list->next_local; table_list= table_list->next_local;
}
place= prev_subselect_item->parsing_place; place= prev_subselect_item->parsing_place;
/* /*
...@@ -3599,18 +3620,13 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ...@@ -3599,18 +3620,13 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
field expression to 'reference', i.e. it substitute that field expression to 'reference', i.e. it substitute that
expression instead of this Item_ref expression instead of this Item_ref
*/ */
if ((from_field= find_field_in_tables(thd, this, table_list, from_field= find_field_in_tables(thd, this, table_list,
reference, reference,
IGNORE_EXCEPT_NON_UNIQUE, IGNORE_EXCEPT_NON_UNIQUE,
TRUE)) != TRUE);
not_found_field) if (! from_field)
{ return TRUE;
if (from_field != view_ref_found) if (from_field == view_ref_found)
{
prev_subselect_item->used_tables_cache|= from_field->table->map;
prev_subselect_item->const_item_cache= 0;
}
else
{ {
Item::Type type= (*reference)->type(); Item::Type type= (*reference)->type();
prev_subselect_item->used_tables_cache|= prev_subselect_item->used_tables_cache|=
...@@ -3628,9 +3644,14 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ...@@ -3628,9 +3644,14 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
*/ */
return FALSE; return FALSE;
} }
if (from_field != not_found_field)
{
prev_subselect_item->used_tables_cache|= from_field->table->map;
prev_subselect_item->const_item_cache= 0;
break; break;
} }
} }
DBUG_ASSERT(from_field == not_found_field);
/* Reference is not found => depend on outer (or just error). */ /* Reference is not found => depend on outer (or just error). */
prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
...@@ -3641,25 +3662,8 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ...@@ -3641,25 +3662,8 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
break; /* Do not consider derived tables. */ break; /* Do not consider derived tables. */
} }
DBUG_ASSERT(ref != 0); DBUG_ASSERT(from_field != 0 && from_field != view_ref_found);
if (!from_field)
return TRUE;
if (ref == not_found_item && from_field == not_found_field)
{
my_error(ER_BAD_FIELD_ERROR, MYF(0),
this->full_name(), current_thd->where);
ref= 0; // Safety
return TRUE;
}
if (from_field != not_found_field) if (from_field != not_found_field)
{
/*
Set ref to 0 as we are replacing this item with the found item and
this will ensure we get an error if this item would be used
elsewhere
*/
ref= 0; // Safety
if (from_field != view_ref_found)
{ {
Item_field* fld; Item_field* fld;
if (!(fld= new Item_field(from_field))) if (!(fld= new Item_field(from_field)))
...@@ -3668,34 +3672,20 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ...@@ -3668,34 +3672,20 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
mark_as_dependent(thd, last, thd->lex->current_select, this, fld); mark_as_dependent(thd, last, thd->lex->current_select, this, fld);
return FALSE; return FALSE;
} }
/* if (ref == 0)
We can leave expression substituted from view for next PS/SP
re-execution (i.e. do not register this substitution for reverting
on cleanup() (register_item_tree_changing())), because this subtree
will be fix_field'ed during setup_tables()->setup_ancestor()
(i.e. before all other expressions of query, and references on
tables which do not present in query will not make problems.
Also we suppose that view can't be changed during PS/SP life.
*/
}
else
{
/* Should be checked in resolve_ref_in_select_and_group(). */
DBUG_ASSERT(*ref && (*ref)->fixed);
mark_as_dependent(thd, last, current_sel, this, this);
}
}
else
{ {
/* The current reference cannot be resolved in this query. */ /* The item was not a table field and not a reference */
my_error(ER_BAD_FIELD_ERROR,MYF(0), my_error(ER_BAD_FIELD_ERROR, MYF(0),
this->full_name(), current_thd->where); this->full_name(), current_thd->where);
return TRUE; return TRUE;
} }
/* Should be checked in resolve_ref_in_select_and_group(). */
DBUG_ASSERT(*ref && (*ref)->fixed);
mark_as_dependent(thd, last, current_sel, this, this);
} }
} }
DBUG_ASSERT(*ref);
/* /*
Check if this is an incorrect reference in a group function or forward Check if this is an incorrect reference in a group function or forward
reference. Do not issue an error if this is an unnamed reference inside an reference. Do not issue an error if this is an unnamed reference inside an
...@@ -3716,11 +3706,12 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ...@@ -3716,11 +3706,12 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
set_properties(); set_properties();
if (ref && (*ref)->check_cols(1)) if ((*ref)->check_cols(1))
return 1; return TRUE;
return 0; return FALSE;
} }
void Item_ref::set_properties() void Item_ref::set_properties()
{ {
max_length= (*ref)->max_length; max_length= (*ref)->max_length;
......
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