Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
af7f287b
Commit
af7f287b
authored
Feb 14, 2017
by
halfspawn
Committed by
Alexander Barkov
Apr 05, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-10697 GOTO statement
parent
d836f52b
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
2092 additions
and
41 deletions
+2092
-41
mysql-test/suite/compat/oracle/r/sp-goto.result
mysql-test/suite/compat/oracle/r/sp-goto.result
+834
-0
mysql-test/suite/compat/oracle/t/sp-goto.test
mysql-test/suite/compat/oracle/t/sp-goto.test
+872
-0
sql/lex.h
sql/lex.h
+1
-0
sql/sp_head.cc
sql/sp_head.cc
+133
-2
sql/sp_head.h
sql/sp_head.h
+29
-0
sql/sp_pcontext.cc
sql/sp_pcontext.cc
+58
-3
sql/sp_pcontext.h
sql/sp_pcontext.h
+49
-6
sql/sql_lex.cc
sql/sql_lex.cc
+48
-0
sql/sql_lex.h
sql/sql_lex.h
+2
-0
sql/sql_yacc.yy
sql/sql_yacc.yy
+2
-0
sql/sql_yacc_ora.yy
sql/sql_yacc_ora.yy
+64
-30
No files found.
mysql-test/suite/compat/oracle/r/sp-goto.result
0 → 100644
View file @
af7f287b
set sql_mode=oracle;
#
# MDEV-10697 sql_mode=ORACLE: GOTO statement
#
# matrice of tests in procedure
# |--------------------------------------------------------
# | | Same | Outside | to sub | No |
# | | block | one block | block | matching |
# | | | | | label |
# |--------------------------------------------------------
# | Forward jump | F1 | F3 | F5 | F7 |
# |--------------------------------------------------------
# | Backward jump | F2 | F4 | F6 | F8 |
# |--------------------------------------------------------
# Jump from handler to outside handling code block : F9
# Jump from handler to handling code block : F10 (forbidden)
# Jump inside handler : F21
# Jump between handler : F22 (forbidden)
# Jump from cascaded block with handler : F11
# Duplicate label in same block : F12 (forbidden)
# Duplicate label in different block : F13
# Jump outside unlabeled block : F14
# Jump inside/outside labeled block : F15
# Jump from if / else : F16
# Jump with cursors : F17
# Jump outside case : F18
# Jump inside/outside case block : F19
# Jump outside labeled loop : F20
# Jump (continue) labeled loop : F23
# Two consecutive label : P24
# Two consecutive label (backward and forward jump) : P25
# Two consecutive label, continue to wrong label : P26
# Consecutive goto label and block label : P27
# Test in function
# backward jump : func1
# forward jump : func2
# Test in trigger
# forward jump : trg1
#
# Forward jump in same block
#
CREATE or replace procedure f1(p2 IN OUT VARCHAR)
AS
BEGIN
p2:='a';
goto lab1;
<<lab1>>
goto lab2;
p2:='b';
<<lab2>>
return ;
END;
$$
call f1(@wp1);
select 'f1',@wp1;
f1 @wp1
f1 a
DROP PROCEDURE f1;
#
# Backward jump in same block
#
CREATE or replace procedure f2(p2 IN OUT VARCHAR)
AS
BEGIN
p2:='a';
<<lab1>>
if (p2='b') then
return ;
end if;
p2:='b';
goto lab1;
END;
$$
call f2(@wp1);
select 'f2',@wp1;
f2 @wp1
f2 b
DROP PROCEDURE f2;
#
# Forward jump outside one block
#
CREATE or replace procedure f3(p2 IN OUT VARCHAR)
AS
BEGIN
p2:='a';
if (p2='a') then
goto lab1;
end if;
p2:='c';
<<lab1>>
return ;
END;
$$
call f3(@wp1);
select 'f3',@wp1;
f3 @wp1
f3 a
DROP PROCEDURE f3;
#
# Backward jump outside one block
#
CREATE or replace procedure f4(p2 IN OUT VARCHAR)
AS
BEGIN
p2:='a';
<<lab1>>
if (p2='a') then
p2:=p2||'b';
goto lab1;
end if;
if (p2='ab') then
p2:=p2||'c';
end if;
return ;
END;
$$
call f4(@wp1);
select 'f4',@wp1;
f4 @wp1
f4 abc
DROP PROCEDURE f4;
#
# Forward jump inside sub block
CREATE or replace procedure f5(p2 IN OUT VARCHAR)
AS
BEGIN
p2:='a';
goto lab5 ;
if (p2='a') then
<<lab5>>
p2:=p2||'b';
end if;
return ;
END;
$$
ERROR 42000: GOTO with no matching label: lab5
#
# Backward jump inside sub block
CREATE or replace procedure f6(p2 IN OUT VARCHAR)
AS
BEGIN
p2:='a';
if (p2='a') then
<<lab6>>
p2:=p2||'b';
return ;
end if;
goto lab6 ;
END;
$$
ERROR 42000: GOTO with no matching label: lab6
#
# Backward jump - missing label
CREATE or replace procedure f7(p2 IN OUT VARCHAR)
AS
BEGIN
<<lab>>
goto lab7 ;
return ;
END;
$$
ERROR 42000: GOTO with no matching label: lab7
#
# Forward jump - missing label
CREATE or replace procedure f8(p2 IN OUT VARCHAR)
AS
BEGIN
goto lab8 ;
<<lab>>
return ;
END;
$$
ERROR 42000: GOTO with no matching label: lab8
#
# Jump from handler to procedure code
#
CREATE or replace procedure f9(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
<<lab9>>
if lim=-1 then
res:=res||' -- goto end limit -1 --';
goto lab9_end;
end if;
begin
SELECT a INTO a FROM information_schema.tables LIMIT lim;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
begin
res:=res||'--- too_many_rows cought ---';
lim:=0;
goto lab9;
end;
WHEN NO_DATA_FOUND THEN
begin
res:=res||'--- no_data_found cought ---';
lim:=-1;
goto lab9;
end;
end;
res:=res||'error';
<<lab9_end>>
return ;
END;
$$
SET @res='';
CALL f9(2, @res);
SELECT 'f9',@res;
f9 @res
f9 --- too_many_rows cought ------ no_data_found cought --- -- goto end limit -1 --
CALL f9(0, @res);
SELECT 'f9',@res;
f9 @res
f9 --- no_data_found cought --- -- goto end limit -1 --
DROP PROCEDURE f9;
#
# Jump from handler to handling bloc
CREATE or replace procedure f10(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
begin
<<lab10>>
SELECT a INTO a FROM information_schema.tables LIMIT lim;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
begin
res:='--- too_many_rows cought ---';
goto lab10;
end;
WHEN NO_DATA_FOUND THEN res:='--- no_data_found cought ---';
end;
return ;
END;
$$
ERROR 42000: GOTO with no matching label: lab10
#
# Jump from cascaded block with handler
#
CREATE or replace procedure f11(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
<<lab11a>>
begin
SELECT a INTO a FROM information_schema.tables LIMIT lim;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
begin
res:=res||'--- too_many_rows cought 1 ---';
goto lab11b;
end;
WHEN NO_DATA_FOUND THEN
begin
res:=res||'--- no_data_found cought 1 ---';
lim:=2;
SELECT a INTO a FROM information_schema.tables LIMIT lim;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
begin
res:=res||'--- too_many_rows cought 2 ---';
goto lab11a;
end;
WHEN NO_DATA_FOUND THEN res:='--- no_data_found cought 2 ---';
end;
end;
set res:=res||' error ';
<<lab11b>>
return ;
END;
$$
SET @res='';
CALL f11(0, @res);
SELECT 'f11',@res;
f11 @res
f11 --- no_data_found cought 1 ------ too_many_rows cought 2 ------ too_many_rows cought 1 ---
DROP PROCEDURE f11;
#
# Jump inside handler
#
CREATE or replace procedure f21(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
begin
SELECT a INTO a FROM information_schema.tables LIMIT lim;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
begin
<<retry>>
lim:=lim-1;
loop
begin
SELECT a INTO a FROM information_schema.tables LIMIT lim;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
begin
lim:=lim-1;
goto retry;
end;
end;
exit ;
end loop;
end;
end;
res:=lim;
return ;
END;
$$
SET @res='';
CALL f21(10, @res);
SELECT 'f21',@res;
f21 @res
f21 1
drop procedure f21;
#
# Jump beetween handler
CREATE or replace procedure f22(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
res:='ok';
begin
SELECT a INTO a FROM information_schema.tables LIMIT lim;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
goto nodata ;
WHEN NO_DATA_FOUND THEN
begin
<<nodata>>
res:='error';
end;
end;
return ;
END;
$$
ERROR 42000: GOTO with no matching label: nodata
#
# Duplicate label in same bloc
CREATE or replace procedure f12(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
<<lab12>>
res:='error';
<<lab12>>
return ;
END;
$$
ERROR 42000: Redefining label lab12
#
# Duplicate label in different block
#
CREATE or replace procedure f13(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
a:=0;
<<lab13>>
a:=a+1;
begin
<<lab13>>
a:=a+1;
if (a<10) then
goto lab13;
end if;
end;
res:=a;
if (a=10) then
goto lab13;
end if;
return ;
END;
$$
SET @res='';
CALL f13(0, @res);
SELECT 'f13',@res;
f13 @res
f13 12
DROP PROCEDURE f13;
#
# Jump outside unlabeled block
#
CREATE or replace procedure f14(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
a:=0;
loop
a:=a+1;
if (a<10) then
continue;
end if;
if (a>=lim) then
goto lab14;
end if;
if (a>=20) then
exit;
end if;
end loop;
<<lab14>>
res:=a;
return ;
END;
$$
SET @res='';
CALL f14(15, @res);
SELECT 'f14',@res;
f14 @res
f14 15
CALL f14(8, @res);
SELECT 'f14',@res;
f14 @res
f14 10
CALL f14(25, @res);
SELECT 'f14',@res;
f14 @res
f14 20
DROP PROCEDURE f14;
#
# Jump inside/outside labeled block
#
CREATE or replace procedure f15(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
a:=0;
<<looplabel>> loop
<<beginlooplabel>>
a:=a+1;
if (a<10) then
continue looplabel;
end if;
if (a>=lim) then
goto lab15;
end if;
if (a>=20) then
exit looplabel;
end if;
goto beginlooplabel;
end loop;
<<lab15>>
res:=a;
return ;
END;
$$
SET @res='';
CALL f15(15, @res);
SELECT 'f15',@res;
f15 @res
f15 15
CALL f15(8, @res);
SELECT 'f15',@res;
f15 @res
f15 10
CALL f15(25, @res);
SELECT 'f15',@res;
f15 @res
f15 20
DROP PROCEDURE f15;
#
# Jump from if / else
#
CREATE or replace procedure f16(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
if (lim<10) then
goto lab16_1;
else
goto lab16_2;
end if;
<<lab16_1>>
res:='if lab16_1';
goto lab16_3;
<<lab16_2>>
res:='else lab16_2';
goto lab16_3;
res:='error lab16_3';
<<lab16_3>>
return ;
END;
$$
SET @res='';
CALL f16(15, @res);
SELECT 'f16',@res;
f16 @res
f16 else lab16_2
CALL f16(8, @res);
SELECT 'f16',@res;
f16 @res
f16 if lab16_1
DROP PROCEDURE f16;
#
# Jump with cursors
#
CREATE or replace procedure f17(lim INT, res OUT VARCHAR)
AS
v_a INT;
v_b VARCHAR(10);
CURSOR cur1 IS SELECT 1 FROM dual where 1=2;
BEGIN
OPEN cur1;
LOOP
FETCH cur1 INTO v_a;
EXIT WHEN cur1%NOTFOUND;
END LOOP;
CLOSE cur1;
<<lab17>>
lim:=lim-1;
begin
declare
CURSOR cur1 IS SELECT 1 FROM dual;
CURSOR cur2 IS SELECT 1 FROM dual where 1=2;
begin
LOOP
OPEN cur1;
FETCH cur1 INTO v_a;
EXIT WHEN cur1%NOTFOUND;
res:=res||'-'||lim ;
close cur1;
if (lim>0) then
goto lab17;
else
goto lab17_end;
end if;
END LOOP;
end;
<<lab17_end>>
null;
end;
END;
$$
SET @res='';
CALL f17(5, @res);
SELECT 'f17',@res;
f17 @res
f17 -4-3-2-1-0
DROP PROCEDURE f17;
#
# Jump outside case
#
CREATE or replace procedure f18(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
case lim
when 1 then
res:='case branch 18_1';
goto lab18_1;
res:='error';
when 2 then
res:='case branch 18_2';
goto lab18_2;
res:='error';
else
res:='default branch 18';
end case;
<<lab18_1>>
null;
<<lab18_2>>
return ;
END;
$$
SET @res='';
CALL f18(0, @res);
SELECT 'f18',@res;
f18 @res
f18 default branch 18
CALL f18(1, @res);
SELECT 'f18',@res;
f18 @res
f18 case branch 18_1
CALL f18(2, @res);
SELECT 'f18',@res;
f18 @res
f18 case branch 18_2
DROP PROCEDURE f18;
#
# Jump inside/outside case block
#
CREATE or replace procedure f19(lim INT, res OUT VARCHAR)
AS
a INT;
BEGIN
a:=1;
case lim
when 1 then
<<lab19_0>>
a:=a+1;
if (a<10) then
goto lab19_0;
else
goto lab19_1;
end if;
res:='case branch 19_1';
else
res:='default branch 18';
end case;
goto lab19_end;
<<lab19_1>>
res:=a;
<<lab19_end>>
return ;
END;
$$
SET @res='';
CALL f19(1, @res);
SELECT 'f19',@res;
f19 @res
f19 10
DROP PROCEDURE f19;
#
# Jump outside labeled loop
#
CREATE OR REPLACE PROCEDURE f20(res OUT VARCHAR)
AS
a INT := 1;
BEGIN
<<lab>>
FOR i IN a..10 LOOP
IF i = 5 THEN
a:= a+1;
goto lab;
END IF;
END LOOP;
res:=a;
END;
$$
CALL f20(@res);
SELECT 'f20',@res;
f20 @res
f20 6
DROP PROCEDURE f20;
#
# Jump (continue) labeled loop
#
CREATE OR REPLACE PROCEDURE f23(res OUT VARCHAR)
AS
a INT := 1;
BEGIN
<<lab>>
FOR i IN a..10 LOOP
IF i = 5 THEN
a:= a+1;
continue lab;
END IF;
END LOOP;
res:=a;
END;
$$
CALL f23(@res);
SELECT 'f23',@res;
f23 @res
f23 2
DROP PROCEDURE f23;
#
# Two consecutive label (backward jump)
#
CREATE OR REPLACE PROCEDURE p24(action IN INT, res OUT varchar) AS
a integer;
BEGIN
<<lab1>>
<<lab2>>
if (action = 1) then
res:=res||' '||action;
action:=2;
goto lab1;
end if;
if (action = 2) then
res:=res||' '||action;
action:=3;
goto lab2;
end if;
END;
$$
call p24(1,@res);
select 'p24',@res;
p24 @res
p24 1 2
DROP PROCEDURE p24;
#
# Two consecutive label (backward and forward jump)
#
CREATE OR REPLACE PROCEDURE p25(action IN INT, res OUT varchar) AS
a integer;
BEGIN
if (action = 1) then
res:=res||' '||action;
action:=2;
goto lab2;
end if;
goto lab_end;
<<lab1>>
<<lab2>>
res:=res||' '||action;
if (action = 2) then
res:=res||' '||action;
action:=3;
goto lab1;
end if;
<<lab_end>>
null;
END;
$$
call p25(1,@res);
select 'p25',@res;
p25 @res
p25 1 2 2 3
DROP PROCEDURE p25;
#
# Two consecutive label, continue to wrong label
CREATE OR REPLACE PROCEDURE p26(action IN INT, res OUT varchar) AS
BEGIN
<<lab1>>
<<lab2>>
FOR i IN 1..10 LOOP
continue lab1;
END LOOP;
END;
$$
ERROR 42000: CONTINUE with no matching label: lab1
#
# Consecutive goto label and block label
#
CREATE OR REPLACE PROCEDURE p27(action IN INT, res OUT varchar) AS
BEGIN
res:='';
<<lab1>>
<<lab2>>
FOR i IN 1..10 LOOP
if (action = 1) then
res:=res||' '||action||'-'||i;
action:=2;
continue lab2;
end if;
if (action = 2) then
res:=res||' '||action||'-'||i;
action:='3';
goto lab2;
end if;
if (action = 3) then
res:=res||' '||action||'-'||i;
action:='4';
goto lab1;
end if;
if (action = 4) then
res:=res||' '||action||'-'||i;
exit lab2;
end if;
END LOOP;
END;
$$
call p27(1,@res);
select 'p27',@res;
p27 @res
p27 1-1 2-2 3-1 4-1
DROP PROCEDURE p27;
# ----------------------
# -- TEST IN FUNCTION --
# ----------------------
#
# FUNCTION : Backward jump
#
CREATE or replace function func1()
return varchar
AS
p2 varchar(10);
BEGIN
p2:='a';
<<lab1>>
if (p2='a') then
p2:=p2||'b';
goto lab1;
end if;
if (p2='ab') then
p2:=p2||'c';
end if;
return p2;
END;
$$
select 'func1',func1();
func1 func1()
func1 abc
DROP function func1;
#
# FUNCTION : forward jump
#
CREATE or replace function func2()
return varchar
AS
p2 varchar(10);
BEGIN
p2:='a';
if (p2='a') then
goto lab1;
end if;
p2:='b';
<<lab1>>
return p2;
END;
$$
select 'func2',func2();
func2 func2()
func2 a
DROP function func2;
# ---------------------
# -- TEST IN TRIGGER --
# ---------------------
#
# TRIGGER : forward jump
#
CREATE TABLE t1 (a INT);
CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW
BEGIN
IF :NEW.a IS NULL
THEN
:NEW.a:= 15;
goto end_trg;
END IF;
:NEW.a:= 10;
<<end_trg>>
null;
END;
$$
insert into t1 values (1);
insert into t1 values (null);
SELECT * FROM t1;
a
10
15
DROP TRIGGER trg1;
DROP TABLE t1;
mysql-test/suite/compat/oracle/t/sp-goto.test
0 → 100644
View file @
af7f287b
set
sql_mode
=
oracle
;
--
echo
#
--
echo
# MDEV-10697 sql_mode=ORACLE: GOTO statement
--
echo
#
--
echo
# matrice of tests in procedure
--
echo
# |--------------------------------------------------------
--
echo
# | | Same | Outside | to sub | No |
--
echo
# | | block | one block | block | matching |
--
echo
# | | | | | label |
--
echo
# |--------------------------------------------------------
--
echo
# | Forward jump | F1 | F3 | F5 | F7 |
--
echo
# |--------------------------------------------------------
--
echo
# | Backward jump | F2 | F4 | F6 | F8 |
--
echo
# |--------------------------------------------------------
--
echo
# Jump from handler to outside handling code block : F9
--
echo
# Jump from handler to handling code block : F10 (forbidden)
--
echo
# Jump inside handler : F21
--
echo
# Jump between handler : F22 (forbidden)
--
echo
# Jump from cascaded block with handler : F11
--
echo
# Duplicate label in same block : F12 (forbidden)
--
echo
# Duplicate label in different block : F13
--
echo
# Jump outside unlabeled block : F14
--
echo
# Jump inside/outside labeled block : F15
--
echo
# Jump from if / else : F16
--
echo
# Jump with cursors : F17
--
echo
# Jump outside case : F18
--
echo
# Jump inside/outside case block : F19
--
echo
# Jump outside labeled loop : F20
--
echo
# Jump (continue) labeled loop : F23
--
echo
# Two consecutive label : P24
--
echo
# Two consecutive label (backward and forward jump) : P25
--
echo
# Two consecutive label, continue to wrong label : P26
--
echo
# Consecutive goto label and block label : P27
--
echo
# Test in function
--
echo
# backward jump : func1
--
echo
# forward jump : func2
--
echo
# Test in trigger
--
echo
# forward jump : trg1
--
echo
#
--
echo
# Forward jump in same block
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f1
(
p2
IN
OUT
VARCHAR
)
AS
BEGIN
p2
:=
'a'
;
goto
lab1
;
<<
lab1
>>
goto
lab2
;
p2
:=
'b'
;
<<
lab2
>>
return
;
END
;
$$
DELIMITER
;
$$
call
f1
(
@
wp1
);
select
'f1'
,
@
wp1
;
DROP
PROCEDURE
f1
;
--
echo
#
--
echo
# Backward jump in same block
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f2
(
p2
IN
OUT
VARCHAR
)
AS
BEGIN
p2
:=
'a'
;
<<
lab1
>>
if
(
p2
=
'b'
)
then
return
;
end
if
;
p2
:=
'b'
;
goto
lab1
;
END
;
$$
DELIMITER
;
$$
call
f2
(
@
wp1
);
select
'f2'
,
@
wp1
;
DROP
PROCEDURE
f2
;
--
echo
#
--
echo
# Forward jump outside one block
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f3
(
p2
IN
OUT
VARCHAR
)
AS
BEGIN
p2
:=
'a'
;
if
(
p2
=
'a'
)
then
goto
lab1
;
end
if
;
p2
:=
'c'
;
<<
lab1
>>
return
;
END
;
$$
DELIMITER
;
$$
call
f3
(
@
wp1
);
select
'f3'
,
@
wp1
;
DROP
PROCEDURE
f3
;
--
echo
#
--
echo
# Backward jump outside one block
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f4
(
p2
IN
OUT
VARCHAR
)
AS
BEGIN
p2
:=
'a'
;
<<
lab1
>>
if
(
p2
=
'a'
)
then
p2
:=
p2
||
'b'
;
goto
lab1
;
end
if
;
if
(
p2
=
'ab'
)
then
p2
:=
p2
||
'c'
;
end
if
;
return
;
END
;
$$
DELIMITER
;
$$
call
f4
(
@
wp1
);
select
'f4'
,
@
wp1
;
DROP
PROCEDURE
f4
;
DELIMITER
$$
;
--
echo
#
--
echo
# Forward jump inside sub block
--
error
ER_SP_LILABEL_MISMATCH
CREATE
or
replace
procedure
f5
(
p2
IN
OUT
VARCHAR
)
AS
BEGIN
p2
:=
'a'
;
goto
lab5
;
if
(
p2
=
'a'
)
then
<<
lab5
>>
p2
:=
p2
||
'b'
;
end
if
;
return
;
END
;
$$
DELIMITER
;
$$
DELIMITER
$$
;
--
echo
#
--
echo
# Backward jump inside sub block
--
error
ER_SP_LILABEL_MISMATCH
CREATE
or
replace
procedure
f6
(
p2
IN
OUT
VARCHAR
)
AS
BEGIN
p2
:=
'a'
;
if
(
p2
=
'a'
)
then
<<
lab6
>>
p2
:=
p2
||
'b'
;
return
;
end
if
;
goto
lab6
;
END
;
$$
DELIMITER
;
$$
DELIMITER
$$
;
--
echo
#
--
echo
# Backward jump - missing label
--
error
ER_SP_LILABEL_MISMATCH
CREATE
or
replace
procedure
f7
(
p2
IN
OUT
VARCHAR
)
AS
BEGIN
<<
lab
>>
goto
lab7
;
return
;
END
;
$$
DELIMITER
;
$$
DELIMITER
$$
;
--
echo
#
--
echo
# Forward jump - missing label
--
error
ER_SP_LILABEL_MISMATCH
CREATE
or
replace
procedure
f8
(
p2
IN
OUT
VARCHAR
)
AS
BEGIN
goto
lab8
;
<<
lab
>>
return
;
END
;
$$
DELIMITER
;
$$
--
echo
#
--
echo
# Jump from handler to procedure code
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f9
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
<<
lab9
>>
if
lim
=-
1
then
res
:=
res
||
' -- goto end limit -1 --'
;
goto
lab9_end
;
end
if
;
begin
SELECT
a
INTO
a
FROM
information_schema
.
tables
LIMIT
lim
;
EXCEPTION
WHEN
TOO_MANY_ROWS
THEN
begin
res
:=
res
||
'--- too_many_rows cought ---'
;
lim
:=
0
;
goto
lab9
;
end
;
WHEN
NO_DATA_FOUND
THEN
begin
res
:=
res
||
'--- no_data_found cought ---'
;
lim
:=-
1
;
goto
lab9
;
end
;
end
;
res
:=
res
||
'error'
;
<<
lab9_end
>>
return
;
END
;
$$
DELIMITER
;
$$
SET
@
res
=
''
;
CALL
f9
(
2
,
@
res
);
SELECT
'f9'
,
@
res
;
CALL
f9
(
0
,
@
res
);
SELECT
'f9'
,
@
res
;
DROP
PROCEDURE
f9
;
DELIMITER
$$
;
--
echo
#
--
echo
# Jump from handler to handling bloc
--
error
ER_SP_LILABEL_MISMATCH
CREATE
or
replace
procedure
f10
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
begin
<<
lab10
>>
SELECT
a
INTO
a
FROM
information_schema
.
tables
LIMIT
lim
;
EXCEPTION
WHEN
TOO_MANY_ROWS
THEN
begin
res
:=
'--- too_many_rows cought ---'
;
goto
lab10
;
end
;
WHEN
NO_DATA_FOUND
THEN
res
:=
'--- no_data_found cought ---'
;
end
;
return
;
END
;
$$
--
echo
#
--
echo
# Jump from cascaded block with handler
--
echo
#
CREATE
or
replace
procedure
f11
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
<<
lab11a
>>
begin
SELECT
a
INTO
a
FROM
information_schema
.
tables
LIMIT
lim
;
EXCEPTION
WHEN
TOO_MANY_ROWS
THEN
begin
res
:=
res
||
'--- too_many_rows cought 1 ---'
;
goto
lab11b
;
end
;
WHEN
NO_DATA_FOUND
THEN
begin
res
:=
res
||
'--- no_data_found cought 1 ---'
;
lim
:=
2
;
SELECT
a
INTO
a
FROM
information_schema
.
tables
LIMIT
lim
;
EXCEPTION
WHEN
TOO_MANY_ROWS
THEN
begin
res
:=
res
||
'--- too_many_rows cought 2 ---'
;
goto
lab11a
;
end
;
WHEN
NO_DATA_FOUND
THEN
res
:=
'--- no_data_found cought 2 ---'
;
end
;
end
;
set
res
:=
res
||
' error '
;
<<
lab11b
>>
return
;
END
;
$$
DELIMITER
;
$$
SET
@
res
=
''
;
CALL
f11
(
0
,
@
res
);
SELECT
'f11'
,
@
res
;
DROP
PROCEDURE
f11
;
DELIMITER
$$
;
--
echo
#
--
echo
# Jump inside handler
--
echo
#
CREATE
or
replace
procedure
f21
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
begin
SELECT
a
INTO
a
FROM
information_schema
.
tables
LIMIT
lim
;
EXCEPTION
WHEN
TOO_MANY_ROWS
THEN
begin
<<
retry
>>
lim
:=
lim
-
1
;
loop
begin
SELECT
a
INTO
a
FROM
information_schema
.
tables
LIMIT
lim
;
EXCEPTION
WHEN
TOO_MANY_ROWS
THEN
begin
lim
:=
lim
-
1
;
goto
retry
;
end
;
end
;
exit
;
end
loop
;
end
;
end
;
res
:=
lim
;
return
;
END
;
$$
DELIMITER
;
$$
SET
@
res
=
''
;
CALL
f21
(
10
,
@
res
);
SELECT
'f21'
,
@
res
;
drop
procedure
f21
;
DELIMITER
$$
;
--
echo
#
--
echo
# Jump beetween handler
--
error
ER_SP_LILABEL_MISMATCH
CREATE
or
replace
procedure
f22
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
res
:=
'ok'
;
begin
SELECT
a
INTO
a
FROM
information_schema
.
tables
LIMIT
lim
;
EXCEPTION
WHEN
TOO_MANY_ROWS
THEN
goto
nodata
;
WHEN
NO_DATA_FOUND
THEN
begin
<<
nodata
>>
res
:=
'error'
;
end
;
end
;
return
;
END
;
$$
DELIMITER
;
$$
DELIMITER
$$
;
--
echo
#
--
echo
# Duplicate label in same bloc
--
error
1309
CREATE
or
replace
procedure
f12
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
<<
lab12
>>
res
:=
'error'
;
<<
lab12
>>
return
;
END
;
$$
DELIMITER
;
$$
--
echo
#
--
echo
# Duplicate label in different block
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f13
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
a
:=
0
;
<<
lab13
>>
a
:=
a
+
1
;
begin
<<
lab13
>>
a
:=
a
+
1
;
if
(
a
<
10
)
then
goto
lab13
;
end
if
;
end
;
res
:=
a
;
if
(
a
=
10
)
then
goto
lab13
;
end
if
;
return
;
END
;
$$
DELIMITER
;
$$
SET
@
res
=
''
;
CALL
f13
(
0
,
@
res
);
SELECT
'f13'
,
@
res
;
DROP
PROCEDURE
f13
;
--
echo
#
--
echo
# Jump outside unlabeled block
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f14
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
a
:=
0
;
loop
a
:=
a
+
1
;
if
(
a
<
10
)
then
continue
;
end
if
;
if
(
a
>=
lim
)
then
goto
lab14
;
end
if
;
if
(
a
>=
20
)
then
exit
;
end
if
;
end
loop
;
<<
lab14
>>
res
:=
a
;
return
;
END
;
$$
DELIMITER
;
$$
SET
@
res
=
''
;
CALL
f14
(
15
,
@
res
);
SELECT
'f14'
,
@
res
;
CALL
f14
(
8
,
@
res
);
SELECT
'f14'
,
@
res
;
CALL
f14
(
25
,
@
res
);
SELECT
'f14'
,
@
res
;
DROP
PROCEDURE
f14
;
--
echo
#
--
echo
# Jump inside/outside labeled block
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f15
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
a
:=
0
;
<<
looplabel
>>
loop
<<
beginlooplabel
>>
a
:=
a
+
1
;
if
(
a
<
10
)
then
continue
looplabel
;
end
if
;
if
(
a
>=
lim
)
then
goto
lab15
;
end
if
;
if
(
a
>=
20
)
then
exit
looplabel
;
end
if
;
goto
beginlooplabel
;
end
loop
;
<<
lab15
>>
res
:=
a
;
return
;
END
;
$$
DELIMITER
;
$$
SET
@
res
=
''
;
CALL
f15
(
15
,
@
res
);
SELECT
'f15'
,
@
res
;
CALL
f15
(
8
,
@
res
);
SELECT
'f15'
,
@
res
;
CALL
f15
(
25
,
@
res
);
SELECT
'f15'
,
@
res
;
DROP
PROCEDURE
f15
;
--
echo
#
--
echo
# Jump from if / else
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f16
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
if
(
lim
<
10
)
then
goto
lab16_1
;
else
goto
lab16_2
;
end
if
;
<<
lab16_1
>>
res
:=
'if lab16_1'
;
goto
lab16_3
;
<<
lab16_2
>>
res
:=
'else lab16_2'
;
goto
lab16_3
;
res
:=
'error lab16_3'
;
<<
lab16_3
>>
return
;
END
;
$$
DELIMITER
;
$$
SET
@
res
=
''
;
CALL
f16
(
15
,
@
res
);
SELECT
'f16'
,
@
res
;
CALL
f16
(
8
,
@
res
);
SELECT
'f16'
,
@
res
;
DROP
PROCEDURE
f16
;
--
echo
#
--
echo
# Jump with cursors
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f17
(
lim
INT
,
res
OUT
VARCHAR
)
AS
v_a
INT
;
v_b
VARCHAR
(
10
);
CURSOR
cur1
IS
SELECT
1
FROM
dual
where
1
=
2
;
BEGIN
OPEN
cur1
;
LOOP
FETCH
cur1
INTO
v_a
;
EXIT
WHEN
cur1
%
NOTFOUND
;
END
LOOP
;
CLOSE
cur1
;
<<
lab17
>>
lim
:=
lim
-
1
;
begin
declare
CURSOR
cur1
IS
SELECT
1
FROM
dual
;
CURSOR
cur2
IS
SELECT
1
FROM
dual
where
1
=
2
;
begin
LOOP
OPEN
cur1
;
FETCH
cur1
INTO
v_a
;
EXIT
WHEN
cur1
%
NOTFOUND
;
res
:=
res
||
'-'
||
lim
;
close
cur1
;
if
(
lim
>
0
)
then
goto
lab17
;
else
goto
lab17_end
;
end
if
;
END
LOOP
;
end
;
<<
lab17_end
>>
null
;
end
;
END
;
$$
DELIMITER
;
$$
SET
@
res
=
''
;
CALL
f17
(
5
,
@
res
);
SELECT
'f17'
,
@
res
;
DROP
PROCEDURE
f17
;
--
echo
#
--
echo
# Jump outside case
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f18
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
case
lim
when
1
then
res
:=
'case branch 18_1'
;
goto
lab18_1
;
res
:=
'error'
;
when
2
then
res
:=
'case branch 18_2'
;
goto
lab18_2
;
res
:=
'error'
;
else
res
:=
'default branch 18'
;
end
case
;
<<
lab18_1
>>
null
;
<<
lab18_2
>>
return
;
END
;
$$
DELIMITER
;
$$
SET
@
res
=
''
;
CALL
f18
(
0
,
@
res
);
SELECT
'f18'
,
@
res
;
CALL
f18
(
1
,
@
res
);
SELECT
'f18'
,
@
res
;
CALL
f18
(
2
,
@
res
);
SELECT
'f18'
,
@
res
;
DROP
PROCEDURE
f18
;
--
echo
#
--
echo
# Jump inside/outside case block
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
procedure
f19
(
lim
INT
,
res
OUT
VARCHAR
)
AS
a
INT
;
BEGIN
a
:=
1
;
case
lim
when
1
then
<<
lab19_0
>>
a
:=
a
+
1
;
if
(
a
<
10
)
then
goto
lab19_0
;
else
goto
lab19_1
;
end
if
;
res
:=
'case branch 19_1'
;
else
res
:=
'default branch 18'
;
end
case
;
goto
lab19_end
;
<<
lab19_1
>>
res
:=
a
;
<<
lab19_end
>>
return
;
END
;
$$
DELIMITER
;
$$
SET
@
res
=
''
;
CALL
f19
(
1
,
@
res
);
SELECT
'f19'
,
@
res
;
DROP
PROCEDURE
f19
;
DELIMITER
$$
;
--
echo
#
--
echo
# Jump outside labeled loop
--
echo
#
CREATE
OR
REPLACE
PROCEDURE
f20
(
res
OUT
VARCHAR
)
AS
a
INT
:=
1
;
BEGIN
<<
lab
>>
FOR
i
IN
a
..
10
LOOP
IF
i
=
5
THEN
a
:=
a
+
1
;
goto
lab
;
END
IF
;
END
LOOP
;
res
:=
a
;
END
;
$$
DELIMITER
;
$$
CALL
f20
(
@
res
);
SELECT
'f20'
,
@
res
;
DROP
PROCEDURE
f20
;
DELIMITER
$$
;
--
echo
#
--
echo
# Jump (continue) labeled loop
--
echo
#
CREATE
OR
REPLACE
PROCEDURE
f23
(
res
OUT
VARCHAR
)
AS
a
INT
:=
1
;
BEGIN
<<
lab
>>
FOR
i
IN
a
..
10
LOOP
IF
i
=
5
THEN
a
:=
a
+
1
;
continue
lab
;
END
IF
;
END
LOOP
;
res
:=
a
;
END
;
$$
DELIMITER
;
$$
CALL
f23
(
@
res
);
SELECT
'f23'
,
@
res
;
DROP
PROCEDURE
f23
;
DELIMITER
$$
;
--
echo
#
--
echo
# Two consecutive label (backward jump)
--
echo
#
CREATE
OR
REPLACE
PROCEDURE
p24
(
action
IN
INT
,
res
OUT
varchar
)
AS
a
integer
;
BEGIN
<<
lab1
>>
<<
lab2
>>
if
(
action
=
1
)
then
res
:=
res
||
' '
||
action
;
action
:=
2
;
goto
lab1
;
end
if
;
if
(
action
=
2
)
then
res
:=
res
||
' '
||
action
;
action
:=
3
;
goto
lab2
;
end
if
;
END
;
$$
DELIMITER
;
$$
call
p24
(
1
,
@
res
);
select
'p24'
,
@
res
;
DROP
PROCEDURE
p24
;
DELIMITER
$$
;
--
echo
#
--
echo
# Two consecutive label (backward and forward jump)
--
echo
#
CREATE
OR
REPLACE
PROCEDURE
p25
(
action
IN
INT
,
res
OUT
varchar
)
AS
a
integer
;
BEGIN
if
(
action
=
1
)
then
res
:=
res
||
' '
||
action
;
action
:=
2
;
goto
lab2
;
end
if
;
goto
lab_end
;
<<
lab1
>>
<<
lab2
>>
res
:=
res
||
' '
||
action
;
if
(
action
=
2
)
then
res
:=
res
||
' '
||
action
;
action
:=
3
;
goto
lab1
;
end
if
;
<<
lab_end
>>
null
;
END
;
$$
DELIMITER
;
$$
call
p25
(
1
,
@
res
);
select
'p25'
,
@
res
;
DROP
PROCEDURE
p25
;
DELIMITER
$$
;
--
echo
#
--
echo
# Two consecutive label, continue to wrong label
--
error
ER_SP_LILABEL_MISMATCH
CREATE
OR
REPLACE
PROCEDURE
p26
(
action
IN
INT
,
res
OUT
varchar
)
AS
BEGIN
<<
lab1
>>
<<
lab2
>>
FOR
i
IN
1.
.
10
LOOP
continue
lab1
;
END
LOOP
;
END
;
$$
DELIMITER
;
$$
DELIMITER
$$
;
--
echo
#
--
echo
# Consecutive goto label and block label
--
echo
#
CREATE
OR
REPLACE
PROCEDURE
p27
(
action
IN
INT
,
res
OUT
varchar
)
AS
BEGIN
res
:=
''
;
<<
lab1
>>
<<
lab2
>>
FOR
i
IN
1.
.
10
LOOP
if
(
action
=
1
)
then
res
:=
res
||
' '
||
action
||
'-'
||
i
;
action
:=
2
;
continue
lab2
;
end
if
;
if
(
action
=
2
)
then
res
:=
res
||
' '
||
action
||
'-'
||
i
;
action
:=
'3'
;
goto
lab2
;
end
if
;
if
(
action
=
3
)
then
res
:=
res
||
' '
||
action
||
'-'
||
i
;
action
:=
'4'
;
goto
lab1
;
end
if
;
if
(
action
=
4
)
then
res
:=
res
||
' '
||
action
||
'-'
||
i
;
exit
lab2
;
end
if
;
END
LOOP
;
END
;
$$
DELIMITER
;
$$
call
p27
(
1
,
@
res
);
select
'p27'
,
@
res
;
DROP
PROCEDURE
p27
;
--
echo
# ----------------------
--
echo
# -- TEST IN FUNCTION --
--
echo
# ----------------------
--
echo
#
--
echo
# FUNCTION : Backward jump
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
function
func1
()
return
varchar
AS
p2
varchar
(
10
);
BEGIN
p2
:=
'a'
;
<<
lab1
>>
if
(
p2
=
'a'
)
then
p2
:=
p2
||
'b'
;
goto
lab1
;
end
if
;
if
(
p2
=
'ab'
)
then
p2
:=
p2
||
'c'
;
end
if
;
return
p2
;
END
;
$$
DELIMITER
;
$$
select
'func1'
,
func1
();
DROP
function
func1
;
--
echo
#
--
echo
# FUNCTION : forward jump
--
echo
#
DELIMITER
$$
;
CREATE
or
replace
function
func2
()
return
varchar
AS
p2
varchar
(
10
);
BEGIN
p2
:=
'a'
;
if
(
p2
=
'a'
)
then
goto
lab1
;
end
if
;
p2
:=
'b'
;
<<
lab1
>>
return
p2
;
END
;
$$
DELIMITER
;
$$
select
'func2'
,
func2
();
DROP
function
func2
;
--
echo
# ---------------------
--
echo
# -- TEST IN TRIGGER --
--
echo
# ---------------------
--
echo
#
--
echo
# TRIGGER : forward jump
--
echo
#
CREATE
TABLE
t1
(
a
INT
);
DELIMITER
$$
;
CREATE
TRIGGER
trg1
BEFORE
INSERT
ON
t1
FOR
EACH
ROW
BEGIN
IF
:
NEW
.
a
IS
NULL
THEN
:
NEW
.
a
:=
15
;
goto
end_trg
;
END
IF
;
:
NEW
.
a
:=
10
;
<<
end_trg
>>
null
;
END
;
$$
DELIMITER
;
$$
insert
into
t1
values
(
1
);
insert
into
t1
values
(
null
);
SELECT
*
FROM
t1
;
DROP
TRIGGER
trg1
;
DROP
TABLE
t1
;
\ No newline at end of file
sql/lex.h
View file @
af7f287b
...
...
@@ -261,6 +261,7 @@ static SYMBOL symbols[] = {
{
"GET_FORMAT"
,
SYM
(
GET_FORMAT
)},
{
"GET"
,
SYM
(
GET_SYM
)},
{
"GLOBAL"
,
SYM
(
GLOBAL_SYM
)},
{
"GOTO"
,
SYM
(
GOTO_SYM
)},
{
"GRANT"
,
SYM
(
GRANT
)},
{
"GRANTS"
,
SYM
(
GRANTS
)},
{
"GROUP"
,
SYM
(
GROUP_SYM
)},
...
...
sql/sp_head.cc
View file @
af7f287b
...
...
@@ -556,6 +556,7 @@ sp_head::sp_head()
DBUG_ENTER
(
"sp_head::sp_head"
);
m_backpatch
.
empty
();
m_backpatch_goto
.
empty
();
m_cont_backpatch
.
empty
();
m_lex
.
empty
();
my_hash_init
(
&
m_sptabs
,
system_charset_info
,
0
,
0
,
0
,
sp_table_key
,
0
,
0
);
...
...
@@ -2212,7 +2213,8 @@ sp_head::merge_lex(THD *thd, LEX *oldlex, LEX *sublex)
Put the instruction on the backpatch list, associated with the label.
*/
int
sp_head
::
push_backpatch
(
THD
*
thd
,
sp_instr
*
i
,
sp_label
*
lab
)
sp_head
::
push_backpatch
(
THD
*
thd
,
sp_instr
*
i
,
sp_label
*
lab
,
List
<
bp_t
>
*
list
,
backpatch_instr_type
itype
)
{
bp_t
*
bp
=
(
bp_t
*
)
thd
->
alloc
(
sizeof
(
bp_t
));
...
...
@@ -2220,7 +2222,45 @@ sp_head::push_backpatch(THD *thd, sp_instr *i, sp_label *lab)
return
1
;
bp
->
lab
=
lab
;
bp
->
instr
=
i
;
return
m_backpatch
.
push_front
(
bp
);
bp
->
instr_type
=
itype
;
return
list
->
push_front
(
bp
);
}
int
sp_head
::
push_backpatch
(
THD
*
thd
,
sp_instr
*
i
,
sp_label
*
lab
)
{
return
push_backpatch
(
thd
,
i
,
lab
,
&
m_backpatch
,
GOTO
);
}
int
sp_head
::
push_backpatch_goto
(
THD
*
thd
,
sp_pcontext
*
ctx
,
sp_label
*
lab
)
{
uint
ip
=
instructions
();
/*
Add cpop/hpop : they will be removed or updated later if target is in
the same block or not
*/
sp_instr_hpop
*
hpop
=
new
(
thd
->
mem_root
)
sp_instr_hpop
(
ip
++
,
ctx
,
0
);
if
(
hpop
==
NULL
||
add_instr
(
hpop
))
return
true
;
if
(
push_backpatch
(
thd
,
hpop
,
lab
,
&
m_backpatch_goto
,
HPOP
))
return
true
;
sp_instr_cpop
*
cpop
=
new
(
thd
->
mem_root
)
sp_instr_cpop
(
ip
++
,
ctx
,
0
);
if
(
cpop
==
NULL
||
add_instr
(
cpop
))
return
true
;
if
(
push_backpatch
(
thd
,
cpop
,
lab
,
&
m_backpatch_goto
,
CPOP
))
return
true
;
// Add jump with ip=0. IP will be updated when label is found.
sp_instr_jump
*
i
=
new
(
thd
->
mem_root
)
sp_instr_jump
(
ip
,
ctx
);
if
(
i
==
NULL
||
add_instr
(
i
))
return
true
;
if
(
push_backpatch
(
thd
,
i
,
lab
,
&
m_backpatch_goto
,
GOTO
))
return
true
;
return
false
;
}
/**
...
...
@@ -2247,6 +2287,97 @@ sp_head::backpatch(sp_label *lab)
DBUG_VOID_RETURN
;
}
void
sp_head
::
backpatch_goto
(
THD
*
thd
,
sp_label
*
lab
,
sp_label
*
lab_begin_block
)
{
bp_t
*
bp
;
uint
dest
=
instructions
();
List_iterator
<
bp_t
>
li
(
m_backpatch_goto
);
DBUG_ENTER
(
"sp_head::backpatch_goto"
);
while
((
bp
=
li
++
))
{
if
(
bp
->
instr
->
m_ip
<
lab_begin_block
->
ip
||
bp
->
instr
->
m_ip
>
lab
->
ip
)
{
/*
Update only jump target from the beginning of the block where the
label is defined.
*/
continue
;
}
if
(
my_strcasecmp
(
system_charset_info
,
bp
->
lab
->
name
.
str
,
lab
->
name
.
str
)
==
0
)
{
if
(
bp
->
instr_type
==
GOTO
)
{
DBUG_PRINT
(
"info"
,
(
"backpatch_goto: (m_ip %d, label 0x%lx <%s>) to dest %d"
,
bp
->
instr
->
m_ip
,
(
ulong
)
lab
,
lab
->
name
.
str
,
dest
));
bp
->
instr
->
backpatch
(
dest
,
lab
->
ctx
);
// Jump resolved, remove from the list
li
.
remove
();
continue
;
}
if
(
bp
->
instr_type
==
CPOP
)
{
int
n
=
lab
->
ctx
->
diff_cursors
(
lab_begin_block
->
ctx
,
true
);
if
(
n
==
0
)
{
// Remove cpop instr
replace_instr_to_nop
(
thd
,
bp
->
instr
->
m_ip
);
}
else
{
// update count of cpop
static_cast
<
sp_instr_cpop
*>
(
bp
->
instr
)
->
update_count
(
n
);
n
=
1
;
}
li
.
remove
();
continue
;
}
if
(
bp
->
instr_type
==
HPOP
)
{
int
n
=
lab
->
ctx
->
diff_handlers
(
lab_begin_block
->
ctx
,
true
);
if
(
n
==
0
)
{
// Remove hpop instr
replace_instr_to_nop
(
thd
,
bp
->
instr
->
m_ip
);
}
else
{
// update count of cpop
static_cast
<
sp_instr_hpop
*>
(
bp
->
instr
)
->
update_count
(
n
);
n
=
1
;
}
li
.
remove
();
continue
;
}
}
}
DBUG_VOID_RETURN
;
}
bool
sp_head
::
check_unresolved_goto
()
{
DBUG_ENTER
(
"sp_head::check_unresolved_goto"
);
bool
has_unresolved_label
=
false
;
if
(
m_backpatch_goto
.
elements
>
0
)
{
List_iterator_fast
<
bp_t
>
li
(
m_backpatch_goto
);
bp_t
*
bp
;
while
((
bp
=
li
++
))
{
if
((
bp
->
instr_type
==
GOTO
))
{
my_error
(
ER_SP_LILABEL_MISMATCH
,
MYF
(
0
),
"GOTO"
,
bp
->
lab
->
name
);
has_unresolved_label
=
true
;
}
}
}
DBUG_RETURN
(
has_unresolved_label
);
}
int
sp_head
::
new_cont_backpatch
(
sp_instr_opt_meta
*
i
)
...
...
sql/sp_head.h
View file @
af7f287b
...
...
@@ -516,11 +516,19 @@ class sp_head :private Query_arena,
/// Put the instruction on the backpatch list, associated with the label.
int
push_backpatch
(
THD
*
thd
,
sp_instr
*
,
sp_label
*
);
int
push_backpatch_goto
(
THD
*
thd
,
sp_pcontext
*
ctx
,
sp_label
*
lab
);
/// Update all instruction with this label in the backpatch list to
/// the current position.
void
backpatch
(
sp_label
*
);
void
backpatch_goto
(
THD
*
thd
,
sp_label
*
,
sp_label
*
);
/// Check for unresolved goto label
bool
check_unresolved_goto
();
/// Start a new cont. backpatch level. If 'i' is NULL, the level is just incr.
int
...
...
@@ -695,12 +703,17 @@ class sp_head :private Query_arena,
sp_pcontext
*
m_pcont
;
///< Parse context
List
<
LEX
>
m_lex
;
///< Temp. store for the other lex
DYNAMIC_ARRAY
m_instr
;
///< The "instructions"
enum
backpatch_instr_type
{
GOTO
,
CPOP
,
HPOP
};
typedef
struct
{
sp_label
*
lab
;
sp_instr
*
instr
;
backpatch_instr_type
instr_type
;
}
bp_t
;
List
<
bp_t
>
m_backpatch
;
///< Instructions needing backpatching
List
<
bp_t
>
m_backpatch_goto
;
// Instructions needing backpatching (for goto)
/**
We need a special list for backpatching of instructions with a continue
destination (in the case of a continue handler catching an error in
...
...
@@ -738,6 +751,12 @@ class sp_head :private Query_arena,
by routine.
*/
bool
merge_table_list
(
THD
*
thd
,
TABLE_LIST
*
table
,
LEX
*
lex_for_tmp_check
);
/// Put the instruction on the a backpatch list, associated with the label.
int
push_backpatch
(
THD
*
thd
,
sp_instr
*
,
sp_label
*
,
List
<
bp_t
>
*
list
,
backpatch_instr_type
itype
);
}
;
// class sp_head : public Sql_alloc
...
...
@@ -1359,6 +1378,11 @@ class sp_instr_hpop : public sp_instr
virtual
~
sp_instr_hpop
()
{}
void
update_count
(
uint
count
)
{
m_count
=
count
;
}
virtual
int
execute
(
THD
*
thd
,
uint
*
nextp
);
virtual
void
print
(
String
*
str
);
...
...
@@ -1451,6 +1475,11 @@ class sp_instr_cpop : public sp_instr
virtual
~
sp_instr_cpop
()
{}
void
update_count
(
uint
count
)
{
m_count
=
count
;
}
virtual
int
execute
(
THD
*
thd
,
uint
*
nextp
);
virtual
void
print
(
String
*
str
);
...
...
sql/sp_pcontext.cc
View file @
af7f287b
...
...
@@ -87,6 +87,7 @@ void sp_pcontext::init(uint var_offset,
m_num_case_exprs
=
num_case_expressions
;
m_labels
.
empty
();
m_goto_labels
.
empty
();
}
...
...
@@ -129,6 +130,12 @@ sp_pcontext *sp_pcontext::push_context(THD *thd, sp_pcontext::enum_scope scope)
}
bool
cmp_labels
(
sp_label
*
a
,
sp_label
*
b
)
{
return
(
my_strcasecmp
(
system_charset_info
,
a
->
name
.
str
,
b
->
name
.
str
)
==
0
&&
a
->
type
==
b
->
type
);
}
sp_pcontext
*
sp_pcontext
::
pop_context
()
{
m_parent
->
m_max_var_index
+=
m_max_var_index
;
...
...
@@ -140,6 +147,18 @@ sp_pcontext *sp_pcontext::pop_context()
if
(
m_num_case_exprs
>
m_parent
->
m_num_case_exprs
)
m_parent
->
m_num_case_exprs
=
m_num_case_exprs
;
/*
** Push unresolved goto label to parent context
*/
sp_label
*
label
;
List_iterator_fast
<
sp_label
>
li
(
m_goto_labels
);
while
((
label
=
li
++
))
{
if
(
label
->
ip
==
0
)
{
m_parent
->
m_goto_labels
.
add_unique
(
label
,
&
cmp_labels
);
}
}
return
m_parent
;
}
...
...
@@ -227,9 +246,9 @@ sp_variable *sp_pcontext::add_variable(THD *thd, LEX_STRING name)
return
m_vars
.
append
(
p
)
?
NULL
:
p
;
}
sp_label
*
sp_pcontext
::
push_label
(
THD
*
thd
,
LEX_STRING
name
,
uint
ip
,
sp_label
::
enum_type
type
)
sp_label
::
enum_type
type
,
List
<
sp_label
>
*
list
)
{
sp_label
*
label
=
new
(
thd
->
mem_root
)
sp_label
(
name
,
ip
,
type
,
this
);
...
...
@@ -237,11 +256,47 @@ sp_label *sp_pcontext::push_label(THD *thd, LEX_STRING name, uint ip,
if
(
!
label
)
return
NULL
;
m_labels
.
push_front
(
label
,
thd
->
mem_root
);
list
->
push_front
(
label
,
thd
->
mem_root
);
return
label
;
}
sp_label
*
sp_pcontext
::
find_goto_label
(
const
LEX_STRING
name
,
bool
recusive
)
{
List_iterator_fast
<
sp_label
>
li
(
m_goto_labels
);
sp_label
*
lab
;
while
((
lab
=
li
++
))
{
if
(
my_strcasecmp
(
system_charset_info
,
name
.
str
,
lab
->
name
.
str
)
==
0
)
return
lab
;
}
if
(
!
recusive
)
return
NULL
;
/*
Note about exception handlers.
See SQL:2003 SQL/PSM (ISO/IEC 9075-4:2003),
section 13.1 <compound statement>,
syntax rule 4.
In short, a DECLARE HANDLER block can not refer
to labels from the parent context, as they are out of scope.
*/
if
(
m_scope
==
HANDLER_SCOPE
&&
m_parent
)
{
if
(
m_parent
->
m_parent
)
{
// Skip the parent context
return
m_parent
->
m_parent
->
find_goto_label
(
name
);
}
}
return
m_parent
&&
(
m_scope
==
REGULAR_SCOPE
)
?
m_parent
->
find_goto_label
(
name
)
:
NULL
;
}
sp_label
*
sp_pcontext
::
find_label
(
const
LEX_STRING
name
)
{
...
...
sql/sp_pcontext.h
View file @
af7f287b
...
...
@@ -94,6 +94,7 @@ class sp_variable : public Sql_alloc
/// IF/WHILE/REPEAT/LOOP, when such statement is rewritten into a
/// combination of low-level jump/jump_if instructions and labels.
class
sp_label
:
public
Sql_alloc
{
public:
...
...
@@ -106,7 +107,10 @@ class sp_label : public Sql_alloc
BEGIN
,
/// Label at iteration control
ITERATION
ITERATION
,
/// Label for jump
GOTO
};
/// Name of the label.
...
...
@@ -132,6 +136,7 @@ class sp_label : public Sql_alloc
{
}
};
///////////////////////////////////////////////////////////////////////////
/// This class represents condition-value term in DECLARE CONDITION or
...
...
@@ -507,15 +512,29 @@ class sp_pcontext : public Sql_alloc
/////////////////////////////////////////////////////////////////////////
sp_label
*
push_label
(
THD
*
thd
,
const
LEX_STRING
name
,
uint
ip
,
sp_label
::
enum_type
type
);
sp_label
::
enum_type
type
,
List
<
sp_label
>
*
list
);
sp_label
*
push_label
(
THD
*
thd
,
LEX_STRING
name
,
uint
ip
,
sp_label
::
enum_type
type
)
{
return
push_label
(
thd
,
name
,
ip
,
type
,
&
m_labels
);
}
sp_label
*
push_goto_label
(
THD
*
thd
,
LEX_STRING
name
,
uint
ip
,
sp_label
::
enum_type
type
)
{
return
push_label
(
thd
,
name
,
ip
,
type
,
&
m_goto_labels
);
}
sp_label
*
push_label
(
THD
*
thd
,
const
LEX_STRING
name
,
uint
ip
)
{
return
push_label
(
thd
,
name
,
ip
,
sp_label
::
IMPLICIT
);
}
{
return
push_label
(
thd
,
name
,
ip
,
sp_label
::
IMPLICIT
);
}
sp_label
*
push_goto_label
(
THD
*
thd
,
const
LEX_STRING
name
,
uint
ip
)
{
return
push_goto_label
(
thd
,
name
,
ip
,
sp_label
::
GOTO
);
}
sp_label
*
find_label
(
const
LEX_STRING
name
);
sp_label
*
find_goto_label
(
const
LEX_STRING
name
,
bool
recusive
);
sp_label
*
find_goto_label
(
const
LEX_STRING
name
)
{
return
find_goto_label
(
name
,
true
);
}
sp_label
*
find_label_current_loop_start
();
sp_label
*
last_label
()
...
...
@@ -528,6 +547,11 @@ class sp_pcontext : public Sql_alloc
return
label
;
}
sp_label
*
last_goto_label
()
{
return
m_goto_labels
.
head
();
}
sp_label
*
pop_label
()
{
return
m_labels
.
pop
();
}
...
...
@@ -697,8 +721,27 @@ class sp_pcontext : public Sql_alloc
/// Stack of SQL-handlers.
Dynamic_array
<
sp_handler
*>
m_handlers
;
/// List of labels.
/*
In the below example the label <<lab>> has two meanings:
- GOTO lab : must go before the beginning of the loop
- CONTINUE lab : must go to the beginning of the loop
We solve this by storing block labels and goto labels into separate lists.
BEGIN
<<lab>>
FOR i IN a..10 LOOP
...
GOTO lab;
...
CONTINUE lab;
...
END LOOP;
END;
*/
/// List of block labels
List
<
sp_label
>
m_labels
;
/// List of goto labels
List
<
sp_label
>
m_goto_labels
;
/// Children contexts, used for destruction.
Dynamic_array
<
sp_pcontext
*>
m_children
;
...
...
sql/sql_lex.cc
View file @
af7f287b
...
...
@@ -5704,6 +5704,54 @@ bool LEX::sp_leave_statement(THD *thd, const LEX_STRING label_name)
return
sp_exit_block
(
thd
,
lab
,
NULL
);
}
bool
LEX
::
sp_goto_statement
(
THD
*
thd
,
const
LEX_STRING
label_name
)
{
sp_label
*
lab
=
spcont
->
find_goto_label
(
label_name
);
if
(
!
lab
||
lab
->
ip
==
0
)
{
sp_label
*
delayedlabel
;
if
(
!
lab
)
{
// Label not found --> add forward jump to an unknown label
spcont
->
push_goto_label
(
thd
,
label_name
,
0
,
sp_label
::
GOTO
);
delayedlabel
=
spcont
->
last_goto_label
();
}
else
{
delayedlabel
=
lab
;
}
return
sphead
->
push_backpatch_goto
(
thd
,
spcont
,
delayedlabel
);
}
else
{
// Label found (backward goto)
return
sp_change_context
(
thd
,
lab
->
ctx
,
false
)
||
sphead
->
add_instr_jump
(
thd
,
spcont
,
lab
->
ip
);
/* Jump back */
}
return
false
;
}
bool
LEX
::
sp_push_goto_label
(
THD
*
thd
,
const
LEX_STRING
label_name
)
{
sp_label
*
lab
=
spcont
->
find_goto_label
(
label_name
,
false
);
if
(
lab
)
{
if
(
lab
->
ip
!=
0
)
{
my_error
(
ER_SP_LABEL_REDEFINE
,
MYF
(
0
),
label_name
.
str
);
return
true
;
}
lab
->
ip
=
sphead
->
instructions
();
sp_label
*
beginblocklabel
=
spcont
->
find_label
(
empty_lex_str
);
sphead
->
backpatch_goto
(
thd
,
lab
,
beginblocklabel
);
}
else
{
spcont
->
push_goto_label
(
thd
,
label_name
,
sphead
->
instructions
());
}
return
false
;
}
bool
LEX
::
sp_exit_block
(
THD
*
thd
,
sp_label
*
lab
)
{
...
...
sql/sql_lex.h
View file @
af7f287b
...
...
@@ -3317,6 +3317,7 @@ struct LEX: public Query_tables_list
bool
sp_exit_statement
(
THD
*
thd
,
Item
*
when
);
bool
sp_exit_statement
(
THD
*
thd
,
const
LEX_STRING
label_name
,
Item
*
item
);
bool
sp_leave_statement
(
THD
*
thd
,
const
LEX_STRING
label_name
);
bool
sp_goto_statement
(
THD
*
thd
,
const
LEX_STRING
label_name
);
bool
sp_continue_statement
(
THD
*
thd
,
Item
*
when
);
bool
sp_continue_statement
(
THD
*
thd
,
const
LEX_STRING
label_name
,
Item
*
when
);
...
...
@@ -3329,6 +3330,7 @@ struct LEX: public Query_tables_list
void
sp_pop_loop_empty_label
(
THD
*
thd
);
bool
sp_while_loop_expression
(
THD
*
thd
,
Item
*
expr
);
bool
sp_while_loop_finalize
(
THD
*
thd
);
bool
sp_push_goto_label
(
THD
*
thd
,
LEX_STRING
label_name
);
Item_param
*
add_placeholder
(
THD
*
thd
,
char
*
name
,
uint
pos_in_query
,
uint
len_in_query
);
...
...
sql/sql_yacc.yy
View file @
af7f287b
...
...
@@ -1098,6 +1098,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token GET_FORMAT /* MYSQL-FUNC */
%token GET_SYM /* SQL-2003-R */
%token GLOBAL_SYM /* SQL-2003-R */
%token GOTO_SYM /* Oracle, reserved in PL/SQL*/
%token GRANT /* SQL-2003-R */
%token GRANTS
%token GROUP_SYM /* SQL-2003-R */
...
...
@@ -14288,6 +14289,7 @@ keyword_sp:
| GET_FORMAT {}
| GRANTS {}
| GLOBAL_SYM {}
| GOTO_SYM {}
| HASH_SYM {}
| HARD_SYM {}
| HOSTS_SYM {}
...
...
sql/sql_yacc_ora.yy
View file @
af7f287b
...
...
@@ -516,6 +516,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token GET_FORMAT /* MYSQL-FUNC */
%token GET_SYM /* SQL-2003-R */
%token GLOBAL_SYM /* SQL-2003-R */
%token GOTO_SYM /* Oracle, reserved in PL/SQL*/
%token GRANT /* SQL-2003-R */
%token GRANTS
%token GROUP_SYM /* SQL-2003-R */
...
...
@@ -1005,7 +1006,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_component key_cache_name
sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
opt_constraint constraint opt_ident
label_declaration_oracle ident_directly_assignable
label_declaration_oracle labels_declaration_oracle
ident_directly_assignable
sp_decl_ident
sp_block_label
...
...
@@ -1307,15 +1309,16 @@ END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
%type <NONE> sp_proc_stmt_statement sp_proc_stmt_return
sp_proc_stmt_in_returns_clause
%type <NONE> sp_proc_stmt_compound_ok
%type <NONE> sp_proc_stmt_if
%type <NONE> sp_labeled_control sp_unlabeled_control
%type <NONE> sp_labeled_block sp_unlabeled_block
%type <NONE> sp_labelable_stmt
%type <NONE> sp_proc_stmt_continue
%type <NONE> sp_proc_stmt_exit
%type <NONE> sp_proc_stmt_leave
%type <NONE> sp_proc_stmt_iterate
%type <NONE> sp_proc_stmt_goto
%type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close
%type <NONE> case_stmt_specification
%type <NONE> loop_body while_body repeat_body
...
...
@@ -2425,6 +2428,17 @@ sp_proc_stmts1:
| sp_proc_stmts1 sp_proc_stmt ';'
;
sp_proc_stmts1_implicit_block:
{
Lex->sp_block_init(thd);
}
sp_proc_stmts1
{
if (Lex->sp_block_finalize(thd))
MYSQL_YYABORT;
}
;
opt_sp_decl_body_list:
/* Empty */
{
...
...
@@ -3034,32 +3048,28 @@ sp_opt_default:
| SET_VAR expr { $$ = $2; }
;
/*
ps_proc_stmt_in_returns_clause is a statement that is allowed
in the RETURNS clause of a stored function definition directly,
without the BEGIN..END block.
It should not include any syntax structures starting with '(', to avoid
shift/reduce conflicts with the rule "field_type" and its sub-rules
that scan an optional length, like CHAR(1) or YEAR(4).
See MDEV-9166.
*/
sp_proc_stmt_in_returns_clause:
sp_proc_stmt_return
| sp_labeled_block
sp_proc_stmt:
sp_labeled_block
| sp_unlabeled_block
| sp_labeled_control
| sp_proc_stmt_compound_ok
| sp_unlabeled_control
| sp_labelable_stmt
| labels_declaration_oracle sp_labelable_stmt {}
;
sp_proc_stmt:
sp_proc_stmt_in_returns_clause
| sp_proc_stmt_statement
sp_labelable_stmt:
sp_proc_stmt_statement
| sp_proc_stmt_continue
| sp_proc_stmt_exit
| sp_proc_stmt_leave
| sp_proc_stmt_iterate
| sp_proc_stmt_goto
| sp_proc_stmt_open
| sp_proc_stmt_fetch
| sp_proc_stmt_close
| sp_proc_stmt_return
| sp_proc_stmt_if
| case_stmt_specification
| NULL_SYM { }
;
...
...
@@ -3245,6 +3255,15 @@ sp_proc_stmt_iterate:
}
;
sp_proc_stmt_goto:
GOTO_SYM label_ident
{
if (Lex->sp_goto_statement(thd, $2))
MYSQL_YYABORT;
}
;
remember_lex:
{
$$= thd->lex;
...
...
@@ -3396,7 +3415,7 @@ sp_if:
if (sp->restore_lex(thd))
MYSQL_YYABORT;
}
sp_proc_stmts1
sp_proc_stmts1
_implicit_block
{
sp_head *sp= Lex->sphead;
sp_pcontext *ctx= Lex->spcont;
...
...
@@ -3419,7 +3438,7 @@ sp_if:
sp_elseifs:
/* Empty */
| ELSIF_SYM sp_if
| ELSE sp_proc_stmts1
| ELSE sp_proc_stmts1
_implicit_block
;
case_stmt_specification:
...
...
@@ -3535,7 +3554,7 @@ simple_when_clause:
MYSQL_YYABORT;
}
THEN_SYM
sp_proc_stmts1
sp_proc_stmts1
_implicit_block
{
if (Lex->case_stmt_action_then())
MYSQL_YYABORT;
...
...
@@ -3557,7 +3576,7 @@ searched_when_clause:
MYSQL_YYABORT;
}
THEN_SYM
sp_proc_stmts1
sp_proc_stmts1
_implicit_block
{
if (Lex->case_stmt_action_then())
MYSQL_YYABORT;
...
...
@@ -3576,7 +3595,7 @@ else_clause_opt:
sp->add_instr(i))
MYSQL_YYABORT;
}
| ELSE sp_proc_stmts1
| ELSE sp_proc_stmts1
_implicit_block
;
sp_opt_label:
...
...
@@ -3585,7 +3604,7 @@ sp_opt_label:
;
sp_block_label:
label_declaration_oracle
label
s
_declaration_oracle
{
if (Lex->spcont->block_label_declare($1))
MYSQL_YYABORT;
...
...
@@ -3819,14 +3838,14 @@ pop_sp_loop_label:
;
sp_labeled_control:
label_declaration_oracle LOOP_SYM
label
s
_declaration_oracle LOOP_SYM
{
if (Lex->sp_push_loop_label(thd, $1))
MYSQL_YYABORT;
}
loop_body pop_sp_loop_label
{ }
| label_declaration_oracle WHILE_SYM
| label
s
_declaration_oracle WHILE_SYM
{
if (Lex->sp_push_loop_label(thd, $1))
MYSQL_YYABORT;
...
...
@@ -3834,7 +3853,7 @@ sp_labeled_control:
}
while_body pop_sp_loop_label
{ }
| label_declaration_oracle FOR_SYM
| label
s
_declaration_oracle FOR_SYM
{
// See "The FOR LOOP statement" comments in sql_lex.cc
Lex->sp_block_init(thd); // The outer DECLARE..BEGIN..END block
...
...
@@ -3858,7 +3877,7 @@ sp_labeled_control:
if (Lex->sp_block_finalize(thd)) // The outer DECLARE..BEGIN..END
MYSQL_YYABORT;
}
| label_declaration_oracle REPEAT_SYM
| label
s
_declaration_oracle REPEAT_SYM
{
if (Lex->sp_push_loop_label(thd, $1))
MYSQL_YYABORT;
...
...
@@ -14188,8 +14207,18 @@ label_ident:
}
;
labels_declaration_oracle:
label_declaration_oracle { $$= $1; }
| labels_declaration_oracle label_declaration_oracle { $$= $2; }
;
label_declaration_oracle:
SHIFT_LEFT label_ident SHIFT_RIGHT { $$= $2; }
SHIFT_LEFT label_ident SHIFT_RIGHT
{
if (Lex->sp_push_goto_label(thd, $2))
MYSQL_YYABORT;
$$= $2;
}
;
ident_or_text:
...
...
@@ -16434,6 +16463,8 @@ trigger_tail:
{ /* $21 */
LEX *lex= Lex;
sp_head *sp= lex->sphead;
if (sp->check_unresolved_goto())
MYSQL_YYABORT;
lex->sql_command= SQLCOM_CREATE_TRIGGER;
sp->set_stmt_end(thd);
...
...
@@ -16517,6 +16548,8 @@ sf_tail:
{
LEX *lex= thd->lex;
sp_head *sp= lex->sphead;
if (sp->check_unresolved_goto())
MYSQL_YYABORT;
if (sp->is_not_allowed_in_function("function"))
MYSQL_YYABORT;
...
...
@@ -16549,7 +16582,8 @@ sp_tail:
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
if (sp->check_unresolved_goto())
MYSQL_YYABORT;
sp->set_stmt_end(thd);
lex->sql_command= SQLCOM_CREATE_PROCEDURE;
sp->restore_thd_mem_root(thd);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment