mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-10598 Variable declarations can go after cursor declarations
Based on a contributed patch from Jerome Brauge.
This commit is contained in:
@@ -1277,3 +1277,74 @@ Pos Instruction
|
|||||||
28 jump 4
|
28 jump 4
|
||||||
29 cpop 1
|
29 cpop 1
|
||||||
DROP PROCEDURE p1;
|
DROP PROCEDURE p1;
|
||||||
|
#
|
||||||
|
# MDEV-10598 sql_mode=ORACLE: Variable declarations can go after cursor declarations
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Cursor declaration and cursor%ROWTYPE declaration in the same block
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a INT, b VARCHAR(10));
|
||||||
|
INSERT INTO t1 VALUES (1,'a');
|
||||||
|
CREATE PROCEDURE p1()
|
||||||
|
AS
|
||||||
|
CURSOR cur1 IS SELECT a FROM t1;
|
||||||
|
rec1 cur1%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
rec1.a:= 10;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
SHOW PROCEDURE CODE p1;
|
||||||
|
Pos Instruction
|
||||||
|
0 cursor_copy_struct cur1 rec1@0
|
||||||
|
1 set rec1@0 NULL
|
||||||
|
2 cpush cur1@0
|
||||||
|
3 set rec1.a@0["a"] 10
|
||||||
|
4 cpop 1
|
||||||
|
CALL p1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# Recursive cursor and cursor%ROWTYPE declarations in the same block
|
||||||
|
#
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
a INT:=10;
|
||||||
|
CURSOR cur1 IS SELECT a;
|
||||||
|
rec1 cur1%ROWTYPE;
|
||||||
|
CURSOR cur2 IS SELECT rec1.a + 1 "a";
|
||||||
|
rec2 cur2%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
OPEN cur1;
|
||||||
|
FETCH cur1 INTO rec1;
|
||||||
|
CLOSE cur1;
|
||||||
|
SELECT rec1.a;
|
||||||
|
open cur2;
|
||||||
|
FETCH cur2 INTO rec2;
|
||||||
|
CLOSE cur2;
|
||||||
|
SELECT rec2.a;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
SHOW PROCEDURE CODE p1;
|
||||||
|
Pos Instruction
|
||||||
|
0 set a@0 10
|
||||||
|
1 cursor_copy_struct cur1 rec1@1
|
||||||
|
2 set rec1@1 NULL
|
||||||
|
3 cursor_copy_struct cur2 rec2@2
|
||||||
|
4 set rec2@2 NULL
|
||||||
|
5 cpush cur1@0
|
||||||
|
6 cpush cur2@1
|
||||||
|
7 copen cur1@0
|
||||||
|
8 cfetch cur1@0 rec1@1
|
||||||
|
9 cclose cur1@0
|
||||||
|
10 stmt 0 "SELECT rec1.a"
|
||||||
|
11 copen cur2@1
|
||||||
|
12 cfetch cur2@1 rec2@2
|
||||||
|
13 cclose cur2@1
|
||||||
|
14 stmt 0 "SELECT rec2.a"
|
||||||
|
15 cpop 2
|
||||||
|
CALL p1();
|
||||||
|
rec1.a
|
||||||
|
10
|
||||||
|
rec2.a
|
||||||
|
11
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
270
mysql-test/suite/compat/oracle/r/sp-cursor-decl.result
Normal file
270
mysql-test/suite/compat/oracle/r/sp-cursor-decl.result
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
SET sql_mode=ORACLE;
|
||||||
|
#
|
||||||
|
# MDEV-10598 sql_mode=ORACLE: Variable declarations can go after cursor declarations
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Variable after cursor declaration
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
insert into t1 values (2);
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
CURSOR c IS SELECT a FROM t1;
|
||||||
|
var1 varchar(10);
|
||||||
|
BEGIN
|
||||||
|
OPEN c;
|
||||||
|
fetch c into var1;
|
||||||
|
SELECT c%ROWCOUNT,var1;
|
||||||
|
close c;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
CALL p1;
|
||||||
|
c%ROWCOUNT var1
|
||||||
|
1 1
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
drop table t1;
|
||||||
|
#
|
||||||
|
# Variable after condition declaration
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
var1 varchar(40);
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 values (1);
|
||||||
|
select var1;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
CALL p1;
|
||||||
|
var1
|
||||||
|
duplicate key in index
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
drop table t1;
|
||||||
|
#
|
||||||
|
# Condition after cursor declaration
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
var1 varchar(40);
|
||||||
|
var2 integer;
|
||||||
|
CURSOR c IS SELECT col1 FROM t1;
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 values (1);
|
||||||
|
SELECT var1;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
CALL p1;
|
||||||
|
var1
|
||||||
|
duplicate key in index
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
drop table t1;
|
||||||
|
#
|
||||||
|
# Cursor after handler declaration
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
var1 varchar(40);
|
||||||
|
var2 integer;
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
CURSOR c IS SELECT col1 FROM t1;
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 values (1);
|
||||||
|
SELECT var1;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CURSOR c IS SELECT col1 FROM t1;
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 values (1);
|
||||||
|
SELE' at line 10
|
||||||
|
drop table t1;
|
||||||
|
#
|
||||||
|
# Condition after handler declaration
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
var1 varchar(40);
|
||||||
|
var2 integer;
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
CURSOR c IS SELECT col1 FROM t1;
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
divide_by_zero CONDITION FOR SQLSTATE '22012';
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 values (1);
|
||||||
|
SELECT var1;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'divide_by_zero CONDITION FOR SQLSTATE '22012';
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 va' at line 11
|
||||||
|
drop table t1;
|
||||||
|
#
|
||||||
|
# Variable after handler declaration
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
var1 varchar(40);
|
||||||
|
var2 integer;
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
CURSOR c IS SELECT col1 FROM t1;
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
divide_by_zero CONDITION FOR SQLSTATE '22012';
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 values (1);
|
||||||
|
SELECT var1;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'divide_by_zero CONDITION FOR SQLSTATE '22012';
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 va' at line 11
|
||||||
|
drop table t1;
|
||||||
|
#
|
||||||
|
# Variable after cursor (inner block)
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
insert into t1 values (2);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
CURSOR c IS SELECT col1 FROM t1;
|
||||||
|
var1 varchar(40);
|
||||||
|
BEGIN
|
||||||
|
OPEN c;
|
||||||
|
begin
|
||||||
|
declare
|
||||||
|
CURSOR c IS SELECT col1 FROM t1 where col1=2;
|
||||||
|
var2 integer;
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
begin
|
||||||
|
OPEN c;
|
||||||
|
fetch c into var1;
|
||||||
|
SELECT 'inner cursor',var1;
|
||||||
|
insert into t1 values (2);
|
||||||
|
close c;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
SELECT var1;
|
||||||
|
fetch c into var1;
|
||||||
|
SELECT c%ROWCOUNT,var1;
|
||||||
|
begin
|
||||||
|
insert into t1 values (2);
|
||||||
|
exception when 1062 then
|
||||||
|
begin
|
||||||
|
SELECT 'dup key caugth';
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
close c;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
CALL p1;
|
||||||
|
inner cursor var1
|
||||||
|
inner cursor 2
|
||||||
|
var1
|
||||||
|
duplicate key in index
|
||||||
|
c%ROWCOUNT var1
|
||||||
|
1 1
|
||||||
|
dup key caugth
|
||||||
|
dup key caugth
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
drop table t1;
|
||||||
|
#
|
||||||
|
# Cursor declaration and row type declaration in same block
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a INT, b VARCHAR(10));
|
||||||
|
insert into t1 values(1,'a');
|
||||||
|
CREATE PROCEDURE p1()
|
||||||
|
AS
|
||||||
|
CURSOR cur1 IS SELECT a FROM t1;
|
||||||
|
rec1 cur1%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
rec1.a:= 10;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
call p1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
drop table t1;
|
||||||
|
#
|
||||||
|
# Recursive cursor and cursor%ROWTYPE declarations in the same block
|
||||||
|
#
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
a INT:=10;
|
||||||
|
b VARCHAR(10):='b0';
|
||||||
|
c DOUBLE:=0.1;
|
||||||
|
CURSOR cur1 IS SELECT a, b, c;
|
||||||
|
rec1 cur1%ROWTYPE;
|
||||||
|
CURSOR cur2 IS SELECT rec1.a + 1 "a", rec1.b||'0' AS b, rec1.c AS c;
|
||||||
|
rec2 cur2%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
OPEN cur1;
|
||||||
|
FETCH cur1 INTO rec1;
|
||||||
|
CLOSE cur1;
|
||||||
|
SELECT rec1.a;
|
||||||
|
OPEN cur2;
|
||||||
|
FETCH cur2 INTO rec2;
|
||||||
|
CLOSE cur2;
|
||||||
|
SELECT rec2.a;
|
||||||
|
CREATE TABLE t2 AS SELECT rec2.a AS a, rec2.b AS b, rec2.c AS c;
|
||||||
|
SHOW CREATE TABLE t2;
|
||||||
|
DROP TABLE t2;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
CALL p1();
|
||||||
|
rec1.a
|
||||||
|
10
|
||||||
|
rec2.a
|
||||||
|
11
|
||||||
|
Table Create Table
|
||||||
|
t2 CREATE TABLE "t2" (
|
||||||
|
"a" bigint(21) DEFAULT NULL,
|
||||||
|
"b" varchar(11) DEFAULT NULL,
|
||||||
|
"c" double DEFAULT NULL
|
||||||
|
)
|
||||||
|
DROP PROCEDURE p1;
|
@@ -917,3 +917,57 @@ $$
|
|||||||
DELIMITER ;$$
|
DELIMITER ;$$
|
||||||
SHOW PROCEDURE CODE p1;
|
SHOW PROCEDURE CODE p1;
|
||||||
DROP PROCEDURE p1;
|
DROP PROCEDURE p1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-10598 sql_mode=ORACLE: Variable declarations can go after cursor declarations
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Cursor declaration and cursor%ROWTYPE declaration in the same block
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INT, b VARCHAR(10));
|
||||||
|
INSERT INTO t1 VALUES (1,'a');
|
||||||
|
DELIMITER $$;
|
||||||
|
CREATE PROCEDURE p1()
|
||||||
|
AS
|
||||||
|
CURSOR cur1 IS SELECT a FROM t1;
|
||||||
|
rec1 cur1%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
rec1.a:= 10;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
SHOW PROCEDURE CODE p1;
|
||||||
|
CALL p1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Recursive cursor and cursor%ROWTYPE declarations in the same block
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
DELIMITER $$;
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
a INT:=10;
|
||||||
|
CURSOR cur1 IS SELECT a;
|
||||||
|
rec1 cur1%ROWTYPE;
|
||||||
|
CURSOR cur2 IS SELECT rec1.a + 1 "a";
|
||||||
|
rec2 cur2%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
OPEN cur1;
|
||||||
|
FETCH cur1 INTO rec1;
|
||||||
|
CLOSE cur1;
|
||||||
|
SELECT rec1.a;
|
||||||
|
open cur2;
|
||||||
|
FETCH cur2 INTO rec2;
|
||||||
|
CLOSE cur2;
|
||||||
|
SELECT rec2.a;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
SHOW PROCEDURE CODE p1;
|
||||||
|
CALL p1();
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
274
mysql-test/suite/compat/oracle/t/sp-cursor-decl.test
Normal file
274
mysql-test/suite/compat/oracle/t/sp-cursor-decl.test
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
SET sql_mode=ORACLE;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-10598 sql_mode=ORACLE: Variable declarations can go after cursor declarations
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Variable after cursor declaration
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
insert into t1 values (2);
|
||||||
|
DELIMITER $$;
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
CURSOR c IS SELECT a FROM t1;
|
||||||
|
var1 varchar(10);
|
||||||
|
BEGIN
|
||||||
|
OPEN c;
|
||||||
|
fetch c into var1;
|
||||||
|
SELECT c%ROWCOUNT,var1;
|
||||||
|
close c;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
CALL p1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Variable after condition declaration
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
DELIMITER $$;
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
var1 varchar(40);
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 values (1);
|
||||||
|
select var1;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
CALL p1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Condition after cursor declaration
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
DELIMITER $$;
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
var1 varchar(40);
|
||||||
|
var2 integer;
|
||||||
|
CURSOR c IS SELECT col1 FROM t1;
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 values (1);
|
||||||
|
SELECT var1;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
CALL p1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Cursor after handler declaration
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
DELIMITER $$;
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
var1 varchar(40);
|
||||||
|
var2 integer;
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
CURSOR c IS SELECT col1 FROM t1;
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 values (1);
|
||||||
|
SELECT var1;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Condition after handler declaration
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
DELIMITER $$;
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
var1 varchar(40);
|
||||||
|
var2 integer;
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
CURSOR c IS SELECT col1 FROM t1;
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
divide_by_zero CONDITION FOR SQLSTATE '22012';
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 values (1);
|
||||||
|
SELECT var1;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Variable after handler declaration
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
DELIMITER $$;
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
var1 varchar(40);
|
||||||
|
var2 integer;
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
CURSOR c IS SELECT col1 FROM t1;
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
divide_by_zero CONDITION FOR SQLSTATE '22012';
|
||||||
|
BEGIN
|
||||||
|
var1:='';
|
||||||
|
insert into t1 values (1);
|
||||||
|
SELECT var1;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Variable after cursor (inner block)
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (col1 INT);
|
||||||
|
insert into t1 values (1);
|
||||||
|
insert into t1 values (2);
|
||||||
|
create unique index t1_col1 on t1 (col1);
|
||||||
|
DELIMITER $$;
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
CURSOR c IS SELECT col1 FROM t1;
|
||||||
|
var1 varchar(40);
|
||||||
|
BEGIN
|
||||||
|
OPEN c;
|
||||||
|
begin
|
||||||
|
declare
|
||||||
|
CURSOR c IS SELECT col1 FROM t1 where col1=2;
|
||||||
|
var2 integer;
|
||||||
|
dup_key CONDITION FOR SQLSTATE '23000';
|
||||||
|
CONTINUE HANDLER FOR dup_key
|
||||||
|
BEGIN
|
||||||
|
var1:='duplicate key in index';
|
||||||
|
END;
|
||||||
|
begin
|
||||||
|
OPEN c;
|
||||||
|
fetch c into var1;
|
||||||
|
SELECT 'inner cursor',var1;
|
||||||
|
insert into t1 values (2);
|
||||||
|
close c;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
SELECT var1;
|
||||||
|
fetch c into var1;
|
||||||
|
SELECT c%ROWCOUNT,var1;
|
||||||
|
begin
|
||||||
|
insert into t1 values (2);
|
||||||
|
exception when 1062 then
|
||||||
|
begin
|
||||||
|
SELECT 'dup key caugth';
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
close c;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
CALL p1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Cursor declaration and row type declaration in same block
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INT, b VARCHAR(10));
|
||||||
|
insert into t1 values(1,'a');
|
||||||
|
delimiter $$;
|
||||||
|
CREATE PROCEDURE p1()
|
||||||
|
AS
|
||||||
|
CURSOR cur1 IS SELECT a FROM t1;
|
||||||
|
rec1 cur1%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
rec1.a:= 10;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
delimiter ;$$
|
||||||
|
call p1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Recursive cursor and cursor%ROWTYPE declarations in the same block
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
delimiter $$;
|
||||||
|
CREATE PROCEDURE p1
|
||||||
|
AS
|
||||||
|
a INT:=10;
|
||||||
|
b VARCHAR(10):='b0';
|
||||||
|
c DOUBLE:=0.1;
|
||||||
|
CURSOR cur1 IS SELECT a, b, c;
|
||||||
|
rec1 cur1%ROWTYPE;
|
||||||
|
CURSOR cur2 IS SELECT rec1.a + 1 "a", rec1.b||'0' AS b, rec1.c AS c;
|
||||||
|
rec2 cur2%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
OPEN cur1;
|
||||||
|
FETCH cur1 INTO rec1;
|
||||||
|
CLOSE cur1;
|
||||||
|
SELECT rec1.a;
|
||||||
|
OPEN cur2;
|
||||||
|
FETCH cur2 INTO rec2;
|
||||||
|
CLOSE cur2;
|
||||||
|
SELECT rec2.a;
|
||||||
|
CREATE TABLE t2 AS SELECT rec2.a AS a, rec2.b AS b, rec2.c AS c;
|
||||||
|
SHOW CREATE TABLE t2;
|
||||||
|
DROP TABLE t2;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
CALL p1();
|
||||||
|
DROP PROCEDURE p1;
|
@@ -2423,6 +2423,23 @@ sp_head::do_cont_backpatch()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
sp_head::sp_add_instr_cpush_for_cursors(THD *thd, sp_pcontext *pcontext)
|
||||||
|
{
|
||||||
|
for (uint i= 0; i < pcontext->frame_cursor_count(); i++)
|
||||||
|
{
|
||||||
|
const sp_pcursor *c= pcontext->get_cursor_by_local_frame_offset(i);
|
||||||
|
sp_instr_cpush *instr= new (thd->mem_root)
|
||||||
|
sp_instr_cpush(instructions(), pcontext, c->lex(),
|
||||||
|
pcontext->cursor_offset() + i);
|
||||||
|
if (instr == NULL || add_instr(instr))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
sp_head::set_info(longlong created, longlong modified,
|
sp_head::set_info(longlong created, longlong modified,
|
||||||
st_sp_chistics *chistics, sql_mode_t sql_mode)
|
st_sp_chistics *chistics, sql_mode_t sql_mode)
|
||||||
|
@@ -573,6 +573,9 @@ public:
|
|||||||
void
|
void
|
||||||
do_cont_backpatch();
|
do_cont_backpatch();
|
||||||
|
|
||||||
|
/// Add cpush instructions for all cursors declared in the current frame
|
||||||
|
bool sp_add_instr_cpush_for_cursors(THD *thd, sp_pcontext *pcontext);
|
||||||
|
|
||||||
char *name(uint *lenp = 0) const
|
char *name(uint *lenp = 0) const
|
||||||
{
|
{
|
||||||
if (lenp)
|
if (lenp)
|
||||||
|
@@ -659,6 +659,15 @@ public:
|
|||||||
/// Find cursor by offset (for SHOW {PROCEDURE|FUNCTION} CODE only).
|
/// Find cursor by offset (for SHOW {PROCEDURE|FUNCTION} CODE only).
|
||||||
const sp_pcursor *find_cursor(uint offset) const;
|
const sp_pcursor *find_cursor(uint offset) const;
|
||||||
|
|
||||||
|
const sp_pcursor *get_cursor_by_local_frame_offset(uint offset) const
|
||||||
|
{ return &m_cursors.at(offset); }
|
||||||
|
|
||||||
|
uint cursor_offset() const
|
||||||
|
{ return m_cursor_offset; }
|
||||||
|
|
||||||
|
uint frame_cursor_count() const
|
||||||
|
{ return m_cursors.elements(); }
|
||||||
|
|
||||||
uint max_cursor_index() const
|
uint max_cursor_index() const
|
||||||
{ return m_max_cursor_index + m_cursors.elements(); }
|
{ return m_max_cursor_index + m_cursors.elements(); }
|
||||||
|
|
||||||
|
@@ -5628,7 +5628,7 @@ bool LEX::sp_for_loop_cursor_finalize(THD *thd, const Lex_for_loop_st &loop)
|
|||||||
|
|
||||||
bool LEX::sp_declare_cursor(THD *thd, const LEX_STRING name,
|
bool LEX::sp_declare_cursor(THD *thd, const LEX_STRING name,
|
||||||
sp_lex_cursor *cursor_stmt,
|
sp_lex_cursor *cursor_stmt,
|
||||||
sp_pcontext *param_ctx)
|
sp_pcontext *param_ctx, bool add_cpush_instr)
|
||||||
{
|
{
|
||||||
uint offp;
|
uint offp;
|
||||||
sp_instr_cpush *i;
|
sp_instr_cpush *i;
|
||||||
@@ -5639,12 +5639,18 @@ bool LEX::sp_declare_cursor(THD *thd, const LEX_STRING name,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
cursor_stmt->set_cursor_name(name);
|
cursor_stmt->set_cursor_name(name);
|
||||||
i= new (thd->mem_root)
|
|
||||||
sp_instr_cpush(sphead->instructions(), spcont, cursor_stmt,
|
if (spcont->add_cursor(name, param_ctx, cursor_stmt))
|
||||||
spcont->current_cursor_count());
|
return true;
|
||||||
return i == NULL ||
|
|
||||||
sphead->add_instr(i) ||
|
if (add_cpush_instr)
|
||||||
spcont->add_cursor(name, param_ctx, cursor_stmt);
|
{
|
||||||
|
i= new (thd->mem_root)
|
||||||
|
sp_instr_cpush(sphead->instructions(), spcont, cursor_stmt,
|
||||||
|
spcont->current_cursor_count() - 1);
|
||||||
|
return i == NULL || sphead->add_instr(i);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -3165,7 +3165,8 @@ public:
|
|||||||
|
|
||||||
bool sp_declare_cursor(THD *thd, const LEX_STRING name,
|
bool sp_declare_cursor(THD *thd, const LEX_STRING name,
|
||||||
class sp_lex_cursor *cursor_stmt,
|
class sp_lex_cursor *cursor_stmt,
|
||||||
sp_pcontext *param_ctx);
|
sp_pcontext *param_ctx, bool add_cpush_instr);
|
||||||
|
|
||||||
bool sp_open_cursor(THD *thd, const LEX_STRING name,
|
bool sp_open_cursor(THD *thd, const LEX_STRING name,
|
||||||
List<sp_assignment_lex> *parameters);
|
List<sp_assignment_lex> *parameters);
|
||||||
Item_splocal *create_item_for_sp_var(LEX_STRING name, sp_variable *spvar,
|
Item_splocal *create_item_for_sp_var(LEX_STRING name, sp_variable *spvar,
|
||||||
|
@@ -3022,7 +3022,7 @@ sp_decl_body:
|
|||||||
}
|
}
|
||||||
| ident CURSOR_SYM FOR_SYM sp_cursor_stmt
|
| ident CURSOR_SYM FOR_SYM sp_cursor_stmt
|
||||||
{
|
{
|
||||||
if (Lex->sp_declare_cursor(thd, $1, $4, NULL))
|
if (Lex->sp_declare_cursor(thd, $1, $4, NULL, true))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
$$.vars= $$.conds= $$.hndlrs= 0;
|
$$.vars= $$.conds= $$.hndlrs= 0;
|
||||||
$$.curs= 1;
|
$$.curs= 1;
|
||||||
|
@@ -1335,7 +1335,9 @@ END_OF_INPUT
|
|||||||
|
|
||||||
%type <num> sp_decl_idents sp_handler_type sp_hcond_list
|
%type <num> sp_decl_idents sp_handler_type sp_hcond_list
|
||||||
%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value
|
%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value
|
||||||
%type <spblock> sp_decl_body sp_decl_body_list opt_sp_decl_body_list
|
%type <spblock> sp_decl_body_list opt_sp_decl_body_list
|
||||||
|
%type <spblock> sp_decl_non_handler sp_decl_non_handler_list
|
||||||
|
%type <spblock> sp_decl_handler sp_decl_handler_list opt_sp_decl_handler_list
|
||||||
%type <spblock_handlers> sp_block_statements_and_exceptions
|
%type <spblock_handlers> sp_block_statements_and_exceptions
|
||||||
%type <sp_instr_addr> sp_instr_addr
|
%type <sp_instr_addr> sp_instr_addr
|
||||||
%type <sp_cursor_name_and_offset> sp_cursor_name_and_offset
|
%type <sp_cursor_name_and_offset> sp_cursor_name_and_offset
|
||||||
@@ -2444,12 +2446,37 @@ opt_sp_decl_body_list:
|
|||||||
;
|
;
|
||||||
|
|
||||||
sp_decl_body_list:
|
sp_decl_body_list:
|
||||||
sp_decl_body ';' { $$= $1; }
|
sp_decl_non_handler_list
|
||||||
| sp_decl_body_list sp_decl_body ';'
|
|
||||||
{
|
{
|
||||||
if (Lex->sp_declarations_join(&$$, $1, $2))
|
if (Lex->sphead->sp_add_instr_cpush_for_cursors(thd, Lex->spcont))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
|
opt_sp_decl_handler_list
|
||||||
|
{
|
||||||
|
$$.join($1, $3);
|
||||||
|
}
|
||||||
|
| sp_decl_handler_list
|
||||||
|
;
|
||||||
|
|
||||||
|
sp_decl_non_handler_list:
|
||||||
|
sp_decl_non_handler ';' { $$= $1; }
|
||||||
|
| sp_decl_non_handler_list sp_decl_non_handler ';'
|
||||||
|
{
|
||||||
|
$$.join($1, $2);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
sp_decl_handler_list:
|
||||||
|
sp_decl_handler ';' { $$= $1; }
|
||||||
|
| sp_decl_handler_list sp_decl_handler ';'
|
||||||
|
{
|
||||||
|
$$.join($1, $2);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
opt_sp_decl_handler_list:
|
||||||
|
/* Empty*/ { $$.init(); }
|
||||||
|
| sp_decl_handler_list
|
||||||
;
|
;
|
||||||
|
|
||||||
qualified_column_ident:
|
qualified_column_ident:
|
||||||
@@ -2527,7 +2554,7 @@ type_or_rowtype:
|
|||||||
| ROWTYPE_SYM { $$= 1; }
|
| ROWTYPE_SYM { $$= 1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
sp_decl_body:
|
sp_decl_non_handler:
|
||||||
sp_decl_idents
|
sp_decl_idents
|
||||||
{
|
{
|
||||||
Lex->sp_variable_declarations_init(thd, $1);
|
Lex->sp_variable_declarations_init(thd, $1);
|
||||||
@@ -2581,18 +2608,6 @@ sp_decl_body:
|
|||||||
$$.vars= $$.hndlrs= $$.curs= 0;
|
$$.vars= $$.hndlrs= $$.curs= 0;
|
||||||
$$.conds= 1;
|
$$.conds= 1;
|
||||||
}
|
}
|
||||||
| sp_handler_type HANDLER_SYM FOR_SYM
|
|
||||||
{
|
|
||||||
if (Lex->sp_handler_declaration_init(thd, $1))
|
|
||||||
MYSQL_YYABORT;
|
|
||||||
}
|
|
||||||
sp_hcond_list sp_proc_stmt
|
|
||||||
{
|
|
||||||
if (Lex->sp_handler_declaration_finalize(thd, $1))
|
|
||||||
MYSQL_YYABORT;
|
|
||||||
$$.vars= $$.conds= $$.curs= 0;
|
|
||||||
$$.hndlrs= 1;
|
|
||||||
}
|
|
||||||
| CURSOR_SYM ident_directly_assignable
|
| CURSOR_SYM ident_directly_assignable
|
||||||
{
|
{
|
||||||
Lex->sp_block_init(thd);
|
Lex->sp_block_init(thd);
|
||||||
@@ -2603,13 +2618,28 @@ sp_decl_body:
|
|||||||
sp_pcontext *param_ctx= Lex->spcont;
|
sp_pcontext *param_ctx= Lex->spcont;
|
||||||
if (Lex->sp_block_finalize(thd))
|
if (Lex->sp_block_finalize(thd))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
if (Lex->sp_declare_cursor(thd, $2, $6, param_ctx))
|
if (Lex->sp_declare_cursor(thd, $2, $6, param_ctx, false))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
$$.vars= $$.conds= $$.hndlrs= 0;
|
$$.vars= $$.conds= $$.hndlrs= 0;
|
||||||
$$.curs= 1;
|
$$.curs= 1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
sp_decl_handler:
|
||||||
|
sp_handler_type HANDLER_SYM FOR_SYM
|
||||||
|
{
|
||||||
|
if (Lex->sp_handler_declaration_init(thd, $1))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
sp_hcond_list sp_proc_stmt
|
||||||
|
{
|
||||||
|
if (Lex->sp_handler_declaration_finalize(thd, $1))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
$$.vars= $$.conds= $$.curs= 0;
|
||||||
|
$$.hndlrs= 1;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
opt_parenthesized_cursor_formal_parameters:
|
opt_parenthesized_cursor_formal_parameters:
|
||||||
/* Empty */
|
/* Empty */
|
||||||
| '(' sp_fdparams ')'
|
| '(' sp_fdparams ')'
|
||||||
@@ -3849,7 +3879,7 @@ sp_for_loop_bounds:
|
|||||||
{
|
{
|
||||||
DBUG_ASSERT(Lex->sphead);
|
DBUG_ASSERT(Lex->sphead);
|
||||||
LEX_STRING name= {C_STRING_WITH_LEN("[implicit_cursor]") };
|
LEX_STRING name= {C_STRING_WITH_LEN("[implicit_cursor]") };
|
||||||
if (Lex->sp_declare_cursor(thd, name, $4, NULL))
|
if (Lex->sp_declare_cursor(thd, name, $4, NULL, true))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
$$.m_direction= 1;
|
$$.m_direction= 1;
|
||||||
if (!($$.m_index= new (thd->mem_root) sp_assignment_lex(thd, thd->lex)))
|
if (!($$.m_index= new (thd->mem_root) sp_assignment_lex(thd, thd->lex)))
|
||||||
|
Reference in New Issue
Block a user