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
64b7a75a
Commit
64b7a75a
authored
Dec 11, 2006
by
malff/marcsql@weblab.(none)
Browse files
Options
Browse Files
Download
Plain Diff
Merge malff@bk-internal.mysql.com:/home/bk/mysql-5.0-runtime
into weblab.(none):/home/marcsql/TREE/mysql-5.0-runtime
parents
704951fa
7696592b
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1240 additions
and
168 deletions
+1240
-168
mysql-test/r/sp-code.result
mysql-test/r/sp-code.result
+415
-0
mysql-test/r/sp_stress_case.result
mysql-test/r/sp_stress_case.result
+120
-0
mysql-test/t/sp-code.test
mysql-test/t/sp-code.test
+235
-0
mysql-test/t/sp_stress_case.test
mysql-test/t/sp_stress_case.test
+89
-0
sql/sp_head.cc
sql/sp_head.cc
+55
-41
sql/sp_head.h
sql/sp_head.h
+28
-11
sql/sql_lex.cc
sql/sql_lex.cc
+0
-1
sql/sql_lex.h
sql/sql_lex.h
+0
-1
sql/sql_yacc.yy
sql/sql_yacc.yy
+298
-114
No files found.
mysql-test/r/sp-code.result
View file @
64b7a75a
...
@@ -199,6 +199,421 @@ Pos Instruction
...
@@ -199,6 +199,421 @@ Pos Instruction
44 jump 14
44 jump 14
45 stmt 9 "drop temporary table sudoku_work, sud..."
45 stmt 9 "drop temporary table sudoku_work, sud..."
drop procedure sudoku_solve;
drop procedure sudoku_solve;
DROP PROCEDURE IF EXISTS proc_19194_simple;
DROP PROCEDURE IF EXISTS proc_19194_searched;
DROP PROCEDURE IF EXISTS proc_19194_nested_1;
DROP PROCEDURE IF EXISTS proc_19194_nested_2;
DROP PROCEDURE IF EXISTS proc_19194_nested_3;
DROP PROCEDURE IF EXISTS proc_19194_nested_4;
CREATE PROCEDURE proc_19194_simple(i int)
BEGIN
DECLARE str CHAR(10);
CASE i
WHEN 1 THEN SET str="1";
WHEN 2 THEN SET str="2";
WHEN 3 THEN SET str="3";
ELSE SET str="unknown";
END CASE;
SELECT str;
END|
CREATE PROCEDURE proc_19194_searched(i int)
BEGIN
DECLARE str CHAR(10);
CASE
WHEN i=1 THEN SET str="1";
WHEN i=2 THEN SET str="2";
WHEN i=3 THEN SET str="3";
ELSE SET str="unknown";
END CASE;
SELECT str;
END|
CREATE PROCEDURE proc_19194_nested_1(i int, j int)
BEGIN
DECLARE str_i CHAR(10);
DECLARE str_j CHAR(10);
CASE i
WHEN 10 THEN SET str_i="10";
WHEN 20 THEN
BEGIN
set str_i="20";
CASE
WHEN j=1 THEN SET str_j="1";
WHEN j=2 THEN SET str_j="2";
WHEN j=3 THEN SET str_j="3";
ELSE SET str_j="unknown";
END CASE;
select "i was 20";
END;
WHEN 30 THEN SET str_i="30";
WHEN 40 THEN SET str_i="40";
ELSE SET str_i="unknown";
END CASE;
SELECT str_i, str_j;
END|
CREATE PROCEDURE proc_19194_nested_2(i int, j int)
BEGIN
DECLARE str_i CHAR(10);
DECLARE str_j CHAR(10);
CASE
WHEN i=10 THEN SET str_i="10";
WHEN i=20 THEN
BEGIN
set str_i="20";
CASE j
WHEN 1 THEN SET str_j="1";
WHEN 2 THEN SET str_j="2";
WHEN 3 THEN SET str_j="3";
ELSE SET str_j="unknown";
END CASE;
select "i was 20";
END;
WHEN i=30 THEN SET str_i="30";
WHEN i=40 THEN SET str_i="40";
ELSE SET str_i="unknown";
END CASE;
SELECT str_i, str_j;
END|
CREATE PROCEDURE proc_19194_nested_3(i int, j int)
BEGIN
DECLARE str_i CHAR(10);
DECLARE str_j CHAR(10);
CASE i
WHEN 10 THEN SET str_i="10";
WHEN 20 THEN
BEGIN
set str_i="20";
CASE j
WHEN 1 THEN SET str_j="1";
WHEN 2 THEN SET str_j="2";
WHEN 3 THEN SET str_j="3";
ELSE SET str_j="unknown";
END CASE;
select "i was 20";
END;
WHEN 30 THEN SET str_i="30";
WHEN 40 THEN SET str_i="40";
ELSE SET str_i="unknown";
END CASE;
SELECT str_i, str_j;
END|
CREATE PROCEDURE proc_19194_nested_4(i int, j int)
BEGIN
DECLARE str_i CHAR(10);
DECLARE str_j CHAR(10);
CASE
WHEN i=10 THEN SET str_i="10";
WHEN i=20 THEN
BEGIN
set str_i="20";
CASE
WHEN j=1 THEN SET str_j="1";
WHEN j=2 THEN SET str_j="2";
WHEN j=3 THEN SET str_j="3";
ELSE SET str_j="unknown";
END CASE;
select "i was 20";
END;
WHEN i=30 THEN SET str_i="30";
WHEN i=40 THEN SET str_i="40";
ELSE SET str_i="unknown";
END CASE;
SELECT str_i, str_j;
END|
SHOW PROCEDURE CODE proc_19194_simple;
Pos Instruction
0 set str@1 NULL
1 set_case_expr (12) 0 i@0
2 jump_if_not 5(12) (case_expr@0 = 1)
3 set str@1 _latin1'1'
4 jump 12
5 jump_if_not 8(12) (case_expr@0 = 2)
6 set str@1 _latin1'2'
7 jump 12
8 jump_if_not 11(12) (case_expr@0 = 3)
9 set str@1 _latin1'3'
10 jump 12
11 set str@1 _latin1'unknown'
12 stmt 0 "SELECT str"
SHOW PROCEDURE CODE proc_19194_searched;
Pos Instruction
0 set str@1 NULL
1 jump_if_not 4(11) (i@0 = 1)
2 set str@1 _latin1'1'
3 jump 11
4 jump_if_not 7(11) (i@0 = 2)
5 set str@1 _latin1'2'
6 jump 11
7 jump_if_not 10(11) (i@0 = 3)
8 set str@1 _latin1'3'
9 jump 11
10 set str@1 _latin1'unknown'
11 stmt 0 "SELECT str"
SHOW PROCEDURE CODE proc_19194_nested_1;
Pos Instruction
0 set str_i@2 NULL
1 set str_j@3 NULL
2 set_case_expr (27) 0 i@0
3 jump_if_not 6(27) (case_expr@0 = 10)
4 set str_i@2 _latin1'10'
5 jump 27
6 jump_if_not 20(27) (case_expr@0 = 20)
7 set str_i@2 _latin1'20'
8 jump_if_not 11(18) (j@1 = 1)
9 set str_j@3 _latin1'1'
10 jump 18
11 jump_if_not 14(18) (j@1 = 2)
12 set str_j@3 _latin1'2'
13 jump 18
14 jump_if_not 17(18) (j@1 = 3)
15 set str_j@3 _latin1'3'
16 jump 18
17 set str_j@3 _latin1'unknown'
18 stmt 0 "select "i was 20""
19 jump 27
20 jump_if_not 23(27) (case_expr@0 = 30)
21 set str_i@2 _latin1'30'
22 jump 27
23 jump_if_not 26(27) (case_expr@0 = 40)
24 set str_i@2 _latin1'40'
25 jump 27
26 set str_i@2 _latin1'unknown'
27 stmt 0 "SELECT str_i, str_j"
SHOW PROCEDURE CODE proc_19194_nested_2;
Pos Instruction
0 set str_i@2 NULL
1 set str_j@3 NULL
2 jump_if_not 5(27) (i@0 = 10)
3 set str_i@2 _latin1'10'
4 jump 27
5 jump_if_not 20(27) (i@0 = 20)
6 set str_i@2 _latin1'20'
7 set_case_expr (18) 0 j@1
8 jump_if_not 11(18) (case_expr@0 = 1)
9 set str_j@3 _latin1'1'
10 jump 18
11 jump_if_not 14(18) (case_expr@0 = 2)
12 set str_j@3 _latin1'2'
13 jump 18
14 jump_if_not 17(18) (case_expr@0 = 3)
15 set str_j@3 _latin1'3'
16 jump 18
17 set str_j@3 _latin1'unknown'
18 stmt 0 "select "i was 20""
19 jump 27
20 jump_if_not 23(27) (i@0 = 30)
21 set str_i@2 _latin1'30'
22 jump 27
23 jump_if_not 26(27) (i@0 = 40)
24 set str_i@2 _latin1'40'
25 jump 27
26 set str_i@2 _latin1'unknown'
27 stmt 0 "SELECT str_i, str_j"
SHOW PROCEDURE CODE proc_19194_nested_3;
Pos Instruction
0 set str_i@2 NULL
1 set str_j@3 NULL
2 set_case_expr (28) 0 i@0
3 jump_if_not 6(28) (case_expr@0 = 10)
4 set str_i@2 _latin1'10'
5 jump 28
6 jump_if_not 21(28) (case_expr@0 = 20)
7 set str_i@2 _latin1'20'
8 set_case_expr (19) 1 j@1
9 jump_if_not 12(19) (case_expr@1 = 1)
10 set str_j@3 _latin1'1'
11 jump 19
12 jump_if_not 15(19) (case_expr@1 = 2)
13 set str_j@3 _latin1'2'
14 jump 19
15 jump_if_not 18(19) (case_expr@1 = 3)
16 set str_j@3 _latin1'3'
17 jump 19
18 set str_j@3 _latin1'unknown'
19 stmt 0 "select "i was 20""
20 jump 28
21 jump_if_not 24(28) (case_expr@0 = 30)
22 set str_i@2 _latin1'30'
23 jump 28
24 jump_if_not 27(28) (case_expr@0 = 40)
25 set str_i@2 _latin1'40'
26 jump 28
27 set str_i@2 _latin1'unknown'
28 stmt 0 "SELECT str_i, str_j"
SHOW PROCEDURE CODE proc_19194_nested_4;
Pos Instruction
0 set str_i@2 NULL
1 set str_j@3 NULL
2 jump_if_not 5(26) (i@0 = 10)
3 set str_i@2 _latin1'10'
4 jump 26
5 jump_if_not 19(26) (i@0 = 20)
6 set str_i@2 _latin1'20'
7 jump_if_not 10(17) (j@1 = 1)
8 set str_j@3 _latin1'1'
9 jump 17
10 jump_if_not 13(17) (j@1 = 2)
11 set str_j@3 _latin1'2'
12 jump 17
13 jump_if_not 16(17) (j@1 = 3)
14 set str_j@3 _latin1'3'
15 jump 17
16 set str_j@3 _latin1'unknown'
17 stmt 0 "select "i was 20""
18 jump 26
19 jump_if_not 22(26) (i@0 = 30)
20 set str_i@2 _latin1'30'
21 jump 26
22 jump_if_not 25(26) (i@0 = 40)
23 set str_i@2 _latin1'40'
24 jump 26
25 set str_i@2 _latin1'unknown'
26 stmt 0 "SELECT str_i, str_j"
CALL proc_19194_nested_1(10, 1);
str_i str_j
10 NULL
CALL proc_19194_nested_1(25, 1);
str_i str_j
unknown NULL
CALL proc_19194_nested_1(20, 1);
i was 20
i was 20
str_i str_j
20 1
CALL proc_19194_nested_1(20, 2);
i was 20
i was 20
str_i str_j
20 2
CALL proc_19194_nested_1(20, 3);
i was 20
i was 20
str_i str_j
20 3
CALL proc_19194_nested_1(20, 4);
i was 20
i was 20
str_i str_j
20 unknown
CALL proc_19194_nested_1(30, 1);
str_i str_j
30 NULL
CALL proc_19194_nested_1(40, 1);
str_i str_j
40 NULL
CALL proc_19194_nested_1(0, 0);
str_i str_j
unknown NULL
CALL proc_19194_nested_2(10, 1);
str_i str_j
10 NULL
CALL proc_19194_nested_2(25, 1);
str_i str_j
unknown NULL
CALL proc_19194_nested_2(20, 1);
i was 20
i was 20
str_i str_j
20 1
CALL proc_19194_nested_2(20, 2);
i was 20
i was 20
str_i str_j
20 2
CALL proc_19194_nested_2(20, 3);
i was 20
i was 20
str_i str_j
20 3
CALL proc_19194_nested_2(20, 4);
i was 20
i was 20
str_i str_j
20 unknown
CALL proc_19194_nested_2(30, 1);
str_i str_j
30 NULL
CALL proc_19194_nested_2(40, 1);
str_i str_j
40 NULL
CALL proc_19194_nested_2(0, 0);
str_i str_j
unknown NULL
CALL proc_19194_nested_3(10, 1);
str_i str_j
10 NULL
CALL proc_19194_nested_3(25, 1);
str_i str_j
unknown NULL
CALL proc_19194_nested_3(20, 1);
i was 20
i was 20
str_i str_j
20 1
CALL proc_19194_nested_3(20, 2);
i was 20
i was 20
str_i str_j
20 2
CALL proc_19194_nested_3(20, 3);
i was 20
i was 20
str_i str_j
20 3
CALL proc_19194_nested_3(20, 4);
i was 20
i was 20
str_i str_j
20 unknown
CALL proc_19194_nested_3(30, 1);
str_i str_j
30 NULL
CALL proc_19194_nested_3(40, 1);
str_i str_j
40 NULL
CALL proc_19194_nested_3(0, 0);
str_i str_j
unknown NULL
CALL proc_19194_nested_4(10, 1);
str_i str_j
10 NULL
CALL proc_19194_nested_4(25, 1);
str_i str_j
unknown NULL
CALL proc_19194_nested_4(20, 1);
i was 20
i was 20
str_i str_j
20 1
CALL proc_19194_nested_4(20, 2);
i was 20
i was 20
str_i str_j
20 2
CALL proc_19194_nested_4(20, 3);
i was 20
i was 20
str_i str_j
20 3
CALL proc_19194_nested_4(20, 4);
i was 20
i was 20
str_i str_j
20 unknown
CALL proc_19194_nested_4(30, 1);
str_i str_j
30 NULL
CALL proc_19194_nested_4(40, 1);
str_i str_j
40 NULL
CALL proc_19194_nested_4(0, 0);
str_i str_j
unknown NULL
DROP PROCEDURE proc_19194_simple;
DROP PROCEDURE proc_19194_searched;
DROP PROCEDURE proc_19194_nested_1;
DROP PROCEDURE proc_19194_nested_2;
DROP PROCEDURE proc_19194_nested_3;
DROP PROCEDURE proc_19194_nested_4;
DROP PROCEDURE IF EXISTS p1;
DROP PROCEDURE IF EXISTS p1;
CREATE PROCEDURE p1() CREATE INDEX idx ON t1 (c1);
CREATE PROCEDURE p1() CREATE INDEX idx ON t1 (c1);
SHOW PROCEDURE CODE p1;
SHOW PROCEDURE CODE p1;
...
...
mysql-test/r/sp_stress_case.result
0 → 100644
View file @
64b7a75a
DROP PROCEDURE IF EXISTS proc_19194_codegen;
DROP PROCEDURE IF EXISTS bug_19194_simple;
DROP PROCEDURE IF EXISTS bug_19194_searched;
CREATE PROCEDURE proc_19194_codegen(
IN proc_name VARCHAR(50),
IN count INTEGER,
IN simple INTEGER,
OUT body MEDIUMTEXT)
BEGIN
DECLARE code MEDIUMTEXT;
DECLARE i INT DEFAULT 1;
SET code = concat("CREATE PROCEDURE ", proc_name, "(i INT)\n");
SET code = concat(code, "BEGIN\n");
SET code = concat(code, " DECLARE str CHAR(10);\n");
IF (simple)
THEN
SET code = concat(code, " CASE i\n");
ELSE
SET code = concat(code, " CASE\n");
END IF;
WHILE (i <= count)
DO
IF (simple)
THEN
SET code = concat(code, " WHEN ", i, " THEN SET str=\"", i, "\";\n");
ELSE
SET code = concat(code, " WHEN i=", i, " THEN SET str=\"", i, "\";\n");
END IF;
SET i = i + 1;
END WHILE;
SET code = concat(code, " ELSE SET str=\"unknown\";\n");
SET code = concat(code, " END CASE;\n");
SET code = concat(code, " SELECT str;\n");
SET code = concat(code, "END\n");
SET body = code;
END|
set @body="";
call proc_19194_codegen("test_simple", 10, 1, @body);
select @body;
@body
CREATE PROCEDURE test_simple(i INT)
BEGIN
DECLARE str CHAR(10);
CASE i
WHEN 1 THEN SET str="1";
WHEN 2 THEN SET str="2";
WHEN 3 THEN SET str="3";
WHEN 4 THEN SET str="4";
WHEN 5 THEN SET str="5";
WHEN 6 THEN SET str="6";
WHEN 7 THEN SET str="7";
WHEN 8 THEN SET str="8";
WHEN 9 THEN SET str="9";
WHEN 10 THEN SET str="10";
ELSE SET str="unknown";
END CASE;
SELECT str;
END
call proc_19194_codegen("test_searched", 10, 0, @body);
select @body;
@body
CREATE PROCEDURE test_searched(i INT)
BEGIN
DECLARE str CHAR(10);
CASE
WHEN i=1 THEN SET str="1";
WHEN i=2 THEN SET str="2";
WHEN i=3 THEN SET str="3";
WHEN i=4 THEN SET str="4";
WHEN i=5 THEN SET str="5";
WHEN i=6 THEN SET str="6";
WHEN i=7 THEN SET str="7";
WHEN i=8 THEN SET str="8";
WHEN i=9 THEN SET str="9";
WHEN i=10 THEN SET str="10";
ELSE SET str="unknown";
END CASE;
SELECT str;
END
CALL bug_19194_simple(1);
str
1
CALL bug_19194_simple(2);
str
2
CALL bug_19194_simple(1000);
str
1000
CALL bug_19194_simple(4998);
str
4998
CALL bug_19194_simple(4999);
str
4999
CALL bug_19194_simple(9999);
str
unknown
CALL bug_19194_searched(1);
str
1
CALL bug_19194_searched(2);
str
2
CALL bug_19194_searched(1000);
str
1000
CALL bug_19194_searched(4998);
str
4998
CALL bug_19194_searched(4999);
str
4999
CALL bug_19194_searched(9999);
str
unknown
DROP PROCEDURE proc_19194_codegen;
DROP PROCEDURE bug_19194_simple;
DROP PROCEDURE bug_19194_searched;
mysql-test/t/sp-code.test
View file @
64b7a75a
...
@@ -191,6 +191,241 @@ show procedure code sudoku_solve;
...
@@ -191,6 +191,241 @@ show procedure code sudoku_solve;
drop
procedure
sudoku_solve
;
drop
procedure
sudoku_solve
;
#
# Bug#19194 (Right recursion in parser for CASE causes excessive stack
# usage, limitation)
# This bug also exposed a flaw in the generated code with nested case
# statements
#
--
disable_warnings
DROP
PROCEDURE
IF
EXISTS
proc_19194_simple
;
DROP
PROCEDURE
IF
EXISTS
proc_19194_searched
;
DROP
PROCEDURE
IF
EXISTS
proc_19194_nested_1
;
DROP
PROCEDURE
IF
EXISTS
proc_19194_nested_2
;
DROP
PROCEDURE
IF
EXISTS
proc_19194_nested_3
;
DROP
PROCEDURE
IF
EXISTS
proc_19194_nested_4
;
--
enable_warnings
delimiter
|
;
CREATE
PROCEDURE
proc_19194_simple
(
i
int
)
BEGIN
DECLARE
str
CHAR
(
10
);
CASE
i
WHEN
1
THEN
SET
str
=
"1"
;
WHEN
2
THEN
SET
str
=
"2"
;
WHEN
3
THEN
SET
str
=
"3"
;
ELSE
SET
str
=
"unknown"
;
END
CASE
;
SELECT
str
;
END
|
CREATE
PROCEDURE
proc_19194_searched
(
i
int
)
BEGIN
DECLARE
str
CHAR
(
10
);
CASE
WHEN
i
=
1
THEN
SET
str
=
"1"
;
WHEN
i
=
2
THEN
SET
str
=
"2"
;
WHEN
i
=
3
THEN
SET
str
=
"3"
;
ELSE
SET
str
=
"unknown"
;
END
CASE
;
SELECT
str
;
END
|
# Outer SIMPLE case, inner SEARCHED case
CREATE
PROCEDURE
proc_19194_nested_1
(
i
int
,
j
int
)
BEGIN
DECLARE
str_i
CHAR
(
10
);
DECLARE
str_j
CHAR
(
10
);
CASE
i
WHEN
10
THEN
SET
str_i
=
"10"
;
WHEN
20
THEN
BEGIN
set
str_i
=
"20"
;
CASE
WHEN
j
=
1
THEN
SET
str_j
=
"1"
;
WHEN
j
=
2
THEN
SET
str_j
=
"2"
;
WHEN
j
=
3
THEN
SET
str_j
=
"3"
;
ELSE
SET
str_j
=
"unknown"
;
END
CASE
;
select
"i was 20"
;
END
;
WHEN
30
THEN
SET
str_i
=
"30"
;
WHEN
40
THEN
SET
str_i
=
"40"
;
ELSE
SET
str_i
=
"unknown"
;
END
CASE
;
SELECT
str_i
,
str_j
;
END
|
# Outer SEARCHED case, inner SIMPLE case
CREATE
PROCEDURE
proc_19194_nested_2
(
i
int
,
j
int
)
BEGIN
DECLARE
str_i
CHAR
(
10
);
DECLARE
str_j
CHAR
(
10
);
CASE
WHEN
i
=
10
THEN
SET
str_i
=
"10"
;
WHEN
i
=
20
THEN
BEGIN
set
str_i
=
"20"
;
CASE
j
WHEN
1
THEN
SET
str_j
=
"1"
;
WHEN
2
THEN
SET
str_j
=
"2"
;
WHEN
3
THEN
SET
str_j
=
"3"
;
ELSE
SET
str_j
=
"unknown"
;
END
CASE
;
select
"i was 20"
;
END
;
WHEN
i
=
30
THEN
SET
str_i
=
"30"
;
WHEN
i
=
40
THEN
SET
str_i
=
"40"
;
ELSE
SET
str_i
=
"unknown"
;
END
CASE
;
SELECT
str_i
,
str_j
;
END
|
# Outer SIMPLE case, inner SIMPLE case
CREATE
PROCEDURE
proc_19194_nested_3
(
i
int
,
j
int
)
BEGIN
DECLARE
str_i
CHAR
(
10
);
DECLARE
str_j
CHAR
(
10
);
CASE
i
WHEN
10
THEN
SET
str_i
=
"10"
;
WHEN
20
THEN
BEGIN
set
str_i
=
"20"
;
CASE
j
WHEN
1
THEN
SET
str_j
=
"1"
;
WHEN
2
THEN
SET
str_j
=
"2"
;
WHEN
3
THEN
SET
str_j
=
"3"
;
ELSE
SET
str_j
=
"unknown"
;
END
CASE
;
select
"i was 20"
;
END
;
WHEN
30
THEN
SET
str_i
=
"30"
;
WHEN
40
THEN
SET
str_i
=
"40"
;
ELSE
SET
str_i
=
"unknown"
;
END
CASE
;
SELECT
str_i
,
str_j
;
END
|
# Outer SEARCHED case, inner SEARCHED case
CREATE
PROCEDURE
proc_19194_nested_4
(
i
int
,
j
int
)
BEGIN
DECLARE
str_i
CHAR
(
10
);
DECLARE
str_j
CHAR
(
10
);
CASE
WHEN
i
=
10
THEN
SET
str_i
=
"10"
;
WHEN
i
=
20
THEN
BEGIN
set
str_i
=
"20"
;
CASE
WHEN
j
=
1
THEN
SET
str_j
=
"1"
;
WHEN
j
=
2
THEN
SET
str_j
=
"2"
;
WHEN
j
=
3
THEN
SET
str_j
=
"3"
;
ELSE
SET
str_j
=
"unknown"
;
END
CASE
;
select
"i was 20"
;
END
;
WHEN
i
=
30
THEN
SET
str_i
=
"30"
;
WHEN
i
=
40
THEN
SET
str_i
=
"40"
;
ELSE
SET
str_i
=
"unknown"
;
END
CASE
;
SELECT
str_i
,
str_j
;
END
|
delimiter
;
|
SHOW
PROCEDURE
CODE
proc_19194_simple
;
SHOW
PROCEDURE
CODE
proc_19194_searched
;
SHOW
PROCEDURE
CODE
proc_19194_nested_1
;
SHOW
PROCEDURE
CODE
proc_19194_nested_2
;
SHOW
PROCEDURE
CODE
proc_19194_nested_3
;
SHOW
PROCEDURE
CODE
proc_19194_nested_4
;
CALL
proc_19194_nested_1
(
10
,
1
);
#
# Before 19194, the generated code was:
# 20 jump_if_not 23(27) 30
# 21 set str_i@2 _latin1'30'
# As opposed to the expected:
# 20 jump_if_not 23(27) (case_expr@0 = 30)
# 21 set str_i@2 _latin1'30'
#
# and as a result, this call returned "30",
# because the expression 30 is always true,
# masking the case 40, case 0 and the else.
#
CALL
proc_19194_nested_1
(
25
,
1
);
CALL
proc_19194_nested_1
(
20
,
1
);
CALL
proc_19194_nested_1
(
20
,
2
);
CALL
proc_19194_nested_1
(
20
,
3
);
CALL
proc_19194_nested_1
(
20
,
4
);
CALL
proc_19194_nested_1
(
30
,
1
);
CALL
proc_19194_nested_1
(
40
,
1
);
CALL
proc_19194_nested_1
(
0
,
0
);
CALL
proc_19194_nested_2
(
10
,
1
);
#
# Before 19194, the generated code was:
# 20 jump_if_not 23(27) (case_expr@0 = (i@0 = 30))
# 21 set str_i@2 _latin1'30'
# As opposed to the expected:
# 20 jump_if_not 23(27) (i@0 = 30)
# 21 set str_i@2 _latin1'30'
# and as a result, this call crashed the server, because there is no
# such variable as "case_expr@0".
#
CALL
proc_19194_nested_2
(
25
,
1
);
CALL
proc_19194_nested_2
(
20
,
1
);
CALL
proc_19194_nested_2
(
20
,
2
);
CALL
proc_19194_nested_2
(
20
,
3
);
CALL
proc_19194_nested_2
(
20
,
4
);
CALL
proc_19194_nested_2
(
30
,
1
);
CALL
proc_19194_nested_2
(
40
,
1
);
CALL
proc_19194_nested_2
(
0
,
0
);
CALL
proc_19194_nested_3
(
10
,
1
);
CALL
proc_19194_nested_3
(
25
,
1
);
CALL
proc_19194_nested_3
(
20
,
1
);
CALL
proc_19194_nested_3
(
20
,
2
);
CALL
proc_19194_nested_3
(
20
,
3
);
CALL
proc_19194_nested_3
(
20
,
4
);
CALL
proc_19194_nested_3
(
30
,
1
);
CALL
proc_19194_nested_3
(
40
,
1
);
CALL
proc_19194_nested_3
(
0
,
0
);
CALL
proc_19194_nested_4
(
10
,
1
);
CALL
proc_19194_nested_4
(
25
,
1
);
CALL
proc_19194_nested_4
(
20
,
1
);
CALL
proc_19194_nested_4
(
20
,
2
);
CALL
proc_19194_nested_4
(
20
,
3
);
CALL
proc_19194_nested_4
(
20
,
4
);
CALL
proc_19194_nested_4
(
30
,
1
);
CALL
proc_19194_nested_4
(
40
,
1
);
CALL
proc_19194_nested_4
(
0
,
0
);
DROP
PROCEDURE
proc_19194_simple
;
DROP
PROCEDURE
proc_19194_searched
;
DROP
PROCEDURE
proc_19194_nested_1
;
DROP
PROCEDURE
proc_19194_nested_2
;
DROP
PROCEDURE
proc_19194_nested_3
;
DROP
PROCEDURE
proc_19194_nested_4
;
#
#
# Bug#19207: Final parenthesis omitted for CREATE INDEX in Stored
# Bug#19207: Final parenthesis omitted for CREATE INDEX in Stored
...
...
mysql-test/t/sp_stress_case.test
0 → 100644
View file @
64b7a75a
#
# Bug#19194 (Right recursion in parser for CASE causes excessive stack
# usage, limitation)
#
--
disable_warnings
DROP
PROCEDURE
IF
EXISTS
proc_19194_codegen
;
DROP
PROCEDURE
IF
EXISTS
bug_19194_simple
;
DROP
PROCEDURE
IF
EXISTS
bug_19194_searched
;
--
enable_warnings
delimiter
|
;
CREATE
PROCEDURE
proc_19194_codegen
(
IN
proc_name
VARCHAR
(
50
),
IN
count
INTEGER
,
IN
simple
INTEGER
,
OUT
body
MEDIUMTEXT
)
BEGIN
DECLARE
code
MEDIUMTEXT
;
DECLARE
i
INT
DEFAULT
1
;
SET
code
=
concat
(
"CREATE PROCEDURE "
,
proc_name
,
"(i INT)
\n
"
);
SET
code
=
concat
(
code
,
"BEGIN
\n
"
);
SET
code
=
concat
(
code
,
" DECLARE str CHAR(10);
\n
"
);
IF
(
simple
)
THEN
SET
code
=
concat
(
code
,
" CASE i
\n
"
);
ELSE
SET
code
=
concat
(
code
,
" CASE
\n
"
);
END
IF
;
WHILE
(
i
<=
count
)
DO
IF
(
simple
)
THEN
SET
code
=
concat
(
code
,
" WHEN "
,
i
,
" THEN SET str=
\"
"
,
i
,
"
\"
;
\n
"
);
ELSE
SET
code
=
concat
(
code
,
" WHEN i="
,
i
,
" THEN SET str=
\"
"
,
i
,
"
\"
;
\n
"
);
END
IF
;
SET
i
=
i
+
1
;
END
WHILE
;
SET
code
=
concat
(
code
,
" ELSE SET str=
\"
unknown
\"
;
\n
"
);
SET
code
=
concat
(
code
,
" END CASE;
\n
"
);
SET
code
=
concat
(
code
,
" SELECT str;
\n
"
);
SET
code
=
concat
(
code
,
"END
\n
"
);
SET
body
=
code
;
END
|
delimiter
;
|
set
@
body
=
""
;
call
proc_19194_codegen
(
"test_simple"
,
10
,
1
,
@
body
);
select
@
body
;
call
proc_19194_codegen
(
"test_searched"
,
10
,
0
,
@
body
);
select
@
body
;
--
disable_query_log
call
proc_19194_codegen
(
"bug_19194_simple"
,
5000
,
1
,
@
body
);
let
$proc_body
=
`select @body`
;
eval
$proc_body
;
call
proc_19194_codegen
(
"bug_19194_searched"
,
5000
,
1
,
@
body
);
let
$proc_body
=
`select @body`
;
eval
$proc_body
;
--
enable_query_log
CALL
bug_19194_simple
(
1
);
CALL
bug_19194_simple
(
2
);
CALL
bug_19194_simple
(
1000
);
CALL
bug_19194_simple
(
4998
);
CALL
bug_19194_simple
(
4999
);
CALL
bug_19194_simple
(
9999
);
CALL
bug_19194_searched
(
1
);
CALL
bug_19194_searched
(
2
);
CALL
bug_19194_searched
(
1000
);
CALL
bug_19194_searched
(
4998
);
CALL
bug_19194_searched
(
4999
);
CALL
bug_19194_searched
(
9999
);
DROP
PROCEDURE
proc_19194_codegen
;
DROP
PROCEDURE
bug_19194_simple
;
DROP
PROCEDURE
bug_19194_searched
;
sql/sp_head.cc
View file @
64b7a75a
...
@@ -603,27 +603,6 @@ sp_head::create(THD *thd)
...
@@ -603,27 +603,6 @@ sp_head::create(THD *thd)
DBUG_PRINT
(
"info"
,
(
"type: %d name: %s params: %s body: %s"
,
DBUG_PRINT
(
"info"
,
(
"type: %d name: %s params: %s body: %s"
,
m_type
,
m_name
.
str
,
m_params
.
str
,
m_body
.
str
));
m_type
,
m_name
.
str
,
m_params
.
str
,
m_body
.
str
));
#ifndef DBUG_OFF
optimize
();
{
String
s
;
sp_instr
*
i
;
uint
ip
=
0
;
while
((
i
=
get_instr
(
ip
)))
{
char
buf
[
8
];
sprintf
(
buf
,
"%4u: "
,
ip
);
s
.
append
(
buf
);
i
->
print
(
&
s
);
s
.
append
(
'\n'
);
ip
+=
1
;
}
s
.
append
(
'\0'
);
DBUG_PRINT
(
"info"
,
(
"Code %s
\n
%s"
,
m_qname
.
str
,
s
.
ptr
()));
}
#endif
if
(
m_type
==
TYPE_ENUM_FUNCTION
)
if
(
m_type
==
TYPE_ENUM_FUNCTION
)
ret
=
sp_create_function
(
thd
,
this
);
ret
=
sp_create_function
(
thd
,
this
);
else
else
...
@@ -2171,7 +2150,7 @@ sp_head::show_create_function(THD *thd)
...
@@ -2171,7 +2150,7 @@ sp_head::show_create_function(THD *thd)
This is the main mark and move loop; it relies on the following methods
This is the main mark and move loop; it relies on the following methods
in sp_instr and its subclasses:
in sp_instr and its subclasses:
opt_mark() Mark instruction as reachable
(will recurse for jumps)
opt_mark() Mark instruction as reachable
opt_shortcut_jump() Shortcut jumps to the final destination;
opt_shortcut_jump() Shortcut jumps to the final destination;
used by opt_mark().
used by opt_mark().
opt_move() Update moved instruction
opt_move() Update moved instruction
...
@@ -2184,7 +2163,7 @@ void sp_head::optimize()
...
@@ -2184,7 +2163,7 @@ void sp_head::optimize()
sp_instr
*
i
;
sp_instr
*
i
;
uint
src
,
dst
;
uint
src
,
dst
;
opt_mark
(
0
);
opt_mark
();
bp
.
empty
();
bp
.
empty
();
src
=
dst
=
0
;
src
=
dst
=
0
;
...
@@ -2218,13 +2197,50 @@ void sp_head::optimize()
...
@@ -2218,13 +2197,50 @@ void sp_head::optimize()
bp
.
empty
();
bp
.
empty
();
}
}
void
sp_head
::
add_mark_lead
(
uint
ip
,
List
<
sp_instr
>
*
leads
)
{
sp_instr
*
i
=
get_instr
(
ip
);
if
(
i
&&
!
i
->
marked
)
leads
->
push_front
(
i
);
}
void
void
sp_head
::
opt_mark
(
uint
ip
)
sp_head
::
opt_mark
()
{
{
uint
ip
;
sp_instr
*
i
;
sp_instr
*
i
;
List
<
sp_instr
>
leads
;
while
((
i
=
get_instr
(
ip
))
&&
!
i
->
marked
)
/*
ip
=
i
->
opt_mark
(
this
);
Forward flow analysis algorithm in the instruction graph:
- first, add the entry point in the graph (the first instruction) to the
'leads' list of paths to explore.
- while there are still leads to explore:
- pick one lead, and follow the path forward. Mark instruction reached.
Stop only if the end of the routine is reached, or the path converge
to code already explored (marked).
- while following a path, collect in the 'leads' list any fork to
another path (caused by conditional jumps instructions), so that these
paths can be explored as well.
*/
/* Add the entry point */
i
=
get_instr
(
0
);
leads
.
push_front
(
i
);
/* For each path of code ... */
while
(
leads
.
elements
!=
0
)
{
i
=
leads
.
pop
();
/* Mark the entire path, collecting new leads. */
while
(
i
&&
!
i
->
marked
)
{
ip
=
i
->
opt_mark
(
this
,
&
leads
);
i
=
get_instr
(
ip
);
}
}
}
}
...
@@ -2617,7 +2633,7 @@ sp_instr_jump::print(String *str)
...
@@ -2617,7 +2633,7 @@ sp_instr_jump::print(String *str)
}
}
uint
uint
sp_instr_jump
::
opt_mark
(
sp_head
*
sp
)
sp_instr_jump
::
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
)
{
{
m_dest
=
opt_shortcut_jump
(
sp
,
this
);
m_dest
=
opt_shortcut_jump
(
sp
,
this
);
if
(
m_dest
!=
m_ip
+
1
)
/* Jumping to following instruction? */
if
(
m_dest
!=
m_ip
+
1
)
/* Jumping to following instruction? */
...
@@ -2711,7 +2727,7 @@ sp_instr_jump_if_not::print(String *str)
...
@@ -2711,7 +2727,7 @@ sp_instr_jump_if_not::print(String *str)
uint
uint
sp_instr_jump_if_not
::
opt_mark
(
sp_head
*
sp
)
sp_instr_jump_if_not
::
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
)
{
{
sp_instr
*
i
;
sp_instr
*
i
;
...
@@ -2721,13 +2737,13 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp)
...
@@ -2721,13 +2737,13 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp)
m_dest
=
i
->
opt_shortcut_jump
(
sp
,
this
);
m_dest
=
i
->
opt_shortcut_jump
(
sp
,
this
);
m_optdest
=
sp
->
get_instr
(
m_dest
);
m_optdest
=
sp
->
get_instr
(
m_dest
);
}
}
sp
->
opt_mark
(
m_dest
);
sp
->
add_mark_lead
(
m_dest
,
leads
);
if
((
i
=
sp
->
get_instr
(
m_cont_dest
)))
if
((
i
=
sp
->
get_instr
(
m_cont_dest
)))
{
{
m_cont_dest
=
i
->
opt_shortcut_jump
(
sp
,
this
);
m_cont_dest
=
i
->
opt_shortcut_jump
(
sp
,
this
);
m_cont_optdest
=
sp
->
get_instr
(
m_cont_dest
);
m_cont_optdest
=
sp
->
get_instr
(
m_cont_dest
);
}
}
sp
->
opt_mark
(
m_cont_dest
);
sp
->
add_mark_lead
(
m_cont_dest
,
leads
);
return
m_ip
+
1
;
return
m_ip
+
1
;
}
}
...
@@ -2848,7 +2864,7 @@ sp_instr_hpush_jump::print(String *str)
...
@@ -2848,7 +2864,7 @@ sp_instr_hpush_jump::print(String *str)
uint
uint
sp_instr_hpush_jump
::
opt_mark
(
sp_head
*
sp
)
sp_instr_hpush_jump
::
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
)
{
{
sp_instr
*
i
;
sp_instr
*
i
;
...
@@ -2858,7 +2874,7 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp)
...
@@ -2858,7 +2874,7 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp)
m_dest
=
i
->
opt_shortcut_jump
(
sp
,
this
);
m_dest
=
i
->
opt_shortcut_jump
(
sp
,
this
);
m_optdest
=
sp
->
get_instr
(
m_dest
);
m_optdest
=
sp
->
get_instr
(
m_dest
);
}
}
sp
->
opt_mark
(
m_dest
);
sp
->
add_mark_lead
(
m_dest
,
leads
);
return
m_ip
+
1
;
return
m_ip
+
1
;
}
}
...
@@ -2923,15 +2939,13 @@ sp_instr_hreturn::print(String *str)
...
@@ -2923,15 +2939,13 @@ sp_instr_hreturn::print(String *str)
uint
uint
sp_instr_hreturn
::
opt_mark
(
sp_head
*
sp
)
sp_instr_hreturn
::
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
)
{
{
if
(
m_dest
)
if
(
m_dest
)
return
sp_instr_jump
::
opt_mark
(
sp
);
return
sp_instr_jump
::
opt_mark
(
sp
,
leads
);
else
{
marked
=
1
;
marked
=
1
;
return
UINT_MAX
;
return
UINT_MAX
;
}
}
}
...
@@ -3274,7 +3288,7 @@ sp_instr_set_case_expr::print(String *str)
...
@@ -3274,7 +3288,7 @@ sp_instr_set_case_expr::print(String *str)
}
}
uint
uint
sp_instr_set_case_expr
::
opt_mark
(
sp_head
*
sp
)
sp_instr_set_case_expr
::
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
)
{
{
sp_instr
*
i
;
sp_instr
*
i
;
...
@@ -3284,7 +3298,7 @@ sp_instr_set_case_expr::opt_mark(sp_head *sp)
...
@@ -3284,7 +3298,7 @@ sp_instr_set_case_expr::opt_mark(sp_head *sp)
m_cont_dest
=
i
->
opt_shortcut_jump
(
sp
,
this
);
m_cont_dest
=
i
->
opt_shortcut_jump
(
sp
,
this
);
m_cont_optdest
=
sp
->
get_instr
(
m_cont_dest
);
m_cont_optdest
=
sp
->
get_instr
(
m_cont_dest
);
}
}
sp
->
opt_mark
(
m_cont_dest
);
sp
->
add_mark_lead
(
m_cont_dest
,
leads
);
return
m_ip
+
1
;
return
m_ip
+
1
;
}
}
...
...
sql/sp_head.h
View file @
64b7a75a
...
@@ -302,8 +302,19 @@ class sp_head :private Query_arena
...
@@ -302,8 +302,19 @@ class sp_head :private Query_arena
void
restore_thd_mem_root
(
THD
*
thd
);
void
restore_thd_mem_root
(
THD
*
thd
);
/**
Optimize the code.
*/
void
optimize
();
void
optimize
();
void
opt_mark
(
uint
ip
);
/**
Helper used during flow analysis during code optimization.
See the implementation of <code>opt_mark()</code>.
@param ip the instruction to add to the leads list
@param leads the list of remaining paths to explore in the graph that
represents the code, during flow analysis.
*/
void
add_mark_lead
(
uint
ip
,
List
<
sp_instr
>
*
leads
);
void
recursion_level_error
(
THD
*
thd
);
void
recursion_level_error
(
THD
*
thd
);
...
@@ -393,6 +404,12 @@ class sp_head :private Query_arena
...
@@ -393,6 +404,12 @@ class sp_head :private Query_arena
bool
bool
execute
(
THD
*
thd
);
execute
(
THD
*
thd
);
/**
Perform a forward flow analysis in the generated code.
Mark reachable instructions, for the optimizer.
*/
void
opt_mark
();
/*
/*
Merge the list of tables used by query into the multi-set of tables used
Merge the list of tables used by query into the multi-set of tables used
by routine.
by routine.
...
@@ -460,10 +477,10 @@ class sp_instr :public Query_arena, public Sql_alloc
...
@@ -460,10 +477,10 @@ class sp_instr :public Query_arena, public Sql_alloc
/*
/*
Mark this instruction as reachable during optimization and return the
Mark this instruction as reachable during optimization and return the
index to the next instruction. Jump instruction will
mark
their
index to the next instruction. Jump instruction will
add
their
destination to
o recursively
.
destination to
the leads list
.
*/
*/
virtual
uint
opt_mark
(
sp_head
*
sp
)
virtual
uint
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
)
{
{
marked
=
1
;
marked
=
1
;
return
m_ip
+
1
;
return
m_ip
+
1
;
...
@@ -735,7 +752,7 @@ class sp_instr_jump : public sp_instr_opt_meta
...
@@ -735,7 +752,7 @@ class sp_instr_jump : public sp_instr_opt_meta
virtual
void
print
(
String
*
str
);
virtual
void
print
(
String
*
str
);
virtual
uint
opt_mark
(
sp_head
*
sp
);
virtual
uint
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
);
virtual
uint
opt_shortcut_jump
(
sp_head
*
sp
,
sp_instr
*
start
);
virtual
uint
opt_shortcut_jump
(
sp_head
*
sp
,
sp_instr
*
start
);
...
@@ -785,7 +802,7 @@ class sp_instr_jump_if_not : public sp_instr_jump
...
@@ -785,7 +802,7 @@ class sp_instr_jump_if_not : public sp_instr_jump
virtual
void
print
(
String
*
str
);
virtual
void
print
(
String
*
str
);
virtual
uint
opt_mark
(
sp_head
*
sp
);
virtual
uint
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
);
/* Override sp_instr_jump's shortcut; we stop here */
/* Override sp_instr_jump's shortcut; we stop here */
virtual
uint
opt_shortcut_jump
(
sp_head
*
sp
,
sp_instr
*
start
)
virtual
uint
opt_shortcut_jump
(
sp_head
*
sp
,
sp_instr
*
start
)
...
@@ -831,7 +848,7 @@ class sp_instr_freturn : public sp_instr
...
@@ -831,7 +848,7 @@ class sp_instr_freturn : public sp_instr
virtual
void
print
(
String
*
str
);
virtual
void
print
(
String
*
str
);
virtual
uint
opt_mark
(
sp_head
*
sp
)
virtual
uint
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
)
{
{
marked
=
1
;
marked
=
1
;
return
UINT_MAX
;
return
UINT_MAX
;
...
@@ -868,7 +885,7 @@ class sp_instr_hpush_jump : public sp_instr_jump
...
@@ -868,7 +885,7 @@ class sp_instr_hpush_jump : public sp_instr_jump
virtual
void
print
(
String
*
str
);
virtual
void
print
(
String
*
str
);
virtual
uint
opt_mark
(
sp_head
*
sp
);
virtual
uint
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
);
/* Override sp_instr_jump's shortcut; we stop here. */
/* Override sp_instr_jump's shortcut; we stop here. */
virtual
uint
opt_shortcut_jump
(
sp_head
*
sp
,
sp_instr
*
start
)
virtual
uint
opt_shortcut_jump
(
sp_head
*
sp
,
sp_instr
*
start
)
...
@@ -933,7 +950,7 @@ class sp_instr_hreturn : public sp_instr_jump
...
@@ -933,7 +950,7 @@ class sp_instr_hreturn : public sp_instr_jump
virtual
void
print
(
String
*
str
);
virtual
void
print
(
String
*
str
);
virtual
uint
opt_mark
(
sp_head
*
sp
);
virtual
uint
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
);
private:
private:
...
@@ -1103,7 +1120,7 @@ class sp_instr_error : public sp_instr
...
@@ -1103,7 +1120,7 @@ class sp_instr_error : public sp_instr
virtual
void
print
(
String
*
str
);
virtual
void
print
(
String
*
str
);
virtual
uint
opt_mark
(
sp_head
*
sp
)
virtual
uint
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
)
{
{
marked
=
1
;
marked
=
1
;
return
UINT_MAX
;
return
UINT_MAX
;
...
@@ -1136,7 +1153,7 @@ class sp_instr_set_case_expr : public sp_instr_opt_meta
...
@@ -1136,7 +1153,7 @@ class sp_instr_set_case_expr : public sp_instr_opt_meta
virtual
void
print
(
String
*
str
);
virtual
void
print
(
String
*
str
);
virtual
uint
opt_mark
(
sp_head
*
sp
);
virtual
uint
opt_mark
(
sp_head
*
sp
,
List
<
sp_instr
>
*
leads
);
virtual
void
opt_move
(
uint
dst
,
List
<
sp_instr
>
*
ibp
);
virtual
void
opt_move
(
uint
dst
,
List
<
sp_instr
>
*
ibp
);
...
...
sql/sql_lex.cc
View file @
64b7a75a
...
@@ -1164,7 +1164,6 @@ void st_select_lex::init_select()
...
@@ -1164,7 +1164,6 @@ void st_select_lex::init_select()
options
=
0
;
options
=
0
;
sql_cache
=
SQL_CACHE_UNSPECIFIED
;
sql_cache
=
SQL_CACHE_UNSPECIFIED
;
braces
=
0
;
braces
=
0
;
when_list
.
empty
();
expr_list
.
empty
();
expr_list
.
empty
();
udf_list
.
empty
();
udf_list
.
empty
();
interval_list
.
empty
();
interval_list
.
empty
();
...
...
sql/sql_lex.h
View file @
64b7a75a
...
@@ -518,7 +518,6 @@ class st_select_lex: public st_select_lex_node
...
@@ -518,7 +518,6 @@ class st_select_lex: public st_select_lex_node
SQL_LIST
order_list
;
/* ORDER clause */
SQL_LIST
order_list
;
/* ORDER clause */
List
<
List_item
>
expr_list
;
List
<
List_item
>
expr_list
;
List
<
List_item
>
when_list
;
/* WHEN clause (expression) */
SQL_LIST
*
gorder_list
;
SQL_LIST
*
gorder_list
;
Item
*
select_limit
,
*
offset_limit
;
/* LIMIT clause parameters */
Item
*
select_limit
,
*
offset_limit
;
/* LIMIT clause parameters */
// Arrays of pointers to top elements of all_fields list
// Arrays of pointers to top elements of all_fields list
...
...
sql/sql_yacc.yy
View file @
64b7a75a
...
@@ -96,6 +96,187 @@ void turn_parser_debug_on()
...
@@ -96,6 +96,187 @@ void turn_parser_debug_on()
}
}
#endif
#endif
/**
Helper action for a case statement (entering the CASE).
This helper is used for both 'simple' and 'searched' cases.
This helper, with the other case_stmt_action_..., is executed when
the following SQL code is parsed:
<pre>
CREATE PROCEDURE proc_19194_simple(i int)
BEGIN
DECLARE str CHAR(10);
CASE i
WHEN 1 THEN SET str="1";
WHEN 2 THEN SET str="2";
WHEN 3 THEN SET str="3";
ELSE SET str="unknown";
END CASE;
SELECT str;
END
</pre>
The actions are used to generate the following code:
<pre>
SHOW PROCEDURE CODE proc_19194_simple;
Pos Instruction
0 set str@1 NULL
1 set_case_expr (12) 0 i@0
2 jump_if_not 5(12) (case_expr@0 = 1)
3 set str@1 _latin1'1'
4 jump 12
5 jump_if_not 8(12) (case_expr@0 = 2)
6 set str@1 _latin1'2'
7 jump 12
8 jump_if_not 11(12) (case_expr@0 = 3)
9 set str@1 _latin1'3'
10 jump 12
11 set str@1 _latin1'unknown'
12 stmt 0 "SELECT str"
</pre>
@param lex the parser lex context
*/
void case_stmt_action_case(LEX *lex)
{
lex->sphead->new_cont_backpatch(NULL);
/*
BACKPATCH: Creating target label for the jump to
"case_stmt_action_end_case"
(Instruction 12 in the example)
*/
lex->spcont->push_label((char *)"", lex->sphead->instructions());
}
/**
Helper action for a case expression statement (the expr in 'CASE expr').
This helper is used for 'searched' cases only.
@param lex the parser lex context
@param expr the parsed expression
@return 0 on success
*/
int case_stmt_action_expr(LEX *lex, Item* expr)
{
sp_head *sp= lex->sphead;
sp_pcontext *parsing_ctx= lex->spcont;
int case_expr_id= parsing_ctx->register_case_expr();
sp_instr_set_case_expr *i;
if (parsing_ctx->push_case_expr_id(case_expr_id))
return 1;
i= new sp_instr_set_case_expr(sp->instructions(),
parsing_ctx, case_expr_id, expr, lex);
sp->add_cont_backpatch(i);
sp->add_instr(i);
return 0;
}
/**
Helper action for a case when condition.
This helper is used for both 'simple' and 'searched' cases.
@param lex the parser lex context
@param when the parsed expression for the WHEN clause
@param simple true for simple cases, false for searched cases
*/
void case_stmt_action_when(LEX *lex, Item *when, bool simple)
{
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
uint ip= sp->instructions();
sp_instr_jump_if_not *i;
Item_case_expr *var;
Item *expr;
if (simple)
{
var= new Item_case_expr(ctx->get_current_case_expr_id());
#ifndef DBUG_OFF
if (var)
{
var->m_sp= sp;
}
#endif
expr= new Item_func_eq(var, when);
i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
}
else
i= new sp_instr_jump_if_not(ip, ctx, when, lex);
/*
BACKPATCH: Registering forward jump from
"case_stmt_action_when" to "case_stmt_action_then"
(jump_if_not from instruction 2 to 5, 5 to 8 ... in the example)
*/
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
sp->add_cont_backpatch(i);
sp->add_instr(i);
}
/**
Helper action for a case then statements.
This helper is used for both 'simple' and 'searched' cases.
@param lex the parser lex context
*/
void case_stmt_action_then(LEX *lex)
{
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
uint ip= sp->instructions();
sp_instr_jump *i = new sp_instr_jump(ip, ctx);
sp->add_instr(i);
/*
BACKPATCH: Resolving forward jump from
"case_stmt_action_when" to "case_stmt_action_then"
(jump_if_not from instruction 2 to 5, 5 to 8 ... in the example)
*/
sp->backpatch(ctx->pop_label());
/*
BACKPATCH: Registering forward jump from
"case_stmt_action_then" to "case_stmt_action_end_case"
(jump from instruction 4 to 12, 7 to 12 ... in the example)
*/
sp->push_backpatch(i, ctx->last_label());
}
/**
Helper action for an end case.
This helper is used for both 'simple' and 'searched' cases.
@param lex the parser lex context
@param simple true for simple cases, false for searched cases
*/
void case_stmt_action_end_case(LEX *lex, bool simple)
{
/*
BACKPATCH: Resolving forward jump from
"case_stmt_action_then" to "case_stmt_action_end_case"
(jump from instruction 4 to 12, 7 to 12 ... in the example)
*/
lex->sphead->backpatch(lex->spcont->pop_label());
if (simple)
lex->spcont->pop_case_expr_id();
lex->sphead->do_cont_backpatch();
}
%}
%}
%union {
%union {
int num;
int num;
...
@@ -832,7 +1013,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
...
@@ -832,7 +1013,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
select_item_list select_item values_list no_braces
select_item_list select_item values_list no_braces
opt_limit_clause delete_limit_clause fields opt_values values
opt_limit_clause delete_limit_clause fields opt_values values
procedure_list procedure_list2 procedure_item
procedure_list procedure_list2 procedure_item
when_list2
expr_list2 udf_expr_list3 handler
expr_list2 udf_expr_list3 handler
opt_precision opt_ignore opt_column opt_restrict
opt_precision opt_ignore opt_column opt_restrict
grant revoke set lock unlock string_list field_options field_option
grant revoke set lock unlock string_list field_options field_option
field_opt_list opt_binary table_lock_list table_lock
field_opt_list opt_binary table_lock_list table_lock
...
@@ -860,6 +1041,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
...
@@ -860,6 +1041,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
view_algorithm view_or_trigger_or_sp view_or_trigger_or_sp_tail
view_algorithm view_or_trigger_or_sp view_or_trigger_or_sp_tail
view_suid view_tail view_list_opt view_list view_select
view_suid view_tail view_list_opt view_list view_select
view_check_option trigger_tail sp_tail
view_check_option trigger_tail sp_tail
case_stmt_specification simple_case_stmt searched_case_stmt
END_OF_INPUT
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
...
@@ -1995,43 +2177,7 @@ sp_proc_stmt:
...
@@ -1995,43 +2177,7 @@ sp_proc_stmt:
{ Lex->sphead->new_cont_backpatch(NULL); }
{ Lex->sphead->new_cont_backpatch(NULL); }
sp_if END IF
sp_if END IF
{ Lex->sphead->do_cont_backpatch(); }
{ Lex->sphead->do_cont_backpatch(); }
| CASE_SYM WHEN_SYM
| case_stmt_specification
{
Lex->sphead->m_flags&= ~sp_head::IN_SIMPLE_CASE;
Lex->sphead->new_cont_backpatch(NULL);
}
sp_case END CASE_SYM { Lex->sphead->do_cont_backpatch(); }
| CASE_SYM
{
Lex->sphead->reset_lex(YYTHD);
Lex->sphead->new_cont_backpatch(NULL);
}
expr WHEN_SYM
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
sp_pcontext *parsing_ctx= lex->spcont;
int case_expr_id= parsing_ctx->register_case_expr();
sp_instr_set_case_expr *i;
if (parsing_ctx->push_case_expr_id(case_expr_id))
YYABORT;
i= new sp_instr_set_case_expr(sp->instructions(),
parsing_ctx,
case_expr_id,
$3,
lex);
sp->add_cont_backpatch(i);
sp->add_instr(i);
sp->m_flags|= sp_head::IN_SIMPLE_CASE;
sp->restore_lex(YYTHD);
}
sp_case END CASE_SYM
{
Lex->spcont->pop_case_expr_id();
Lex->sphead->do_cont_backpatch();
}
| sp_labeled_control
| sp_labeled_control
{}
{}
| { /* Unlabeled controls get a secret label. */
| { /* Unlabeled controls get a secret label. */
...
@@ -2242,72 +2388,114 @@ sp_elseifs:
...
@@ -2242,72 +2388,114 @@ sp_elseifs:
| ELSE sp_proc_stmts1
| ELSE sp_proc_stmts1
;
;
sp_case:
case_stmt_specification:
{ Lex->sphead->reset_lex(YYTHD); }
simple_case_stmt
expr THEN_SYM
| searched_case_stmt
{
;
LEX *lex= Lex;
sp_head *sp= lex->sphead;
sp_pcontext *ctx= Lex->spcont;
uint ip= sp->instructions();
sp_instr_jump_if_not *i;
if (! (sp->m_flags & sp_head::IN_SIMPLE_CASE))
i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
else
{ /* Simple case: <caseval> = <whenval> */
Item_case_expr *var;
simple_case_stmt:
Item *expr;
CASE_SYM
{
LEX *lex= Lex;
case_stmt_action_case(lex);
lex->sphead->reset_lex(YYTHD); /* For expr $3 */
}
expr
{
LEX *lex= Lex;
if (case_stmt_action_expr(lex, $3))
YYABORT;
var= new Item_case_expr(ctx->get_current_case_expr_id());
lex->sphead->restore_lex(YYTHD); /* For expr $3 */
}
simple_when_clause_list
else_clause_opt
END
CASE_SYM
{
LEX *lex= Lex;
case_stmt_action_end_case(lex, true);
}
;
#ifndef DBUG_OFF
searched_case_stmt:
if (var)
CASE_SYM
var->m_sp= sp;
{
#endif
LEX *lex= Lex;
case_stmt_action_case(lex);
}
searched_when_clause_list
else_clause_opt
END
CASE_SYM
{
LEX *lex= Lex;
case_stmt_action_end_case(lex, false);
}
;
expr= new Item_func_eq(var, $2);
simple_when_clause_list:
simple_when_clause
| simple_when_clause_list simple_when_clause
;
i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
searched_when_clause_list:
}
searched_when_clause
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
| searched_when_clause_list searched_when_clause
sp->add_cont_backpatch(i);
;
sp->add_instr(i);
sp->restore_lex(YYTHD);
}
sp_proc_stmts1
{
sp_head *sp= Lex->sphead;
sp_pcontext *ctx= Lex->spcont;
uint ip= sp->instructions();
sp_instr_jump *i = new sp_instr_jump(ip, ctx);
sp->add_instr(i);
simple_when_clause:
sp->backpatch(ctx->pop_label());
WHEN_SYM
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
{
}
Lex->sphead->reset_lex(YYTHD); /* For expr $3 */
sp_whens
}
{
expr
LEX *lex= Lex;
{
/* Simple case: <caseval> = <whenval> */
lex->sphead->backpatch(lex->spcont->pop_label());
LEX *lex= Lex;
}
case_stmt_action_when(lex, $3, true);
;
lex->sphead->restore_lex(YYTHD); /* For expr $3 */
}
THEN_SYM
sp_proc_stmts1
{
LEX *lex= Lex;
case_stmt_action_then(lex);
}
;
sp_whens:
searched_when_clause:
/* Empty */
WHEN_SYM
{
{
sp_head *sp= Lex->sphead;
Lex->sphead->reset_lex(YYTHD); /* For expr $3 */
uint ip= sp->instructions();
}
sp_instr_error *i= new sp_instr_error(ip, Lex->spcont,
expr
ER_SP_CASE_NOT_FOUND);
{
LEX *lex= Lex;
case_stmt_action_when(lex, $3, false);
lex->sphead->restore_lex(YYTHD); /* For expr $3 */
}
THEN_SYM
sp_proc_stmts1
{
LEX *lex= Lex;
case_stmt_action_then(lex);
}
;
sp->add_instr(i);
else_clause_opt:
}
/* empty */
| ELSE sp_proc_stmts1 {}
{
| WHEN_SYM sp_case {}
LEX *lex= Lex;
;
sp_head *sp= lex->sphead;
uint ip= sp->instructions();
sp_instr_error *i= new sp_instr_error(ip, lex->spcont,
ER_SP_CASE_NOT_FOUND);
sp->add_instr(i);
}
| ELSE sp_proc_stmts1
;
sp_labeled_control:
sp_labeled_control:
label_ident ':'
label_ident ':'
...
@@ -4374,8 +4562,8 @@ simple_expr:
...
@@ -4374,8 +4562,8 @@ simple_expr:
if (!$$)
if (!$$)
YYABORT;
YYABORT;
}
}
| CASE_SYM opt_expr
WHEN_SYM
when_list opt_else END
| CASE_SYM opt_expr when_list opt_else END
{ $$= new Item_func_case(* $
4, $2, $5
); }
{ $$= new Item_func_case(* $
3, $2, $4
); }
| CONVERT_SYM '(' expr ',' cast_type ')'
| CONVERT_SYM '(' expr ',' cast_type ')'
{
{
$$= create_func_cast($3, $5,
$$= create_func_cast($3, $5,
...
@@ -5184,23 +5372,19 @@ opt_else:
...
@@ -5184,23 +5372,19 @@ opt_else:
| ELSE expr { $$= $2; };
| ELSE expr { $$= $2; };
when_list:
when_list:
{ Select->when_list.push_front(new List<Item>); }
WHEN_SYM expr THEN_SYM expr
when_list2
{
{ $$= Select->when_list.pop(); };
$$= new List<Item>;
$$->push_back($2);
when_list2:
$$->push_back($4);
expr THEN_SYM expr
}
{
| when_list WHEN_SYM expr THEN_SYM expr
SELECT_LEX *sel=Select;
{
sel->when_list.head()->push_back($1);
$1->push_back($3);
sel->when_list.head()->push_back($3);
$1->push_back($5);
}
$$= $1;
| when_list2 WHEN_SYM expr THEN_SYM expr
}
{
;
SELECT_LEX *sel=Select;
sel->when_list.head()->push_back($3);
sel->when_list.head()->push_back($5);
};
/* Warning - may return NULL in case of incomplete SELECT */
/* Warning - may return NULL in case of incomplete SELECT */
table_ref:
table_ref:
...
...
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