diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 02662f9900a..a7186c6953b 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2160,3 +2160,17 @@ ERROR 42S22: Unknown column 'a2' in 'scalar IN/ALL/ANY subquery' select * from t1 where a1 > any(select b1 from t2); a1 drop table t1,t2; +create table t1 (a integer, b integer); +select (select * from t1) = (select 1,2); +(select * from t1) = (select 1,2) +NULL +select (select 1,2) = (select * from t1); +(select 1,2) = (select * from t1) +NULL +select row(1,2) = ANY (select * from t1); +row(1,2) = ANY (select * from t1) +0 +select row(1,2) != ALL (select * from t1); +row(1,2) != ALL (select * from t1) +1 +drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 3ee498ee380..c8b44252139 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1414,8 +1414,11 @@ SELECT f1 FROM t1 WHERE f1 <> ALL ( SELECT SUM(f1) AS sf1 FROM t2 HAVING sf1 > 10000); drop table t1,t2; + +# # Test for BUG#7885: Server crash when 'any' subselect compared to # non-existant field. +# create table t1 (a1 int); create table t2 (b1 int); --error 1054 @@ -1423,3 +1426,14 @@ select * from t1 where a2 > any(select b1 from t2); select * from t1 where a1 > any(select b1 from t2); drop table t1,t2; + +# +# Comparison subquery with * and row +# +create table t1 (a integer, b integer); +select (select * from t1) = (select 1,2); +select (select 1,2) = (select * from t1); +# queries whih can be converted to IN +select row(1,2) = ANY (select * from t1); +select row(1,2) != ALL (select * from t1); +drop table t1; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 6834799688d..061ed468b78 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -213,7 +213,7 @@ class Item_bool_rowready_func2 :public Item_bool_func2 public: Item_bool_rowready_func2(Item *a, Item *b) :Item_bool_func2(a, b) { - allowed_arg_cols= a->cols(); + allowed_arg_cols= 0; // Fetch this value from first argument } Item *neg_transformer(THD *thd); virtual Item *negated_item(); @@ -390,7 +390,10 @@ class Item_func_interval :public Item_int_func double *intervals; public: Item_func_interval(Item_row *a) - :Item_int_func(a),row(a),intervals(0) { allowed_arg_cols= a->cols(); } + :Item_int_func(a),row(a),intervals(0) + { + allowed_arg_cols= 0; // Fetch this value from first argument + } longlong val_int(); void fix_length_and_dec(); const char *func_name() const { return "interval"; } @@ -743,7 +746,7 @@ class Item_func_in :public Item_int_func Item_func_in(List &list) :Item_int_func(list), array(0), in_item(0), have_null(0) { - allowed_arg_cols= args[0]->cols(); + allowed_arg_cols= 0; // Fetch this value from first argument } longlong val_int(); void fix_length_and_dec(); diff --git a/sql/item_func.cc b/sql/item_func.cc index 7125f4704b8..bff49541252 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -303,10 +303,24 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) We can't yet set item to *arg as fix_fields may change *arg We shouldn't call fix_fields() twice, so check 'fixed' field first */ - if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg)) || - (*arg)->check_cols(allowed_arg_cols)) + if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg))) return 1; /* purecov: inspected */ + item= *arg; + + if (allowed_arg_cols) + { + if (item->check_cols(allowed_arg_cols)) + return 1; + } + else + { + /* we have to fetch allowed_arg_cols from first argument */ + DBUG_ASSERT(arg == args); // it is first argument + allowed_arg_cols= item->cols(); + DBUG_ASSERT(allowed_arg_cols); // Can't be 0 any more + } + if (item->maybe_null) maybe_null=1; diff --git a/sql/item_func.h b/sql/item_func.h index ce2b34499d6..8a5347d675e 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -32,6 +32,10 @@ class Item_func :public Item_result_field { protected: Item **args, *tmp_arg[2]; + /* + Allowed numbers of columns in result (usually 1, which means scalar value) + 0 means get this number from first argument + */ uint allowed_arg_cols; public: uint arg_count; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8516ea76a7e..2597427253c 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1421,13 +1421,15 @@ int subselect_indexsubquery_engine::exec() uint subselect_single_select_engine::cols() { - return select_lex->item_list.elements; + DBUG_ASSERT(select_lex->join); // should be called after fix_fields() + return select_lex->join->fields_list.elements; } uint subselect_union_engine::cols() { - return unit->first_select()->item_list.elements; + DBUG_ASSERT(unit->is_prepared()); // should be called after fix_fields() + return unit->types.elements; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e2e0bc61c23..7cb71607edf 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -371,6 +371,7 @@ public: ulong init_prepare_fake_select_lex(THD *thd); int change_result(select_subselect *result, select_subselect *old_result); + inline bool is_prepared() { return prepared; } friend void lex_start(THD *thd, uchar *buf, uint length); friend int subselect_union_engine::exec();