diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 2618741a520..b5b944583da 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -159,6 +159,23 @@ UNIQUE KEY `email` (`email`) INSERT INTO inscrit (pseudo,email) VALUES ('joce','test'); INSERT INTO inscrit (pseudo,email) VALUES ('joce1','test1'); INSERT INTO inscrit (pseudo,email) VALUES ('2joce1','2test1'); +EXPLAIN SELECT pseudo,(SELECT email FROM inscrit WHERE pseudo=(SELECT +pseudo FROM inscrit WHERE pseudo='joce')) FROM inscrit WHERE pseudo=(SELECT +pseudo FROM inscrit WHERE pseudo='joce'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY inscrit const PRIMARY PRIMARY 35 const 1 +4 SUBSELECT inscrit const PRIMARY PRIMARY 35 const 1 +2 SUBSELECT inscrit const PRIMARY PRIMARY 35 const 1 +3 SUBSELECT inscrit const PRIMARY PRIMARY 35 const 1 +SELECT pseudo FROM inscrit WHERE pseudo=(SELECT pseudo,email FROM +inscrit WHERE pseudo='joce'); +Subselect returns more than 1 field +SELECT pseudo FROM inscrit WHERE pseudo=(SELECT * FROM inscrit WHERE +pseudo='joce'); +Subselect returns more than 1 field +SELECT pseudo FROM inscrit WHERE pseudo=(SELECT pseudo FROM inscrit WHERE pseudo='joce'); +pseudo +joce SELECT pseudo FROM inscrit WHERE pseudo=(SELECT pseudo FROM inscrit WHERE pseudo LIKE '%joce%'); Subselect returns more than 1 record drop table if exists t1,t2,t3,t4,t5,attend,clinic,inscrit; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index c34332d6d90..120cbcbc05f 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -82,6 +82,16 @@ CREATE TABLE `inscrit` ( INSERT INTO inscrit (pseudo,email) VALUES ('joce','test'); INSERT INTO inscrit (pseudo,email) VALUES ('joce1','test1'); INSERT INTO inscrit (pseudo,email) VALUES ('2joce1','2test1'); +EXPLAIN SELECT pseudo,(SELECT email FROM inscrit WHERE pseudo=(SELECT +pseudo FROM inscrit WHERE pseudo='joce')) FROM inscrit WHERE pseudo=(SELECT +pseudo FROM inscrit WHERE pseudo='joce'); +-- error 1239 +SELECT pseudo FROM inscrit WHERE pseudo=(SELECT pseudo,email FROM +inscrit WHERE pseudo='joce'); +-- error 1239 +SELECT pseudo FROM inscrit WHERE pseudo=(SELECT * FROM inscrit WHERE +pseudo='joce'); +SELECT pseudo FROM inscrit WHERE pseudo=(SELECT pseudo FROM inscrit WHERE pseudo='joce'); -- error 1240 SELECT pseudo FROM inscrit WHERE pseudo=(SELECT pseudo FROM inscrit WHERE pseudo LIKE '%joce%'); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 2d08b9cb6b5..de9c7e11313 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -81,15 +81,17 @@ void Item_subselect::make_field (Send_field *tmp_field) bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { - // Is it one field subselect? - if (engine->cols() > max_columns) - { - my_message(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0)); - return 1; - } int res= engine->prepare(); if (!res) + { + // Is it one field subselect? + if (engine->cols() > max_columns) + { + my_message(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0)); + return 1; + } fix_length_and_dec(); + } return res; } @@ -150,6 +152,8 @@ String *Item_singleval_subselect::val_str (String *str) assign_null(); return 0; } + // Assign temporary buffer with stored value + str_value.set(string_value, 0, string_value.length()); return &str_value; } @@ -208,7 +212,7 @@ subselect_single_select_engine::subselect_single_select_engine(THD *thd, select_subselect *result, Item_subselect *item): subselect_engine(thd, item, result), - executed(0), optimized(0) + prepared(0), optimized(0), executed(0) { select_lex= select; SELECT_LEX_UNIT *unit= select_lex->master_unit(); @@ -247,6 +251,9 @@ subselect_union_engine::subselect_union_engine(THD *thd, int subselect_single_select_engine::prepare() { + if (prepared) + return 0; + prepared= 1; SELECT_LEX *save_select= thd->lex.select; thd->lex.select= select_lex; if(join->prepare((TABLE_LIST*) select_lex->table_list.first, diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 5d070871b49..33f82982708 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -80,10 +80,16 @@ public: class Item_singleval_subselect :public Item_subselect { protected: - longlong int_value; /* here stored integer value of this item */ - double real_value; /* here stored real value of this item */ + longlong int_value; /* Here stored integer value of this item */ + double real_value; /* Here stored real value of this item */ + /* + Here stored string value of this item. + (str_value used only as temporary buffer, because it can be changed + by Item::save_field) + */ + String string_value; enum Item_result res_type; /* type of results */ - + public: Item_singleval_subselect(THD *thd, st_select_lex *select_lex); Item_singleval_subselect(Item_singleval_subselect *item): @@ -91,6 +97,7 @@ public: { int_value= item->int_value; real_value= item->real_value; + string_value.set(item->string_value, 0, item->string_value.length()); max_length= item->max_length; decimals= item->decimals; res_type= item->res_type; @@ -172,8 +179,9 @@ public: class subselect_single_select_engine: public subselect_engine { - my_bool executed; /* simple subselect is executed */ + my_bool prepared; /* simple subselect is prepared */ my_bool optimized; /* simple subselect is optimized */ + my_bool executed; /* simple subselect is executed */ st_select_lex *select_lex; /* corresponding select_lex */ JOIN * join; /* corresponding JOIN structure */ public: diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 648e05c1610..f778a721f54 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -884,9 +884,14 @@ bool select_singleval_subselect::send_data(List &items) it->decimals= val_item->decimals; it->binary= val_item->binary; it->int_value= val_item->val_int(); - String *s= val_item->val_str(&it->str_value); - if (s != &it->str_value) - it->str_value.set(*s, 0, s->length()); + String *s= val_item->val_str(&it->string_value); + if (s != &it->string_value) + { + it->string_value.set(*s, 0, s->length()); + } + // TODO: remove when correct charset handling appeared for Item + it->str_value.set(*s, 0, s->length()); // store charset + it->res_type= val_item->result_type(); } it->assigned(1); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 122ceeedc54..46206079084 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -944,7 +944,7 @@ void st_select_lex_unit::init_query() global_parameters= this; select_limit_cnt= HA_POS_ERROR; offset_limit_cnt= 0; - optimized= 0; + prepared= optimized= 0; item= 0; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index acf73f34d5d..fe708d3b782 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -227,6 +227,7 @@ protected: select_result *result; int res; bool describe, found_rows_for_union, + prepared, //prepare phase already performed for UNION (unit) optimized; // optimize phase already performed for UNION (unit) public: /* diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 1a18759eb5b..74cb8f6ffea 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -104,11 +104,16 @@ bool select_union::flush() typedef JOIN * JOIN_P; int st_select_lex_unit::prepare(THD *thd, select_result *result) { + DBUG_ENTER("st_select_lex_unit::prepare"); + + if (prepared) + DBUG_RETURN(0); + prepared= 1; + describe=(first_select()->options & SELECT_DESCRIBE) ? 1 : 0; res= 0; found_rows_for_union= false; TMP_TABLE_PARAM tmp_table_param; - DBUG_ENTER("st_select_lex_unit::prepare"); this->thd= thd; this->result= result; SELECT_LEX *lex_select_save= thd->lex.select;