diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 62 |
1 files changed, 56 insertions, 6 deletions
diff --git a/sql/item.cc b/sql/item.cc index 415fe4d72af..81c5168b72d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -446,12 +446,13 @@ String *Item_copy_string::val_str(String *str) /* ARGSUSED */ bool Item::fix_fields(THD *thd, - struct st_table_list *list) + struct st_table_list *list, + Item ** ref) { return 0; } -bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) +bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { if (!field) // If field is not checked { @@ -467,7 +468,7 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) mention of table name, but if we join tables in one list it will cause error ER_NON_UNIQ_ERROR in find_field_in_tables. */ - SELECT_LEX *last; + SELECT_LEX *last= 0; for (SELECT_LEX *sl= thd->lex.select->outer_select(); sl && !tmp; sl= sl->outer_select()) @@ -476,6 +477,8 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) if (!tmp) return 1; else + { + depended_from= last; /* Mark all selects from resolved to 1 before select where was found table as depended (of select where was found table) @@ -493,6 +496,7 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) tbl= tbl->next) tbl->shared= 1; } + } } set_field(tmp); } @@ -504,6 +508,14 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) table->used_fields++; table->used_keys&=field->part_of_key; } + if (depended_from != 0 && depended_from->having_fix_field) + { + *ref= new Item_ref((char *)db_name, (char *)table_name, + (char *)field_name); + if (!*ref) + return 1; + return (*ref)->fix_fields(thd, tables, ref); + } return 0; } @@ -787,12 +799,50 @@ bool Item_null::send(THD *thd, String *packet) Find field in select list having the same name */ -bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables) +bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) { if (!ref) { - if (!(ref=find_item_in_list(this,thd->lex.select->item_list))) - return 1; + if (!(ref= find_item_in_list(this,thd->lex.select->item_list))) + { + /* + We can't find table field in table list of current select, + consequently we have to find it in outer subselect(s). + We can't join lists of outer & current select, because of scope + of view rules. For example if both tables (outer & current) have + field 'field' it is not mistake to refer to this field without + mention of table name, but if we join tables in one list it will + cause error ER_NON_UNIQ_ERROR in find_field_in_tables. + */ + SELECT_LEX *last=0; + for (SELECT_LEX *sl= thd->lex.select->outer_select(); + sl && !ref; + sl= sl->outer_select()) + ref= find_item_in_list(this, (last= sl)->item_list); + if (!ref) + return 1; + else + { + depended_from= last; + /* + Mark all selects from resolved to 1 before select where was + found table as depended (of select where was found table) + */ + for (SELECT_LEX *s= thd->lex.select; + s &&s != last; + s= s->outer_select()) + if( !s->depended ) + { + s->depended= 1; //Select is depended of outer select + //Tables will be reopened many times + for (TABLE_LIST *tbl= + (TABLE_LIST*)s->table_list.first; + tbl; + tbl= tbl->next) + tbl->shared= 1; + } + } + } max_length= (*ref)->max_length; maybe_null= (*ref)->maybe_null; decimals= (*ref)->decimals; |