diff options
-rw-r--r-- | mysql-test/r/subselect.result | 8 | ||||
-rw-r--r-- | mysql-test/t/subselect.test | 10 | ||||
-rw-r--r-- | sql/item.cc | 19 | ||||
-rw-r--r-- | sql/sql_lex.cc | 2 | ||||
-rw-r--r-- | sql/sql_lex.h | 8 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 7 |
6 files changed, 45 insertions, 9 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 1a4701d8d0e..c5ea027fed4 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -580,12 +580,12 @@ a b drop table t11, t12, t2; CREATE TABLE t1 (x int); create table t2 (a int); -create table t3 (a int); +create table t3 (b int); insert into t2 values (1); insert into t3 values (1),(2); INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); You can't specify target table 't1' for update in FROM clause -INSERT INTO t1 (x) VALUES ((SELECT a FROM t3)); +INSERT INTO t1 (x) VALUES ((SELECT b FROM t3)); Subselect returns more than 1 record INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); select * from t1; @@ -607,13 +607,15 @@ x INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2; You can't specify target table 't1' for update in FROM clause INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2)); +Unknown column 'x' in 'field list' +INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2)); select * from t1; x 1 2 3 3 -0 +2 drop table t1, t2, t3; CREATE TABLE t1 (x int not null, y int, primary key (x)); create table t2 (a int); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 8e8a3dfe1d4..5040f400514 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -334,13 +334,13 @@ drop table t11, t12, t2; #insert with subselects CREATE TABLE t1 (x int); create table t2 (a int); -create table t3 (a int); +create table t3 (b int); insert into t2 values (1); insert into t3 values (1),(2); -- error 1093 INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); -- error 1240 -INSERT INTO t1 (x) VALUES ((SELECT a FROM t3)); +INSERT INTO t1 (x) VALUES ((SELECT b FROM t3)); INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); select * from t1; insert into t2 values (1); @@ -351,9 +351,15 @@ INSERT INTO t1 (x) select (SELECT SUM(a)+1 FROM t2) FROM t2; select * from t1; -- error 1093 INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2; +-- error 1054 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2)); +INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2)); -- sleep 1 select * from t1; +# +#TODO: should be uncommented after bug 380 fix pushed +#INSERT INTO t1 (x) SELECT (SELECT SUM(a)+b FROM t2) from t3; +#select * from t1; drop table t1, t2, t3; #replace with subselects diff --git a/sql/item.cc b/sql/item.cc index 053a94cb695..871031f1571 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -758,6 +758,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) #ifdef EMBEDDED_LIBRARY thd->net.last_errno= 0; #endif + TABLE_LIST *table_list; Item **refer= (Item **)not_found_item; uint counter; // Prevent using outer fields in subselects, that is not supported now @@ -768,8 +769,14 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) sl; sl= sl->outer_select()) { + table_list= (last= sl)->get_table_list(); + if (sl->insert_select && table_list) + { + // it is primary INSERT st_select_lex => skip first table resolving + table_list= table_list->next; + } if ((tmp= find_field_in_tables(thd, this, - (last= sl)->get_table_list(), &where, + table_list, &where, 0)) != not_found_field) break; if ((refer= find_item_in_list(this, sl->item_list, &counter, @@ -1221,7 +1228,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) uint counter; if (!ref) { - TABLE_LIST *where= 0; + TABLE_LIST *where= 0, *table_list; SELECT_LEX *sl= (outer_resolving? thd->lex.current_select->select_lex(): thd->lex.current_select->outer_select()); @@ -1260,8 +1267,14 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) REPORT_EXCEPT_NOT_FOUND)) != (Item **)not_found_item) break; + table_list= sl->get_table_list(); + if (sl->insert_select && table_list) + { + // it is primary INSERT st_select_lex => skip first table resolving + table_list= table_list->next; + } if ((tmp= find_field_in_tables(thd, this, - sl->get_table_list(), &where, + table_list, &where, 0)) != not_found_field) break; if (sl->master_unit()->first_select()->linkage == diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 9bc4dfc74e7..6dc4b419f18 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1000,7 +1000,7 @@ void st_select_lex::init_query() item_list.empty(); join= 0; olap= UNSPECIFIED_OLAP_TYPE; - having_fix_field= 0; + insert_select= having_fix_field= 0; with_wild= 0; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index f31b3305e07..5f6ae02cca3 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -352,6 +352,14 @@ public: bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */ /* TRUE when having fix field called in processing of this SELECT */ bool having_fix_field; + /* + TRUE for primary st_select_lex structure of simple INSERT/REPLACE + (used for name resolution, see Item_fiels & Item_ref fix_fields, + FALSE for INSERT/REPLACE ... SELECT, because it's + st_select_lex->table_list will be preprocessed (first table removed) + before passing to handle_select) + */ + bool insert_select; void init_query(); void init_select(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4de0e2f8c13..b62e34e279f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3270,6 +3270,7 @@ insert: lex->sql_command = SQLCOM_INSERT; /* for subselects */ lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; + lex->select_lex.insert_select= 1; } insert_lock_option opt_ignore insert2 { @@ -3285,6 +3286,7 @@ replace: LEX *lex=Lex; lex->sql_command = SQLCOM_REPLACE; lex->duplicates= DUP_REPLACE; + lex->select_lex.insert_select= 1; } replace_lock_option insert2 { @@ -3349,6 +3351,11 @@ insert_values: SQLCOM_INSERT_SELECT : SQLCOM_REPLACE_SELECT); lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; mysql_init_select(lex); + /* + it is not simple select => table list will be + preprocessed before passing to handle_select + */ + lex->select_lex.insert_select= 0; } select_options select_item_list opt_select_from select_lock_type union_clause {} |