Commit fc681ea7 authored by unknown's avatar unknown

Merge bk-internal.mysql.com:/home/bk/mysql-5.0

into  bodhi.local:/opt/local/work/mysql-5.0-runtime


sql/item_func.cc:
  Auto merged
sql/sql_class.h:
  Auto merged
sql/sql_lex.cc:
  Auto merged
parents 7a9892cc 4a819ce1
...@@ -75,7 +75,7 @@ int hp_get_new_block(HP_BLOCK *block, ulong *alloc_length) ...@@ -75,7 +75,7 @@ int hp_get_new_block(HP_BLOCK *block, ulong *alloc_length)
and my_default_record_cache_size we get about 1/128 unused memory. and my_default_record_cache_size we get about 1/128 unused memory.
*/ */
*alloc_length=sizeof(HP_PTRS)*i+block->records_in_block* block->recbuffer; *alloc_length=sizeof(HP_PTRS)*i+block->records_in_block* block->recbuffer;
if (!(root=(HP_PTRS*) my_malloc(*alloc_length,MYF(0)))) if (!(root=(HP_PTRS*) my_malloc(*alloc_length,MYF(MY_WME))))
return 1; return 1;
if (i == 0) if (i == 0)
......
...@@ -67,11 +67,17 @@ int heap_write(HP_INFO *info, const byte *record) ...@@ -67,11 +67,17 @@ int heap_write(HP_INFO *info, const byte *record)
DBUG_RETURN(0); DBUG_RETURN(0);
err: err:
DBUG_PRINT("info",("Duplicate key: %d", (int) (keydef - share->keydef))); if (my_errno == HA_ERR_FOUND_DUPP_KEY)
DBUG_PRINT("info",("Duplicate key: %d", keydef - share->keydef));
info->errkey= keydef - share->keydef; info->errkey= keydef - share->keydef;
if (keydef->algorithm == HA_KEY_ALG_BTREE) /*
We don't need to delete non-inserted key from rb-tree. Also, if
we got ENOMEM, the key wasn't inserted, so don't try to delete it
either. Otherwise for HASH index on HA_ERR_FOUND_DUPP_KEY the key
was inserted and we have to delete it.
*/
if (keydef->algorithm == HA_KEY_ALG_BTREE || my_errno == ENOMEM)
{ {
/* we don't need to delete non-inserted key from rb-tree */
keydef--; keydef--;
} }
while (keydef >= share->keydef) while (keydef >= share->keydef)
......
...@@ -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;
......
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;
...@@ -3014,4 +3014,13 @@ i j ...@@ -3014,4 +3014,13 @@ i j
6 3 6 3
DROP VIEW v1, v2; DROP VIEW v1, v2;
DROP TABLE t1; DROP TABLE t1;
DROP VIEW IF EXISTS v1;
CREATE VIEW v1 AS SELECT 'The\ZEnd';
SELECT * FROM v1;
TheEnd
TheEnd
SHOW CREATE VIEW v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select _latin1'The\ZEnd' AS `TheEnd`
DROP VIEW v1;
End of 5.0 tests. End of 5.0 tests.
#!/bin/bash #!/bin/sh
########################################################################### ###########################################################################
......
...@@ -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
......
#
# 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;
...@@ -2960,4 +2960,19 @@ DROP VIEW v1, v2; ...@@ -2960,4 +2960,19 @@ DROP VIEW v1, v2;
DROP TABLE t1; DROP TABLE t1;
#
# BUG#24293: '\Z' token is not handled correctly in views
#
--disable_warnings
DROP VIEW IF EXISTS v1;
--enable_warnings
CREATE VIEW v1 AS SELECT 'The\ZEnd';
SELECT * FROM v1;
SHOW CREATE VIEW v1;
DROP VIEW v1;
--echo End of 5.0 tests. --echo End of 5.0 tests.
...@@ -187,7 +187,7 @@ void Listener_thread::run() ...@@ -187,7 +187,7 @@ void Listener_thread::run()
else else
{ {
shutdown(client_fd, SHUT_RDWR); shutdown(client_fd, SHUT_RDWR);
close(client_fd); closesocket(client_fd);
} }
} }
} }
...@@ -199,7 +199,7 @@ void Listener_thread::run() ...@@ -199,7 +199,7 @@ void Listener_thread::run()
log_info("Listener_thread::run(): shutdown requested, exiting..."); log_info("Listener_thread::run(): shutdown requested, exiting...");
for (i= 0; i < num_sockets; i++) for (i= 0; i < num_sockets; i++)
close(sockets[i]); closesocket(sockets[i]);
#ifndef __WIN__ #ifndef __WIN__
unlink(unix_socket_address.sun_path); unlink(unix_socket_address.sun_path);
...@@ -212,7 +212,7 @@ void Listener_thread::run() ...@@ -212,7 +212,7 @@ void Listener_thread::run()
err: err:
// we have to close the ip sockets in case of error // we have to close the ip sockets in case of error
for (i= 0; i < num_sockets; i++) for (i= 0; i < num_sockets; i++)
close(sockets[i]); closesocket(sockets[i]);
thread_registry.unregister_thread(&thread_info); thread_registry.unregister_thread(&thread_info);
thread_registry.request_shutdown(); thread_registry.request_shutdown();
...@@ -259,7 +259,7 @@ int Listener_thread::create_tcp_socket() ...@@ -259,7 +259,7 @@ int Listener_thread::create_tcp_socket()
{ {
log_error("Listener_thread::run(): bind(ip socket) failed, '%s'", log_error("Listener_thread::run(): bind(ip socket) failed, '%s'",
strerror(errno)); strerror(errno));
close(ip_socket); closesocket(ip_socket);
return -1; return -1;
} }
...@@ -267,7 +267,7 @@ int Listener_thread::create_tcp_socket() ...@@ -267,7 +267,7 @@ int Listener_thread::create_tcp_socket()
{ {
log_error("Listener_thread::run(): listen(ip socket) failed, %s", log_error("Listener_thread::run(): listen(ip socket) failed, %s",
strerror(errno)); strerror(errno));
close(ip_socket); closesocket(ip_socket);
return -1; return -1;
} }
......
...@@ -3688,8 +3688,9 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, ...@@ -3688,8 +3688,9 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry)); char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
if (entry->value == pos) if (entry->value == pos)
entry->value=0; entry->value=0;
if (!(entry->value=(char*) my_realloc(entry->value, length, entry->value= (char*) my_realloc(entry->value, length,
MYF(MY_ALLOW_ZERO_PTR)))) MYF(MY_ALLOW_ZERO_PTR | MY_WME));
if (!entry->value)
return 1; return 1;
} }
} }
......
...@@ -605,27 +605,6 @@ sp_head::create(THD *thd) ...@@ -605,27 +605,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
...@@ -2173,7 +2152,7 @@ sp_head::show_create_function(THD *thd) ...@@ -2173,7 +2152,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
...@@ -2186,7 +2165,7 @@ void sp_head::optimize() ...@@ -2186,7 +2165,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;
...@@ -2220,13 +2199,50 @@ void sp_head::optimize() ...@@ -2220,13 +2199,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;
/*
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) /* Mark the entire path, collecting new leads. */
ip= i->opt_mark(this); while (i && ! i->marked)
{
ip= i->opt_mark(this, & leads);
i= get_instr(ip);
}
}
} }
...@@ -2619,7 +2635,7 @@ sp_instr_jump::print(String *str) ...@@ -2619,7 +2635,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? */
...@@ -2713,7 +2729,7 @@ sp_instr_jump_if_not::print(String *str) ...@@ -2713,7 +2729,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;
...@@ -2723,13 +2739,13 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp) ...@@ -2723,13 +2739,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;
} }
...@@ -2850,7 +2866,7 @@ sp_instr_hpush_jump::print(String *str) ...@@ -2850,7 +2866,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;
...@@ -2860,7 +2876,7 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp) ...@@ -2860,7 +2876,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;
} }
...@@ -2925,15 +2941,13 @@ sp_instr_hreturn::print(String *str) ...@@ -2925,15 +2941,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;
}
} }
...@@ -3276,7 +3290,7 @@ sp_instr_set_case_expr::print(String *str) ...@@ -3276,7 +3290,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;
...@@ -3286,7 +3300,7 @@ sp_instr_set_case_expr::opt_mark(sp_head *sp) ...@@ -3286,7 +3300,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;
} }
......
...@@ -301,8 +301,19 @@ public: ...@@ -301,8 +301,19 @@ public:
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);
...@@ -392,6 +403,12 @@ private: ...@@ -392,6 +403,12 @@ private:
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.
...@@ -459,10 +476,10 @@ public: ...@@ -459,10 +476,10 @@ public:
/* /*
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 too 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;
...@@ -734,7 +751,7 @@ public: ...@@ -734,7 +751,7 @@ public:
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);
...@@ -784,7 +801,7 @@ public: ...@@ -784,7 +801,7 @@ public:
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)
...@@ -830,7 +847,7 @@ public: ...@@ -830,7 +847,7 @@ public:
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;
...@@ -867,7 +884,7 @@ public: ...@@ -867,7 +884,7 @@ public:
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)
...@@ -932,7 +949,7 @@ public: ...@@ -932,7 +949,7 @@ public:
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:
...@@ -1102,7 +1119,7 @@ public: ...@@ -1102,7 +1119,7 @@ public:
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;
...@@ -1135,7 +1152,7 @@ public: ...@@ -1135,7 +1152,7 @@ public:
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);
......
...@@ -884,6 +884,13 @@ void select_result::cleanup() ...@@ -884,6 +884,13 @@ void select_result::cleanup()
/* do nothing */ /* do nothing */
} }
bool select_result::check_simple_select() const
{
my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
return TRUE;
}
static String default_line_term("\n",default_charset_info); static String default_line_term("\n",default_charset_info);
static String default_escaped("\\",default_charset_info); static String default_escaped("\\",default_charset_info);
static String default_field_term("\t",default_charset_info); static String default_field_term("\t",default_charset_info);
...@@ -1521,6 +1528,13 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) ...@@ -1521,6 +1528,13 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
} }
bool select_dumpvar::check_simple_select() const
{
my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0));
return TRUE;
}
void select_dumpvar::cleanup() void select_dumpvar::cleanup()
{ {
row_count= 0; row_count= 0;
......
...@@ -1723,7 +1723,14 @@ public: ...@@ -1723,7 +1723,14 @@ public:
virtual bool initialize_tables (JOIN *join=0) { return 0; } virtual bool initialize_tables (JOIN *join=0) { return 0; }
virtual void send_error(uint errcode,const char *err); virtual void send_error(uint errcode,const char *err);
virtual bool send_eof()=0; virtual bool send_eof()=0;
virtual bool simple_select() { return 0; } /**
Check if this query returns a result set and therefore is allowed in
cursors and set an error message if it is not the case.
@retval FALSE success
@retval TRUE error, an error message is set
*/
virtual bool check_simple_select() const;
virtual void abort() {} virtual void abort() {}
/* /*
Cleanup instance of this class for next execution of a prepared Cleanup instance of this class for next execution of a prepared
...@@ -1761,7 +1768,7 @@ public: ...@@ -1761,7 +1768,7 @@ public:
bool send_fields(List<Item> &list, uint flags); bool send_fields(List<Item> &list, uint flags);
bool send_data(List<Item> &items); bool send_data(List<Item> &items);
bool send_eof(); bool send_eof();
bool simple_select() { return 1; } virtual bool check_simple_select() const { return FALSE; }
void abort(); void abort();
}; };
...@@ -2200,6 +2207,7 @@ public: ...@@ -2200,6 +2207,7 @@ public:
int prepare(List<Item> &list, SELECT_LEX_UNIT *u); int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items); bool send_data(List<Item> &items);
bool send_eof(); bool send_eof();
virtual bool check_simple_select() const;
void cleanup(); void cleanup();
}; };
......
...@@ -1163,7 +1163,6 @@ void st_select_lex::init_select() ...@@ -1163,7 +1163,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();
......
...@@ -517,7 +517,6 @@ public: ...@@ -517,7 +517,6 @@ public:
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
......
...@@ -2902,10 +2902,9 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) ...@@ -2902,10 +2902,9 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
in INSERT ... SELECT and similar commands. in INSERT ... SELECT and similar commands.
*/ */
if (open_cursor && lex->result && !lex->result->simple_select()) if (open_cursor && lex->result && lex->result->check_simple_select())
{ {
DBUG_PRINT("info",("Cursor asked for not SELECT stmt")); DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
return TRUE; return TRUE;
} }
......
...@@ -1032,8 +1032,8 @@ void String::print(String *str) ...@@ -1032,8 +1032,8 @@ void String::print(String *str)
case '\r': case '\r':
str->append(STRING_WITH_LEN("\\r")); str->append(STRING_WITH_LEN("\\r"));
break; break;
case 26: //Ctrl-Z case '\032': // Ctrl-Z
str->append(STRING_WITH_LEN("\\z")); str->append(STRING_WITH_LEN("\\Z"));
break; break;
default: default:
str->append(c); str->append(c);
......
This diff is collapsed.
...@@ -15455,6 +15455,33 @@ static void test_bug21635() ...@@ -15455,6 +15455,33 @@ static void test_bug21635()
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/*
Bug#24179 "select b into $var" fails with --cursor_protocol"
The failure is correct, check that the returned message is meaningful.
*/
static void test_bug24179()
{
int rc;
MYSQL_STMT *stmt;
DBUG_ENTER("test_bug24179");
myheader("test_bug24179");
stmt= open_cursor("select 1 into @a");
rc= mysql_stmt_execute(stmt);
DIE_UNLESS(rc);
if (!opt_silent)
{
printf("Got error (as expected): %d %s\n",
mysql_stmt_errno(stmt),
mysql_stmt_error(stmt));
}
DIE_UNLESS(mysql_stmt_errno(stmt) == 1323);
DBUG_VOID_RETURN;
}
/* /*
Read and parse arguments and MySQL options from my.cnf Read and parse arguments and MySQL options from my.cnf
...@@ -15734,6 +15761,7 @@ static struct my_tests_st my_tests[]= { ...@@ -15734,6 +15761,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug21726", test_bug21726 }, { "test_bug21726", test_bug21726 },
{ "test_bug23383", test_bug23383 }, { "test_bug23383", test_bug23383 },
{ "test_bug21635", test_bug21635 }, { "test_bug21635", test_bug21635 },
{ "test_bug24179", test_bug24179 },
{ 0, 0 } { 0, 0 }
}; };
......
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