diff options
-rw-r--r-- | mysql-test/r/subselect.result | 4 | ||||
-rw-r--r-- | mysql-test/t/subselect.test | 6 | ||||
-rw-r--r-- | sql/item.cc | 43 | ||||
-rw-r--r-- | sql/item_subselect.cc | 3 | ||||
-rw-r--r-- | sql/mysql_priv.h | 7 | ||||
-rw-r--r-- | sql/sql_base.cc | 85 | ||||
-rw-r--r-- | sql/sql_select.cc | 4 |
7 files changed, 121 insertions, 31 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index ec5a12cdfc8..2618741a520 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -131,6 +131,8 @@ patient_uq clinic_uq 1 1 1 2 2 2 +select * from t1 where a= (select a from t2,t4 where t2.b=t4.b); +Column: 'a' in field list is ambiguous drop table if exists t1,t2,t3; CREATE TABLE t3 (a varchar(20),b char(1) NOT NULL default '0'); INSERT INTO t3 VALUES ('W','a'),('A','c'),('J','b'); @@ -159,4 +161,4 @@ INSERT INTO inscrit (pseudo,email) VALUES ('joce1','test1'); INSERT INTO inscrit (pseudo,email) VALUES ('2joce1','2test1'); SELECT pseudo FROM inscrit WHERE pseudo=(SELECT pseudo FROM inscrit WHERE pseudo LIKE '%joce%'); Subselect returns more than 1 record -drop table if exists inscrit; +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 00d58c218aa..c34332d6d90 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -53,6 +53,10 @@ insert into clinic values(1,"Oblastnaia bolnitsa"),(2,"Bolnitsa Krasnogo Kresta" insert into attend values (1,1),(1,2),(2,2),(1,3); select * from attend where exists (select * from clinic where uq = clinic_uq); +# not unique fields +-- error 1052 +select * from t1 where a= (select a from t2,t4 where t2.b=t4.b); + # different tipes & group functions drop table if exists t1,t2,t3; @@ -81,4 +85,4 @@ INSERT INTO inscrit (pseudo,email) VALUES ('2joce1','2test1'); -- error 1240 SELECT pseudo FROM inscrit WHERE pseudo=(SELECT pseudo FROM inscrit WHERE pseudo LIKE '%joce%'); -drop table if exists inscrit;
\ No newline at end of file +drop table if exists t1,t2,t3,t4,t5,attend,clinic,inscrit;
\ No newline at end of file diff --git a/sql/item.cc b/sql/item.cc index f1e25fb4d97..6da53b98657 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -432,7 +432,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) if (!field) // If field is not checked { Field *tmp; - if (!(tmp=find_field_in_tables(thd, this, tables, 0))) + if ((tmp= find_field_in_tables(thd, this, tables, 0)) == not_found_field) { /* We can't find table field in table list of current select, @@ -445,14 +445,18 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) */ SELECT_LEX *last= 0; for (SELECT_LEX *sl= thd->lex.select->outer_select(); - sl && !tmp; + sl; sl= sl->outer_select()) - tmp=find_field_in_tables(thd, this, - (TABLE_LIST*)(last= sl)->table_list.first, - 0); + if ((tmp= find_field_in_tables(thd, this, + (TABLE_LIST*) + (last= sl)->table_list.first, + 0)) != not_found_field) + break; if (!tmp) + return -1; + else if (tmp == not_found_field) { - // Call to produce appropriate error message + // call to return error code find_field_in_tables(thd, this, tables, 1); return -1; } @@ -478,7 +482,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) tbl->shared= 1; } } - } + } + else if (!tmp) + return -1; + set_field(tmp); } else if (thd && thd->set_query_id && field->query_id != thd->query_id) @@ -786,7 +793,9 @@ 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, 0))) + if ((ref= find_item_in_list(this, thd->lex.select->item_list, + REPORT_EXCEPT_NOT_FOUND)) == + not_found_item) { /* We can't find table field in table list of current select, @@ -795,17 +804,25 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) 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. + cause error ER_NON_UNIQ_ERROR in find_item_in_list. */ SELECT_LEX *last=0; for (SELECT_LEX *sl= thd->lex.select->outer_select(); - sl && !ref; + sl; sl= sl->outer_select()) - ref= find_item_in_list(this, (last= sl)->item_list, 0); + if((ref= find_item_in_list(this, (last= sl)->item_list, + REPORT_EXCEPT_NOT_FOUND)) != + not_found_item) + break; + if (!ref) { + return 1; + } + else if (ref == not_found_item) + { // Call to report error - find_item_in_list(this, thd->lex.select->item_list, 1); + find_item_in_list(this, thd->lex.select->item_list, REPORT_ALL_ERRORS); return 1; } else @@ -831,6 +848,8 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) } } } + else if (!ref) + return 1; max_length= (*ref)->max_length; maybe_null= (*ref)->maybe_null; decimals= (*ref)->decimals; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 7e0b2e201ec..e8ee6a780ea 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -83,7 +83,8 @@ bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return 1; } int res= engine->prepare(); - fix_length_and_dec(); + if (!res) + fix_length_and_dec(); return res; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8e691c8f96c..b74a2da5f6d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -456,6 +456,7 @@ bool wait_for_tables(THD *thd); 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, bool report_error); Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, @@ -545,7 +546,11 @@ TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); SQL_SELECT *make_select(TABLE *head, table_map const_tables, table_map read_tables, COND *conds, int *error); -Item ** find_item_in_list(Item *item, List<Item> &items, bool report_error); +enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, + IGNORE_ERRORS}; +extern const Item **not_found_item; +Item ** find_item_in_list(Item *item, List<Item> &items, + find_item_error_report_type report_error); bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator<Item> *it); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8deae314484..78774b376b1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1781,9 +1781,29 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, return field; } +// Special Field pointer for find_field_in_tables returning +const Field *not_found_field= (Field*) 0x1; +/* + Find field in table list. + + SYNOPSIS + find_field_in_tables() + thd - pointer to current thread structure + item - field item that should be found + tables - tables for scaning + report_error - if FALSE then do not report error if item not found and + return not_found_field; + + RETURN VALUES + 0 - field is not found or field is not unique, error message is + reported + not_found_field - function was called with report_error == FALSE and + field if not found, no error message reported + found field +*/ Field * -find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables, +find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables, bool report_error) { Field *found=0; @@ -1829,13 +1849,18 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables, strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS); table_name=buff; } - my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),table_name, - thd->where); + if (report_error) + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + table_name, thd->where); + else + return (Field*) not_found_field; } else if (report_error) my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), item->full_name(),thd->where); + else + return (Field*) not_found_field; return (Field*) 0; } bool allow_rowid= tables && !tables->next; // Only one table @@ -1850,11 +1875,10 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables, return (Field*) 0; if (found) { - if (!report_error) // Returns first found + if (!thd->where) // Returns first found break; - if (report_error) - my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0), - name,thd->where); + my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0), + name,thd->where); return (Field*) 0; } found=field; @@ -1865,11 +1889,39 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables, if (report_error) my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0), item->full_name(), thd->where); + else + return (Field*) not_found_field; return (Field*) 0; } +// Special Item pointer for find_item_in_list returning +const Item **not_found_item= (const Item**) 0x1; + +/* + Find Item in list of items (find_field_in_tables analog) + + SYNOPSIS + find_item_in_list() + find - item to find + items - list of items + report_error + REPORT_ALL_ERRORS - report errors, return 0 if error + REPORT_EXCEPT_NOT_FOUND - do not report 'not found' error and return not_ found_item, report other errors, return 0 + IGNORE_ERRORS - do not report errors, return 0 if error + + RETURN VALUES + 0 - item is not found or item is not unique, error message is + reported + not_found_item - function was called with report_error == + REPORT_EXCEPT_NOT_FOUND and item if not found, no error + message reported + found field + +*/ + Item ** -find_item_in_list(Item *find, List<Item> &items, bool report_error) +find_item_in_list(Item *find, List<Item> &items, + find_item_error_report_type report_error) { List_iterator<Item> li(items); Item **found=0,*item; @@ -1894,7 +1946,7 @@ find_item_in_list(Item *find, List<Item> &items, bool report_error) { if ((*found)->eq(item,0)) continue; // Same field twice (Access?) - if (report_error) + if (report_error != IGNORE_ERRORS) my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0), find->full_name(), current_thd->where); return (Item**) 0; @@ -1917,10 +1969,17 @@ find_item_in_list(Item *find, List<Item> &items, bool report_error) break; } } - if (!found && report_error) - my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0), - find->full_name(), current_thd->where); - return found; + if (found) + return found; + else if (report_error != REPORT_EXCEPT_NOT_FOUND) + { + if (report_error == REPORT_ALL_ERRORS) + my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0), + find->full_name(), current_thd->where); + return (Item **) 0; + } + else + return (Item **) not_found_item; } /**************************************************************************** diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 35703e57d82..09d41e2891b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6487,7 +6487,7 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields, order->in_field_list=1; return 0; } - Item **item=find_item_in_list(*order->item, fields, 0); + Item **item= find_item_in_list(*order->item, fields, IGNORE_ERRORS); if (item) { order->item=item; // use it @@ -6587,7 +6587,7 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, thd->set_query_id=1; // Not really needed, but... for (; new_field ; new_field= new_field->next) { - if ((item= find_item_in_list(*new_field->item, fields, 0))) + if ((item= find_item_in_list(*new_field->item, fields, IGNORE_ERRORS))) new_field->item=item; /* Change to shared Item */ else { |