diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 3617f8c7782..8b82032e2e1 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -411,6 +411,8 @@ a b 0 10 1 11 2 12 +update t1 set b= (select b from t1); +INSERT TABLE 't1' isn't allowed in FROM table list update t1 set b= (select b from t2 where t1.a = t2.a); select * from t1; a b @@ -430,6 +432,8 @@ a b select * from t1 where b = (select b from t2 where t1.a = t2.a); a b 2 12 +delete from t1 where b = (select b from t1); +INSERT TABLE 't1' isn't allowed in FROM table list delete from t1 where b = (select b from t2 where t1.a = t2.a); select * from t1; a b @@ -453,6 +457,8 @@ a b 33 10 22 11 2 12 +delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t12 where t11.a = t12.a); +INSERT TABLE 't12' isn't allowed in FROM table list delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2 where t11.a = t2.a); select * from t11; a b @@ -466,6 +472,8 @@ drop table t11, t12, t2; CREATE TABLE t1 (x int); create table t2 (a int); insert into t2 values (1); +INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); +INSERT TABLE 't1' isn't allowed in FROM table list INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); select * from t1; x @@ -485,20 +493,22 @@ x 3 INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2; INSERT TABLE 't1' isn't allowed in FROM table list -INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t1)); +INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2)); select * from t1; x 1 2 3 3 -9 +0 drop table t1, t2; CREATE TABLE t1 (x int not null, y int, primary key (x)); create table t2 (a int); insert into t2 values (1); select * from t1; x y +replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2)); +INSERT TABLE 't1' isn't allowed in FROM table list replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2)); select * from t1; x y @@ -559,4 +569,10 @@ id SELECT * FROM t WHERE id IN (SELECT 5 UNION SELECT 2); id 2 -drop table if exists t; +INSERT INTO t VALUES ((SELECT * FROM t)); +INSERT TABLE 't' isn't allowed in FROM table list +SELECT * FROM t; +id +1 +2 +drop table t; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 3e01dc5f5e9..1b8946b4696 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -244,6 +244,8 @@ create table t2 (a int NOT NULL, b int, primary key (a)); insert into t1 values (0, 10),(1, 11),(2, 12); insert into t2 values (1, 21),(2, 22),(3, 23); select * from t1; +-- error 1093 +update t1 set b= (select b from t1); update t1 set b= (select b from t2 where t1.a = t2.a); select * from t1; drop table t1, t2; @@ -255,6 +257,8 @@ insert into t1 values (0, 10),(1, 11),(2, 12); insert into t2 values (1, 21),(2, 12),(3, 23); select * from t1; select * from t1 where b = (select b from t2 where t1.a = t2.a); +-- error 1093 +delete from t1 where b = (select b from t1); delete from t1 where b = (select b from t2 where t1.a = t2.a); select * from t1; drop table t1, t2; @@ -269,6 +273,8 @@ insert into t12 values (33, 10),(22, 11),(2, 12); insert into t2 values (1, 21),(2, 12),(3, 23); select * from t11; select * from t12; +-- error 1093 +delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t12 where t11.a = t12.a); delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2 where t11.a = t2.a); select * from t11; select * from t12; @@ -278,6 +284,8 @@ drop table t11, t12, t2; CREATE TABLE t1 (x int); create table t2 (a int); insert into t2 values (1); +-- error 1093 +INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); select * from t1; insert into t2 values (1); @@ -288,7 +296,7 @@ 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; -INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t1)); +INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2)); -- sleep 1 select * from t1; drop table t1, t2; @@ -298,6 +306,8 @@ CREATE TABLE t1 (x int not null, y int, primary key (x)); create table t2 (a int); insert into t2 values (1); select * from t1; +-- error 1093 +replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2)); replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2)); select * from t1; replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+2 FROM t2)); @@ -325,5 +335,7 @@ EXPLAIN SELECT * FROM t WHERE id IN (SELECT 1+(select 1)); EXPLAIN SELECT * FROM t WHERE id IN (SELECT 1 UNION SELECT 3); SELECT * FROM t WHERE id IN (SELECT 5 UNION SELECT 3); SELECT * FROM t WHERE id IN (SELECT 5 UNION SELECT 2); -drop table if exists t; - +-- error 1093 +INSERT INTO t VALUES ((SELECT * FROM t)); +SELECT * FROM t; +drop table t; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 242f8601b23..61e0f8f7ffa 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -580,6 +580,9 @@ bool close_thread_table(THD *thd, TABLE **table_ptr); void close_temporary_tables(THD *thd); TABLE_LIST * find_table_in_list(TABLE_LIST *table, const char *db_name, const char *table_name); +TABLE_LIST * find_real_table_in_list(TABLE_LIST *table, + const char *db_name, + const char *table_name); TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name); bool close_temporary_table(THD *thd, const char *db, const char *table_name); void close_temporary(TABLE *table, bool delete_table=1); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 18ff2bf38db..fc7629caae3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -744,7 +744,7 @@ void close_temporary_tables(THD *thd) } /* - Find first suitable table in given list. + Find first suitable table by alias in given list. SYNOPSIS find_table_in_list() @@ -767,6 +767,31 @@ TABLE_LIST * find_table_in_list(TABLE_LIST *table, return table; } +/* + Find real table in given list. + + SYNOPSIS + find_table_in_list() + table - pointer to table list + db_name - data base name + table_name - table name + + RETURN VALUES + NULL Table not found + # Pointer to found table. +*/ + +TABLE_LIST * find_real_table_in_list(TABLE_LIST *table, + const char *db_name, + const char *table_name) +{ + for (; table; table= table->next) + if (!strcmp(table->db, db_name) && + !strcmp(table->real_name, table_name)) + break; + return table; +} + TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name) { char key[MAX_DBKEY_LENGTH]; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 07958ebcfab..fe1a967f936 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -51,6 +51,12 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, if (setup_conds(thd, delete_table_list, &conds) || setup_ftfuncs(&thd->lex.select_lex)) DBUG_RETURN(-1); + if (find_real_table_in_list(table_list->next, + table_list->db, table_list->real_name)) + { + my_error(ER_INSERT_TABLE_USED, MYF(0), table_list->real_name); + DBUG_RETURN(-1); + } const_cond= (!conds || conds->const_item()); safe_update=test(thd->options & OPTION_SAFE_UPDATES); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 1ca44046997..83b125ee630 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -171,6 +171,13 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List &fields, table->time_stamp= save_time_stamp; goto abort; } + if (find_real_table_in_list(table_list->next, + table_list->db, table_list->real_name)) + { + my_error(ER_INSERT_TABLE_USED, MYF(0), table_list->real_name); + goto abort; + } + value_count= values->elements; while ((values= its++)) { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 724933e08d4..d765c741932 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -442,13 +442,13 @@ inline static uint int_token(const char *str,uint length) // STATE_OPERATOR_OR_IDENT ; last state was an ident, text or number // (which can't be followed by a signed number) -int yylex(void *arg) +int yylex(void *arg, void *yythd) { reg1 uchar c; int tokval; uint length; enum lex_states state,prev_state; - LEX *lex=current_lex; + LEX *lex= &(((THD *)yythd)->lex); YYSTYPE *yylval=(YYSTYPE*) arg; lex->yylval=yylval; // The global state diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index bce05095bcc..d60542528d2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -61,7 +61,6 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc); static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables); -static bool check_dup(const char *db, const char *name, TABLE_LIST *tables); static void remove_escape(char *name); static void refresh_status(void); static bool append_file_to_dir(THD *thd, char **filename_ptr, @@ -1645,7 +1644,7 @@ mysql_execute_command(THD *thd) select_result *result; if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) && - check_dup(tables->db, tables->real_name, tables->next)) + find_real_table_in_list(tables->next, tables->db, tables->real_name)) { net_printf(thd,ER_INSERT_TABLE_USED,tables->real_name); DBUG_VOID_RETURN; @@ -2007,7 +2006,7 @@ mysql_execute_command(THD *thd) if (unit->select_limit_cnt < select_lex->select_limit) unit->select_limit_cnt= HA_POS_ERROR; // No limit - if (check_dup(tables->db, tables->real_name, tables->next)) + if (find_real_table_in_list(tables->next, tables->db, tables->real_name)) { net_printf(thd,ER_INSERT_TABLE_USED,tables->real_name); DBUG_VOID_RETURN; @@ -2100,6 +2099,17 @@ mysql_execute_command(THD *thd) /* Fix tables-to-be-deleted-from list to point at opened tables */ for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next) auxi->table= auxi->table_list->table; + if (&lex->select_lex != lex->all_selects_list) + for (TABLE_LIST *t= select_lex->get_table_list(); + t; t= t->next) + { + if (find_real_table_in_list(t->table_list->next, t->db, t->real_name)) + { + my_error(ER_INSERT_TABLE_USED, MYF(0), t->real_name); + res= -1; + break; + } + } fix_tables_pointers(lex->all_selects_list); if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables, table_count))) @@ -3528,16 +3538,6 @@ void add_join_natural(TABLE_LIST *a,TABLE_LIST *b) b->natural_join=a; } - /* Check if name is used in table list */ - -static bool check_dup(const char *db, const char *name, TABLE_LIST *tables) -{ - for (; tables ; tables=tables->next) - if (!strcmp(name,tables->real_name) && !strcmp(db,tables->db)) - return 1; - return 0; -} - bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables) { bool result=0; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c2ba65248a7..4e15011c254 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -86,6 +86,13 @@ int mysql_update(THD *thd, setup_conds(thd,update_table_list,&conds) || setup_ftfuncs(&thd->lex.select_lex)) DBUG_RETURN(-1); /* purecov: inspected */ + if (find_real_table_in_list(table_list->next, + table_list->db, table_list->real_name)) + { + my_error(ER_INSERT_TABLE_USED, MYF(0), table_list->real_name); + DBUG_RETURN(-1); + } + old_used_keys=table->used_keys; // Keys used in WHERE /* diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b3ca9125c10..ed17053910c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -17,10 +17,12 @@ /* sql_yacc.yy */ %{ -/* Pass thd as an arg to yyparse(). The type will be void*, so it -** must be cast to (THD*) when used. Use the YYTHD macro for this. +/* thd is passed as an arg to yyparse(), and subsequently to yylex(). +** The type will be void*, so it must be cast to (THD*) when used. +** Use the YYTHD macro for this. */ #define YYPARSE_PARAM yythd +#define YYLEX_PARAM yythd #define YYTHD ((THD *)yythd) #define MYSQL_YACC @@ -37,7 +39,7 @@ #include extern void yyerror(const char*); -int yylex(void *yylval); +int yylex(void *yylval, void *yythd); #define yyoverflow(A,B,C,D,E,F) if (my_yyoverflow((B),(D),(int*) (F))) { yyerror((char*) (A)); return 2; }