diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2020-08-11 16:37:48 +0200 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2020-08-31 14:40:34 +0200 |
commit | 0f080dd60a9a4fbfcd9c8a2d0361c9d7f0c080aa (patch) | |
tree | b3d3281f2182f1cc40a215d9c8cbe31d188dd9c0 | |
parent | 571764c04fc9b736366959b2c0e00d9bd0eb5a4e (diff) | |
download | mariadb-git-0f080dd60a9a4fbfcd9c8a2d0361c9d7f0c080aa.tar.gz |
MDEV-23094: Multiple calls to a Stored Procedure from another Stored Procedure crashes serverbb-10.4-MDEV-23094
Added system-SELECT to IF/WHILE/REPET/FOR for correct subqueries connecting.
Added control of system/usual selects for correct error detection.
-rw-r--r-- | mysql-test/main/parser.result | 89 | ||||
-rw-r--r-- | mysql-test/main/parser.test | 97 | ||||
-rw-r--r-- | mysql-test/suite/compat/oracle/r/parser.result | 115 | ||||
-rw-r--r-- | mysql-test/suite/compat/oracle/t/parser.test | 132 | ||||
-rw-r--r-- | sql/sql_lex.cc | 6 | ||||
-rw-r--r-- | sql/sql_lex.h | 14 | ||||
-rw-r--r-- | sql/sql_parse.cc | 1 | ||||
-rw-r--r-- | sql/sql_select.cc | 5 | ||||
-rw-r--r-- | sql/sql_union.cc | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 85 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 85 |
11 files changed, 601 insertions, 30 deletions
diff --git a/mysql-test/main/parser.result b/mysql-test/main/parser.result index 78156c842ea..49ef2073971 100644 --- a/mysql-test/main/parser.result +++ b/mysql-test/main/parser.result @@ -1908,4 +1908,93 @@ KILL ( SELECT 1 ) + LASTVAL(s); ERROR 42000: KILL does not support subqueries or stored functions KILL LASTVAL(s); ERROR 42000: KILL does not support subqueries or stored functions +# +# MDEV-23094: Multiple calls to a Stored Procedure from another +# Stored Procedure crashes server +# +create table t1 (id1 int primary key, data1 int); +create table t2 (id2 int primary key, data2 int); +create procedure p1(IN id int, IN dt int) +begin +if (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +then +select 1; +end if; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(IN id int, IN dt int) +begin +case (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +when 1 then +select 1; +else +select 0; +end case; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(IN id int, IN dt int) +begin +declare wcont int default 1; +while (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) and wcont +do +select 1; +set wcont=0; +end while; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(IN id int, IN dt int) +begin +declare count int default 1; +repeat +select 1; +set count=count+1; +until (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) and +count < 3 +end repeat; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(IN id int, IN dt int) +begin +for i in 1..(exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +do +select 1; +end for; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +drop table t1,t2; # End of 10.4 tests diff --git a/mysql-test/main/parser.test b/mysql-test/main/parser.test index 608f76557e5..502bbde5ea5 100644 --- a/mysql-test/main/parser.test +++ b/mysql-test/main/parser.test @@ -1696,4 +1696,101 @@ KILL ( SELECT 1 ) + LASTVAL(s); --error ER_SUBQUERIES_NOT_SUPPORTED KILL LASTVAL(s); +--echo # +--echo # MDEV-23094: Multiple calls to a Stored Procedure from another +--echo # Stored Procedure crashes server +--echo # + +create table t1 (id1 int primary key, data1 int); +create table t2 (id2 int primary key, data2 int); + +delimiter //; +create procedure p1(IN id int, IN dt int) +begin + if (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) + then + select 1; + end if; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(IN id int, IN dt int) +begin +case (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) +when 1 then + select 1; +else + select 0; +end case; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(IN id int, IN dt int) +begin +declare wcont int default 1; +while (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) and wcont +do + select 1; + set wcont=0; +end while; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(IN id int, IN dt int) +begin +declare count int default 1; +repeat + select 1; + set count=count+1; +until (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) and + count < 3 +end repeat; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(IN id int, IN dt int) +begin +for i in 1..(exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) +do + select 1; +end for; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +drop table t1,t2; + --echo # End of 10.4 tests diff --git a/mysql-test/suite/compat/oracle/r/parser.result b/mysql-test/suite/compat/oracle/r/parser.result index 0b573027c6d..2d9416d59c1 100644 --- a/mysql-test/suite/compat/oracle/r/parser.result +++ b/mysql-test/suite/compat/oracle/r/parser.result @@ -643,3 +643,118 @@ END; # # End of 10.3 tests # +# +# MDEV-21998: Server crashes in st_select_lex::add_table_to_list +# upon mix of KILL and sequences +# +KILL ( SELECT 1 ) + LASTVAL(s); +ERROR 42000: KILL does not support subqueries or stored functions +KILL LASTVAL(s); +ERROR 42000: KILL does not support subqueries or stored functions +# +# MDEV-23094: Multiple calls to a Stored Procedure from another +# Stored Procedure crashes server +# +create table t1 (id1 int primary key, data1 int); +create table t2 (id2 int primary key, data2 int); +create procedure p1(id int,dt int) as +begin +if (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +then +select 1; +end if; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(id int, dt int) as +begin +case (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +when 1 then +select 1; +else +select 0; +end case; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(id int, dt int) as +begin +declare wcont int default 1; +begin +while (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) and wcont +loop +select 1; +set wcont=0; +end loop; +end; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(id int, dt int) as +begin +declare count int default 1; +begin +repeat +select 1; +set count=count+1; +until (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) and +count < 3 +end repeat; +end; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(id int, dt int) as +begin +for i in 1..(exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +loop +select 1; +end loop; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +set sql_mode=ORACLE; +create or replace procedure p1(id int, dt int) as +begin +while (1) +loop +exit when (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)); +end loop; +end; +// +call p1(1,2); +call p1(1,2); +drop procedure p1; +drop table t1,t2; +# End of 10.4 tests diff --git a/mysql-test/suite/compat/oracle/t/parser.test b/mysql-test/suite/compat/oracle/t/parser.test index 4d558c5d153..8dabdc1b3bd 100644 --- a/mysql-test/suite/compat/oracle/t/parser.test +++ b/mysql-test/suite/compat/oracle/t/parser.test @@ -459,3 +459,135 @@ DELIMITER ;// --echo # --echo # End of 10.3 tests --echo # + + +--echo # +--echo # MDEV-21998: Server crashes in st_select_lex::add_table_to_list +--echo # upon mix of KILL and sequences +--echo # + +--error ER_SUBQUERIES_NOT_SUPPORTED +KILL ( SELECT 1 ) + LASTVAL(s); +--error ER_SUBQUERIES_NOT_SUPPORTED +KILL LASTVAL(s); + +--echo # +--echo # MDEV-23094: Multiple calls to a Stored Procedure from another +--echo # Stored Procedure crashes server +--echo # + +create table t1 (id1 int primary key, data1 int); +create table t2 (id2 int primary key, data2 int); + +delimiter //; +create procedure p1(id int,dt int) as +begin + if (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) + then + select 1; + end if; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +case (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) +when 1 then + select 1; +else + select 0; +end case; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +declare wcont int default 1; +begin + while (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) and wcont + loop + select 1; + set wcont=0; + end loop; +end; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +declare count int default 1; +begin + repeat + select 1; + set count=count+1; + until (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) and + count < 3 + end repeat; +end; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +for i in 1..(exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) +loop + select 1; +end loop; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +set sql_mode=ORACLE; +create or replace procedure p1(id int, dt int) as +begin + while (1) + loop + exit when (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)); + end loop; +end; +// +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +drop table t1,t2; + +--echo # End of 10.4 tests diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index bb75ebd12a1..cbb1138fe4d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2428,6 +2428,7 @@ void st_select_lex::init_query() changed_elements= 0; first_natural_join_processing= 1; first_cond_optimization= 1; + is_service_select= 0; parsing_place= NO_MATTER; save_parsing_place= NO_MATTER; exclude_from_table_unique_test= no_wrap_view_item= FALSE; @@ -7614,7 +7615,7 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name, return new (thd->mem_root) Item_func_sqlerrm(thd); } - if (!select_stack_head() && + if (fields_are_impossible() && (current_select->parsing_place != FOR_LOOP_BOUND || spcont->find_cursor(name, &unused_off, false) == NULL)) { @@ -8940,11 +8941,12 @@ void st_select_lex::add_statistics(SELECT_LEX_UNIT *unit) } -bool LEX::main_select_push() +bool LEX::main_select_push(bool service) { DBUG_ENTER("LEX::main_select_push"); current_select_number= 1; builtin_select.select_number= 1; + builtin_select.is_service_select= service; if (push_select(&builtin_select)) DBUG_RETURN(TRUE); DBUG_RETURN(FALSE); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ce30a630388..c8fca748b77 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1249,6 +1249,8 @@ public: bool no_wrap_view_item; /* exclude this select from check of unique_table() */ bool exclude_from_table_unique_test; + /* the select is "service-select" and can not have tables*/ + bool is_service_select; /* index in the select list of the expression currently being fixed */ int cur_pos_in_select_list; @@ -4413,7 +4415,7 @@ public: SELECT_LEX_UNIT *create_unit(SELECT_LEX*); SELECT_LEX *wrap_unit_into_derived(SELECT_LEX_UNIT *unit); SELECT_LEX *wrap_select_chain_into_derived(SELECT_LEX *sel); - bool main_select_push(); + bool main_select_push(bool service= false); bool insert_select_hack(SELECT_LEX *sel); SELECT_LEX *create_priority_nest(SELECT_LEX *first_in_nest); @@ -4530,6 +4532,16 @@ public: Lex_field_type_st *type) const; void mark_first_table_as_inserting(); + + bool fields_are_impossible() + { + // no select or it is last select with no tables (service select) + return !select_stack_head() || + (select_stack_top == 1 && + select_stack[0]->is_service_select); + } + + }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index bf33148811e..909cb245b2e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -8049,6 +8049,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, (alias ? alias->str : table->table.str), table, this, select_number)); + DBUG_ASSERT(!is_service_select || (table_options & TL_OPTION_SEQUENCE)); if (unlikely(!table)) DBUG_RETURN(0); // End of memory diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7091ffc2c58..a813de0ef85 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1131,6 +1131,8 @@ JOIN::prepare(TABLE_LIST *tables_init, proc_param= proc_param_init; tables_list= tables_init; select_lex= select_lex_arg; + DBUG_PRINT("info", ("select %p (%u) = JOIN %p", + select_lex, select_lex->select_number, this)); select_lex->join= this; join_list= &select_lex->top_join_list; union_part= unit_arg->is_unit_op(); @@ -4494,6 +4496,9 @@ int JOIN::destroy() { DBUG_ENTER("JOIN::destroy"); + + DBUG_PRINT("info", ("select %p (%u) <> JOIN %p", + select_lex, select_lex->select_number, this)); select_lex->join= 0; cond_equal= 0; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index e8b66bb8bd7..a487f4d4d73 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -2080,6 +2080,8 @@ bool st_select_lex::cleanup() bool error= FALSE; DBUG_ENTER("st_select_lex::cleanup()"); + DBUG_PRINT("info", ("select: %p (%u) JOIN %p", + this, select_number, join)); cleanup_order(order_list.first); cleanup_order(group_list.first); cleanup_ftfuncs(this); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 14b7a5589e1..83323e3f7e3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2809,8 +2809,6 @@ create: { Lex->create_info.default_table_charset= NULL; Lex->create_info.used_fields= 0; - if (Lex->main_select_push()) - MYSQL_YYABORT; } opt_create_database_options { @@ -2819,7 +2817,6 @@ create: $1 | $3))) MYSQL_YYABORT; lex->name= $4; - Lex->pop_select(); //main select } | create_or_replace definer_opt opt_view_suid VIEW_SYM opt_if_not_exists table_ident @@ -3653,10 +3650,13 @@ sp_cursor_stmt: { DBUG_ASSERT(thd->free_list == NULL); Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } select { DBUG_ASSERT(Lex == $1); + Lex->pop_select(); //main select if (unlikely($1->stmt_finalize(thd)) || unlikely($1->sphead->restore_lex(thd))) MYSQL_YYABORT; @@ -4154,6 +4154,11 @@ sp_proc_stmt_statement: Lex_input_stream *lip= YYLIP; lex->sphead->reset_lex(thd); + /* + We should not push main select here, it will be done or not + done by the statement, we just provide only a new LEX for the + statement here as if it is start of parsing a new statement. + */ lex->sphead->m_tmp_query= lip->get_tok_start(); } statement @@ -4172,11 +4177,16 @@ RETURN_ALLMODES_SYM: sp_proc_stmt_return: RETURN_ALLMODES_SYM - { Lex->sphead->reset_lex(thd); } + { + Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } expr { LEX *lex= Lex; sp_head *sp= lex->sphead; + Lex->pop_select(); //main select if (unlikely(sp->m_handler->add_instr_freturn(thd, sp, lex->spcont, $3, lex)) || unlikely(sp->restore_lex(thd))) @@ -4193,7 +4203,16 @@ sp_proc_stmt_return: ; reset_lex_expr: - { Lex->sphead->reset_lex(thd); } expr { $$= $2; } + { + Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } + expr + { + Lex->pop_select(); //main select + $$= $2; + } ; sp_proc_stmt_exit_oracle: @@ -4285,6 +4304,8 @@ assignment_source_expr: { DBUG_ASSERT(thd->free_list == NULL); Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } expr { @@ -4293,6 +4314,7 @@ assignment_source_expr: $$->sp_lex_in_use= true; $$->set_item_and_free_list($3, thd->free_list); thd->free_list= NULL; + Lex->pop_select(); //min select if ($$->sphead->restore_lex(thd)) MYSQL_YYABORT; } @@ -4302,6 +4324,8 @@ for_loop_bound_expr: assignment_source_lex { Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; Lex->current_select->parsing_place= FOR_LOOP_BOUND; } expr @@ -4310,6 +4334,7 @@ for_loop_bound_expr: $$= $1; $$->sp_lex_in_use= true; $$->set_item_and_free_list($3, NULL); + Lex->pop_select(); //main select if (unlikely($$->sphead->restore_lex(thd))) MYSQL_YYABORT; Lex->current_select->parsing_place= NO_MATTER; @@ -4424,7 +4449,11 @@ sp_fetch_list: ; sp_if: - { Lex->sphead->reset_lex(thd); } + { + Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } expr THEN_SYM { LEX *lex= Lex; @@ -4438,6 +4467,7 @@ sp_if: unlikely(sp->add_cont_backpatch(i)) || unlikely(sp->add_instr(i))) MYSQL_YYABORT; + Lex->pop_select(); //main select if (unlikely(sp->restore_lex(thd))) MYSQL_YYABORT; } @@ -4538,12 +4568,17 @@ case_stmt_specification: ; case_stmt_body: - { Lex->sphead->reset_lex(thd); /* For expr $2 */ } + { + Lex->sphead->reset_lex(thd); /* For expr $2 */ + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } expr { if (unlikely(Lex->case_stmt_action_expr($2))) MYSQL_YYABORT; + Lex->pop_select(); //main select if (Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } @@ -4567,6 +4602,8 @@ simple_when_clause: WHEN_SYM { Lex->sphead->reset_lex(thd); /* For expr $3 */ + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } expr { @@ -4575,6 +4612,7 @@ simple_when_clause: LEX *lex= Lex; if (unlikely(lex->case_stmt_action_when($3, true))) MYSQL_YYABORT; + Lex->pop_select(); //main select /* For expr $3 */ if (unlikely(lex->sphead->restore_lex(thd))) MYSQL_YYABORT; @@ -4591,12 +4629,15 @@ searched_when_clause: WHEN_SYM { Lex->sphead->reset_lex(thd); /* For expr $3 */ + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } expr { LEX *lex= Lex; if (unlikely(lex->case_stmt_action_when($3, false))) MYSQL_YYABORT; + Lex->pop_select(); //main select /* For expr $3 */ if (unlikely(lex->sphead->restore_lex(thd))) MYSQL_YYABORT; @@ -4695,9 +4736,15 @@ opt_sp_for_loop_direction: ; sp_for_loop_index_and_bounds: - ident sp_for_loop_bounds + ident { - if (unlikely(Lex->sp_for_loop_declarations(thd, &$$, &$1, $2))) + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } + sp_for_loop_bounds + { + Lex->pop_select(); //main select + if (unlikely(Lex->sp_for_loop_declarations(thd, &$$, &$1, $3))) MYSQL_YYABORT; } ; @@ -4743,8 +4790,11 @@ while_body: LEX *lex= Lex; if (unlikely(lex->sp_while_loop_expression(thd, $1))) MYSQL_YYABORT; + Lex->pop_select(); //main select if (lex->sphead->restore_lex(thd)) MYSQL_YYABORT; + if (lex->main_select_push(true)) + MYSQL_YYABORT; } sp_proc_stmts1 END WHILE_SYM { @@ -4755,7 +4805,11 @@ while_body: repeat_body: sp_proc_stmts1 UNTIL_SYM - { Lex->sphead->reset_lex(thd); } + { + Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } expr END REPEAT_SYM { LEX *lex= Lex; @@ -4766,6 +4820,7 @@ repeat_body: if (unlikely(i == NULL) || unlikely(lex->sphead->add_instr(i))) MYSQL_YYABORT; + Lex->pop_select(); //main select if (lex->sphead->restore_lex(thd)) MYSQL_YYABORT; /* We can shortcut the cont_backpatch here */ @@ -4794,6 +4849,8 @@ sp_labeled_control: if (unlikely(Lex->sp_push_loop_label(thd, &$1))) MYSQL_YYABORT; Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } while_body pop_sp_loop_label { } @@ -4845,6 +4902,8 @@ sp_unlabeled_control: if (unlikely(Lex->sp_push_loop_empty_label(thd))) MYSQL_YYABORT; Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } while_body { @@ -7816,7 +7875,7 @@ alter: { Lex->create_info.default_table_charset= NULL; Lex->create_info.used_fields= 0; - if (Lex->main_select_push()) + if (Lex->main_select_push(true)) MYSQL_YYABORT; } create_database_options @@ -13265,7 +13324,7 @@ do: { LEX *lex=Lex; lex->sql_command = SQLCOM_DO; - if (lex->main_select_push()) + if (lex->main_select_push(true)) MYSQL_YYABORT; mysql_init_select(lex); } @@ -16453,7 +16512,7 @@ set: SET { LEX *lex=Lex; - if (lex->main_select_push()) + if (lex->main_select_push(true)) MYSQL_YYABORT; lex->set_stmt_init(); lex->var_list.empty(); diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 9366a7bcd9f..c8084f8109c 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -2311,8 +2311,6 @@ create: { Lex->create_info.default_table_charset= NULL; Lex->create_info.used_fields= 0; - if (Lex->main_select_push()) - MYSQL_YYABORT; } opt_create_database_options { @@ -2321,7 +2319,6 @@ create: $1 | $3))) MYSQL_YYABORT; lex->name= $4; - Lex->pop_select(); //main select } | create_or_replace definer_opt opt_view_suid VIEW_SYM opt_if_not_exists table_ident @@ -3547,10 +3544,13 @@ sp_cursor_stmt: { DBUG_ASSERT(thd->free_list == NULL); Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } select { DBUG_ASSERT(Lex == $1); + Lex->pop_select(); //main select if (unlikely($1->stmt_finalize(thd)) || unlikely($1->sphead->restore_lex(thd))) MYSQL_YYABORT; @@ -4061,6 +4061,11 @@ sp_proc_stmt_statement: Lex_input_stream *lip= YYLIP; lex->sphead->reset_lex(thd); + /* + We should not push main select here, it will be done or not + done by the statement, we just provide only new LEX for the + statement here as if it is start of parsing new statement. + */ lex->sphead->m_tmp_query= lip->get_tok_start(); } sp_statement @@ -4079,11 +4084,16 @@ RETURN_ALLMODES_SYM: sp_proc_stmt_return: RETURN_ALLMODES_SYM - { Lex->sphead->reset_lex(thd); } + { + Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } expr { LEX *lex= Lex; sp_head *sp= lex->sphead; + Lex->pop_select(); //main select if (unlikely(sp->m_handler->add_instr_freturn(thd, sp, lex->spcont, $3, lex)) || unlikely(sp->restore_lex(thd))) @@ -4100,9 +4110,16 @@ sp_proc_stmt_return: ; reset_lex_expr: - { Lex->sphead->reset_lex(thd); } + { + Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } expr - { $$= $2; } + { + $$= $2; + Lex->pop_select(); //main select + } ; sp_proc_stmt_exit_oracle: @@ -4201,6 +4218,8 @@ assignment_source_expr: { DBUG_ASSERT(thd->free_list == NULL); Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } expr { @@ -4209,6 +4228,7 @@ assignment_source_expr: $$->sp_lex_in_use= true; $$->set_item_and_free_list($3, thd->free_list); thd->free_list= NULL; + Lex->pop_select(); //main select if ($$->sphead->restore_lex(thd)) MYSQL_YYABORT; } @@ -4218,6 +4238,8 @@ for_loop_bound_expr: assignment_source_lex { Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; Lex->current_select->parsing_place= FOR_LOOP_BOUND; } expr @@ -4226,6 +4248,7 @@ for_loop_bound_expr: $$= $1; $$->sp_lex_in_use= true; $$->set_item_and_free_list($3, NULL); + Lex->pop_select(); //main select if (unlikely($$->sphead->restore_lex(thd))) MYSQL_YYABORT; Lex->current_select->parsing_place= NO_MATTER; @@ -4338,7 +4361,11 @@ sp_fetch_list: ; sp_if: - { Lex->sphead->reset_lex(thd); } + { + Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } expr THEN_SYM { LEX *lex= Lex; @@ -4352,6 +4379,7 @@ sp_if: unlikely(sp->add_cont_backpatch(i)) || unlikely(sp->add_instr(i))) MYSQL_YYABORT; + Lex->pop_select(); //main select if (unlikely(sp->restore_lex(thd))) MYSQL_YYABORT; } @@ -4452,12 +4480,17 @@ case_stmt_specification: ; case_stmt_body: - { Lex->sphead->reset_lex(thd); /* For expr $2 */ } + { + Lex->sphead->reset_lex(thd); /* For expr $2 */ + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } expr { if (unlikely(Lex->case_stmt_action_expr($2))) MYSQL_YYABORT; + Lex->pop_select(); //main select if (Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } @@ -4481,6 +4514,8 @@ simple_when_clause: WHEN_SYM { Lex->sphead->reset_lex(thd); /* For expr $3 */ + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } expr { @@ -4489,6 +4524,7 @@ simple_when_clause: LEX *lex= Lex; if (unlikely(lex->case_stmt_action_when($3, true))) MYSQL_YYABORT; + Lex->pop_select(); //main select /* For expr $3 */ if (unlikely(lex->sphead->restore_lex(thd))) MYSQL_YYABORT; @@ -4505,12 +4541,15 @@ searched_when_clause: WHEN_SYM { Lex->sphead->reset_lex(thd); /* For expr $3 */ + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } expr { LEX *lex= Lex; if (unlikely(lex->case_stmt_action_when($3, false))) MYSQL_YYABORT; + Lex->pop_select(); //main select /* For expr $3 */ if (unlikely(lex->sphead->restore_lex(thd))) MYSQL_YYABORT; @@ -4699,9 +4738,15 @@ opt_sp_for_loop_direction: ; sp_for_loop_index_and_bounds: - ident_directly_assignable sp_for_loop_bounds + ident_directly_assignable { - if (unlikely(Lex->sp_for_loop_declarations(thd, &$$, &$1, $2))) + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } + sp_for_loop_bounds + { + Lex->pop_select(); //main select + if (unlikely(Lex->sp_for_loop_declarations(thd, &$$, &$1, $3))) MYSQL_YYABORT; } ; @@ -4747,8 +4792,11 @@ while_body: LEX *lex= Lex; if (unlikely(lex->sp_while_loop_expression(thd, $1))) MYSQL_YYABORT; + Lex->pop_select(); //main select if (lex->sphead->restore_lex(thd)) MYSQL_YYABORT; + if (lex->main_select_push(true)) + MYSQL_YYABORT; } sp_proc_stmts1 END LOOP_SYM { @@ -4759,7 +4807,11 @@ while_body: repeat_body: sp_proc_stmts1 UNTIL_SYM - { Lex->sphead->reset_lex(thd); } + { + Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } expr END REPEAT_SYM { LEX *lex= Lex; @@ -4770,6 +4822,7 @@ repeat_body: if (unlikely(i == NULL) || unlikely(lex->sphead->add_instr(i))) MYSQL_YYABORT; + Lex->pop_select(); //main select if (lex->sphead->restore_lex(thd)) MYSQL_YYABORT; /* We can shortcut the cont_backpatch here */ @@ -4798,6 +4851,8 @@ sp_labeled_control: if (unlikely(Lex->sp_push_loop_label(thd, &$1))) MYSQL_YYABORT; Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } while_body pop_sp_loop_label { } @@ -4849,6 +4904,8 @@ sp_unlabeled_control: if (unlikely(Lex->sp_push_loop_empty_label(thd))) MYSQL_YYABORT; Lex->sphead->reset_lex(thd); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } while_body { @@ -7914,7 +7971,7 @@ alter: { Lex->create_info.default_table_charset= NULL; Lex->create_info.used_fields= 0; - if (Lex->main_select_push()) + if (Lex->main_select_push(true)) MYSQL_YYABORT; } create_database_options @@ -13372,7 +13429,7 @@ do: { LEX *lex=Lex; lex->sql_command = SQLCOM_DO; - if (lex->main_select_push()) + if (lex->main_select_push(true)) MYSQL_YYABORT; mysql_init_select(lex); } @@ -16619,7 +16676,7 @@ set: SET { LEX *lex=Lex; - if (lex->main_select_push()) + if (lex->main_select_push(true)) MYSQL_YYABORT; lex->set_stmt_init(); lex->var_list.empty(); |