diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 4a4cbcc38cd..03dcc23c919 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2182,3 +2182,17 @@ ERROR 21000: Operand should contain 2 column(s) select (select * from t1) = row(1,(2,2)); ERROR 21000: Operand should contain 1 column(s) drop table t1; +create table t1 (a integer); +insert into t1 values (1); +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx ; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 as xx, 1 = ALL ( select 1 from t1 where 1 = xx ); +xx 1 = ALL ( select 1 from t1 where 1 = xx ) +1 1 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx from DUAL; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index d8e58facaad..55400dae0be 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1449,3 +1449,19 @@ select row(1,(2,2)) = (select * from t1 ); -- error 1241 select (select * from t1) = row(1,(2,2)); drop table t1; + +# +# Forward reference detection +# +create table t1 (a integer); +insert into t1 values (1); +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx ; +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +select 1 as xx, 1 = ALL ( select 1 from t1 where 1 = xx ); +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx from DUAL; +drop table t1; diff --git a/sql/item.cc b/sql/item.cc index 640cc17411f..412cf315d4a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1482,12 +1482,13 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } else if (refer != (Item **)not_found_item) { - if (!(*refer)->fixed) + if (!last->ref_pointer_array[counter]) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, "forward reference in item list"); return -1; } + DBUG_ASSERT((*refer)->fixed); /* Here, a subset of actions performed by Item_ref::set_properties is not enough. So we pass ptr to NULL into Item_[direct]_ref @@ -2173,12 +2174,13 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) mark_as_dependent(thd, last, thd->lex->current_select, fld); return 0; } - if (!(*ref)->fixed) + if (!last->ref_pointer_array[counter]) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, "forward reference in item list"); return -1; } + DBUG_ASSERT((*ref)->fixed); mark_as_dependent(thd, last, thd->lex->current_select, this); if (place == IN_HAVING) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 263c68a82b7..fc987ef09b2 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2405,6 +2405,20 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, thd->allow_sum_func= allow_sum_func; thd->where="field list"; + /* + To prevent fail on forward lookup we fill it with zerows, + then if we got pointer on zero after find_item_in_list we will know + that it is forward lookup. + + There is other way to solve problem: fill array with pointers to list, + but it will be slower. + + TODO: remove it when (if) we made one list for allfields and + ref_pointer_array + */ + if (ref_pointer_array) + bzero(ref_pointer_array, sizeof(Item *) * fields.elements); + Item **ref= ref_pointer_array; while ((item= it++)) {