MDEV-23094: Multiple calls to a Stored Procedure from another Stored Procedure crashes server

Added system-SELECT to IF/WHILE/REPET/FOR for correct subqueries connecting.

Added control of system/usual selects for correct error detection.
This commit is contained in:
Oleksandr Byelkin 2020-08-11 16:37:48 +02:00
parent 571764c04f
commit 0f080dd60a
11 changed files with 601 additions and 30 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);
}
};

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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();