summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2020-08-11 16:37:48 +0200
committerOleksandr Byelkin <sanja@mariadb.com>2020-08-31 14:40:34 +0200
commit0f080dd60a9a4fbfcd9c8a2d0361c9d7f0c080aa (patch)
treeb3d3281f2182f1cc40a215d9c8cbe31d188dd9c0
parent571764c04fc9b736366959b2c0e00d9bd0eb5a4e (diff)
downloadmariadb-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.result89
-rw-r--r--mysql-test/main/parser.test97
-rw-r--r--mysql-test/suite/compat/oracle/r/parser.result115
-rw-r--r--mysql-test/suite/compat/oracle/t/parser.test132
-rw-r--r--sql/sql_lex.cc6
-rw-r--r--sql/sql_lex.h14
-rw-r--r--sql/sql_parse.cc1
-rw-r--r--sql/sql_select.cc5
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_yacc.yy85
-rw-r--r--sql/sql_yacc_ora.yy85
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();