Commit 996fa0df authored by malff/marcsql@weblab.(none)'s avatar malff/marcsql@weblab.(none)

Merge malff@bk-internal.mysql.com:/home/bk/mysql-5.0-runtime

into  weblab.(none):/home/marcsql/TREE/mysql-5.0-19194
parents 80fe32d5 506c2a72
......@@ -199,6 +199,421 @@ Pos Instruction
44 jump 14
45 stmt 9 "drop temporary table sudoku_work, sud..."
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;
CREATE PROCEDURE p1() CREATE INDEX idx ON t1 (c1);
SHOW PROCEDURE CODE p1;
......
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;
......@@ -191,6 +191,241 @@ show procedure code 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#19194 (Right recursion in parser for CASE causes excessive stack
# usage, limitation)
#
# This test takes some time (8 min) in debug builds
# It's provided as a separate file so that the next line can be uncommented
# later if needed:
# -- source include/big_test.inc
--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;
......@@ -603,27 +603,6 @@ sp_head::create(THD *thd)
DBUG_PRINT("info", ("type: %d name: %s params: %s body: %s",
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)
ret= sp_create_function(thd, this);
else
......@@ -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
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;
used by opt_mark().
opt_move() Update moved instruction
......@@ -2184,7 +2163,7 @@ void sp_head::optimize()
sp_instr *i;
uint src, dst;
opt_mark(0);
opt_mark();
bp.empty();
src= dst= 0;
......@@ -2218,13 +2197,50 @@ void sp_head::optimize()
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
sp_head::opt_mark(uint ip)
sp_head::opt_mark()
{
uint ip;
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)
}
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);
if (m_dest != m_ip+1) /* Jumping to following instruction? */
......@@ -2711,7 +2727,7 @@ sp_instr_jump_if_not::print(String *str)
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;
......@@ -2721,13 +2737,13 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp)
m_dest= i->opt_shortcut_jump(sp, this);
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)))
{
m_cont_dest= i->opt_shortcut_jump(sp, this);
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;
}
......@@ -2848,7 +2864,7 @@ sp_instr_hpush_jump::print(String *str)
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;
......@@ -2858,7 +2874,7 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp)
m_dest= i->opt_shortcut_jump(sp, this);
m_optdest= sp->get_instr(m_dest);
}
sp->opt_mark(m_dest);
sp->add_mark_lead(m_dest, leads);
return m_ip+1;
}
......@@ -2923,15 +2939,13 @@ sp_instr_hreturn::print(String *str)
uint
sp_instr_hreturn::opt_mark(sp_head *sp)
sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads)
{
if (m_dest)
return sp_instr_jump::opt_mark(sp);
else
{
marked= 1;
return UINT_MAX;
}
return sp_instr_jump::opt_mark(sp, leads);
marked= 1;
return UINT_MAX;
}
......@@ -3274,7 +3288,7 @@ sp_instr_set_case_expr::print(String *str)
}
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;
......@@ -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_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;
}
......
......@@ -302,8 +302,19 @@ public:
void restore_thd_mem_root(THD *thd);
/**
Optimize the code.
*/
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);
......@@ -393,6 +404,12 @@ private:
bool
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
by routine.
......@@ -460,10 +477,10 @@ public:
/*
Mark this instruction as reachable during optimization and return the
index to the next instruction. Jump instruction will mark their
destination too recursively.
index to the next instruction. Jump instruction will add their
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;
return m_ip+1;
......@@ -735,7 +752,7 @@ public:
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);
......@@ -785,7 +802,7 @@ public:
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 */
virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
......@@ -831,7 +848,7 @@ public:
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;
return UINT_MAX;
......@@ -868,7 +885,7 @@ public:
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. */
virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
......@@ -933,7 +950,7 @@ public:
virtual void print(String *str);
virtual uint opt_mark(sp_head *sp);
virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
private:
......@@ -1103,7 +1120,7 @@ public:
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;
return UINT_MAX;
......@@ -1136,7 +1153,7 @@ public:
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);
......
......@@ -1164,7 +1164,6 @@ void st_select_lex::init_select()
options= 0;
sql_cache= SQL_CACHE_UNSPECIFIED;
braces= 0;
when_list.empty();
expr_list.empty();
udf_list.empty();
interval_list.empty();
......
......@@ -518,7 +518,6 @@ public:
SQL_LIST order_list; /* ORDER clause */
List<List_item> expr_list;
List<List_item> when_list; /* WHEN clause (expression) */
SQL_LIST *gorder_list;
Item *select_limit, *offset_limit; /* LIMIT clause parameters */
// Arrays of pointers to top elements of all_fields list
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment