Commit 1ec10680 authored by unknown's avatar unknown
Browse files

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

into  weblab.(none):/home/marcsql/TREE/mysql-5.0-19194


sql/sp_head.cc:
  Auto merged
sql/sql_lex.cc:
  Auto merged
sql/sql_lex.h:
  Auto merged
sql/sql_yacc.yy:
  Auto merged
parents 3d5c638b c01c4cc3
Loading
Loading
Loading
Loading
+415 −0
Original line number Diff line number Diff line
@@ -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;
+120 −0
Original line number Diff line number Diff line
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;
+235 −0
Original line number Diff line number Diff line
@@ -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
+94 −0
Original line number Diff line number Diff line
#
# 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;
+55 −41
Original line number Diff line number Diff line
@@ -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;

  /*
    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();

  while ((i= get_instr(ip)) && !i->marked)
    ip= i->opt_mark(this);
    /* 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,16 +2939,14 @@ 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
  {
    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;
}

Loading