diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 848a90fba8f..87db58f4f04 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -17,6 +17,16 @@ SELECT (SELECT 1),MAX(1) FROM (SELECT 1); 1 1 SELECT (SELECT a) as a; Reference 'a' not supported (forward reference in item list) +EXPLAIN SELECT 1 FROM (SELECT 1 as a) HAVING (SELECT a)=1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY system NULL NULL NULL NULL 1 +3 DEPENDENT SUBSELECT No tables used +2 DERIVED No tables used +SELECT 1 FROM (SELECT 1 as a) HAVING (SELECT a)=1; +1 +1 +SELECT (SELECT 1), a; +Unknown column 'a' in 'field list' drop table if exists t1,t2,t3,t4,t5,t6,t7,t8; create table t1 (a int); create table t2 (a int, b int); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 17f24f387d3..3d0ba76683b 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -8,6 +8,10 @@ SELECT (SELECT 1 FROM (SELECT 1) HAVING b=1) as a,(SELECT 1 FROM (SELECT 1) HAVI SELECT (SELECT 1),MAX(1) FROM (SELECT 1); -- error 1245 SELECT (SELECT a) as a; +EXPLAIN SELECT 1 FROM (SELECT 1 as a) HAVING (SELECT a)=1; +SELECT 1 FROM (SELECT 1 as a) HAVING (SELECT a)=1; +-- error 1054 +SELECT (SELECT 1), a; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8; create table t1 (a int); create table t2 (a int, b int); diff --git a/sql/item.cc b/sql/item.cc index 3ec6e9a3aa9..f5733d2151d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -468,7 +468,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) (last= sl)->get_table_list(), 0)) != not_found_field) break; - if((refer= find_item_in_list(this, (last= sl)->item_list, + if ((refer= find_item_in_list(this, sl->item_list, REPORT_EXCEPT_NOT_FOUND)) != (Item **)not_found_item) break; @@ -867,6 +867,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) REPORT_ALL_ERRORS))) == (Item **)not_found_item) { + Field *tmp= (Field*) not_found_field; /* We can't find table field in table list of current select, consequently we have to find it in outer subselect(s). @@ -878,16 +879,21 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) */ SELECT_LEX *last=0; for ( ; sl ; sl= sl->outer_select()) - if((ref= find_item_in_list(this, (last= sl)->item_list, + { + if ((ref= find_item_in_list(this, (last= sl)->item_list, REPORT_EXCEPT_NOT_FOUND)) != (Item **)not_found_item) break; + if ((tmp= find_field_in_tables(thd, this, + sl->get_table_list(), + 0)) != not_found_field); + } if (!ref) - { return 1; - } - else if (ref == (Item **)not_found_item) + else if (!tmp) + return -1; + else if (ref == (Item **)not_found_item && tmp == not_found_field) { // Call to report error find_item_in_list(this, @@ -896,6 +902,16 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) ref= 0; return 1; } + else if (tmp != not_found_field) + { + ref= 0; // To prevent "delete *ref;" on ~Item_erf() of this item + Item_field* f; + if (!((*reference)= f= new Item_field(tmp))) + return 1; + f->depended_from= last; + thd->lex.current_select->mark_as_dependent(last); + return 0; + } else { depended_from= last; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 01ce5fad4a6..7650ecc01c0 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -81,6 +81,7 @@ void Item_subselect::make_field (Send_field *tmp_field) bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { + char const *save_where= thd->where; int res= engine->prepare(); if (!res) { @@ -93,6 +94,7 @@ bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) fix_length_and_dec(); } fixed= 1; + thd->where= save_where; return res; } @@ -312,11 +314,13 @@ void subselect_union_engine::fix_length_and_dec() int subselect_single_select_engine::exec() { DBUG_ENTER("subselect_single_select_engine::exec"); + char const *save_where= join->thd->where; if (!optimized) { optimized=1; if (join->optimize()) { + join->thd->where= save_where; executed= 1; DBUG_RETURN(join->error?join->error:1); } @@ -324,7 +328,10 @@ int subselect_single_select_engine::exec() if (select_lex->dependent && executed) { if (join->reinit()) + { + join->thd->where= save_where; DBUG_RETURN(1); + } item->assign_null(); item->assigned((executed= 0)); } @@ -335,14 +342,19 @@ int subselect_single_select_engine::exec() join->exec(); join->thd->lex.current_select= save_select; executed= 1; + join->thd->where= save_where; DBUG_RETURN(join->error||thd->fatal_error); } + join->thd->where= save_where; DBUG_RETURN(0); } int subselect_union_engine::exec() { - return unit->exec(); + char const *save_where= unit->thd->where; + int res= unit->exec(); + unit->thd->where= save_where; + return res; } uint subselect_single_select_engine::cols() diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3ba88d493bd..0b6c2872925 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -463,7 +463,7 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock); bool drop_locked_tables(THD *thd,const char *db, const char *table_name); void abort_locked_tables(THD *thd,const char *db, const char *table_name); extern const Field *not_found_field; -Field *find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables, +Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, bool report_error); Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, bool check_grant,bool allow_rowid); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d105d44fe12..755d64a97e8 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1861,7 +1861,7 @@ const Field *not_found_field= (Field*) 0x1; */ Field * -find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables, +find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, bool report_error) { Field *found=0; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index dd41af4b250..53bd0c0489a 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -294,6 +294,7 @@ public: int cleanup(); friend void mysql_init_query(THD *thd); + friend int subselect_union_engine::exec(); private: bool create_total_list_n_last_return(THD *thd, st_lex *lex, TABLE_LIST ***result);