summaryrefslogtreecommitdiff
path: root/mysql-test/suite/compat/oracle
diff options
context:
space:
mode:
Diffstat (limited to 'mysql-test/suite/compat/oracle')
-rw-r--r--mysql-test/suite/compat/oracle/r/binlog_stm_ps.result67
-rw-r--r--mysql-test/suite/compat/oracle/r/binlog_stm_sp.result477
-rw-r--r--mysql-test/suite/compat/oracle/r/exception.result409
-rw-r--r--mysql-test/suite/compat/oracle/r/func_case.result7
-rw-r--r--mysql-test/suite/compat/oracle/r/func_concat.result257
-rw-r--r--mysql-test/suite/compat/oracle/r/func_decode.result33
-rw-r--r--mysql-test/suite/compat/oracle/r/func_length.result21
-rw-r--r--mysql-test/suite/compat/oracle/r/func_misc.result319
-rw-r--r--mysql-test/suite/compat/oracle/r/misc.result12
-rw-r--r--mysql-test/suite/compat/oracle/r/ps.result249
-rw-r--r--mysql-test/suite/compat/oracle/r/sequence.result77
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-anonymous.result220
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-code.result1483
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-cursor-decl.result290
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-cursor-rowtype.result1332
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-cursor.result951
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-goto.result834
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-param.result132
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-row.result3072
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-security.result288
-rw-r--r--mysql-test/suite/compat/oracle/r/sp.result2284
-rw-r--r--mysql-test/suite/compat/oracle/r/trigger.result100
-rw-r--r--mysql-test/suite/compat/oracle/r/truncate.result10
-rw-r--r--mysql-test/suite/compat/oracle/r/type_blob.result8
-rw-r--r--mysql-test/suite/compat/oracle/r/type_clob.result15
-rw-r--r--mysql-test/suite/compat/oracle/r/type_date.result8
-rw-r--r--mysql-test/suite/compat/oracle/r/type_number.result15
-rw-r--r--mysql-test/suite/compat/oracle/r/type_raw.result15
-rw-r--r--mysql-test/suite/compat/oracle/r/type_varchar.result9
-rw-r--r--mysql-test/suite/compat/oracle/r/type_varchar2.result23
-rw-r--r--mysql-test/suite/compat/oracle/r/variables.result39
-rw-r--r--mysql-test/suite/compat/oracle/t/binlog_stm_ps.test37
-rw-r--r--mysql-test/suite/compat/oracle/t/binlog_stm_sp.test196
-rw-r--r--mysql-test/suite/compat/oracle/t/exception.test457
-rw-r--r--mysql-test/suite/compat/oracle/t/func_case.test9
-rw-r--r--mysql-test/suite/compat/oracle/t/func_concat.test116
-rw-r--r--mysql-test/suite/compat/oracle/t/func_decode.test21
-rw-r--r--mysql-test/suite/compat/oracle/t/func_length.test18
-rw-r--r--mysql-test/suite/compat/oracle/t/func_misc.test346
-rw-r--r--mysql-test/suite/compat/oracle/t/misc.test10
-rw-r--r--mysql-test/suite/compat/oracle/t/ps.test266
-rw-r--r--mysql-test/suite/compat/oracle/t/sequence.test43
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-anonymous.test244
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-code.test1057
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-cursor-decl.test295
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-cursor-rowtype.test1424
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-cursor.test954
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-goto.test872
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-param.inc9
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-param.test37
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-row-vs-var.inc6
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-row.test2377
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-security.test345
-rw-r--r--mysql-test/suite/compat/oracle/t/sp.test2133
-rw-r--r--mysql-test/suite/compat/oracle/t/trigger.test106
-rw-r--r--mysql-test/suite/compat/oracle/t/truncate.test16
-rw-r--r--mysql-test/suite/compat/oracle/t/type_blob.test4
-rw-r--r--mysql-test/suite/compat/oracle/t/type_clob.test10
-rw-r--r--mysql-test/suite/compat/oracle/t/type_date.test4
-rw-r--r--mysql-test/suite/compat/oracle/t/type_number.test9
-rw-r--r--mysql-test/suite/compat/oracle/t/type_raw.test10
-rw-r--r--mysql-test/suite/compat/oracle/t/type_varchar.test9
-rw-r--r--mysql-test/suite/compat/oracle/t/type_varchar2.test19
-rw-r--r--mysql-test/suite/compat/oracle/t/variables.test38
64 files changed, 24553 insertions, 0 deletions
diff --git a/mysql-test/suite/compat/oracle/r/binlog_stm_ps.result b/mysql-test/suite/compat/oracle/r/binlog_stm_ps.result
new file mode 100644
index 00000000000..c60e3493b3f
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/binlog_stm_ps.result
@@ -0,0 +1,67 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-10801 sql_mode: dynamic SQL placeholders
+#
+CREATE TABLE t1 (a INT, b INT);
+SET @a=10, @b=20;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (?,?)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:a,:b)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:aaa,:bbb)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:"a",:"b")';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:"aaa",:"bbb")';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:1,:2)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:222,:111)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:0,:65535)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:65535,:0)';
+EXECUTE stmt USING @a, @b;
+SELECT * FROM t1;
+a b
+10 20
+10 20
+10 20
+10 20
+10 20
+10 20
+10 20
+10 20
+10 20
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b INT)
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20)
+master-bin.000001 # Query # # COMMIT
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/binlog_stm_sp.result b/mysql-test/suite/compat/oracle/r/binlog_stm_sp.result
new file mode 100644
index 00000000000..9823b155c8f
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/binlog_stm_sp.result
@@ -0,0 +1,477 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-10914 ROW data type for stored routine variables
+#
+CREATE TABLE t1 (a INT, b INT);
+CREATE PROCEDURE p1
+AS
+rec ROW(a INT,b INT);
+BEGIN
+rec.a:=100;
+rec.b:=200;
+INSERT INTO t1 VALUES (rec.a,rec.b);
+INSERT INTO t1 VALUES (10, rec=ROW(100,200));
+INSERT INTO t1 VALUES (10, ROW(100,200)=rec);
+INSERT INTO t1 SELECT 10, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 10, 21 FROM DUAL WHERE ROW(100,200)=rec;
+rec.a:=NULL;
+INSERT INTO t1 VALUES (11, rec=ROW(100,200));
+INSERT INTO t1 VALUES (11, rec=ROW(100,201));
+INSERT INTO t1 VALUES (11, ROW(100,200)=rec);
+INSERT INTO t1 VALUES (11, ROW(100,201)=rec);
+INSERT INTO t1 SELECT 11, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 11, 21 FROM DUAL WHERE ROW(100,200)=rec;
+rec.b:=NULL;
+INSERT INTO t1 VALUES (12, rec=ROW(100,200));
+INSERT INTO t1 VALUES (12, ROW(100,200)=rec);
+INSERT INTO t1 SELECT 12, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 12, 21 FROM DUAL WHERE ROW(100,200)=rec;
+END;
+$$
+CALL p1();
+SELECT * FROM t1;
+a b
+100 200
+10 1
+10 1
+10 20
+10 21
+11 NULL
+11 0
+11 NULL
+11 0
+12 NULL
+12 NULL
+DROP TABLE t1;
+DROP PROCEDURE p1;
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b INT)
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
+AS
+rec ROW(a INT,b INT);
+BEGIN
+rec.a:=100;
+rec.b:=200;
+INSERT INTO t1 VALUES (rec.a,rec.b);
+INSERT INTO t1 VALUES (10, rec=ROW(100,200));
+INSERT INTO t1 VALUES (10, ROW(100,200)=rec);
+INSERT INTO t1 SELECT 10, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 10, 21 FROM DUAL WHERE ROW(100,200)=rec;
+rec.a:=NULL;
+INSERT INTO t1 VALUES (11, rec=ROW(100,200));
+INSERT INTO t1 VALUES (11, rec=ROW(100,201));
+INSERT INTO t1 VALUES (11, ROW(100,200)=rec);
+INSERT INTO t1 VALUES (11, ROW(100,201)=rec);
+INSERT INTO t1 SELECT 11, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 11, 21 FROM DUAL WHERE ROW(100,200)=rec;
+rec.b:=NULL;
+INSERT INTO t1 VALUES (12, rec=ROW(100,200));
+INSERT INTO t1 VALUES (12, ROW(100,200)=rec);
+INSERT INTO t1 SELECT 12, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 12, 21 FROM DUAL WHERE ROW(100,200)=rec;
+END
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('rec.a',100), NAME_CONST('rec.b',200))
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10, ROW(100,200)=ROW(100,200))
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10, ROW(100,200)=ROW(100,200))
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 SELECT 10, 20 FROM DUAL WHERE ROW(100,200)=ROW(100,200)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 SELECT 10, 21 FROM DUAL WHERE ROW(100,200)=ROW(100,200)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (11, ROW(NULL,200)=ROW(100,200))
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (11, ROW(NULL,200)=ROW(100,201))
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (11, ROW(100,200)=ROW(NULL,200))
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (11, ROW(100,201)=ROW(NULL,200))
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 SELECT 11, 20 FROM DUAL WHERE ROW(NULL,200)=ROW(100,200)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 SELECT 11, 21 FROM DUAL WHERE ROW(100,200)=ROW(NULL,200)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (12, ROW(NULL,NULL)=ROW(100,200))
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (12, ROW(100,200)=ROW(NULL,NULL))
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 SELECT 12, 20 FROM DUAL WHERE ROW(NULL,NULL)=ROW(100,200)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 SELECT 12, 21 FROM DUAL WHERE ROW(100,200)=ROW(NULL,NULL)
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; DROP TABLE "t1" /* generated by server */
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; DROP PROCEDURE p1
+#
+# Testing ROW fields in LIMIT
+#
+FLUSH LOGS;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(10);
+CREATE TABLE t2 (a INT);
+CREATE PROCEDURE p1()
+AS
+a INT:= 1;
+rec ROW(a INT);
+BEGIN
+rec.a:= 1;
+INSERT INTO t2 SELECT 1 FROM t1 LIMIT a;
+INSERT INTO t2 SELECT 2 FROM t1 LIMIT rec.a;
+END;
+$$
+CALL p1();
+Warnings:
+Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted
+DROP TABLE t1,t2;
+DROP PROCEDURE p1;
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000002 # Binlog_checkpoint # # master-bin.000002
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; CREATE TABLE t1 (a INT)
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (10),(10)
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; CREATE TABLE t2 (a INT)
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
+AS
+a INT:= 1;
+rec ROW(a INT);
+BEGIN
+rec.a:= 1;
+INSERT INTO t2 SELECT 1 FROM t1 LIMIT a;
+INSERT INTO t2 SELECT 2 FROM t1 LIMIT rec.a;
+END
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t2 SELECT 1 FROM t1 LIMIT 1
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t2 SELECT 2 FROM t1 LIMIT 1
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; DROP TABLE "t1","t2" /* generated by server */
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; DROP PROCEDURE p1
+#
+# End of MDEV-10914 ROW data type for stored routine variables
+#
+#
+# MDEV-12133 sql_mode=ORACLE: table%ROWTYPE in variable declarations
+#
+CREATE TABLE t1 (a INT, b INT);
+CREATE PROCEDURE p1
+AS
+rec t1%ROWTYPE;
+BEGIN
+rec.a:=100;
+rec.b:=200;
+SELECT rec=ROW(100,200) AS true1, ROW(100,200)=rec AS true2;
+INSERT INTO t1 VALUES (rec.a,rec.b);
+INSERT INTO t1 VALUES (10, rec=ROW(100,200));
+INSERT INTO t1 VALUES (10, ROW(100,200)=rec);
+INSERT INTO t1 SELECT 10, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 10, 21 FROM DUAL WHERE ROW(100,200)=rec;
+rec.a:=NULL;
+INSERT INTO t1 VALUES (11, rec=ROW(100,200));
+INSERT INTO t1 VALUES (11, rec=ROW(100,201));
+INSERT INTO t1 VALUES (11, ROW(100,200)=rec);
+INSERT INTO t1 VALUES (11, ROW(100,201)=rec);
+INSERT INTO t1 SELECT 11, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 11, 21 FROM DUAL WHERE ROW(100,200)=rec;
+rec.b:=NULL;
+INSERT INTO t1 VALUES (12, rec=ROW(100,200));
+INSERT INTO t1 VALUES (12, ROW(100,200)=rec);
+INSERT INTO t1 SELECT 12, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 12, 21 FROM DUAL WHERE ROW(100,200)=rec;
+END;
+$$
+CALL p1();
+true1 true2
+1 1
+SELECT * FROM t1;
+a b
+100 200
+10 1
+10 1
+10 20
+10 21
+11 NULL
+11 0
+11 NULL
+11 0
+12 NULL
+12 NULL
+DROP TABLE t1;
+DROP PROCEDURE p1;
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000002 # Binlog_checkpoint # # master-bin.000002
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; CREATE TABLE t1 (a INT)
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (10),(10)
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; CREATE TABLE t2 (a INT)
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
+AS
+a INT:= 1;
+rec ROW(a INT);
+BEGIN
+rec.a:= 1;
+INSERT INTO t2 SELECT 1 FROM t1 LIMIT a;
+INSERT INTO t2 SELECT 2 FROM t1 LIMIT rec.a;
+END
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t2 SELECT 1 FROM t1 LIMIT 1
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t2 SELECT 2 FROM t1 LIMIT 1
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; DROP TABLE "t1","t2" /* generated by server */
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; DROP PROCEDURE p1
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; CREATE TABLE t1 (a INT, b INT)
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
+AS
+rec t1%ROWTYPE;
+BEGIN
+rec.a:=100;
+rec.b:=200;
+SELECT rec=ROW(100,200) AS true1, ROW(100,200)=rec AS true2;
+INSERT INTO t1 VALUES (rec.a,rec.b);
+INSERT INTO t1 VALUES (10, rec=ROW(100,200));
+INSERT INTO t1 VALUES (10, ROW(100,200)=rec);
+INSERT INTO t1 SELECT 10, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 10, 21 FROM DUAL WHERE ROW(100,200)=rec;
+rec.a:=NULL;
+INSERT INTO t1 VALUES (11, rec=ROW(100,200));
+INSERT INTO t1 VALUES (11, rec=ROW(100,201));
+INSERT INTO t1 VALUES (11, ROW(100,200)=rec);
+INSERT INTO t1 VALUES (11, ROW(100,201)=rec);
+INSERT INTO t1 SELECT 11, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 11, 21 FROM DUAL WHERE ROW(100,200)=rec;
+rec.b:=NULL;
+INSERT INTO t1 VALUES (12, rec=ROW(100,200));
+INSERT INTO t1 VALUES (12, ROW(100,200)=rec);
+INSERT INTO t1 SELECT 12, 20 FROM DUAL WHERE rec=ROW(100,200);
+INSERT INTO t1 SELECT 12, 21 FROM DUAL WHERE ROW(100,200)=rec;
+END
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('rec.a',100), NAME_CONST('rec.b',200))
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (10, ROW(100,200)=ROW(100,200))
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (10, ROW(100,200)=ROW(100,200))
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 SELECT 10, 20 FROM DUAL WHERE ROW(100,200)=ROW(100,200)
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 SELECT 10, 21 FROM DUAL WHERE ROW(100,200)=ROW(100,200)
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (11, ROW(NULL,200)=ROW(100,200))
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (11, ROW(NULL,200)=ROW(100,201))
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (11, ROW(100,200)=ROW(NULL,200))
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (11, ROW(100,201)=ROW(NULL,200))
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 SELECT 11, 20 FROM DUAL WHERE ROW(NULL,200)=ROW(100,200)
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 SELECT 11, 21 FROM DUAL WHERE ROW(100,200)=ROW(NULL,200)
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (12, ROW(NULL,NULL)=ROW(100,200))
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 VALUES (12, ROW(100,200)=ROW(NULL,NULL))
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 SELECT 12, 20 FROM DUAL WHERE ROW(NULL,NULL)=ROW(100,200)
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # BEGIN GTID #-#-#
+master-bin.000002 # Query # # use `test`; INSERT INTO t1 SELECT 12, 21 FROM DUAL WHERE ROW(100,200)=ROW(NULL,NULL)
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; DROP TABLE "t1" /* generated by server */
+master-bin.000002 # Gtid # # GTID #-#-#
+master-bin.000002 # Query # # use `test`; DROP PROCEDURE p1
+#
+# MDEV-12291 Allow ROW variables as SELECT INTO targets
+#
+FLUSH LOGS;
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10, 'b10');
+CREATE TABLE t2 LIKE t1;
+CREATE PROCEDURE p1
+AS
+rec1 ROW(a INT, b VARCHAR(32));
+BEGIN
+SELECT * INTO rec1 FROM t1;
+INSERT INTO t2 VALUES (rec1.a, rec1.b);
+END;
+$$
+CALL p1();
+SELECT * FROM t1;
+a b
+10 b10
+DROP TABLE t1;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000003 # Binlog_checkpoint # # master-bin.000003
+master-bin.000003 # Gtid # # GTID #-#-#
+master-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT, b VARCHAR(32))
+master-bin.000003 # Gtid # # BEGIN GTID #-#-#
+master-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (10, 'b10')
+master-bin.000003 # Query # # COMMIT
+master-bin.000003 # Gtid # # GTID #-#-#
+master-bin.000003 # Query # # use `test`; CREATE TABLE t2 LIKE t1
+master-bin.000003 # Gtid # # GTID #-#-#
+master-bin.000003 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
+AS
+rec1 ROW(a INT, b VARCHAR(32));
+BEGIN
+SELECT * INTO rec1 FROM t1;
+INSERT INTO t2 VALUES (rec1.a, rec1.b);
+END
+master-bin.000003 # Gtid # # BEGIN GTID #-#-#
+master-bin.000003 # Query # # use `test`; INSERT INTO t2 VALUES ( NAME_CONST('rec1.a',10), NAME_CONST('rec1.b',_latin1'b10' COLLATE 'latin1_swedish_ci'))
+master-bin.000003 # Query # # COMMIT
+master-bin.000003 # Gtid # # GTID #-#-#
+master-bin.000003 # Query # # use `test`; DROP TABLE "t1" /* generated by server */
+master-bin.000003 # Gtid # # GTID #-#-#
+master-bin.000003 # Query # # use `test`; DROP TABLE "t2" /* generated by server */
+master-bin.000003 # Gtid # # GTID #-#-#
+master-bin.000003 # Query # # use `test`; DROP PROCEDURE p1
+FLUSH LOGS;
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10, 'b10');
+CREATE TABLE t2 LIKE t1;
+CREATE PROCEDURE p1
+AS
+rec1 t1%ROWTYPE;
+BEGIN
+SELECT * INTO rec1 FROM t1;
+INSERT INTO t2 VALUES (rec1.a, rec1.b);
+END;
+$$
+CALL p1();
+SELECT * FROM t1;
+a b
+10 b10
+DROP TABLE t1;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000004 # Binlog_checkpoint # # master-bin.000004
+master-bin.000004 # Gtid # # GTID #-#-#
+master-bin.000004 # Query # # use `test`; CREATE TABLE t1 (a INT, b VARCHAR(32))
+master-bin.000004 # Gtid # # BEGIN GTID #-#-#
+master-bin.000004 # Query # # use `test`; INSERT INTO t1 VALUES (10, 'b10')
+master-bin.000004 # Query # # COMMIT
+master-bin.000004 # Gtid # # GTID #-#-#
+master-bin.000004 # Query # # use `test`; CREATE TABLE t2 LIKE t1
+master-bin.000004 # Gtid # # GTID #-#-#
+master-bin.000004 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
+AS
+rec1 t1%ROWTYPE;
+BEGIN
+SELECT * INTO rec1 FROM t1;
+INSERT INTO t2 VALUES (rec1.a, rec1.b);
+END
+master-bin.000004 # Gtid # # BEGIN GTID #-#-#
+master-bin.000004 # Query # # use `test`; INSERT INTO t2 VALUES ( NAME_CONST('rec1.a',10), NAME_CONST('rec1.b',_latin1'b10' COLLATE 'latin1_swedish_ci'))
+master-bin.000004 # Query # # COMMIT
+master-bin.000004 # Gtid # # GTID #-#-#
+master-bin.000004 # Query # # use `test`; DROP TABLE "t1" /* generated by server */
+master-bin.000004 # Gtid # # GTID #-#-#
+master-bin.000004 # Query # # use `test`; DROP TABLE "t2" /* generated by server */
+master-bin.000004 # Gtid # # GTID #-#-#
+master-bin.000004 # Query # # use `test`; DROP PROCEDURE p1
+FLUSH LOGS;
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10, 'b10');
+CREATE TABLE t2 LIKE t1;
+CREATE PROCEDURE p1
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+rec1 cur1%ROWTYPE;
+BEGIN
+SELECT * INTO rec1 FROM t1;
+INSERT INTO t2 VALUES (rec1.a, rec1.b);
+END;
+$$
+CALL p1();
+SELECT * FROM t1;
+a b
+10 b10
+DROP TABLE t1;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000005 # Binlog_checkpoint # # master-bin.000005
+master-bin.000005 # Gtid # # GTID #-#-#
+master-bin.000005 # Query # # use `test`; CREATE TABLE t1 (a INT, b VARCHAR(32))
+master-bin.000005 # Gtid # # BEGIN GTID #-#-#
+master-bin.000005 # Query # # use `test`; INSERT INTO t1 VALUES (10, 'b10')
+master-bin.000005 # Query # # COMMIT
+master-bin.000005 # Gtid # # GTID #-#-#
+master-bin.000005 # Query # # use `test`; CREATE TABLE t2 LIKE t1
+master-bin.000005 # Gtid # # GTID #-#-#
+master-bin.000005 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+rec1 cur1%ROWTYPE;
+BEGIN
+SELECT * INTO rec1 FROM t1;
+INSERT INTO t2 VALUES (rec1.a, rec1.b);
+END
+master-bin.000005 # Gtid # # BEGIN GTID #-#-#
+master-bin.000005 # Query # # use `test`; INSERT INTO t2 VALUES ( NAME_CONST('rec1.a',10), NAME_CONST('rec1.b',_latin1'b10' COLLATE 'latin1_swedish_ci'))
+master-bin.000005 # Query # # COMMIT
+master-bin.000005 # Gtid # # GTID #-#-#
+master-bin.000005 # Query # # use `test`; DROP TABLE "t1" /* generated by server */
+master-bin.000005 # Gtid # # GTID #-#-#
+master-bin.000005 # Query # # use `test`; DROP TABLE "t2" /* generated by server */
+master-bin.000005 # Gtid # # GTID #-#-#
+master-bin.000005 # Query # # use `test`; DROP PROCEDURE p1
diff --git a/mysql-test/suite/compat/oracle/r/exception.result b/mysql-test/suite/compat/oracle/r/exception.result
new file mode 100644
index 00000000000..b61d25f36ee
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/exception.result
@@ -0,0 +1,409 @@
+SET sql_mode=ORACLE;
+#
+# sql_mode=ORACLE: Predefined exceptions: TOO_MANY_ROWS, NO_DATA_FOUND, DUP_VAL_ON_INDEX
+#
+#
+# Testing NO_DATA_FOUND and TOO_MANY_ROWS
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+CREATE PROCEDURE p1(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+SELECT a INTO a FROM t1 LIMIT lim;
+EXCEPTION
+WHEN TOO_MANY_ROWS THEN res:='--- too_many_rows cought ---';
+WHEN NO_DATA_FOUND THEN res:='--- no_data_found cought ---';
+END;
+$$
+SET @res='';
+CALL p1(0, @res);
+SELECT @res;
+@res
+--- no_data_found cought ---
+CALL p1(2, @res);
+SELECT @res;
+@res
+--- too_many_rows cought ---
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Testing DUP_VAL_ON_INDEX
+#
+CREATE TABLE t1 (a INT PRIMARY KEY);
+CREATE PROCEDURE p1(res OUT VARCHAR)
+AS
+BEGIN
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (10);
+EXCEPTION
+WHEN DUP_VAL_ON_INDEX THEN res:='--- dup_val_on_index cought ---';
+END;
+$$
+SET @res='';
+CALL p1(@res);
+SELECT @res;
+@res
+--- dup_val_on_index cought ---
+SELECT * FROM t1;
+a
+10
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# MDEV-10840 sql_mode=ORACLE: RAISE statement for predefined exceptions
+#
+#
+# RAISE outside of an SP context
+#
+RAISE NO_DATA_FOUND;
+ERROR 42000: Undefined CONDITION: NO_DATA_FOUND
+RAISE INVALID_CURSOR;
+ERROR 42000: Undefined CONDITION: INVALID_CURSOR
+RAISE DUP_VAL_ON_INDEX;
+ERROR 42000: Undefined CONDITION: DUP_VAL_ON_INDEX
+RAISE TOO_MANY_ROWS;
+ERROR 42000: Undefined CONDITION: TOO_MANY_ROWS
+RAISE;
+ERROR 0K000: RESIGNAL when handler not active
+#
+# RAISE for an undefinite exception
+#
+CREATE PROCEDURE p1
+AS
+BEGIN
+RAISE xxx;
+END;
+$$
+ERROR 42000: Undefined CONDITION: xxx
+#
+# RAISE for predefined exceptions
+#
+CREATE PROCEDURE p1
+AS
+BEGIN
+RAISE no_data_found;
+END;
+$$
+CALL p1();
+Warnings:
+Warning 1329 No data - zero rows fetched, selected, or processed
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+BEGIN
+RAISE invalid_cursor;
+END;
+$$
+CALL p1();
+ERROR 24000: Cursor is not open
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+BEGIN
+RAISE dup_val_on_index;
+END;
+$$
+CALL p1();
+ERROR 23000: Duplicate entry '%-.192s' for key %d
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+BEGIN
+raise too_many_rows;
+END;
+$$
+CALL p1();
+ERROR 42000: Result consisted of more than one row
+DROP PROCEDURE p1;
+#
+# RAISE with no exception name (resignal)
+#
+CREATE PROCEDURE p1()
+AS
+BEGIN
+RAISE;
+END;
+$$
+CALL p1();
+ERROR 0K000: RESIGNAL when handler not active
+DROP PROCEDURE p1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+CREATE PROCEDURE p1(lim INT)
+AS
+a INT;
+BEGIN
+SELECT a INTO a FROM t1 LIMIT lim;
+EXCEPTION
+WHEN TOO_MANY_ROWS THEN RAISE;
+WHEN NO_DATA_FOUND THEN RAISE;
+END;
+$$
+CALL p1(0);
+Warnings:
+Warning 1329 No data - zero rows fetched, selected, or processed
+CALL p1(2);
+ERROR 42000: Result consisted of more than one row
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+CREATE PROCEDURE p1(lim INT)
+AS
+a INT;
+BEGIN
+SELECT a INTO a FROM t1 LIMIT lim;
+EXCEPTION
+WHEN OTHERS THEN RAISE;
+END;
+$$
+CALL p1(0);
+Warnings:
+Warning 1329 No data - zero rows fetched, selected, or processed
+CALL p1(2);
+ERROR 42000: Result consisted of more than one row
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+CREATE PROCEDURE p1()
+AS
+a INT;
+CURSOR c IS SELECT a FROM t1;
+BEGIN
+FETCH c INTO a;
+EXCEPTION
+WHEN INVALID_CURSOR THEN RAISE;
+END;
+$$
+CALL p1();
+ERROR 24000: Cursor is not open
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+CREATE PROCEDURE p1()
+AS
+a INT;
+CURSOR c IS SELECT a FROM t1;
+BEGIN
+FETCH c INTO a;
+EXCEPTION
+WHEN OTHERS THEN RAISE;
+END;
+$$
+CALL p1();
+ERROR 24000: Cursor is not open
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Testing that warning-alike errors are caught by OTHERS
+#
+CREATE TABLE t1 (a INT);
+CREATE FUNCTION f1 RETURN VARCHAR
+AS
+a INT:=10;
+BEGIN
+SELECT a INTO a FROM t1;
+RETURN 'OK';
+EXCEPTION
+WHEN OTHERS THEN RETURN 'Exception';
+END;
+$$
+SELECT f1() FROM DUAL;
+f1()
+Exception
+DROP FUNCTION f1;
+DROP TABLE t1;
+#
+# End of MDEV-10840 sql_mode=ORACLE: RAISE statement for predefined exceptions
+#
+#
+# MDEV-10587 sql_mode=ORACLE: User defined exceptions
+#
+#
+# Checking that duplicate WHEN clause is not allowed
+#
+CREATE FUNCTION f1() RETURN VARCHAR
+AS
+e EXCEPTION;
+BEGIN
+RETURN 'Got no exceptions';
+EXCEPTION
+WHEN e THEN RETURN 'Got exception e';
+WHEN e THEN RETURN 'Got exception e';
+END;
+$$
+ERROR 42000: Duplicate handler declared in the same block
+#
+# Checking that raised user exceptions are further caught by name
+#
+CREATE FUNCTION f1(c VARCHAR) RETURN VARCHAR
+AS
+e EXCEPTION;
+f EXCEPTION;
+BEGIN
+IF c = 'e' THEN RAISE e; END IF;
+IF c = 'f' THEN RAISE f; END IF;
+RETURN 'Got no exceptions';
+EXCEPTION
+WHEN e THEN RETURN 'Got exception e';
+END;
+$$
+SELECT f1('');
+f1('')
+Got no exceptions
+SELECT f1('e');
+f1('e')
+Got exception e
+SELECT f1('f');
+ERROR 45000: Unhandled user-defined exception condition
+DROP FUNCTION f1;
+#
+# Checking that raised user exceptions are further caught by OTHERS
+#
+CREATE FUNCTION f1(c VARCHAR) RETURN VARCHAR
+AS
+e EXCEPTION;
+f EXCEPTION;
+BEGIN
+IF c = 'e' THEN RAISE e; END IF;
+IF c = 'f' THEN RAISE f; END IF;
+RETURN 'Got no exceptions';
+EXCEPTION
+WHEN OTHERS THEN RETURN 'Got some exception';
+END;
+$$
+SELECT f1('');
+f1('')
+Got no exceptions
+SELECT f1('e');
+f1('e')
+Got some exception
+SELECT f1('f');
+f1('f')
+Got some exception
+DROP FUNCTION f1;
+#
+# Checking that 'WHEN e .. WHEN f' does not produce ER_SP_DUP_HANDLER
+#
+CREATE FUNCTION f1(c VARCHAR) RETURN VARCHAR
+AS
+e EXCEPTION;
+f EXCEPTION;
+a VARCHAR(64):='';
+BEGIN
+BEGIN
+IF c = 'e' THEN RAISE e; END IF;
+IF c = 'f' THEN RAISE f; END IF;
+EXCEPTION
+WHEN e THEN BEGIN a:='Got EXCEPTION1/e; '; RAISE e; END;
+WHEN f THEN BEGIN a:='Got EXCEPTION1/f; '; RAISE f; END;
+END;
+RETURN 'Got no exceptions';
+EXCEPTION
+WHEN OTHERS THEN RETURN a || 'Got EXCEPTION2/OTHERS;';
+END;
+$$
+SELECT f1('');
+f1('')
+Got no exceptions
+SELECT f1('e');
+f1('e')
+Got EXCEPTION1/e; Got EXCEPTION2/OTHERS;
+SELECT f1('f');
+f1('f')
+Got EXCEPTION1/f; Got EXCEPTION2/OTHERS;
+DROP FUNCTION f1;
+#
+# Checking that resignaled user exceptions are further caught by name
+#
+CREATE FUNCTION f1(c VARCHAR) RETURN VARCHAR
+AS
+e EXCEPTION;
+f EXCEPTION;
+a VARCHAR(64):='';
+BEGIN
+BEGIN
+IF c = 'e' THEN RAISE e; END IF;
+IF c = 'f' THEN RAISE f; END IF;
+EXCEPTION
+WHEN e THEN BEGIN a:='Got EXCEPTION1/e; '; RAISE; END;
+WHEN f THEN BEGIN a:='Got EXCEPTION1/f; '; RAISE; END;
+END;
+RETURN 'Got no exceptions';
+EXCEPTION
+WHEN e THEN RETURN a || 'Got EXCEPTION2/e;';
+END;
+$$
+SELECT f1('');
+f1('')
+Got no exceptions
+SELECT f1('e');
+f1('e')
+Got EXCEPTION1/e; Got EXCEPTION2/e;
+SELECT f1('f');
+ERROR 45000: Unhandled user-defined exception condition
+DROP FUNCTION f1;
+#
+# Checking that resignaled user exceptions are further caught by OTHERS
+#
+CREATE FUNCTION f1(c VARCHAR) RETURN VARCHAR
+AS
+e EXCEPTION;
+f EXCEPTION;
+a VARCHAR(64):='';
+BEGIN
+BEGIN
+IF c = 'e' THEN RAISE e; END IF;
+IF c = 'f' THEN RAISE f; END IF;
+EXCEPTION
+WHEN e THEN BEGIN a:='Got EXCEPTION1/e; '; RAISE; END;
+WHEN f THEN BEGIN a:='Got EXCEPTION1/f; '; RAISE; END;
+END;
+RETURN 'Got no exceptions';
+EXCEPTION
+WHEN OTHERS THEN RETURN a || 'Got EXCEPTION2/OTHERS;';
+END;
+$$
+SELECT f1('');
+f1('')
+Got no exceptions
+SELECT f1('e');
+f1('e')
+Got EXCEPTION1/e; Got EXCEPTION2/OTHERS;
+SELECT f1('f');
+f1('f')
+Got EXCEPTION1/f; Got EXCEPTION2/OTHERS;
+DROP FUNCTION f1;
+#
+# End of MDEV-10587 sql_mode=ORACLE: User defined exceptions
+#
+#
+# MDEV-12088 sql_mode=ORACLE: Do not require BEGIN..END in multi-statement exception handlers in THEN clause
+#
+CREATE TABLE t1 (a INT PRIMARY KEY);
+INSERT INTO t1 VALUES (10),(20),(30);
+CREATE PROCEDURE p1(a INT) AS
+BEGIN
+INSERT INTO t1 (a) VALUES (a);
+EXCEPTION
+WHEN DUP_VAL_ON_INDEX THEN
+a:= a+1;
+INSERT INTO t1 VALUES (a);
+WHEN OTHERS THEN
+NULL;
+NULL;
+END;
+$$
+CALL p1(30);
+SELECT * FROM t1;
+a
+10
+20
+30
+31
+DROP PROCEDURE p1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/func_case.result b/mysql-test/suite/compat/oracle/r/func_case.result
new file mode 100644
index 00000000000..dfe2d165b88
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/func_case.result
@@ -0,0 +1,7 @@
+SET sql_mode=ORACLE;
+SELECT NVL(NULL, 'a'), NVL('a', 'b');
+NVL(NULL, 'a') NVL('a', 'b')
+a a
+SELECT NVL2(NULL, 'a', 'b'), NVL2('a', 'b', 'c');
+NVL2(NULL, 'a', 'b') NVL2('a', 'b', 'c')
+b b
diff --git a/mysql-test/suite/compat/oracle/r/func_concat.result b/mysql-test/suite/compat/oracle/r/func_concat.result
new file mode 100644
index 00000000000..230b36b94a5
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/func_concat.result
@@ -0,0 +1,257 @@
+SET sql_mode=ORACLE;
+EXPLAIN EXTENDED SELECT 'a'||'b'||'c';
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select concat_operator_oracle(concat_operator_oracle('a','b'),'c') AS "'a'||'b'||'c'"
+EXPLAIN EXTENDED SELECT CONCAT('a'||'b'||'c');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select concat_operator_oracle(concat_operator_oracle(concat_operator_oracle('a','b'),'c')) AS "CONCAT('a'||'b'||'c')"
+SELECT '' || '';
+'' || ''
+
+SELECT '' || 'b';
+'' || 'b'
+b
+SELECT '' || NULL;
+'' || NULL
+
+SELECT 'a' || '';
+'a' || ''
+a
+SELECT 'a' || 'b';
+'a' || 'b'
+ab
+SELECT 'a' || NULL;
+'a' || NULL
+a
+SELECT NULL || '';
+NULL || ''
+
+SELECT NULL || 'b';
+NULL || 'b'
+b
+SELECT NULL || NULL;
+NULL || NULL
+NULL
+SELECT '' || '' || '';
+'' || '' || ''
+
+SELECT '' || '' || 'c';
+'' || '' || 'c'
+c
+SELECT '' || '' || NULL;
+'' || '' || NULL
+
+SELECT '' || 'b' || '';
+'' || 'b' || ''
+b
+SELECT '' || 'b' || 'c';
+'' || 'b' || 'c'
+bc
+SELECT '' || 'b' || NULL;
+'' || 'b' || NULL
+b
+SELECT '' || NULL || '';
+'' || NULL || ''
+
+SELECT '' || NULL || 'c';
+'' || NULL || 'c'
+c
+SELECT '' || NULL || NULL;
+'' || NULL || NULL
+
+SELECT 'a' || '' || '';
+'a' || '' || ''
+a
+SELECT 'a' || '' || 'c';
+'a' || '' || 'c'
+ac
+SELECT 'a' || '' || NULL;
+'a' || '' || NULL
+a
+SELECT 'a' || 'b' || '';
+'a' || 'b' || ''
+ab
+SELECT 'a' || 'b' || 'c';
+'a' || 'b' || 'c'
+abc
+SELECT 'a' || 'b' || NULL;
+'a' || 'b' || NULL
+ab
+SELECT 'a' || NULL || '';
+'a' || NULL || ''
+a
+SELECT 'a' || NULL || 'c';
+'a' || NULL || 'c'
+ac
+SELECT 'a' || NULL || NULL;
+'a' || NULL || NULL
+a
+SELECT NULL || '' || '';
+NULL || '' || ''
+
+SELECT NULL || '' || 'c';
+NULL || '' || 'c'
+c
+SELECT NULL || '' || NULL;
+NULL || '' || NULL
+
+SELECT NULL || 'b' || '';
+NULL || 'b' || ''
+b
+SELECT NULL || 'b' || 'c';
+NULL || 'b' || 'c'
+bc
+SELECT NULL || 'b' || NULL;
+NULL || 'b' || NULL
+b
+SELECT NULL || NULL || '';
+NULL || NULL || ''
+
+SELECT NULL || NULL || 'c';
+NULL || NULL || 'c'
+c
+SELECT NULL || NULL || NULL;
+NULL || NULL || NULL
+NULL
+CREATE TABLE t1 (a VARCHAR(10), b VARCHAR(10), c VARCHAR(10));
+INSERT INTO t1 VALUES ('', '', '');
+INSERT INTO t1 VALUES ('', '', 'c');
+INSERT INTO t1 VALUES ('', '', NULL);
+INSERT INTO t1 VALUES ('', 'b', '');
+INSERT INTO t1 VALUES ('', 'b', 'c');
+INSERT INTO t1 VALUES ('', 'b', NULL);
+INSERT INTO t1 VALUES ('', NULL, '');
+INSERT INTO t1 VALUES ('', NULL, 'c');
+INSERT INTO t1 VALUES ('', NULL, NULL);
+INSERT INTO t1 VALUES ('a', '', '');
+INSERT INTO t1 VALUES ('a', '', 'c');
+INSERT INTO t1 VALUES ('a', '', NULL);
+INSERT INTO t1 VALUES ('a', 'b', '');
+INSERT INTO t1 VALUES ('a', 'b', 'c');
+INSERT INTO t1 VALUES ('a', 'b', NULL);
+INSERT INTO t1 VALUES ('a', NULL, '');
+INSERT INTO t1 VALUES ('a', NULL, 'c');
+INSERT INTO t1 VALUES ('a', NULL, NULL);
+INSERT INTO t1 VALUES (NULL, '', '');
+INSERT INTO t1 VALUES (NULL, '', 'c');
+INSERT INTO t1 VALUES (NULL, '', NULL);
+INSERT INTO t1 VALUES (NULL, 'b', '');
+INSERT INTO t1 VALUES (NULL, 'b', 'c');
+INSERT INTO t1 VALUES (NULL, 'b', NULL);
+INSERT INTO t1 VALUES (NULL, NULL, '');
+INSERT INTO t1 VALUES (NULL, NULL, 'c');
+INSERT INTO t1 VALUES (NULL, NULL, NULL);
+SELECT LENGTH(a||b||c), a||b||c FROM t1 ORDER BY a,b,c;
+LENGTH(a||b||c) a||b||c
+NULL NULL
+0
+1 c
+0
+0
+1 c
+1 b
+1 b
+2 bc
+0
+0
+1 c
+0
+0
+1 c
+1 b
+1 b
+2 bc
+1 a
+1 a
+2 ac
+1 a
+1 a
+2 ac
+2 ab
+2 ab
+3 abc
+SELECT LENGTH(CONCAT(a||b||c)), CONCAT(a||b||c) FROM t1 ORDER BY a,b,c;
+LENGTH(CONCAT(a||b||c)) CONCAT(a||b||c)
+NULL NULL
+0
+1 c
+0
+0
+1 c
+1 b
+1 b
+2 bc
+0
+0
+1 c
+0
+0
+1 c
+1 b
+1 b
+2 bc
+1 a
+1 a
+2 ac
+1 a
+1 a
+2 ac
+2 ab
+2 ab
+3 abc
+DROP TABLE t1;
+#
+# MDEV-12478 CONCAT function inside view casts values incorrectly with Oracle sql_mode
+#
+SET sql_mode=ORACLE;
+CREATE VIEW v1 AS SELECT 'foo'||NULL||'bar' AS test;
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE VIEW "v1" AS select concat_operator_oracle(concat_operator_oracle('foo',NULL),'bar') AS "test" latin1 latin1_swedish_ci
+SELECT * FROM v1;
+test
+foobar
+SET sql_mode=DEFAULT;
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select concat_operator_oracle(concat_operator_oracle('foo',NULL),'bar') AS `test` latin1 latin1_swedish_ci
+SELECT * FROM v1;
+test
+foobar
+DROP VIEW v1;
+SET sql_mode=DEFAULT;
+CREATE VIEW v1 AS SELECT CONCAT('foo',NULL,'bar') AS test;
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select concat('foo',NULL,'bar') AS `test` latin1 latin1_swedish_ci
+SELECT * FROM v1;
+test
+NULL
+SET sql_mode=ORACLE;
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE VIEW "v1" AS select concat('foo',NULL,'bar') AS "test" latin1 latin1_swedish_ci
+SELECT * FROM v1;
+test
+NULL
+DROP VIEW v1;
+SET sql_mode=DEFAULT;
+CREATE VIEW v1 AS SELECT '0'||'1' AS test;
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select '0' or '1' AS `test` latin1 latin1_swedish_ci
+SELECT * FROM v1;
+test
+1
+SET sql_mode=ORACLE;
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE VIEW "v1" AS select '0' or '1' AS "test" latin1 latin1_swedish_ci
+SELECT * FROM v1;
+test
+1
+DROP VIEW v1;
diff --git a/mysql-test/suite/compat/oracle/r/func_decode.result b/mysql-test/suite/compat/oracle/r/func_decode.result
new file mode 100644
index 00000000000..c4bfb713e61
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/func_decode.result
@@ -0,0 +1,33 @@
+SET sql_mode=ORACLE;
+SELECT DECODE(10);
+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 ')' at line 1
+SELECT DECODE(10,10);
+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 ')' at line 1
+SELECT DECODE(10,10,'x10');
+DECODE(10,10,'x10')
+x10
+SELECT DECODE(11,10,'x10');
+DECODE(11,10,'x10')
+NULL
+SELECT DECODE(10,10,'x10','def');
+DECODE(10,10,'x10','def')
+x10
+SELECT DECODE(11,10,'x10','def');
+DECODE(11,10,'x10','def')
+def
+SELECT DECODE(10,10,'x10',11,'x11','def');
+DECODE(10,10,'x10',11,'x11','def')
+x10
+SELECT DECODE(11,10,'x10',11,'x11','def');
+DECODE(11,10,'x10',11,'x11','def')
+x11
+SELECT DECODE(12,10,'x10',11,'x11','def');
+DECODE(12,10,'x10',11,'x11','def')
+def
+EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11','def');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select case 12 when 10 then 'x10' when 11 then 'x11' else 'def' end AS "DECODE(12,10,'x10',11,'x11','def')"
+CREATE TABLE decode (decode int);
+DROP TABLE decode;
diff --git a/mysql-test/suite/compat/oracle/r/func_length.result b/mysql-test/suite/compat/oracle/r/func_length.result
new file mode 100644
index 00000000000..e260f5ad6da
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/func_length.result
@@ -0,0 +1,21 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-12783 sql_mode=ORACLE: Functions LENGTH() and LENGTHB()
+#
+SELECT LENGTH(null), LENGTH('a'), LENGTH(123);
+LENGTH(null) LENGTH('a') LENGTH(123)
+NULL 1 3
+SELECT LENGTHB(null), LENGTHB('a'), LENGTHB(123);
+LENGTHB(null) LENGTHB('a') LENGTHB(123)
+NULL 1 3
+SELECT LENGTH(_utf8 0xC39F), LENGTH(CHAR(14844588 USING utf8));
+LENGTH(_utf8 0xC39F) LENGTH(CHAR(14844588 USING utf8))
+1 1
+SELECT LENGTHB(_utf8 0xC39F), LENGTHB(CHAR(14844588 USING utf8));
+LENGTHB(_utf8 0xC39F) LENGTHB(CHAR(14844588 USING utf8))
+2 3
+EXPLAIN EXTENDED SELECT LENGTH('a'), LENGTHB('a');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select char_length('a') AS "LENGTH('a')",octet_length('a') AS "LENGTHB('a')"
diff --git a/mysql-test/suite/compat/oracle/r/func_misc.result b/mysql-test/suite/compat/oracle/r/func_misc.result
new file mode 100644
index 00000000000..0e2ba0c6f50
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/func_misc.result
@@ -0,0 +1,319 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-10578 sql_mode=ORACLE: SP control functions SQLCODE, SQLERRM
+#
+#
+# Using SQLCODE and SQLERRM outside of an SP
+#
+SELECT SQLCODE;
+ERROR 42S22: Unknown column 'SQLCODE' in 'field list'
+SELECT SQLERRM;
+ERROR 42S22: Unknown column 'SQLERRM' in 'field list'
+CREATE TABLE t1 (SQLCODE INT, SQLERRM VARCHAR(10));
+INSERT INTO t1 VALUES (10, 'test');
+SELECT SQLCODE, SQLERRM FROM t1;
+SQLCODE SQLERRM
+10 test
+DROP TABLE t1;
+#
+# Normal SQLCODE and SQLERRM usage
+#
+CREATE PROCEDURE p1(stmt VARCHAR)
+AS
+BEGIN
+EXECUTE IMMEDIATE stmt;
+SELECT 'Error1: ' || SQLCODE || ' ' || SQLERRM;
+EXCEPTION
+WHEN OTHERS THEN
+SELECT 'Error2: ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CALL p1('SELECT 1');
+1
+1
+'Error1: ' || SQLCODE || ' ' || SQLERRM
+Error1: 0 normal, successful completition
+CALL p1('xxx');
+'Error2: ' || SQLCODE || ' ' || SQLERRM
+Error2: 1193 Unknown system variable 'xxx'
+CALL p1('SELECT 1');
+1
+1
+'Error1: ' || SQLCODE || ' ' || SQLERRM
+Error1: 0 normal, successful completition
+DROP PROCEDURE p1;
+#
+# SQLCODE and SQLERRM hidden by local variables
+#
+CREATE PROCEDURE p1()
+AS
+sqlcode INT:= 10;
+sqlerrm VARCHAR(64) := 'test';
+BEGIN
+SELECT 'Error: ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CALL p1;
+'Error: ' || SQLCODE || ' ' || SQLERRM
+Error: 10 test
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+sqlcode INT;
+sqlerrm VARCHAR(64);
+BEGIN
+SQLCODE:= 10;
+sqlerrm:= 'test';
+SELECT 'Error: ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CALL p1;
+'Error: ' || SQLCODE || ' ' || SQLERRM
+Error: 10 test
+DROP PROCEDURE p1;
+#
+# SQLCODE and SQLERRM hidden by parameters
+#
+CREATE PROCEDURE p1(sqlcode INT, sqlerrm VARCHAR)
+AS
+BEGIN
+SELECT 'Error: ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CALL p1(10, 'test');
+'Error: ' || SQLCODE || ' ' || SQLERRM
+Error: 10 test
+DROP PROCEDURE p1;
+#
+# SQLCODE and SQLERRM in CREATE..SELECT
+#
+CREATE PROCEDURE p1
+AS
+BEGIN
+CREATE TABLE t1 AS SELECT SQLCODE, SQLERRM;
+END;
+$$
+CALL p1;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "SQLCODE" int(11) NOT NULL,
+ "SQLERRM" varchar(512) CHARACTER SET utf8 NOT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# SQLCODE and SQLERRM in EXPLAIN EXTENDED SELECT
+#
+CREATE PROCEDURE p1
+AS
+BEGIN
+EXPLAIN EXTENDED SELECT SQLCode, SQLErrm;
+END;
+$$
+CALL p1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select SQLCODE AS "SQLCode",SQLERRM AS "SQLErrm"
+DROP PROCEDURE p1;
+#
+# Warning-alike errors in stored functions
+#
+CREATE TABLE t1 (a INT);
+CREATE FUNCTION f1 RETURN VARCHAR
+AS
+a INT;
+BEGIN
+SELECT a INTO a FROM t1;
+RETURN 'No exception ' || SQLCODE || ' ' || SQLERRM;
+EXCEPTION
+WHEN NO_DATA_FOUND THEN
+RETURN 'Exception ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+SELECT f1() FROM DUAL;
+f1()
+Exception 1329 No data - zero rows fetched, selected, or processed
+DROP FUNCTION f1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+CREATE FUNCTION f1 RETURN VARCHAR
+AS
+a INT;
+BEGIN
+SELECT a INTO a FROM t1;
+RETURN 'No exception ' || SQLCODE || ' ' || SQLERRM;
+EXCEPTION
+WHEN OTHERS THEN
+RETURN 'Exception ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+SELECT f1() FROM DUAL;
+f1()
+Exception 1329 No data - zero rows fetched, selected, or processed
+DROP FUNCTION f1;
+DROP TABLE t1;
+#
+# Warning-alike errors in stored procedures
+#
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1(res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+SELECT a INTO a FROM t1;
+res:= 'No exception ' || SQLCODE || ' ' || SQLERRM;
+EXCEPTION
+WHEN NO_DATA_FOUND THEN
+res:= 'Exception ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CALL p1(@a);
+SELECT @a;
+@a
+Exception 1329 No data - zero rows fetched, selected, or processed
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1(res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+SELECT a INTO a FROM t1;
+res:= 'No exception ' || SQLCODE || ' ' || SQLERRM;
+EXCEPTION
+WHEN OTHERS THEN
+res:= 'Exception ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CALL p1(@a);
+SELECT @a;
+@a
+Exception 1329 No data - zero rows fetched, selected, or processed
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# SQLCODE and SQLERRM are cleared on RETURN
+#
+CREATE TABLE t1 (a INT);
+CREATE FUNCTION f1 RETURN VARCHAR
+AS
+a INT:=10;
+BEGIN
+SELECT a INTO a FROM t1;
+RETURN 'Value=' || a;
+EXCEPTION
+WHEN NO_DATA_FOUND THEN RETURN 'Exception|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CREATE FUNCTION f2 RETURN VARCHAR
+AS
+a VARCHAR(128);
+BEGIN
+RETURN f1() || '|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+SELECT f1() FROM DUAL;
+f1()
+Exception|1329 No data - zero rows fetched, selected, or processed
+SELECT f2() FROM DUAL;
+f2()
+Exception|1329 No data - zero rows fetched, selected, or processed|0 normal, successful completition
+DROP TABLE t1;
+DROP FUNCTION f2;
+DROP FUNCTION f1;
+CREATE TABLE t1 (a INT);
+CREATE FUNCTION f1 RETURN VARCHAR
+AS
+a INT:=10;
+BEGIN
+SELECT a INTO a FROM t1;
+RETURN 'Value=' || a;
+EXCEPTION
+WHEN OTHERS THEN RETURN 'Exception|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CREATE FUNCTION f2 RETURN VARCHAR
+AS
+a VARCHAR(128);
+BEGIN
+RETURN f1() || '|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+SELECT f1() FROM DUAL;
+f1()
+Exception|1329 No data - zero rows fetched, selected, or processed
+SELECT f2() FROM DUAL;
+f2()
+Exception|1329 No data - zero rows fetched, selected, or processed|0 normal, successful completition
+DROP TABLE t1;
+DROP FUNCTION f2;
+DROP FUNCTION f1;
+#
+# SQLCODE and SQLERRM are cleared on a return from a PROCEDURE
+#
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1(res OUT VARCHAR)
+AS
+a INT:=10;
+BEGIN
+SELECT a INTO a FROM t1;
+res:='Value=' || a;
+EXCEPTION
+WHEN NO_DATA_FOUND THEN res:='Exception|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CREATE FUNCTION f2 RETURN VARCHAR
+AS
+res VARCHAR(128);
+BEGIN
+CALL p1(res);
+RETURN res || '|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+SELECT f2() FROM DUAL;
+f2()
+Exception|1329 No data - zero rows fetched, selected, or processed|0 normal, successful completition
+DROP FUNCTION f2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1(res OUT VARCHAR)
+AS
+a INT:=10;
+BEGIN
+SELECT a INTO a FROM t1;
+res:='Value=' || a;
+EXCEPTION
+WHEN OTHERS THEN res:='Exception|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CREATE FUNCTION f2 RETURN VARCHAR
+AS
+res VARCHAR(128);
+BEGIN
+CALL p1(res);
+RETURN res || '|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+SELECT f2() FROM DUAL;
+f2()
+Exception|1329 No data - zero rows fetched, selected, or processed|0 normal, successful completition
+DROP FUNCTION f2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# End of MDEV-10578 sql_mode=ORACLE: SP control functions SQLCODE, SQLERRM
+#
+#
+# MDEV-12854 Synchronize CREATE..SELECT data type and result set metadata data type for INT functions
+#
+BEGIN
+SELECT SQLCODE;
+END
+$$
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def SQLCODE 3 11 1 N 32897 0 63
+SQLCODE
+0
diff --git a/mysql-test/suite/compat/oracle/r/misc.result b/mysql-test/suite/compat/oracle/r/misc.result
new file mode 100644
index 00000000000..38f38bd07e6
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/misc.result
@@ -0,0 +1,12 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-12086 sql_mode=ORACLE: allow SELECT UNIQUE as a synonym for SELECT DISTINCT
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20),(20),(30),(30),(30);
+SELECT UNIQUE a FROM t1;
+a
+10
+20
+30
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/ps.result b/mysql-test/suite/compat/oracle/r/ps.result
new file mode 100644
index 00000000000..ed7cb4c51d5
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/ps.result
@@ -0,0 +1,249 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-10801 sql_mode: dynamic SQL placeholders
+#
+SET @a=10, @b=20;
+PREPARE stmt FROM 'SELECT ?,?';
+EXECUTE stmt USING @a, @b;
+? ?
+10 20
+PREPARE stmt FROM 'SELECT :a,:b';
+EXECUTE stmt USING @a, @b;
+:a :b
+10 20
+PREPARE stmt FROM 'SELECT :aaa,:bbb';
+EXECUTE stmt USING @a, @b;
+:aaa :bbb
+10 20
+PREPARE stmt FROM 'SELECT :"a",:"b"';
+EXECUTE stmt USING @a, @b;
+:"a" :"b"
+10 20
+PREPARE stmt FROM 'SELECT :"aaa",:"bbb"';
+EXECUTE stmt USING @a, @b;
+:"aaa" :"bbb"
+10 20
+PREPARE stmt FROM 'SELECT :1,:2';
+EXECUTE stmt USING @a, @b;
+:1 :2
+10 20
+PREPARE stmt FROM 'SELECT :222,:111';
+EXECUTE stmt USING @a, @b;
+:222 :111
+10 20
+PREPARE stmt FROM 'SELECT :0,:65535';
+EXECUTE stmt USING @a, @b;
+:0 :65535
+10 20
+PREPARE stmt FROM 'SELECT :65535,:0';
+EXECUTE stmt USING @a, @b;
+:65535 :0
+10 20
+#
+# MDEV-10709 Expressions as parameters to Dynamic SQL
+#
+#
+# Testing disallowed expressions in USING
+#
+PREPARE stmt FROM 'SELECT :1 FROM DUAL';
+EXECUTE stmt USING (SELECT 1);
+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 'SELECT 1)' at line 1
+DEALLOCATE PREPARE stmt;
+CREATE FUNCTION f1() RETURN VARCHAR
+AS
+BEGIN
+RETURN 'test';
+END;
+$$
+PREPARE stmt FROM 'SELECT ? FROM DUAL';
+EXECUTE stmt USING f1();
+ERROR 42000: EXECUTE..USING does not support subqueries or stored functions
+DEALLOCATE PREPARE stmt;
+DROP FUNCTION f1;
+#
+# Using a user variable as a EXECUTE..USING out parameter
+#
+CREATE PROCEDURE p1(a OUT INT)
+AS
+BEGIN
+a:= 10;
+END;
+/
+SET @a=1;
+CALL p1(@a);
+SELECT @a;
+@a
+10
+SET @a=2;
+PREPARE stmt FROM 'CALL p1(?)';
+EXECUTE stmt USING @a;
+SELECT @a;
+@a
+10
+DROP PROCEDURE p1;
+#
+# Using an SP variable as a EXECUTE..USING out parameter
+#
+CREATE PROCEDURE p1 (a OUT INT)
+AS
+BEGIN
+a:=10;
+END;
+/
+CREATE PROCEDURE p2 (a OUT INT)
+AS
+BEGIN
+PREPARE stmt FROM 'CALL p1(?)';
+EXECUTE stmt USING a;
+END;
+/
+SET @a= 1;
+CALL p2(@a);
+SELECT @a;
+@a
+10
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+#
+# Using a trigger field as a EXECUTE..USING out parameter
+#
+CREATE PROCEDURE p1 (a OUT INT)
+AS
+BEGIN
+a:= 10;
+END;
+/
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW CALL p1(:NEW.a);
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1;
+a
+10
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Testing re-prepare on a table metadata update between PREPARE and EXECUTE
+#
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1(a IN INT)
+AS
+BEGIN
+INSERT INTO t1 VALUES (a);
+END;
+/
+PREPARE stmt FROM 'CALL p1(?)';
+EXECUTE stmt USING 10;
+SELECT * FROM t1;
+a
+10
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW NEW.a:=NEW.a+1;
+EXECUTE stmt USING 20;
+SELECT * FROM t1;
+a
+10
+21
+DEALLOCATE PREPARE stmt;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# End of MDEV-10709 Expressions as parameters to Dynamic SQL
+#
+#
+# MDEV-10585 EXECUTE IMMEDIATE statement
+#
+#
+# Testing disallowed expressions in USING
+#
+EXECUTE IMMEDIATE 'SELECT :1 FROM DUAL' USING (SELECT 1);
+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 'SELECT 1)' at line 1
+CREATE FUNCTION f1() RETURN VARCHAR
+AS
+BEGIN
+RETURN 'test';
+END;
+$$
+EXECUTE IMMEDIATE 'SELECT ? FROM DUAL' USING f1();
+ERROR 42000: EXECUTE..USING does not support subqueries or stored functions
+DROP FUNCTION f1;
+#
+# Testing simple expressions
+#
+EXECUTE IMMEDIATE 'SELECT :1 FROM DUAL' USING 10;
+:1
+10
+#
+# MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
+#
+#
+# Testing erroneous and diallowed prepare source
+#
+EXECUTE IMMEDIATE _latin1'SELECT 1 AS c FROM ' || _latin2 'DUAL';
+ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'concat_operator_oracle'
+PREPARE stmt FROM _latin1'SELECT 1 AS c FROM ' || _latin2 'DUAL';
+ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'concat_operator_oracle'
+EXECUTE IMMEDIATE (SELECT 'SELECT 1');
+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 'SELECT 'SELECT 1')' at line 1
+PREPARE stmt FROM (SELECT 'SELECT 1');
+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 'SELECT 'SELECT 1')' at line 1
+EXECUTE IMMEDIATE a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+PREPARE stmt FROM a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+EXECUTE IMMEDIATE NULL;
+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 'NULL' at line 1
+PREPARE stmt FROM NULL;
+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 'NULL' at line 1
+EXECUTE IMMEDIATE COALESCE(NULL);
+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 'NULL' at line 1
+PREPARE stmt FROM COALESCE(NULL);
+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 'NULL' at line 1
+CREATE FUNCTION f1() RETURN VARCHAR
+AS
+BEGIN
+RETURN 't1';
+END;
+$$
+EXECUTE IMMEDIATE f1();
+ERROR 42000: EXECUTE IMMEDIATE does not support subqueries or stored functions
+PREPARE stmt FROM f1();
+ERROR 42000: PREPARE..FROM does not support subqueries or stored functions
+DROP FUNCTION f1;
+#
+# Testing user variables in prepare source
+#
+SET @table_name='DUAL';
+EXECUTE IMMEDIATE 'SELECT 1 AS a FROM ' || @table_name;
+a
+1
+PREPARE stmt FROM 'SELECT 1 AS a FROM ' || @table_name;
+EXECUTE stmt;
+a
+1
+DEALLOCATE PREPARE stmt;
+#
+# Testing SP parameters and variables in prepare source
+#
+CREATE PROCEDURE p1(table_name VARCHAR)
+AS
+BEGIN
+EXECUTE IMMEDIATE 'SELECT 1 AS c FROM '|| table_name;
+END;
+$$
+CALL p1('DUAL');
+c
+1
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+table_name VARCHAR(64):='DUAL';
+BEGIN
+EXECUTE IMMEDIATE 'SELECT 1 AS c FROM ' || table_name;
+END;
+$$
+CALL p1();
+c
+1
+DROP PROCEDURE p1;
+#
+# End of MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
+#
diff --git a/mysql-test/suite/compat/oracle/r/sequence.result b/mysql-test/suite/compat/oracle/r/sequence.result
new file mode 100644
index 00000000000..dbbabc36683
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sequence.result
@@ -0,0 +1,77 @@
+SET sql_mode=ORACLE;
+CREATE SEQUENCE s1;
+SHOW CREATE SEQUENCE s1;
+Table Create Table
+s1 CREATE SEQUENCE "s1" start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle
+SELECT s1.currval;
+s1.currval
+NULL
+SELECT s1.nextval;
+s1.nextval
+1
+SELECT s1.nextval;
+s1.nextval
+2
+SELECT s1.nextval;
+s1.nextval
+3
+EXPLAIN EXTENDED SELECT s1.nextval;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select nextval("test"."s1") AS "s1.nextval"
+SELECT nextval(s1);
+nextval(s1)
+4
+EXPLAIN EXTENDED SELECT s1.currval;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select lastval("test"."s1") AS "s1.currval"
+SELECT lastval(s1);
+lastval(s1)
+4
+DROP SEQUENCE s1;
+CREATE SEQUENCE s1;
+CREATE VIEW v1 AS SELECT s1.nextval AS a;
+SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='v1';
+VIEW_DEFINITION
+select nextval(`test`.`s1`) AS `a`
+SELECT * FROM v1;
+a
+1
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE VIEW "v1" AS select nextval("test"."s1") AS "a" latin1 latin1_swedish_ci
+DROP VIEW v1;
+DROP SEQUENCE s1;
+CREATE SEQUENCE s1;
+CREATE VIEW v1 AS SELECT s1.currval AS a;
+SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='v1';
+VIEW_DEFINITION
+select lastval(`test`.`s1`) AS `a`
+SELECT * FROM v1;
+a
+NULL
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE VIEW "v1" AS select lastval("test"."s1") AS "a" latin1 latin1_swedish_ci
+DROP VIEW v1;
+DROP SEQUENCE s1;
+#
+# MDEV-12533 sql_mode=ORACLE: Add support for database qualified sequence names in NEXTVAL and CURRVAL
+#
+CREATE SEQUENCE s1;
+SELECT test.s1.nextval;
+test.s1.nextval
+1
+SELECT test.s1.currval;
+test.s1.currval
+1
+SELECT .s1.nextval;
+.s1.nextval
+2
+SELECT .s1.currval;
+.s1.currval
+2
+DROP SEQUENCE s1;
diff --git a/mysql-test/suite/compat/oracle/r/sp-anonymous.result b/mysql-test/suite/compat/oracle/r/sp-anonymous.result
new file mode 100644
index 00000000000..26bce0f435f
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp-anonymous.result
@@ -0,0 +1,220 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-10655 Anonymous blocks
+#
+# Testing BEGIN NOT ATOMIC with no declarations
+BEGIN NOT ATOMIC
+SELECT 1 AS a;
+END
+/
+a
+1
+# Testing BEGIN NOT ATOMIC with declarations
+# DECLARE starts a new block and thus must be followed by BEGIN .. END
+BEGIN NOT ATOMIC
+DECLARE
+i INT DEFAULT 5;
+x INT DEFAULT 10;
+BEGIN
+<<label>>
+WHILE i > 3 LOOP
+i:= i - 1;
+SELECT i;
+END LOOP label;
+END;
+END
+/
+i
+4
+i
+3
+# Anonymous blocks with no declarations and no exceptions
+BEGIN
+SELECT 1 AS a;
+END
+$$
+a
+1
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+BEGIN
+INSERT INTO t1 VALUES(20);
+INSERT INTO t1 VALUES(30);
+ROLLBACK;
+END;
+$$
+SELECT * FROM t1;
+a
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+BEGIN
+INSERT INTO t1 VALUES(20);
+INSERT INTO t1 VALUES(30);
+END;
+$$
+ROLLBACK;
+SELECT * FROM t1;
+a
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+BEGIN
+INSERT INTO t1 VALUES(20);
+INSERT INTO t1 VALUES(30);
+COMMIT;
+END;
+$$
+SELECT * FROM t1;
+a
+10
+20
+30
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+BEGIN
+INSERT INTO t1 VALUES(20);
+INSERT INTO t1 VALUES(30);
+END;
+$$
+COMMIT;
+SELECT * FROM t1;
+a
+10
+20
+30
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+BEGIN
+INSERT INTO t1 VALUES(20);
+INSERT INTO t1 VALUES(20);
+END;
+$$
+ERROR 23000: Duplicate entry '20' for key 'PRIMARY'
+COMMIT;
+SELECT * FROM t1;
+a
+10
+20
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+# Anonymous blocks with no declarations, with exceptions
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+BEGIN
+INSERT INTO t1 VALUES(20);
+INSERT INTO t1 VALUES(20);
+EXCEPTION
+WHEN DUP_VAL_ON_INDEX THEN NULL;
+END;
+$$
+COMMIT;
+SELECT * FROM t1;
+a
+10
+20
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+# Anonymous blocks with declarations, with no exceptions
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DECLARE
+a20 INT:=20;
+a30 INT:=30;
+BEGIN
+INSERT INTO t1 VALUES(a20);
+INSERT INTO t1 VALUES(a30);
+ROLLBACK;
+END;
+$$
+SELECT * FROM t1;
+a
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DECLARE
+a20 INT:=20;
+a30 INT:=30;
+BEGIN
+INSERT INTO t1 VALUES(a20);
+INSERT INTO t1 VALUES(a30);
+END;
+$$
+ROLLBACK;
+SELECT * FROM t1;
+a
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DECLARE
+a20 INT:=20;
+a30 INT:=30;
+BEGIN
+INSERT INTO t1 VALUES(a20);
+INSERT INTO t1 VALUES(a30);
+COMMIT;
+END;
+$$
+SELECT * FROM t1;
+a
+10
+20
+30
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DECLARE
+a20 INT:=20;
+a30 INT:=30;
+BEGIN
+INSERT INTO t1 VALUES(a20);
+INSERT INTO t1 VALUES(a30);
+END;
+$$
+COMMIT;
+SELECT * FROM t1;
+a
+10
+20
+30
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+# Anonymous blocks with declarations, with exceptions
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DECLARE
+a20 INT:=20;
+BEGIN
+INSERT INTO t1 VALUES(a20);
+INSERT INTO t1 VALUES(a20);
+EXCEPTION
+WHEN DUP_VAL_ON_INDEX THEN NULL;
+END;
+$$
+COMMIT;
+SELECT * FROM t1;
+a
+10
+20
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
diff --git a/mysql-test/suite/compat/oracle/r/sp-code.result b/mysql-test/suite/compat/oracle/r/sp-code.result
new file mode 100644
index 00000000000..1087e10552b
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp-code.result
@@ -0,0 +1,1483 @@
+SET sql_mode=ORACLE;
+#
+# Testing exceptions in the top-level blocks
+#
+# No HANDLER declarations, no exceptions
+CREATE FUNCTION f1 RETURN INT
+AS
+BEGIN
+RETURN 10;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 freturn int 10
+SELECT f1();
+f1()
+10
+DROP FUNCTION f1;
+# No HANDLER declarations, no code, no exceptions
+CREATE PROCEDURE p1 ()
+IS
+BEGIN
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 jump 2
+CALL p1;
+DROP PROCEDURE p1;
+# No HANDLER declarations, no code, some exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+EXCEPTION
+WHEN 1002 THEN v:=225;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 jump 1
+1 hpush_jump 4 1 EXIT
+2 set v@0 225
+3 hreturn 0 4
+4 hpop 1
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+@v
+10
+DROP PROCEDURE p1;
+# No HANDLER declarations, some code, some exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+v:=224;
+EXCEPTION
+WHEN 1002 THEN v:=225;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 jump 3
+1 set v@0 224
+2 jump 6
+3 hpush_jump 1 1 EXIT
+4 set v@0 225
+5 hreturn 0 6
+6 hpop 1
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+@v
+224
+DROP PROCEDURE p1;
+# Some HANDLER declarations, no code, no exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+EXIT HANDLER FOR 1000
+BEGIN
+v:=123;
+END;
+BEGIN
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 hpush_jump 3 1 EXIT
+1 set v@0 123
+2 hreturn 0 3
+3 hpop 1
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+@v
+10
+DROP PROCEDURE p1;
+# Some HANDLER declarations, no code, some exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+EXIT HANDLER FOR 1000
+BEGIN
+v:=123;
+END;
+BEGIN
+EXCEPTION
+WHEN 1002 THEN v:=225;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 hpush_jump 3 1 EXIT
+1 set v@0 123
+2 hreturn 0 6
+3 hpush_jump 6 1 EXIT
+4 set v@0 225
+5 hreturn 0 6
+6 hpop 2
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+@v
+10
+DROP PROCEDURE p1;
+# Some HANDLER declarations, some code, no exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+EXIT HANDLER FOR 1000
+BEGIN
+v:=123;
+END;
+BEGIN
+v:=223;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 hpush_jump 3 1 EXIT
+1 set v@0 123
+2 hreturn 0 4
+3 set v@0 223
+4 hpop 1
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+@v
+223
+DROP PROCEDURE p1;
+# Some HANDLER declarations, some code, some exceptions
+CREATE PROCEDURE p1 (v IN OUT VARCHAR2(20))
+IS
+EXIT HANDLER FOR 1000
+BEGIN
+v:=123;
+END;
+CONTINUE HANDLER FOR 1001
+BEGIN
+SET v=223;
+END;
+BEGIN
+v:= 1;
+EXCEPTION
+WHEN 1002 THEN SET v=225;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 hpush_jump 3 1 EXIT
+1 set v@0 123
+2 hreturn 0 12
+3 hpush_jump 8 1 CONTINUE
+4 set v@0 223
+5 hreturn 1
+6 set v@0 1
+7 jump 12
+8 hpush_jump 6 1 EXIT
+9 set v@0 225
+10 hreturn 0 12
+11 jump 6
+12 hpop 3
+DROP PROCEDURE p1;
+#
+# Testing EXCEPTIONS in internal blocks
+#
+# No HANDLER declarations, no code, no exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+v:=123;
+BEGIN
+END;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set v@0 123
+1 jump 5
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+@v
+123
+DROP PROCEDURE p1;
+# No HANDLER declarations, no code, some exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+v:=123;
+BEGIN
+EXCEPTION
+WHEN 20002 THEN v:=335;
+END;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set v@0 123
+1 jump 2
+2 hpush_jump 5 1 EXIT
+3 set v@0 335
+4 hreturn 0 5
+5 hpop 1
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+@v
+123
+DROP PROCEDURE p1;
+# No HANDLER declarations, some code, no exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+v:=123;
+BEGIN
+v:=223;
+END;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set v@0 123
+1 set v@0 223
+2 jump 6
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+@v
+223
+DROP PROCEDURE p1;
+# No HANDLER declarations, some code, some exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+v:=123;
+BEGIN
+v:=223;
+EXCEPTION
+WHEN 20002 THEN v:=335;
+END;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set v@0 123
+1 jump 4
+2 set v@0 223
+3 jump 7
+4 hpush_jump 2 1 EXIT
+5 set v@0 335
+6 hreturn 0 7
+7 hpop 1
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+@v
+223
+DROP PROCEDURE p1;
+# Some HANDLER declarations, no code, no exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+v:=123;
+DECLARE
+EXIT HANDLER FOR 1000
+BEGIN
+v:=323;
+END;
+BEGIN
+END;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set v@0 123
+1 hpush_jump 4 1 EXIT
+2 set v@0 323
+3 hreturn 0 4
+4 hpop 1
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+@v
+123
+DROP PROCEDURE p1;
+# Some HANDLER declarations, no code, some exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+v:=123;
+DECLARE
+EXIT HANDLER FOR 1000
+BEGIN
+v:=323;
+END;
+BEGIN
+EXCEPTION
+WHEN 20002 THEN v:=335;
+END;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set v@0 123
+1 hpush_jump 4 1 EXIT
+2 set v@0 323
+3 hreturn 0 7
+4 hpush_jump 7 1 EXIT
+5 set v@0 335
+6 hreturn 0 7
+7 hpop 2
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+@v
+123
+DROP PROCEDURE p1;
+# Some HANDLER declarations, some code, no exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+v:=123;
+DECLARE
+EXIT HANDLER FOR 1000
+BEGIN
+v:=323;
+END;
+BEGIN
+v:= 324;
+END;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set v@0 123
+1 hpush_jump 4 1 EXIT
+2 set v@0 323
+3 hreturn 0 5
+4 set v@0 324
+5 hpop 1
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+@v
+324
+DROP PROCEDURE p1;
+# Some HANDLER declarations, some code, some exceptions
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+v:=123;
+DECLARE
+EXIT HANDLER FOR 1000
+BEGIN
+v:=323;
+END;
+BEGIN
+v:= 324;
+EXCEPTION WHEN 2002 THEN v:= 325;
+END;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set v@0 123
+1 hpush_jump 6 1 EXIT
+2 set v@0 323
+3 hreturn 0 9
+4 set v@0 324
+5 jump 9
+6 hpush_jump 4 1 EXIT
+7 set v@0 325
+8 hreturn 0 9
+9 hpop 2
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+@v
+324
+DROP PROCEDURE p1;
+#
+# Testing EXIT statement
+#
+CREATE FUNCTION f1 RETURN INT
+IS
+i INT := 0;
+BEGIN
+LOOP
+i:= i + 1;
+IF i >= 5 THEN
+EXIT;
+END IF;
+END LOOP;
+RETURN i;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set i@0 0
+1 set i@0 i@0 + 1
+2 jump_if_not 1(1) i@0 >= 5
+3 jump 4
+4 freturn int i@0
+SELECT f1() FROM DUAL;
+f1()
+5
+DROP FUNCTION f1;
+CREATE FUNCTION f1 RETURN INT
+IS
+i INT := 0;
+BEGIN
+LOOP
+i:= i + 1;
+EXIT WHEN i >=5;
+END LOOP;
+RETURN i;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set i@0 0
+1 set i@0 i@0 + 1
+2 jump_if_not 1(0) i@0 >= 5
+3 jump 4
+4 freturn int i@0
+SELECT f1() FROM DUAL;
+f1()
+5
+DROP FUNCTION f1;
+CREATE FUNCTION f1 RETURN INT
+IS
+i INT := 0;
+BEGIN
+LOOP
+BEGIN
+i:= i + 1;
+IF i >= 5 THEN
+EXIT;
+END IF;
+EXCEPTION
+WHEN OTHERS THEN i:= 1000;
+END;
+END LOOP;
+RETURN i;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set i@0 0
+1 jump 5
+2 set i@0 i@0 + 1
+3 jump_if_not 8(8) i@0 >= 5
+4 jump 10
+5 hpush_jump 2 1 EXIT
+6 set i@0 1000
+7 hreturn 0 8
+8 hpop 1
+9 jump 5
+10 freturn int i@0
+SELECT f1() FROM DUAL;
+f1()
+5
+DROP FUNCTION f1;
+CREATE PROCEDURE p1(a IN OUT INT)
+IS
+i INT := 0;
+BEGIN
+LOOP
+LOOP
+BEGIN
+i:= i + 1;
+IF i >=5 THEN
+EXIT;
+END IF;
+EXCEPTION
+WHEN OTHERS THEN a:=1000;
+END;
+END LOOP;
+i:= i + 100;
+EXIT;
+END LOOP;
+a:= i;
+EXCEPTION
+WHEN OTHERS THEN a:=11;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set i@1 0
+1 jump 14
+2 set i@1 i@1 + 1
+3 jump_if_not 8(8) i@1 >= 5
+4 jump 10
+5 hpush_jump 2 2 EXIT
+6 set a@0 1000
+7 hreturn 0 8
+8 hpop 1
+9 jump 5
+10 set i@1 i@1 + 100
+11 jump 12
+12 set a@0 i@1
+13 jump 17
+14 hpush_jump 5 2 EXIT
+15 set a@0 11
+16 hreturn 0 17
+17 hpop 1
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+@v
+105
+DROP PROCEDURE p1;
+# Testing RETURN in procedures
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+BEGIN
+IF a < 10 THEN
+BEGIN
+a:= a + 1;
+RETURN;
+END;
+END IF;
+a:= 200;
+EXCEPTION
+WHEN OTHERS THEN
+BEGIN
+a:= 100;
+RETURN;
+END;
+END;
+/
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 jump 6
+1 jump_if_not 4(4) a@0 < 10
+2 set a@0 a@0 + 1
+3 preturn
+4 set a@0 200
+5 jump 9
+6 hpush_jump 1 1 EXIT
+7 set a@0 100
+8 preturn
+9 hpop 1
+DROP PROCEDURE p1;
+# Testing FOR loop statement
+CREATE FUNCTION f1 (a INT, b INT) RETURN INT
+AS
+total INT := 0;
+BEGIN
+FOR i IN 1 .. a
+LOOP
+total:= total + i;
+IF i = b THEN
+EXIT;
+END IF;
+END LOOP;
+RETURN total;
+END
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set total@2 0
+1 set i@3 1
+2 set [upper_bound]@4 a@0
+3 jump_if_not 9(9) i@3 <= [upper_bound]@4
+4 set total@2 total@2 + i@3
+5 jump_if_not 7(7) i@3 = b@1
+6 jump 9
+7 set i@3 i@3 + 1
+8 jump 3
+9 freturn int total@2
+SELECT f1(3, 100) FROM DUAL;
+f1(3, 100)
+6
+SELECT f1(3, 2) FROM DUAL;
+f1(3, 2)
+3
+DROP FUNCTION f1;
+CREATE FUNCTION f1 (a INT, b INT) RETURN INT
+AS
+total INT := 0;
+BEGIN
+FOR i IN REVERSE a..1
+LOOP
+total:= total + i;
+IF i = b THEN
+EXIT;
+END IF;
+END LOOP;
+RETURN total;
+END
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set total@2 0
+1 set i@3 a@0
+2 set [upper_bound]@4 1
+3 jump_if_not 9(9) i@3 >= [upper_bound]@4
+4 set total@2 total@2 + i@3
+5 jump_if_not 7(7) i@3 = b@1
+6 jump 9
+7 set i@3 i@3 + -1
+8 jump 3
+9 freturn int total@2
+SELECT f1(3, 100) FROM DUAL;
+f1(3, 100)
+6
+SELECT f1(3, 2) FROM DUAL;
+f1(3, 2)
+5
+DROP FUNCTION f1;
+# Testing labeled FOR LOOP statement
+CREATE FUNCTION f1 (a INT, limita INT, b INT, limitb INT) RETURN INT
+AS
+total INT := 0;
+BEGIN
+<<la>>
+FOR ia IN 1 .. a
+LOOP
+total:= total + 1000;
+<<lb>>
+FOR ib IN 1 .. b
+LOOP
+total:= total + 1;
+EXIT lb WHEN ib = limitb;
+EXIT la WHEN ia = limita;
+END LOOP lb;
+END LOOP la;
+RETURN total;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set total@4 0
+1 set ia@5 1
+2 set [upper_bound]@6 a@0
+3 jump_if_not 17(17) ia@5 <= [upper_bound]@6
+4 set total@4 total@4 + 1000
+5 set ib@7 1
+6 set [upper_bound]@8 b@2
+7 jump_if_not 15(15) ib@7 <= [upper_bound]@8
+8 set total@4 total@4 + 1
+9 jump_if_not 11(0) ib@7 = limitb@3
+10 jump 15
+11 jump_if_not 13(0) ia@5 = limita@1
+12 jump 17
+13 set ib@7 ib@7 + 1
+14 jump 7
+15 set ia@5 ia@5 + 1
+16 jump 3
+17 freturn int total@4
+SELECT f1(2, 1, 2, 2) FROM DUAL;
+f1(2, 1, 2, 2)
+1001
+SELECT f1(2, 2, 2, 2) FROM DUAL;
+f1(2, 2, 2, 2)
+2003
+SELECT f1(2, 3, 2, 3) FROM DUAL;
+f1(2, 3, 2, 3)
+2004
+DROP FUNCTION f1;
+# Testing labeled ITERATE in a labeled FOR LOOP
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+total INT:= 0;
+BEGIN
+<<li>>
+FOR i IN 1 .. a
+LOOP
+total:= total + 1000;
+IF i = 5 THEN
+ITERATE li;
+END IF;
+total:= total + 1;
+END LOOP;
+RETURN total;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set total@1 0
+1 set i@2 1
+2 set [upper_bound]@3 a@0
+3 jump_if_not 11(11) i@2 <= [upper_bound]@3
+4 set total@1 total@1 + 1000
+5 jump_if_not 8(8) i@2 = 5
+6 set i@2 i@2 + 1
+7 jump 3
+8 set total@1 total@1 + 1
+9 set i@2 i@2 + 1
+10 jump 3
+11 freturn int total@1
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+f1(3) f1(4) f1(5) f1(6)
+3003 4004 5004 6005
+DROP FUNCTION f1;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+total INT:= 0;
+BEGIN
+<<li>>
+FOR i IN 1 .. a
+LOOP
+FOR j IN 1 .. 2
+LOOP
+total:= total + 1000;
+IF i = 5 THEN
+ITERATE li;
+END IF;
+total:= total + 1;
+END LOOP;
+END LOOP;
+RETURN total;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set total@1 0
+1 set i@2 1
+2 set [upper_bound]@3 a@0
+3 jump_if_not 16(16) i@2 <= [upper_bound]@3
+4 set j@4 1
+5 set [upper_bound]@5 2
+6 jump_if_not 14(14) j@4 <= [upper_bound]@5
+7 set total@1 total@1 + 1000
+8 jump_if_not 11(11) i@2 = 5
+9 set i@2 i@2 + 1
+10 jump 3
+11 set total@1 total@1 + 1
+12 set j@4 j@4 + 1
+13 jump 6
+14 set i@2 i@2 + 1
+15 jump 3
+16 freturn int total@1
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+f1(3) f1(4) f1(5) f1(6)
+6006 8008 9008 11010
+DROP FUNCTION f1;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+total INT:= 0;
+BEGIN
+<<lj>>
+FOR j IN 1 .. 2
+LOOP
+<<li>>
+FOR i IN 1 .. a
+LOOP
+total:= total + 1000;
+IF i = 5 THEN
+ITERATE li;
+END IF;
+total:= total + 1;
+END LOOP;
+END LOOP;
+RETURN total;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set total@1 0
+1 set j@2 1
+2 set [upper_bound]@3 2
+3 jump_if_not 16(16) j@2 <= [upper_bound]@3
+4 set i@4 1
+5 set [upper_bound]@5 a@0
+6 jump_if_not 14(14) i@4 <= [upper_bound]@5
+7 set total@1 total@1 + 1000
+8 jump_if_not 11(11) i@4 = 5
+9 set i@4 i@4 + 1
+10 jump 6
+11 set total@1 total@1 + 1
+12 set i@4 i@4 + 1
+13 jump 6
+14 set j@2 j@2 + 1
+15 jump 3
+16 freturn int total@1
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+f1(3) f1(4) f1(5) f1(6)
+6006 8008 10008 12010
+DROP FUNCTION f1;
+# Testing CONTINUE statement
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+total INT:= 0;
+BEGIN
+FOR i IN 1 .. a
+LOOP
+CONTINUE WHEN i=5;
+total:= total + 1;
+END LOOP;
+RETURN total;
+END;
+/
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set total@1 0
+1 set i@2 1
+2 set [upper_bound]@3 a@0
+3 jump_if_not 10(10) i@2 <= [upper_bound]@3
+4 jump_if_not 7(0) i@2 = 5
+5 set i@2 i@2 + 1
+6 jump 3
+7 set total@1 total@1 + 1
+8 set i@2 i@2 + 1
+9 jump 3
+10 freturn int total@1
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+f1(3) f1(4) f1(5) f1(6)
+3 4 4 5
+DROP FUNCTION f1;
+#
+# Start of MDEV-10597 Cursors with parameters
+#
+CREATE PROCEDURE p1(arg_value_a VARCHAR, arg_value_b VARCHAR,
+arg_pattern_a VARCHAR, arg_pattern_b VARCHAR)
+AS
+v_a VARCHAR(10);
+v_b VARCHAR(20);
+CURSOR c (p_value_a VARCHAR,
+p_value_b VARCHAR,
+p_pattern_a VARCHAR,
+p_pattern_b VARCHAR,
+p_limit_a INT,
+p_limit_b INT,
+p_unused TEXT) IS
+(SELECT p_value_a, p_value_b FROM DUAL
+WHERE p_value_a LIKE p_pattern_a LIMIT p_limit_a)
+UNION
+(SELECT p_value_b, p_value_a FROM DUAL
+WHERE p_value_b LIKE p_pattern_b LIMIT p_limit_b);
+BEGIN
+OPEN c(arg_value_a, (SELECT arg_value_b),
+arg_pattern_a, arg_pattern_b, 100, 101, 'x');
+LOOP
+FETCH c INTO v_a, v_b;
+EXIT WHEN c%NOTFOUND;
+SELECT v_a, v_b;
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1('aaa','bbb','aaa','bbb');
+v_a v_b
+aaa bbb
+v_a v_b
+bbb aaa
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set v_a@4 NULL
+1 set v_b@5 NULL
+2 cpush c@0
+3 set p_value_a@6 arg_value_a@0
+4 set p_value_b@7 (select arg_value_b@1)
+5 set p_pattern_a@8 arg_pattern_a@2
+6 set p_pattern_b@9 arg_pattern_b@3
+7 set p_limit_a@10 100
+8 set p_limit_b@11 101
+9 set p_unused@12 'x'
+10 copen c@0
+11 cfetch c@0 v_a@4 v_b@5
+12 jump_if_not 14(0) "c"%NOTFOUND
+13 jump 16
+14 stmt 0 "SELECT v_a, v_b"
+15 jump 11
+16 cclose c@0
+17 cpop 1
+DROP PROCEDURE p1;
+#
+# End of MDEV-10597 Cursors with parameters
+#
+#
+# MDEV-10914 ROW data type for stored routine variables
+#
+CREATE FUNCTION f1() RETURN INT
+AS
+a ROW(a INT, b INT);
+BEGIN
+a.b:= 200;
+RETURN a.b;
+END;
+$$
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 set a@0 NULL
+1 set a.b@0[1] 200
+2 freturn int a.b@0[1]
+SELECT f1();
+f1()
+200
+DROP FUNCTION f1;
+CREATE PROCEDURE p1
+AS
+rec ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10));
+BEGIN
+rec:= ROW(10,20.123456,30.123,'test');
+SELECT rec.a, rec.b, rec.c, rec.d;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set rec@0 NULL
+1 set rec@0 (10,20.123456,30.123,'test')
+2 stmt 0 "SELECT rec.a, rec.b, rec.c, rec.d"
+CALL p1;
+rec.a rec.b rec.c rec.d
+10 20.123456 30.123 test
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+rec ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10)) :=
+ROW(10,20.123456,30.123,'test');
+BEGIN
+SELECT rec.a, rec.b, rec.c, rec.d;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set rec@0 (10,20.123456,30.123,'test')
+1 stmt 0 "SELECT rec.a, rec.b, rec.c, rec.d"
+CALL p1;
+rec.a rec.b rec.c rec.d
+10 20.123456 30.123 test
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+rec1 ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10));
+rec2 ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10));
+BEGIN
+rec1:= ROW(10,20.123456,30.123,'test');
+rec2:= rec1;
+SELECT rec2.a, rec2.b, rec2.c, rec2.d;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set rec1@0 NULL
+1 set rec2@1 NULL
+2 set rec1@0 (10,20.123456,30.123,'test')
+3 set rec2@1 rec1@0
+4 stmt 0 "SELECT rec2.a, rec2.b, rec2.c, rec2.d"
+CALL p1;
+rec2.a rec2.b rec2.c rec2.d
+10 20.123456 30.123 test
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+rec1 ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10)) :=
+ROW(10,20.123456,30.123,'test');
+rec2 ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10)) := rec1;
+BEGIN
+SELECT rec2.a, rec2.b, rec2.c, rec2.d;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set rec1@0 (10,20.123456,30.123,'test')
+1 set rec2@1 rec1@0
+2 stmt 0 "SELECT rec2.a, rec2.b, rec2.c, rec2.d"
+CALL p1;
+rec2.a rec2.b rec2.c rec2.d
+10 20.123456 30.123 test
+DROP PROCEDURE p1;
+#
+# End of MDEV-10914 ROW data type for stored routine variables
+#
+#
+# MDEV-12133 sql_mode=ORACLE: table%ROWTYPE in variable declarations
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE;
+BEGIN
+rec1.a:= 10;
+rec1.b:= 'bbb';
+rec1.c:= 10e2;
+rec1.d:= 10.12;
+rec1.c:= rec1.d;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set rec1@0 NULL
+1 set rec1.a@0["a"] 10
+2 set rec1.b@0["b"] 'bbb'
+3 set rec1.c@0["c"] 10e2
+4 set rec1.d@0["d"] 10.12
+5 set rec1.c@0["c"] rec1.d@0["d"]
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# MDEV-12011 sql_mode=ORACLE: cursor%ROWTYPE in variable declarations
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+CURSOR cur2 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1,rec2 cur1%ROWTYPE;
+rec3 cur2%ROWTYPE;
+BEGIN
+rec1.a:= 10;
+rec1.b:= 'bbb';
+END;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 cpush cur1@0
+1 cpush cur2@1
+2 cursor_copy_struct cur1 rec1@0
+3 set rec1@0 NULL
+4 cursor_copy_struct cur1 rec2@1
+5 set rec2@1 NULL
+6 cursor_copy_struct cur2 rec3@2
+7 set rec3@2 NULL
+8 set rec1.a@0["a"] 10
+9 set rec1.b@0["b"] 'bbb'
+10 jump 11
+11 cpop 2
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# MDEV-10581 sql_mode=ORACLE: Explicit cursor FOR LOOP
+#
+CREATE PROCEDURE p1
+AS
+CURSOR cur0 IS SELECT 10 AS a, 'b0' AS b;
+CURSOR cur1 IS SELECT 10 AS a, 'b0' AS b;
+CURSOR cur2 IS SELECT 10 AS a, 'b0' AS b;
+BEGIN
+FOR rec1 IN cur1
+LOOP
+SELECT rec1.a, rec1.b;
+rec1.a:= 11;
+rec1.b:= 'b1';
+SELECT rec1.a, rec1.b;
+END LOOP;
+FOR rec0 IN cur0
+LOOP
+rec0.a:= 10;
+rec0.b:='b0';
+END LOOP;
+FOR rec2 IN cur2
+LOOP
+rec2.a:= 10;
+rec2.b:='b0';
+END LOOP;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 cpush cur0@0
+1 cpush cur1@1
+2 cpush cur2@2
+3 cursor_copy_struct cur1 rec1@0
+4 copen cur1@1
+5 cfetch cur1@1 rec1@0
+6 jump_if_not 13(13) "cur1"%FOUND
+7 stmt 0 "SELECT rec1.a, rec1.b"
+8 set rec1.a@0["a"] 11
+9 set rec1.b@0["b"] 'b1'
+10 stmt 0 "SELECT rec1.a, rec1.b"
+11 cfetch cur1@1 rec1@0
+12 jump 6
+13 cursor_copy_struct cur0 rec0@1
+14 copen cur0@0
+15 cfetch cur0@0 rec0@1
+16 jump_if_not 21(21) "cur0"%FOUND
+17 set rec0.a@1["a"] 10
+18 set rec0.b@1["b"] 'b0'
+19 cfetch cur0@0 rec0@1
+20 jump 16
+21 cursor_copy_struct cur2 rec2@2
+22 copen cur2@2
+23 cfetch cur2@2 rec2@2
+24 jump_if_not 29(29) "cur2"%FOUND
+25 set rec2.a@2["a"] 10
+26 set rec2.b@2["b"] 'b0'
+27 cfetch cur2@2 rec2@2
+28 jump 24
+29 cpop 3
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+CURSOR cur0 IS SELECT 10 AS a, 'b0' AS b;
+BEGIN
+FOR rec0 IN cur0
+LOOP
+DECLARE
+CURSOR cur1 IS SELECT 11 AS a, 'b1' AS b;
+BEGIN
+rec0.a:= 11;
+rec0.b:= 'b0';
+FOR rec1 IN cur1
+LOOP
+rec1.a:= 11;
+rec1.b:= 'b1';
+DECLARE
+CURSOR cur2 IS SELECT 12 AS a, 'b2' AS b;
+BEGIN
+FOR rec2 IN cur2
+LOOP
+rec2.a:=12;
+rec2.b:='b2';
+END LOOP;
+END;
+END LOOP;
+END;
+END LOOP;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 cpush cur0@0
+1 cursor_copy_struct cur0 rec0@0
+2 copen cur0@0
+3 cfetch cur0@0 rec0@0
+4 jump_if_not 29(29) "cur0"%FOUND
+5 cpush cur1@1
+6 set rec0.a@0["a"] 11
+7 set rec0.b@0["b"] 'b0'
+8 cursor_copy_struct cur1 rec1@1
+9 copen cur1@1
+10 cfetch cur1@1 rec1@1
+11 jump_if_not 26(26) "cur1"%FOUND
+12 set rec1.a@1["a"] 11
+13 set rec1.b@1["b"] 'b1'
+14 cpush cur2@2
+15 cursor_copy_struct cur2 rec2@2
+16 copen cur2@2
+17 cfetch cur2@2 rec2@2
+18 jump_if_not 23(23) "cur2"%FOUND
+19 set rec2.a@2["a"] 12
+20 set rec2.b@2["b"] 'b2'
+21 cfetch cur2@2 rec2@2
+22 jump 18
+23 cpop 1
+24 cfetch cur1@1 rec1@1
+25 jump 11
+26 cpop 1
+27 cfetch cur0@0 rec0@0
+28 jump 4
+29 cpop 1
+DROP PROCEDURE p1;
+#
+# MDEV-12098 sql_mode=ORACLE: Implicit cursor FOR loop
+#
+CREATE PROCEDURE p1
+AS
+BEGIN
+FOR rec1 IN (SELECT 11 AS a, 'b1' AS b)
+LOOP
+SELECT rec1.a, rec1.b;
+rec1.a:= 11;
+rec1.b:= 'b1';
+SELECT rec1.a, rec1.b;
+END LOOP;
+FOR rec0 IN (SELECT 10 AS a, 'b0' AS b)
+LOOP
+rec0.a:= 10;
+rec0.b:='b0';
+END LOOP;
+FOR rec2 IN (SELECT 12 AS a, 'b2' AS b)
+LOOP
+rec2.a:= 10;
+rec2.b:='b0';
+END LOOP;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 cpush [implicit_cursor]@0
+1 cursor_copy_struct [implicit_cursor] rec1@0
+2 copen [implicit_cursor]@0
+3 cfetch [implicit_cursor]@0 rec1@0
+4 jump_if_not 11(11) "[implicit_cursor]"%FOUND
+5 stmt 0 "SELECT rec1.a, rec1.b"
+6 set rec1.a@0["a"] 11
+7 set rec1.b@0["b"] 'b1'
+8 stmt 0 "SELECT rec1.a, rec1.b"
+9 cfetch [implicit_cursor]@0 rec1@0
+10 jump 4
+11 cpop 1
+12 cpush [implicit_cursor]@0
+13 cursor_copy_struct [implicit_cursor] rec0@1
+14 copen [implicit_cursor]@0
+15 cfetch [implicit_cursor]@0 rec0@1
+16 jump_if_not 21(21) "[implicit_cursor]"%FOUND
+17 set rec0.a@1["a"] 10
+18 set rec0.b@1["b"] 'b0'
+19 cfetch [implicit_cursor]@0 rec0@1
+20 jump 16
+21 cpop 1
+22 cpush [implicit_cursor]@0
+23 cursor_copy_struct [implicit_cursor] rec2@2
+24 copen [implicit_cursor]@0
+25 cfetch [implicit_cursor]@0 rec2@2
+26 jump_if_not 31(31) "[implicit_cursor]"%FOUND
+27 set rec2.a@2["a"] 10
+28 set rec2.b@2["b"] 'b0'
+29 cfetch [implicit_cursor]@0 rec2@2
+30 jump 26
+31 cpop 1
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+BEGIN
+FOR rec0 IN (SELECT 10 AS a, 'b0' AS b)
+LOOP
+rec0.a:= 11;
+rec0.b:= 'b0';
+FOR rec1 IN (SELECT 11 AS a, 'b1' AS b)
+LOOP
+rec1.a:= 11;
+rec1.b:= 'b1';
+FOR rec2 IN (SELECT 12 AS a, 'b2' AS b)
+LOOP
+rec2.a:=12;
+rec2.b:='b2';
+END LOOP;
+END LOOP;
+END LOOP;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 cpush [implicit_cursor]@0
+1 cursor_copy_struct [implicit_cursor] rec0@0
+2 copen [implicit_cursor]@0
+3 cfetch [implicit_cursor]@0 rec0@0
+4 jump_if_not 29(29) "[implicit_cursor]"%FOUND
+5 set rec0.a@0["a"] 11
+6 set rec0.b@0["b"] 'b0'
+7 cpush [implicit_cursor]@1
+8 cursor_copy_struct [implicit_cursor] rec1@1
+9 copen [implicit_cursor]@1
+10 cfetch [implicit_cursor]@1 rec1@1
+11 jump_if_not 26(26) "[implicit_cursor]"%FOUND
+12 set rec1.a@1["a"] 11
+13 set rec1.b@1["b"] 'b1'
+14 cpush [implicit_cursor]@2
+15 cursor_copy_struct [implicit_cursor] rec2@2
+16 copen [implicit_cursor]@2
+17 cfetch [implicit_cursor]@2 rec2@2
+18 jump_if_not 23(23) "[implicit_cursor]"%FOUND
+19 set rec2.a@2["a"] 12
+20 set rec2.b@2["b"] 'b2'
+21 cfetch [implicit_cursor]@2 rec2@2
+22 jump 18
+23 cpop 1
+24 cfetch [implicit_cursor]@1 rec1@1
+25 jump 11
+26 cpop 1
+27 cfetch [implicit_cursor]@0 rec0@0
+28 jump 4
+29 cpop 1
+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;
+#
+# MDEV-12441 Variables declared after cursors with parameters lose values
+#
+CREATE PROCEDURE p1() AS
+x0 INT:=100;
+CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+x1 INT:=101;
+BEGIN
+OPEN cur(10,11);
+CLOSE cur;
+SELECT x0, x1;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set x0@0 100
+1 set x1@3 101
+2 cpush cur@0
+3 set cp1@1 10
+4 set cp2@2 11
+5 copen cur@0
+6 cclose cur@0
+7 stmt 0 "SELECT x0, x1"
+8 cpop 1
+CALL p1();
+x0 x1
+100 101
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS
+x0 INT:=100;
+CURSOR cur0(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+x1 INT:=101;
+CURSOR cur1(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+x2 INT:=102;
+CURSOR cur2(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+x3 INT:=103;
+BEGIN
+OPEN cur0(0,1);
+CLOSE cur0;
+SELECT x0, x1, x2, x3;
+OPEN cur1(10,11);
+CLOSE cur1;
+SELECT x0, x1, x2, x3;
+OPEN cur2(20,21);
+CLOSE cur2;
+SELECT x0, x1, x2, x3;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set x0@0 100
+1 set x1@3 101
+2 set x2@6 102
+3 set x3@9 103
+4 cpush cur0@0
+5 cpush cur1@1
+6 cpush cur2@2
+7 set cp1@1 0
+8 set cp2@2 1
+9 copen cur0@0
+10 cclose cur0@0
+11 stmt 0 "SELECT x0, x1, x2, x3"
+12 set cp1@4 10
+13 set cp2@5 11
+14 copen cur1@1
+15 cclose cur1@1
+16 stmt 0 "SELECT x0, x1, x2, x3"
+17 set cp1@7 20
+18 set cp2@8 21
+19 copen cur2@2
+20 cclose cur2@2
+21 stmt 0 "SELECT x0, x1, x2, x3"
+22 cpop 3
+CALL p1();
+x0 x1 x2 x3
+100 101 102 103
+x0 x1 x2 x3
+100 101 102 103
+x0 x1 x2 x3
+100 101 102 103
+DROP PROCEDURE p1;
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1() AS
+x0 INT:=100;
+CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+x1 t1.a%TYPE:=101;
+BEGIN
+OPEN cur(10,11);
+CLOSE cur;
+SELECT x0, x1;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set x0@0 100
+1 set x1@3 101
+2 cpush cur@0
+3 set cp1@1 10
+4 set cp2@2 11
+5 copen cur@0
+6 cclose cur@0
+7 stmt 0 "SELECT x0, x1"
+8 cpop 1
+CALL p1();
+x0 x1
+100 101
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE PROCEDURE p1() AS
+x0 INT:=100;
+CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+x1 ROW(a INT,b INT):=ROW(101,102);
+BEGIN
+OPEN cur(10,11);
+CLOSE cur;
+SELECT x0, x1.a, x1.b;
+END;
+$$
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 set x0@0 100
+1 set x1@3 (101,102)
+2 cpush cur@0
+3 set cp1@1 10
+4 set cp2@2 11
+5 copen cur@0
+6 cclose cur@0
+7 stmt 0 "SELECT x0, x1.a, x1.b"
+8 cpop 1
+CALL p1();
+x0 x1.a x1.b
+100 101 102
+DROP PROCEDURE p1;
diff --git a/mysql-test/suite/compat/oracle/r/sp-cursor-decl.result b/mysql-test/suite/compat/oracle/r/sp-cursor-decl.result
new file mode 100644
index 00000000000..b75b5d5be9d
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp-cursor-decl.result
@@ -0,0 +1,290 @@
+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(20) DEFAULT NULL,
+ "b" varchar(11) DEFAULT NULL,
+ "c" double DEFAULT NULL
+)
+DROP PROCEDURE p1;
+#
+# MDEV-12916 Wrong column data type for an INT field of a cursor-anchored ROW variable
+#
+CREATE PROCEDURE p1
+AS
+a INT DEFAULT 10;
+CURSOR cur1 IS SELECT a;
+rec1 cur1%ROWTYPE;
+BEGIN
+CREATE TABLE t1 AS SELECT rec1.a;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+END;
+$$
+CALL p1();
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "rec1.a" int(11) DEFAULT NULL
+)
+DROP PROCEDURE p1;
diff --git a/mysql-test/suite/compat/oracle/r/sp-cursor-rowtype.result b/mysql-test/suite/compat/oracle/r/sp-cursor-rowtype.result
new file mode 100644
index 00000000000..726f8bcf9ca
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp-cursor-rowtype.result
@@ -0,0 +1,1332 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-12011 sql_mode=ORACLE: cursor%ROWTYPE in variable declarations
+#
+#
+# A complete working example
+#
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+CREATE TABLE t2 LIKE t1;
+INSERT INTO t1 VALUES (10,'b10');
+INSERT INTO t1 VALUES (20,'b20');
+INSERT INTO t1 VALUES (30,'b30');
+CREATE PROCEDURE p1 AS
+CURSOR c IS SELECT a,b FROM t1;
+BEGIN
+DECLARE
+rec c%ROWTYPE;
+BEGIN
+OPEN c;
+LOOP
+FETCH c INTO rec;
+EXIT WHEN c%NOTFOUND;
+SELECT 'rec=(' || rec.a ||','|| rec.b||')' AS c FROM dual;
+INSERT INTO t2 VALUES (rec.a, rec.b);
+END LOOP;
+CLOSE c;
+END;
+END;
+$$
+CALL p1();
+c
+rec=(10,b10)
+c
+rec=(20,b20)
+c
+rec=(30,b30)
+SELECT * FROM t2;
+a b
+10 b10
+20 b20
+30 b30
+DROP PROCEDURE p1;
+DROP TABLE t2;
+DROP TABLE t1;
+#
+# cursor%ROWTYPE referring to a table in a non-existing database
+#
+CREATE PROCEDURE p1()
+AS
+CURSOR cur IS SELECT * FROM tes2.t1;
+BEGIN
+DECLARE
+rec cur%ROWTYPE;
+BEGIN
+NULL;
+END;
+END;
+$$
+CALL p1();
+ERROR 42S02: Table 'tes2.t1' doesn't exist
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CALL p1();
+ERROR 42S02: Table 'tes2.t1' doesn't exist
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# cursor%ROWTYPE referring to a table in the current database
+#
+CREATE PROCEDURE p1()
+AS
+CURSOR cur IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec cur%ROWTYPE;
+BEGIN
+CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+END;
+$$
+CALL p1();
+ERROR 42S02: Table 'test.t1' doesn't exist
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CALL p1();
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "rec.a" int(11) DEFAULT NULL,
+ "rec.b" varchar(10) DEFAULT NULL,
+ "rec.c" double DEFAULT NULL,
+ "rec.d" decimal(10,0) DEFAULT NULL
+)
+DROP TABLE t1;
+CALL p1();
+ERROR 42S02: Table 'test.t1' doesn't exist
+DROP PROCEDURE p1;
+#
+# cursor%ROWTYPE referring to a table in an explicitly specified database
+#
+CREATE PROCEDURE p1()
+AS
+CURSOR cur IS SELECT * FROM test.t1;
+BEGIN
+DECLARE
+rec cur%ROWTYPE;
+BEGIN
+CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+END;
+$$
+CALL p1();
+ERROR 42S02: Table 'test.t1' doesn't exist
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CALL p1();
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "rec.a" int(11) DEFAULT NULL,
+ "rec.b" varchar(10) DEFAULT NULL,
+ "rec.c" double DEFAULT NULL,
+ "rec.d" decimal(10,0) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Cursor%ROWTYPE referring to a view in the current database
+#
+CREATE PROCEDURE p1()
+AS
+CURSOR cur IS SELECT * FROM v1;
+BEGIN
+DECLARE
+rec cur%ROWTYPE;
+BEGIN
+CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+END;
+$$
+CALL p1();
+ERROR 42S02: Table 'test.v1' doesn't exist
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CREATE VIEW v1 AS SELECT * FROM t1;
+CALL p1();
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "rec.a" int(11) DEFAULT NULL,
+ "rec.b" varchar(10) DEFAULT NULL,
+ "rec.c" double DEFAULT NULL,
+ "rec.d" decimal(10,0) DEFAULT NULL
+)
+DROP VIEW v1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# cursor%ROWTYPE referring to a view in an explicitly specified database
+#
+CREATE PROCEDURE p1()
+AS
+CURSOR cur IS SELECT * FROM test.v1;
+BEGIN
+DECLARE
+rec cur%ROWTYPE;
+BEGIN
+CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+END;
+$$
+CALL p1();
+ERROR 42S02: Table 'test.v1' doesn't exist
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CREATE VIEW v1 AS SELECT * FROM t1;
+CALL p1();
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "rec.a" int(11) DEFAULT NULL,
+ "rec.b" varchar(10) DEFAULT NULL,
+ "rec.c" double DEFAULT NULL,
+ "rec.d" decimal(10,0) DEFAULT NULL
+)
+DROP VIEW v1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Checking that all cursor%ROWTYPE fields are NULL by default
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE;
+BEGIN
+SELECT rec1.a, rec1.b, rec1.c, rec1.d;
+END;
+END;
+$$
+CALL p1();
+rec1.a rec1.b rec1.c rec1.d
+NULL NULL NULL NULL
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# A cursor%ROWTYPE variable with a ROW expression as a default
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE := ROW(10,'bbb');
+BEGIN
+SELECT rec1.a, rec1.b;
+END;
+END;
+$$
+CALL p1();
+rec1.a rec1.b
+10 bbb
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# A cursor%ROWTYPE variable with an incompatible ROW expression as a default
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE := ROW(10,'bbb','ccc');
+BEGIN
+SELECT rec1.a, rec1.b;
+END;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# A cursor%ROWTYPE variable with a ROW variable as a default
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+CURSOR cur IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 ROW(a INT, b VARCHAR(10)):= ROW(10,'bbb');
+rec2 cur%ROWTYPE := rec1;
+BEGIN
+SELECT rec2.a, rec2.b;
+END;
+END;
+$$
+CALL p1();
+rec2.a rec2.b
+10 bbb
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# A ROW variable using a cursor%ROWTYPE variable as a default
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE := ROW(10,'bbb');
+rec2 ROW(a INT, b VARCHAR(10)):= rec1;
+BEGIN
+SELECT rec2.a, rec2.b;
+END;
+END;
+$$
+CALL p1();
+rec2.a rec2.b
+10 bbb
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Assigning cursor%ROWTYPE variables with a different column count
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE);
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE;
+rec2 cur2%ROWTYPE;
+BEGIN
+rec2:=rec1;
+END;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE;
+rec2 cur2%ROWTYPE;
+BEGIN
+rec1:=rec2;
+END;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 3 column(s)
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Assigning compatible cursor%ROWTYPE variables (equal number of fields)
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (x INT, y VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE;
+rec2 cur2%ROWTYPE;
+BEGIN
+rec1.a:= 10;
+rec1.b:= 'bbb';
+rec2:=rec1;
+SELECT rec2.x, rec2.y;
+END;
+END;
+$$
+CALL p1();
+rec2.x rec2.y
+10 bbb
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Assigning between incompatible cursor%ROWTYPE and explicit ROW variables
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE;
+rec2 ROW(x INT,y INT,z INT);
+BEGIN
+rec2.x:= 10;
+rec2.y:= 20;
+rec2.z:= 30;
+rec1:= rec2;
+END;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Assigning between compatible cursor%ROWTYPE and explicit ROW variables
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE;
+rec2 ROW(x INT,y INT);
+BEGIN
+rec2.x:= 10;
+rec2.y:= 20;
+rec1:= rec2;
+SELECT rec1.a, rec1.b;
+rec1.a:= 11;
+rec1.b:= 21;
+rec2:= rec1;
+SELECT rec2.x, rec2.y;
+END;
+END;
+$$
+CALL p1();
+rec1.a rec1.b
+10 20
+rec2.x rec2.y
+11 21
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Assigning cursor%ROWTYPE from a ROW expression
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE;
+BEGIN
+rec1:= ROW(10,20);
+SELECT rec1.a, rec1.b;
+END;
+END;
+$$
+CALL p1();
+rec1.a rec1.b
+10 20
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Fetching a cursor into a cursor%ROWTYPE variable with a wrong field count
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'bb1',111.111e2, 12.31);
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+DECLARE
+rec2 cur2%ROWTYPE;
+BEGIN
+OPEN cur1;
+FETCH cur1 INTO rec2;
+CLOSE cur1;
+END;
+END;
+$$
+CALL p1();
+ERROR HY000: Incorrect number of FETCH variables
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Fetching a cursor into a cursor%ROWTYPE variable
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE TABLE t2 LIKE t1;
+INSERT INTO t1 VALUES (10,'bb1',111.111e2, 12.31);
+INSERT INTO t1 VALUES (20,'bb2',222.222e2, 12.32);
+INSERT INTO t1 VALUES (30,'bb3',333.333e2, 12.33);
+CREATE PROCEDURE p1()
+AS
+CURSOR cur IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec cur%ROWTYPE;
+BEGIN
+OPEN cur;
+LOOP
+FETCH cur INTO rec;
+EXIT WHEN cur%NOTFOUND;
+SELECT rec.a, rec.b, rec.c, rec.d;
+INSERT INTO t2 VALUES (rec.a, rec.b, rec.c, rec.d);
+END LOOP;
+CLOSE cur;
+END;
+END;
+$$
+CALL p1();
+rec.a rec.b rec.c rec.d
+10 bb1 11111.1 12.31
+rec.a rec.b rec.c rec.d
+20 bb2 22222.2 12.32
+rec.a rec.b rec.c rec.d
+30 bb3 33333.3 12.33
+SELECT * FROM t2;
+a b c d
+10 bb1 11111.1 12.31
+20 bb2 22222.2 12.32
+30 bb3 33333.3 12.33
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Fetching a cursor into a cursor%ROWTYPE variable, cur%ROWTYPE declared inside the LOOP
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE TABLE t2 LIKE t1;
+INSERT INTO t1 VALUES (10,'bb1',111.111e2, 12.31);
+INSERT INTO t1 VALUES (20,'bb2',222.222e2, 12.32);
+INSERT INTO t1 VALUES (30,'bb3',333.333e2, 12.33);
+CREATE PROCEDURE p1()
+AS
+CURSOR cur IS SELECT * FROM t1;
+BEGIN
+OPEN cur;
+LOOP
+DECLARE
+rec cur%ROWTYPE;
+BEGIN
+FETCH cur INTO rec;
+EXIT WHEN cur%NOTFOUND;
+SELECT rec.a, rec.b, rec.c, rec.d;
+INSERT INTO t2 VALUES (rec.a, rec.b, rec.c, rec.d);
+END;
+END LOOP;
+CLOSE cur;
+END;
+$$
+CALL p1();
+rec.a rec.b rec.c rec.d
+10 bb1 11111.1 12.31
+rec.a rec.b rec.c rec.d
+20 bb2 22222.2 12.32
+rec.a rec.b rec.c rec.d
+30 bb3 33333.3 12.33
+SELECT * FROM t2;
+a b c d
+10 bb1 11111.1 12.31
+20 bb2 22222.2 12.32
+30 bb3 33333.3 12.33
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Fetching a cursor into a cursor%ROWTYPE variable with different column names
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (x INT, y VARCHAR(10));
+INSERT INTO t1 VALUES (10,'bbb');
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+DECLARE
+rec2 cur2%ROWTYPE;
+BEGIN
+OPEN cur1;
+FETCH cur1 INTO rec2;
+SELECT rec2.x, rec2.y;
+CLOSE cur1;
+END;
+END;
+$$
+CALL p1();
+rec2.x rec2.y
+10 bbb
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Fetching a cursor into a cursor%ROWTYPE variable, with truncation
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (a INT, b INT);
+INSERT INTO t1 VALUES (10,'11x');
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+DECLARE
+rec2 cur2%ROWTYPE;
+BEGIN
+OPEN cur1;
+FETCH cur1 INTO rec2;
+SELECT rec2.a, rec2.b;
+CLOSE cur1;
+END;
+END;
+$$
+CALL p1();
+rec2.a rec2.b
+10 11
+Warnings:
+Warning 1265 Data truncated for column 'b' at row 1
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# cursor%ROWTYPE variables are not allowed in LIMIT
+#
+CREATE TABLE t1 (a INT, b INT);
+INSERT INTO t1 VALUES (1,2);
+CREATE PROCEDURE p1()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE:=(1,2);
+BEGIN
+SELECT * FROM t1 LIMIT rec1.a;
+END;
+END;
+$$
+ERROR HY000: A variable of a non-integer based type in LIMIT clause
+DROP TABLE t1;
+#
+# cursor%ROWTYPE variable fields as OUT parameters
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1(a OUT INT,b OUT VARCHAR(10))
+AS
+BEGIN
+a:=10;
+b:='bb';
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE;
+BEGIN
+CALL p1(rec1.a, rec1.b);
+SELECT rec1.a, rec1.b;
+END;
+END;
+$$
+CALL p2();
+rec1.a rec1.b
+10 bb
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Passing the entire cursor%ROWTYPE variable
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1(a ROW(a INT, b VARCHAR(10)))
+AS
+BEGIN
+SELECT a.a, a.b;
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+CURSOR cur IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 cur%ROWTYPE:= ROW(10,'bb');
+BEGIN
+CALL p1(rec1);
+END;
+END;
+$$
+CALL p2();
+a.a a.b
+10 bb
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Passing the entire cursor%ROWTYPE variable as an OUT parameter
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1(a OUT ROW(a INT, b VARCHAR(10)))
+AS
+BEGIN
+a:= ROW(10,'bb');
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+CURSOR cur IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec1 cur%ROWTYPE;
+BEGIN
+CALL p1(rec1);
+SELECT rec1.a, rec1.b;
+END;
+END;
+$$
+CALL p2();
+rec1.a rec1.b
+10 bb
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Assigning a cursor%ROWTYPE field to an OUT parameter
+#
+CREATE PROCEDURE p1 (res IN OUT INTEGER)
+AS
+a INT:=10;
+CURSOR cur1 IS SELECT a FROM DUAL;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE;
+BEGIN
+OPEN cur1;
+FETCH cur1 INTO rec1;
+CLOSE cur1;
+res:=rec1.a;
+END;
+END;
+$$
+CALL p1(@res);
+SELECT @res;
+@res
+10
+SET @res=NULL;
+DROP PROCEDURE p1;
+#
+# Testing Item_splocal_row_field_by_name::print
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec cur1%ROWTYPE:=ROW(10,'bb');
+BEGIN
+EXPLAIN EXTENDED SELECT rec.a, rec.b;
+END;
+END;
+$$
+CALL p1();
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select rec.a@0["a"] AS "rec.a",rec.b@0["b"] AS "rec.b"
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Run time error in the cursor statement
+#
+CREATE PROCEDURE p1
+AS
+CURSOR cur1 IS SELECT
+10 AS a,
+CONCAT(_latin1'a' COLLATE latin1_bin,
+_latin1'a' COLLATE latin1_swedish_ci) AS b;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE;
+BEGIN
+OPEN cur1;
+FETCH cur1 INTO rec1;
+CLOSE cur1;
+SELECT a,b;
+END;
+END;
+$$
+CALL p1();
+ERROR HY000: Illegal mix of collations (latin1_bin,EXPLICIT) and (latin1_swedish_ci,EXPLICIT) for operation 'concat_operator_oracle'
+DROP PROCEDURE p1;
+#
+# Non-existing field
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec cur1%ROWTYPE;
+BEGIN
+SELECT rec.c;
+END;
+END;
+$$
+CALL p1();
+ERROR HY000: Row variable 'rec' does not have a field 'c'
+ALTER TABLE t1 ADD c INT;
+ALTER PROCEDURE p1 COMMENT 'test';
+CALL p1();
+rec.c
+NULL
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Testing that field names are case insensitive
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1
+AS
+CURSOR cur IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec cur%ROWTYPE:=ROW(10,'bb');
+BEGIN
+SELECT rec.A, rec.B;
+END;
+END;
+$$
+CALL p1();
+rec.A rec.B
+10 bb
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Testing that cursor%ROWTYPE uses temporary tables vs shadowed real tables
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TEMPORARY TABLE t1 (x INT, y VARCHAR(10));
+CREATE PROCEDURE p1
+AS
+CURSOR cur IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec cur%ROWTYPE:=ROW(10,'bb');
+BEGIN
+SELECT rec.A, rec.B;
+END;
+END;
+$$
+CALL p1();
+ERROR HY000: Row variable 'rec' does not have a field 'A'
+DROP TEMPORARY TABLE t1;
+ALTER PROCEDURE p1 COMMENT 'test';
+CALL p1();
+rec.A rec.B
+10 bb
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Testing that the structure of cursor%ROWTYPE variables is determined at the CURSOR instantiation time
+#
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+CURSOR cur IS SELECT * FROM t1;
+BEGIN
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b VARCHAR(32), c INT);
+DECLARE
+rec cur%ROWTYPE; -- This has a column "c"
+ BEGIN
+rec.c:=10;
+END;
+END;
+$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+CURSOR cur IS SELECT * FROM t1;
+BEGIN
+DECLARE
+rec cur%ROWTYPE; -- This does not have a column "c"
+ BEGIN
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b VARCHAR(32), c INT);
+rec.c:=10;
+END;
+END;
+$$
+CALL p1();
+ERROR HY000: Row variable 'rec' does not have a field 'c'
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Duplicate field nams in a cursor referenced by %ROWTYPE
+#
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT);
+CREATE PROCEDURE p1 AS
+CURSOR cur IS SELECT * FROM t1, t2;
+BEGIN
+DECLARE
+rec cur%ROWTYPE;
+BEGIN
+SELECT rec.a;
+rec.a:=10;
+END;
+END;
+$$
+CALL p1();
+ERROR 42S21: Duplicate column name 'a'
+DROP PROCEDURE p1;
+DROP TABLE t2;
+DROP TABLE t1;
+#
+# Tricky field names a cursor referenced by %ROWTYPE
+#
+SET NAMES utf8;
+CREATE TABLE t1 (a VARCHAR(10));
+INSERT INTO t1 VALUES ('a');
+CREATE PROCEDURE p1 AS
+CURSOR cur IS SELECT a, CONCAT(a,'a'), CONCAT(a,'ö') FROM t1;
+BEGIN
+DECLARE
+rec cur%ROWTYPE;
+BEGIN
+OPEN cur;
+FETCH cur INTO rec;
+CLOSE cur;
+SELECT rec.a, rec."CONCAT(a,'a')", rec."CONCAT(a,'ö')";
+END;
+END;
+$$
+CALL p1();
+rec.a rec."CONCAT(a,'a')" rec."CONCAT(a,'ö')"
+a aa aö
+DROP PROCEDURE p1;
+DROP TABLE t1;
+SET NAMES latin1;
+#
+# Using definitions recursively (cursor%ROWTYPE variables in another cursor SELECT)
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'b1'),(20,'b2'),(30,'b3');
+CREATE PROCEDURE p1 AS
+CURSOR cur1 IS SELECT a,b FROM t1;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE:=ROW(0,'b0');
+CURSOR cur2 IS SELECT rec1.a AS a, rec1.b AS b FROM t1;
+BEGIN
+DECLARE
+rec2 cur2%ROWTYPE;
+BEGIN
+OPEN cur2;
+LOOP
+FETCH cur2 INTO rec2;
+EXIT WHEN cur2%NOTFOUND;
+SELECT rec2.a, rec2.b;
+END LOOP;
+CLOSE cur2;
+END;
+END;
+END;
+$$
+CALL p1();
+rec2.a rec2.b
+0 b0
+rec2.a rec2.b
+0 b0
+rec2.a rec2.b
+0 b0
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Testing queries with auto-generated Items.
+# An instance of Item_func_conv_charset is created during the below SELECT query.
+# We check here that during an implicit cursor OPEN
+# done in sp_instr_cursor_copy_struct::exec_core()
+# all temporary Items are created on a proper memory root and are safely destroyed.
+#
+CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1, b VARCHAR(10) CHARACTER SET utf8);
+INSERT INTO t1 VALUES (0xFF, 'a');
+CREATE PROCEDURE p1
+AS
+CURSOR cur1 IS SELECT CONCAT(a,b) AS c FROM t1;
+BEGIN
+DECLARE
+rec1 cur1%ROWTYPE;
+BEGIN
+OPEN cur1;
+FETCH cur1 INTO rec1;
+CLOSE cur1;
+SELECT HEX(rec1.c);
+END;
+END;
+$$
+CALL p1();
+HEX(rec1.c)
+C3BF61
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# MDEV-10581 sql_mode=ORACLE: Explicit cursor FOR LOOP
+#
+# IN followed by a non-identifier
+CREATE PROCEDURE p1 AS
+CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+FOR rec IN 10
+LOOP
+NULL;
+END LOOP;
+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 'LOOP
+NULL;
+END LOOP;
+END' at line 6
+# IN followed by a quoted identifier: table.column
+CREATE PROCEDURE p1 AS
+CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+FOR rec IN c1.c2
+LOOP
+NULL;
+END LOOP;
+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 'LOOP
+NULL;
+END LOOP;
+END' at line 6
+# IN followed by a quoted identifier: .table.column
+CREATE PROCEDURE p1 AS
+CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+FOR rec IN .c1.c2
+LOOP
+NULL;
+END LOOP;
+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 'LOOP
+NULL;
+END LOOP;
+END' at line 6
+# IN followed by a quoted identifier: schema.table.column
+CREATE PROCEDURE p1 AS
+CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+FOR rec IN c1.c2.c3
+LOOP
+NULL;
+END LOOP;
+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 'LOOP
+NULL;
+END LOOP;
+END' at line 6
+# IN followed by an unknown cursor name
+CREATE PROCEDURE p1 AS
+CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+FOR rec IN c2
+LOOP
+NULL;
+END LOOP;
+END;
+$$
+ERROR 42000: Undefined CURSOR: c2
+# Make sure "rec" shadows other declarations outside the loop
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10, 'b0');
+CREATE PROCEDURE p1 AS
+rec INT:=10;
+CURSOR c1 IS SELECT a,b FROM t1;
+BEGIN
+FOR rec IN c1
+LOOP
+SELECT rec.a;
+END LOOP;
+SELECT rec;
+END;
+$$
+CALL p1;
+rec.a
+10
+rec
+10
+DROP PROCEDURE p1;
+DROP TABLE t1;
+# Make sure "rec" is not visible after END LOOP
+CREATE PROCEDURE p1 AS
+CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+FOR rec IN c1
+LOOP
+NULL;
+END LOOP;
+rec.a:= 10;
+END;
+$$
+ERROR HY000: Unknown structured system variable or ROW routine variable 'rec'
+# Make sure that duplicate column names are not allowed
+CREATE PROCEDURE p1 AS
+CURSOR cur IS SELECT 'a' AS a, 'A' as a;
+BEGIN
+FOR rec IN cur
+LOOP
+NULL;
+END LOOP;
+END;
+$$
+CALL p1;
+ERROR 42S21: Duplicate column name 'a'
+DROP PROCEDURE p1;
+# A complete working example
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'b0');
+INSERT INTO t1 VALUES (11,'b1');
+INSERT INTO t1 VALUES (12,'b2');
+CREATE TABLE t2 LIKE t1;
+CREATE TABLE t3 LIKE t1;
+CREATE PROCEDURE p1 AS
+CURSOR cur IS SELECT a, b FROM t1;
+BEGIN
+FOR rec IN cur
+LOOP
+SELECT rec.a, rec.b;
+INSERT INTO t2 VALUES (rec.a, rec.b);
+rec.a:= rec.a + 1000;
+rec.b:= 'b' || rec.b;
+INSERT INTO t3 VALUES (rec.a, rec.b);
+END LOOP;
+END;
+$$
+CALL p1();
+rec.a rec.b
+10 b0
+rec.a rec.b
+11 b1
+rec.a rec.b
+12 b2
+SELECT * FROM t2;
+a b
+10 b0
+11 b1
+12 b2
+SELECT * FROM t3;
+a b
+1010 bb0
+1011 bb1
+1012 bb2
+DROP PROCEDURE p1;
+DROP TABLE t3;
+DROP TABLE t2;
+DROP TABLE t1;
+#
+# MDEV-12314 Implicit cursor FOR LOOP for cursors with parameters
+#
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b0');
+INSERT INTO t1 VALUES (11,'b1');
+INSERT INTO t1 VALUES (12,'b2');
+CREATE PROCEDURE p1(pa INT, pb VARCHAR(32)) AS
+CURSOR cur(va INT, vb VARCHAR(32)) IS
+SELECT a, b FROM t1 WHERE a=va AND b=vb;
+BEGIN
+FOR rec IN cur(pa,pb)
+LOOP
+SELECT rec.a, rec.b;
+END LOOP;
+END;
+$$
+CALL p1(10,'B0');
+rec.a rec.b
+10 b0
+CALL p1(11,'B1');
+rec.a rec.b
+11 b1
+CALL p1(12,'B2');
+rec.a rec.b
+12 b2
+CALL p1(12,'non-existing');
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# MDEV-12098 sql_mode=ORACLE: Implicit cursor FOR loop
+#
+# Parse error in the cursor SELECT statement
+CREATE PROCEDURE p1 AS
+BEGIN
+FOR rec IN (SELECT a, b FROM)
+LOOP
+SELECT rec.a, rec.b;
+END LOOP;
+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 ')
+LOOP
+SELECT rec.a, rec.b;
+END LOOP;
+END' at line 3
+# Make sure "rec" is not visible after END LOOP
+CREATE PROCEDURE p1 AS
+BEGIN
+FOR rec IN (SELECT 'test' AS a)
+LOOP
+NULL;
+END LOOP;
+rec.a:= 10;
+END;
+$$
+ERROR HY000: Unknown structured system variable or ROW routine variable 'rec'
+# Make sure "rec" is not visible inside the SELECT statement
+CREATE PROCEDURE p1 AS
+BEGIN
+FOR rec IN (SELECT rec)
+LOOP
+NULL;
+END LOOP;
+END;
+$$
+CALL p1;
+ERROR 42S22: Unknown column 'rec' in 'field list'
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1 AS
+BEGIN
+FOR rec IN (SELECT rec.a)
+LOOP
+NULL;
+END LOOP;
+END;
+$$
+CALL p1;
+ERROR 42S02: Unknown table 'rec' in field list
+DROP PROCEDURE p1;
+# Totally confusing name mixture
+CREATE TABLE rec (rec INT);
+INSERT INTO rec VALUES (10);
+CREATE PROCEDURE p1 AS
+BEGIN
+FOR rec IN (SELECT rec FROM rec)
+LOOP
+SELECT rec.rec;
+END LOOP;
+END;
+$$
+CALL p1;
+rec.rec
+10
+DROP PROCEDURE p1;
+DROP TABLE rec;
+# Make sure that duplicate column names are not allowed
+CREATE PROCEDURE p1 AS
+BEGIN
+FOR rec IN (SELECT 'a' AS a, 'A' as a)
+LOOP
+NULL;
+END LOOP;
+END;
+$$
+CALL p1;
+ERROR 42S21: Duplicate column name 'a'
+DROP PROCEDURE p1;
+# A complete working example
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'b0');
+INSERT INTO t1 VALUES (11,'b1');
+INSERT INTO t1 VALUES (12,'b2');
+CREATE TABLE t2 LIKE t1;
+CREATE TABLE t3 LIKE t1;
+CREATE PROCEDURE p1 AS
+BEGIN
+FOR rec IN (SELECT a, b FROM t1)
+LOOP
+SELECT rec.a, rec.b;
+INSERT INTO t2 VALUES (rec.a, rec.b);
+rec.a:= rec.a + 1000;
+rec.b:= 'b'|| rec.b;
+INSERT INTO t3 VALUES (rec.a, rec.b);
+END LOOP;
+END;
+$$
+CALL p1();
+rec.a rec.b
+10 b0
+rec.a rec.b
+11 b1
+rec.a rec.b
+12 b2
+SELECT * FROM t2;
+a b
+10 b0
+11 b1
+12 b2
+SELECT * FROM t3;
+a b
+1010 bb0
+1011 bb1
+1012 bb2
+DROP PROCEDURE p1;
+DROP TABLE t3;
+DROP TABLE t2;
+DROP TABLE t1;
+# A combination of explicit and implicit cursors
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'b1');
+INSERT INTO t1 VALUES (11,'b2');
+INSERT INTO t1 VALUES (12,'b3');
+CREATE PROCEDURE p1 AS
+BEGIN
+FOR rec1 IN (SELECT a, b FROM t1)
+LOOP
+DECLARE
+CURSOR cur2 IS SELECT a+1000 AS a, 'bb'||b AS b FROM t1 WHERE a=rec1.a AND b=rec1.b;
+BEGIN
+SELECT rec1.a, rec1.b;
+FOR rec2 IN cur2
+LOOP
+SELECT rec2.a, rec2.b;
+END LOOP;
+END;
+END LOOP;
+FOR rec1 IN (SELECT a,b FROM t1)
+LOOP
+FOR rec2 IN (SELECT a+2000 AS a,'bbb'||b AS b FROM t1 WHERE a=rec1.a AND b=rec1.b)
+LOOP
+SELECT rec2.a, rec2.b;
+END LOOP;
+END LOOP;
+END;
+$$
+CALL p1();
+rec1.a rec1.b
+10 b1
+rec2.a rec2.b
+1010 bbb1
+rec1.a rec1.b
+11 b2
+rec2.a rec2.b
+1011 bbb2
+rec1.a rec1.b
+12 b3
+rec2.a rec2.b
+1012 bbb3
+rec2.a rec2.b
+2010 bbbb1
+rec2.a rec2.b
+2011 bbbb2
+rec2.a rec2.b
+2012 bbbb3
+DROP PROCEDURE p1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/sp-cursor.result b/mysql-test/suite/compat/oracle/r/sp-cursor.result
new file mode 100644
index 00000000000..03211509f8b
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp-cursor.result
@@ -0,0 +1,951 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-10582 sql_mode=ORACLE: explicit cursor attributes %ISOPEN, %ROWCOUNT, %FOUND, %NOTFOUND
+#
+#
+# Cursor attributes outside of an SP context
+#
+SELECT c%ISOPEN;
+ERROR 42000: Undefined CURSOR: c
+SELECT c%FOUND;
+ERROR 42000: Undefined CURSOR: c
+SELECT c%NOTFOUND;
+ERROR 42000: Undefined CURSOR: c
+SELECT c%ROWCOUNT;
+ERROR 42000: Undefined CURSOR: c
+#
+# Undefinite cursor attributes
+#
+CREATE PROCEDURE p1
+AS
+BEGIN
+SELECT c%ISOPEN;
+END;
+$$
+ERROR 42000: Undefined CURSOR: c
+CREATE PROCEDURE p1
+AS
+BEGIN
+SELECT c%ROWCOUNT;
+END;
+$$
+ERROR 42000: Undefined CURSOR: c
+CREATE PROCEDURE p1
+AS
+BEGIN
+SELECT c%FOUND;
+END;
+$$
+ERROR 42000: Undefined CURSOR: c
+CREATE PROCEDURE p1
+AS
+BEGIN
+SELECT c%NOTFOUND;
+END;
+$$
+ERROR 42000: Undefined CURSOR: c
+#
+# Not opened cursor attributes %FOUND, %NOTFOUND, %ROWCOUNT
+#
+CREATE PROCEDURE p1
+AS
+CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+SELECT c%ROWCOUNT;
+END;
+$$
+CALL p1;
+ERROR 24000: Cursor is not open
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+SELECT c%FOUND;
+END;
+$$
+CALL p1;
+ERROR 24000: Cursor is not open
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+SELECT c%NOTFOUND;
+END;
+$$
+CALL p1;
+ERROR 24000: Cursor is not open
+DROP PROCEDURE p1;
+#
+# Not opened cursor attributes %FOUND, %NOTFOUND, %ROWCOUNT with INVALID_CURSOR exception
+#
+CREATE PROCEDURE p1
+AS
+CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+SELECT c%ROWCOUNT;
+EXCEPTION
+WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
+END;
+$$
+CALL p1;
+c%ROWCOUNT
+msg
+INVALID_CURSOR caught
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+SELECT c%FOUND;
+EXCEPTION
+WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
+END;
+$$
+CALL p1;
+c%FOUND
+msg
+INVALID_CURSOR caught
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+SELECT c%NOTFOUND;
+EXCEPTION
+WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
+END;
+$$
+CALL p1;
+c%NOTFOUND
+msg
+INVALID_CURSOR caught
+DROP PROCEDURE p1;
+#
+# print()
+#
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1
+AS
+CURSOR c IS SELECT * FROM t1 ORDER BY a;
+BEGIN
+EXPLAIN EXTENDED SELECT c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+END;
+$$
+CALL p1();
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select "c"%ISOPEN AS "c%ISOPEN","c"%ROWCOUNT AS "c%ROWCOUNT","c"%FOUND AS "c%FOUND","c"%NOTFOUND AS "c%NOTFOUND"
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Declared data type of the attributes
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+CREATE PROCEDURE p1
+AS
+CURSOR c IS SELECT * FROM t1 ORDER BY a;
+BEGIN
+OPEN c;
+CREATE TABLE t2 AS SELECT c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+CLOSE c;
+END;
+$$
+CALL p1();
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "c%ISOPEN" int(1) NOT NULL,
+ "c%ROWCOUNT" bigint(21) DEFAULT NULL,
+ "c%FOUND" int(1) DEFAULT NULL,
+ "c%NOTFOUND" int(1) DEFAULT NULL
+)
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Core functionality
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+INSERT INTO t1 VALUES (30);
+CREATE PROCEDURE p1
+AS
+a INT:=0;
+CURSOR c IS SELECT * FROM t1 ORDER BY a;
+BEGIN
+SELECT a, c%ISOPEN;
+OPEN c;
+/*
+After OPEN and before FETCH:
+- %ROWCOUNT returns 0
+- %FOUND and %NOTFOUND return NULL
+*/
+SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+FETCH c INTO a;
+SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+FETCH c INTO a;
+SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+FETCH c INTO a;
+SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+FETCH c INTO a;
+SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+CLOSE c;
+SELECT a, c%ISOPEN;
+/*
+After reopen and before FETCH:
+- %ROWCOUNT returns 0
+- %FOUND and %NOTFOUND return NULL
+*/
+OPEN c;
+SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+FETCH c INTO a;
+SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+CLOSE c;
+END;
+$$
+CALL p1();
+a c%ISOPEN
+0 0
+a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
+0 1 0 NULL NULL
+a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
+10 1 1 1 0
+a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
+20 1 2 1 0
+a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
+30 1 3 1 0
+a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
+30 1 3 0 1
+a c%ISOPEN
+30 0
+a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
+30 1 0 NULL NULL
+a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
+10 1 1 1 0
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# %NOTFOUND as a loop exit condition
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+INSERT INTO t1 VALUES (30);
+CREATE PROCEDURE p1
+AS
+a INT:=0;
+CURSOR c IS SELECT * FROM t1 ORDER BY a;
+BEGIN
+OPEN c;
+LOOP
+FETCH c INTO a;
+EXIT WHEN c%NOTFOUND;
+SELECT a;
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1();
+a
+10
+a
+20
+a
+30
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# %FOUND as a loop exit condition
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+INSERT INTO t1 VALUES (30);
+CREATE PROCEDURE p1
+AS
+a INT:=0;
+CURSOR c IS SELECT * FROM t1 ORDER BY a;
+BEGIN
+OPEN c;
+LOOP
+FETCH c INTO a;
+EXIT WHEN NOT c%FOUND;
+SELECT a;
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1();
+a
+10
+a
+20
+a
+30
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# End of MDEV-10582 sql_mode=ORACLE: explicit cursor attributes %ISOPEN, %ROWCOUNT, %FOUND, %NOTFOUND
+#
+#
+# MDEV-10597 Cursors with parameters
+#
+#
+# OPEN with a wrong number of parameters
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1(a_a INT,a_b VARCHAR)
+AS
+v_a INT;
+v_b VARCHAR(10);
+CURSOR c (p_a INT, p_b VARCHAR) IS SELECT * FROM t1 WHERE a=p_a;
+BEGIN
+OPEN c(a_a);
+LOOP
+FETCH c INTO v_a, v_b;
+EXIT WHEN c%NOTFOUND;
+DBMS_OUTPUT.PUT_LINE('Fetched a record a='||TO_CHAR(v_a)||' b='||v_b);
+END LOOP;
+CLOSE c;
+END;
+$$
+ERROR 42000: Incorrect parameter count to cursor 'c'
+DROP TABLE t1;
+#
+# Cursor parameters are not visible outside of the cursor
+#
+CREATE PROCEDURE p1(a_a INT)
+AS
+v_a INT;
+CURSOR c (p_a INT) IS SELECT a FROM t1 WHERE a=p_a;
+BEGIN
+OPEN c(a_a);
+p_a:=10;
+END;
+$$
+ERROR HY000: Unknown system variable 'p_a'
+CREATE PROCEDURE p1(a_a INT)
+AS
+v_a INT;
+CURSOR c (p_a INT) IS SELECT a FROM t1 WHERE a=p_a;
+BEGIN
+p_a:=10;
+OPEN c(a_a);
+END;
+$$
+ERROR HY000: Unknown system variable 'p_a'
+#
+# Cursor parameter shadowing a local variable
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+CREATE PROCEDURE p1(a INT)
+AS
+v_a INT:=NULL;
+p_a INT:=NULL;
+CURSOR c (p_a VARCHAR2) IS SELECT a FROM t1 WHERE p_a IS NOT NULL;
+BEGIN
+OPEN c(a);
+FETCH c INTO v_a;
+IF c%NOTFOUND THEN
+BEGIN
+SELECT 'No records found' AS msg;
+RETURN;
+END;
+END IF;
+CLOSE c;
+SELECT 'Fetched a record a='||v_a AS msg;
+INSERT INTO t1 VALUES (v_a);
+END;
+$$
+CALL p1(1);
+msg
+Fetched a record a=1
+SELECT * FROM t1;
+a
+1
+1
+CALL p1(NULL);
+msg
+No records found
+SELECT * FROM t1;
+a
+1
+1
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Parameters in SELECT list
+#
+CREATE PROCEDURE p1(a_a INT, a_b VARCHAR)
+AS
+v_a INT;
+v_b VARCHAR(10);
+CURSOR c (p_a INT, p_b VARCHAR) IS SELECT p_a,p_b FROM DUAL;
+BEGIN
+FOR i IN 0..1
+LOOP
+OPEN c(a_a + i,a_b);
+LOOP
+FETCH c INTO v_a, v_b;
+EXIT WHEN c%NOTFOUND;
+SELECT 'Fetched a record a=' || v_a || ' b=' || v_b AS msg;
+END LOOP;
+CLOSE c;
+END LOOP;
+END;
+$$
+CALL p1(1,'b1');
+msg
+Fetched a record a=1 b=b1
+msg
+Fetched a record a=2 b=b1
+DROP PROCEDURE p1;
+#
+# Parameters in SELECT list + UNION
+#
+CREATE PROCEDURE p1(a_a INT, a_b VARCHAR)
+AS
+v_a INT;
+v_b VARCHAR(10);
+CURSOR c (p_a INT, p_b VARCHAR) IS
+SELECT p_a,p_b FROM DUAL
+UNION ALL
+SELECT p_a+1,p_b||'b' FROM DUAL;
+BEGIN
+OPEN c(a_a,a_b);
+LOOP
+FETCH c INTO v_a, v_b;
+EXIT WHEN c%NOTFOUND;
+SELECT 'Fetched a record a=' || v_a || ' b=' || v_b AS msg;
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1(1,'b1');
+msg
+Fetched a record a=1 b=b1
+msg
+Fetched a record a=2 b=b1b
+DROP PROCEDURE p1;
+#
+# Parameters in SELECT list + type conversion + warnings
+#
+CREATE PROCEDURE p1(a_a VARCHAR)
+AS
+v_a INT;
+CURSOR c (p_a INT) IS SELECT p_a FROM DUAL;
+BEGIN
+OPEN c(a_a);
+LOOP
+FETCH c INTO v_a;
+EXIT WHEN c%NOTFOUND;
+SELECT 'Fetched a record a=' || v_a AS msg;
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1('1b');
+msg
+Fetched a record a=1
+Warnings:
+Warning 1265 Data truncated for column 'p_a' at row 1
+CALL p1('b1');
+msg
+Fetched a record a=0
+Warnings:
+Warning 1366 Incorrect integer value: 'b1' for column 'p_a' at row 1
+DROP PROCEDURE p1;
+#
+# One parameter in SELECT list + subselect
+#
+CREATE PROCEDURE p1(a_a VARCHAR)
+AS
+v_a VARCHAR(10);
+CURSOR c (p_a VARCHAR) IS
+SELECT p_a FROM DUAL UNION SELECT REVERSE(p_a) FROM DUAL;
+BEGIN
+OPEN c((SELECT a_a));
+LOOP
+FETCH c INTO v_a;
+EXIT WHEN c%NOTFOUND;
+SELECT v_a;
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1('ab');
+v_a
+ab
+v_a
+ba
+DROP PROCEDURE p1;
+#
+# Two parameters in SELECT list + subselect
+#
+SET sql_mode=ORACLE;
+CREATE PROCEDURE p1()
+AS
+v_a VARCHAR(10);
+v_b VARCHAR(20);
+CURSOR c (p_a VARCHAR, p_b VARCHAR) IS
+SELECT p_a, p_b FROM DUAL
+UNION
+SELECT p_b, p_a FROM DUAL;
+BEGIN
+OPEN c((SELECT 'aaa'),(SELECT 'bbb'));
+LOOP
+FETCH c INTO v_a, v_b;
+EXIT WHEN c%NOTFOUND;
+SELECT v_a, v_b;
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1();
+v_a v_b
+aaa bbb
+v_a v_b
+bbb aaa
+DROP PROCEDURE p1;
+#
+# Two parameters in SELECT list + two parameters in WHERE + subselects
+#
+SET sql_mode=ORACLE;
+CREATE PROCEDURE p1(a_a VARCHAR, a_b VARCHAR)
+AS
+v_a VARCHAR(10);
+v_b VARCHAR(20);
+CURSOR c (value_a VARCHAR, value_b VARCHAR,
+pattern_a VARCHAR, pattern_b VARCHAR) IS
+SELECT value_a, value_b FROM DUAL WHERE value_a LIKE pattern_a
+UNION
+SELECT value_b, value_a FROM DUAL WHERE value_b LIKE pattern_b;
+BEGIN
+OPEN c((SELECT 'aaa'),(SELECT 'bbb'),(SELECT a_a),(SELECT a_b));
+LOOP
+FETCH c INTO v_a, v_b;
+EXIT WHEN c%NOTFOUND;
+SELECT v_a, v_b;
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1('%','%');
+v_a v_b
+aaa bbb
+v_a v_b
+bbb aaa
+CALL p1('aaa','xxx');
+v_a v_b
+aaa bbb
+CALL p1('xxx','bbb');
+v_a v_b
+bbb aaa
+CALL p1('xxx','xxx');
+DROP PROCEDURE p1;
+#
+# Parameters in SELECT list + stored function
+#
+CREATE FUNCTION f1 (a VARCHAR) RETURN VARCHAR
+AS
+BEGIN
+RETURN a || 'y';
+END;
+$$
+CREATE PROCEDURE p1(a_a VARCHAR)
+AS
+v_a VARCHAR(10);
+v_b VARCHAR(10);
+CURSOR c (p_sel_a VARCHAR, p_cmp_a VARCHAR) IS
+SELECT p_sel_a, p_cmp_a FROM DUAL;
+BEGIN
+OPEN c(f1(a_a), f1(a_a));
+LOOP
+FETCH c INTO v_a, v_b;
+EXIT WHEN c%NOTFOUND;
+SELECT v_a;
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1('x');
+v_a
+xy
+CALL p1(f1(COALESCE(NULL, f1('x'))));
+v_a
+xyyy
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+#
+# One parameter in WHERE clause
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (1,'11');
+INSERT INTO t1 VALUES (1,'12');
+INSERT INTO t1 VALUES (2,'21');
+INSERT INTO t1 VALUES (2,'22');
+INSERT INTO t1 VALUES (3,'31');
+INSERT INTO t1 VALUES (3,'32');
+CREATE PROCEDURE p1(a_a INT)
+AS
+v_a INT;
+v_b VARCHAR(10);
+CURSOR c (p_a INT) IS SELECT a,b FROM t1 WHERE a=p_a;
+BEGIN
+OPEN c(a_a);
+LOOP
+FETCH c INTO v_a, v_b;
+EXIT WHEN c%NOTFOUND;
+INSERT INTO t2 VALUES (v_a,v_b);
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1(1);
+SELECT * FROM t2;
+a b
+1 11
+1 12
+DROP TABLE t1;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+#
+# Two parameters in WHERE clause
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (1,'11');
+INSERT INTO t1 VALUES (1,'12');
+INSERT INTO t1 VALUES (2,'21');
+INSERT INTO t1 VALUES (2,'22');
+INSERT INTO t1 VALUES (3,'31');
+INSERT INTO t1 VALUES (3,'32');
+CREATE PROCEDURE p1(a_a INT, a_b VARCHAR)
+AS
+v_a INT;
+v_b VARCHAR(10);
+CURSOR c (p_a INT, p_b VARCHAR) IS SELECT a,b FROM t1 WHERE a=p_a AND b=p_b;
+BEGIN
+OPEN c(a_a, a_b);
+LOOP
+FETCH c INTO v_a, v_b;
+EXIT WHEN c%NOTFOUND;
+INSERT INTO t2 VALUES (v_a,v_b);
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1(1,'11');
+SELECT * FROM t2;
+a b
+1 11
+DROP TABLE t1;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+#
+# Parameters in WHERE and HAVING clauses
+#
+CREATE TABLE t1 (name VARCHAR(10), value INT);
+INSERT INTO t1 VALUES ('but',1);
+INSERT INTO t1 VALUES ('but',1);
+INSERT INTO t1 VALUES ('but',1);
+INSERT INTO t1 VALUES ('bin',1);
+INSERT INTO t1 VALUES ('bin',1);
+INSERT INTO t1 VALUES ('bot',1);
+CREATE PROCEDURE p1 (arg_name_limit VARCHAR, arg_total_limit INT)
+AS
+v_name VARCHAR(10);
+v_total INT;
+-- +0 is needed to work around the bug MDEV-11081
+CURSOR c(p_v INT) IS
+SELECT name, SUM(value + p_v) + 0 AS total FROM t1
+WHERE name LIKE arg_name_limit
+GROUP BY name HAVING total>=arg_total_limit;
+BEGIN
+FOR i IN 0..1
+LOOP
+OPEN c(i);
+LOOP
+FETCH c INTO v_name, v_total;
+EXIT WHEN c%NOTFOUND;
+SELECT v_name, v_total;
+END LOOP;
+CLOSE c;
+END LOOP;
+END;
+$$
+CALL p1('%', 2);
+v_name v_total
+bin 2
+v_name v_total
+but 3
+v_name v_total
+bin 4
+v_name v_total
+bot 2
+v_name v_total
+but 6
+CALL p1('b_t', 0);
+v_name v_total
+bot 1
+v_name v_total
+but 3
+v_name v_total
+bot 2
+v_name v_total
+but 6
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# One parameter in LIMIT clause
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (1,'b1');
+INSERT INTO t1 VALUES (2,'b2');
+INSERT INTO t1 VALUES (3,'b3');
+INSERT INTO t1 VALUES (4,'b4');
+INSERT INTO t1 VALUES (5,'b5');
+INSERT INTO t1 VALUES (6,'b6');
+CREATE PROCEDURE p1(a_a INT)
+AS
+v_a INT;
+v_b VARCHAR(10);
+CURSOR c (p_a INT) IS SELECT a,b FROM t1 ORDER BY a LIMIT p_a;
+BEGIN
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+OPEN c(a_a);
+LOOP
+FETCH c INTO v_a, v_b;
+EXIT WHEN c%NOTFOUND;
+INSERT INTO t2 VALUES (v_a,v_b);
+END LOOP;
+CLOSE c;
+SELECT * FROM t2;
+DROP TABLE t2;
+END;
+$$
+CALL p1(1);
+a b
+1 b1
+CALL p1(3);
+a b
+1 b1
+2 b2
+3 b3
+CALL p1(6);
+a b
+1 b1
+2 b2
+3 b3
+4 b4
+5 b5
+6 b6
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# End of MDEV-10597 Cursors with parameters
+#
+#
+# MDEV-12209 sql_mode=ORACLE: Syntax error in a OPEN cursor with parameters makes the server crash
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (1,'A');
+CREATE PROCEDURE p1(a INT,b VARCHAR)
+AS
+CURSOR c (p_a INT, p_b VARCHAR) IS SELECT * FROM t1 WHERE a=p_a;
+BEGIN
+OPEN c(a+, b);
+LOOP
+FETCH c INTO a, b;
+EXIT WHEN c%NOTFOUND;
+SELECT a, b;
+END LOOP;
+CLOSE c;
+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 ' b);
+LOOP
+FETCH c INTO a, b;
+EXIT WHEN c%NOTFOUND;
+SELECT a, b;
+END LOOP;
+CLOSE ' at line 5
+DROP TABLE t1;
+#
+# MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10),c DATETIME(3));
+INSERT INTO t1 VALUES (1,'b1','2001-01-01 10:20:30.123');
+INSERT INTO t1 VALUES (2,'b2','2001-01-02 10:20:30.123');
+CREATE TABLE t2 LIKE t1;
+CREATE PROCEDURE p1()
+AS
+v_a t1.a%TYPE;
+v_b t1.b%TYPE;
+v_c t1.c%TYPE;
+CURSOR c IS SELECT a,b,c FROM t1;
+BEGIN
+OPEN c;
+LOOP
+FETCH c INTO v_a, v_b, v_c;
+EXIT WHEN c%NOTFOUND;
+INSERT INTO t2 (a,b,c) VALUES (v_a, v_b, v_c);
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1();
+SELECT * FROM t2;
+a b c
+1 b1 2001-01-01 10:20:30.123
+2 b2 2001-01-02 10:20:30.123
+DROP TABLE t2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# MDEV-12007 Allow ROW variables as a cursor FETCH target
+#
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+INSERT INTO t1 VALUES (20,'b20');
+INSERT INTO t1 VALUES (30,'b30');
+CREATE PROCEDURE p1 AS
+rec ROW(a INT, b VARCHAR(32));
+CURSOR c IS SELECT a,b FROM t1;
+BEGIN
+OPEN c;
+LOOP
+FETCH c INTO rec;
+EXIT WHEN c%NOTFOUND;
+SELECT ('rec=(' || rec.a ||','|| rec.b||')') AS c;
+END LOOP;
+CLOSE c;
+END;
+$$
+CALL p1();
+c
+rec=(10,b10)
+c
+rec=(20,b20)
+c
+rec=(30,b30)
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# MDEV-12441 Variables declared after cursors with parameters lose values
+#
+CREATE PROCEDURE p1() AS
+x0 INT:=100;
+CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+x1 INT:=101;
+BEGIN
+OPEN cur(10,11);
+CLOSE cur;
+SELECT x0, x1;
+END;
+$$
+CALL p1();
+x0 x1
+100 101
+DROP PROCEDURE p1;
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1() AS
+x0 INT:=100;
+CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+x1 t1.a%TYPE:=101;
+BEGIN
+OPEN cur(10,11);
+CLOSE cur;
+SELECT x0, x1;
+END;
+$$
+CALL p1();
+x0 x1
+100 101
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE PROCEDURE p1() AS
+x0 INT:=100;
+CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+x1 ROW(a INT,b INT):=ROW(101,102);
+BEGIN
+OPEN cur(10,11);
+CLOSE cur;
+SELECT x0, x1.a, x1.b;
+END;
+$$
+CALL p1();
+x0 x1.a x1.b
+100 101 102
+DROP PROCEDURE p1;
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'Tbl-t1.b0');
+CREATE PROCEDURE p1() AS
+x0 INT:=100;
+CURSOR cur(cp1 INT, cp2 INT) IS SELECT a,b FROM t1;
+x1 t1%ROWTYPE:=ROW(101,'Var-x1.b0');
+BEGIN
+SELECT x0, x1.a, x1.b;
+OPEN cur(10,11);
+FETCH cur INTO x1;
+CLOSE cur;
+SELECT x0, x1.a, x1.b;
+END;
+$$
+CALL p1();
+x0 x1.a x1.b
+100 101 Var-x1.b0
+x0 x1.a x1.b
+100 10 Tbl-t1.b0
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'Tbl-t1.b0');
+CREATE PROCEDURE p1() AS
+x0 INT:=100;
+CURSOR cur(cp1 INT, cp2 INT) IS SELECT a,b FROM t1;
+x1 cur%ROWTYPE:=ROW(101,'Var-x1.b0');
+BEGIN
+SELECT x0, x1.a, x1.b;
+OPEN cur(10,11);
+FETCH cur INTO x1;
+CLOSE cur;
+SELECT x0, x1.a, x1.b;
+END;
+$$
+CALL p1();
+x0 x1.a x1.b
+100 101 Var-x1.b0
+x0 x1.a x1.b
+100 10 Tbl-t1.b0
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# MDEV-12854 Synchronize CREATE..SELECT data type and result set metadata data type for INT functions
+#
+DECLARE
+CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+OPEN c;
+SELECT
+c%ISOPEN,
+c%NOTFOUND,
+c%FOUND,
+c%ROWCOUNT;
+CLOSE c;
+END;
+$$
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def c%ISOPEN 3 1 1 N 32897 0 63
+def c%NOTFOUND 3 1 0 Y 32896 0 63
+def c%FOUND 3 1 0 Y 32896 0 63
+def c%ROWCOUNT 8 21 1 Y 32896 0 63
+c%ISOPEN c%NOTFOUND c%FOUND c%ROWCOUNT
+1 NULL NULL 0
diff --git a/mysql-test/suite/compat/oracle/r/sp-goto.result b/mysql-test/suite/compat/oracle/r/sp-goto.result
new file mode 100644
index 00000000000..259be7a34e6
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp-goto.result
@@ -0,0 +1,834 @@
+set sql_mode=oracle;
+#
+# MDEV-10697 sql_mode=ORACLE: GOTO statement
+#
+# matrice of tests in procedure
+# |--------------------------------------------------------
+# | | Same | Outside | to sub | No |
+# | | block | one block | block | matching |
+# | | | | | label |
+# |--------------------------------------------------------
+# | Forward jump | F1 | F3 | F5 | F7 |
+# |--------------------------------------------------------
+# | Backward jump | F2 | F4 | F6 | F8 |
+# |--------------------------------------------------------
+# Jump from handler to outside handling code block : F9
+# Jump from handler to handling code block : F10 (forbidden)
+# Jump inside handler : F21
+# Jump between handler : F22 (forbidden)
+# Jump from cascaded block with handler : F11
+# Duplicate label in same block : F12 (forbidden)
+# Duplicate label in different block : F13
+# Jump outside unlabeled block : F14
+# Jump inside/outside labeled block : F15
+# Jump from if / else : F16
+# Jump with cursors : F17
+# Jump outside case : F18
+# Jump inside/outside case block : F19
+# Jump outside labeled loop : F20
+# Jump (continue) labeled loop : F23
+# Two consecutive label : P24
+# Two consecutive label (backward and forward jump) : P25
+# Two consecutive label, continue to wrong label : P26
+# Consecutive goto label and block label : P27
+# Test in function
+# backward jump : func1
+# forward jump : func2
+# Test in trigger
+# forward jump : trg1
+#
+# Forward jump in same block
+#
+CREATE or replace procedure f1(p2 IN OUT VARCHAR)
+AS
+BEGIN
+p2:='a';
+goto lab1;
+<<lab1>>
+goto lab2;
+p2:='b';
+<<lab2>>
+return ;
+END;
+$$
+call f1(@wp1);
+select 'f1',@wp1;
+f1 @wp1
+f1 a
+DROP PROCEDURE f1;
+#
+# Backward jump in same block
+#
+CREATE or replace procedure f2(p2 IN OUT VARCHAR)
+AS
+BEGIN
+p2:='a';
+<<lab1>>
+if (p2='b') then
+return ;
+end if;
+p2:='b';
+goto lab1;
+END;
+$$
+call f2(@wp1);
+select 'f2',@wp1;
+f2 @wp1
+f2 b
+DROP PROCEDURE f2;
+#
+# Forward jump outside one block
+#
+CREATE or replace procedure f3(p2 IN OUT VARCHAR)
+AS
+BEGIN
+p2:='a';
+if (p2='a') then
+goto lab1;
+end if;
+p2:='c';
+<<lab1>>
+return ;
+END;
+$$
+call f3(@wp1);
+select 'f3',@wp1;
+f3 @wp1
+f3 a
+DROP PROCEDURE f3;
+#
+# Backward jump outside one block
+#
+CREATE or replace procedure f4(p2 IN OUT VARCHAR)
+AS
+BEGIN
+p2:='a';
+<<lab1>>
+if (p2='a') then
+p2:=p2||'b';
+goto lab1;
+end if;
+if (p2='ab') then
+p2:=p2||'c';
+end if;
+return ;
+END;
+$$
+call f4(@wp1);
+select 'f4',@wp1;
+f4 @wp1
+f4 abc
+DROP PROCEDURE f4;
+#
+# Forward jump inside sub block
+CREATE or replace procedure f5(p2 IN OUT VARCHAR)
+AS
+BEGIN
+p2:='a';
+goto lab5 ;
+if (p2='a') then
+<<lab5>>
+p2:=p2||'b';
+end if;
+return ;
+END;
+$$
+ERROR 42000: GOTO with no matching label: lab5
+#
+# Backward jump inside sub block
+CREATE or replace procedure f6(p2 IN OUT VARCHAR)
+AS
+BEGIN
+p2:='a';
+if (p2='a') then
+<<lab6>>
+p2:=p2||'b';
+return ;
+end if;
+goto lab6 ;
+END;
+$$
+ERROR 42000: GOTO with no matching label: lab6
+#
+# Backward jump - missing label
+CREATE or replace procedure f7(p2 IN OUT VARCHAR)
+AS
+BEGIN
+<<lab>>
+goto lab7 ;
+return ;
+END;
+$$
+ERROR 42000: GOTO with no matching label: lab7
+#
+# Forward jump - missing label
+CREATE or replace procedure f8(p2 IN OUT VARCHAR)
+AS
+BEGIN
+goto lab8 ;
+<<lab>>
+return ;
+END;
+$$
+ERROR 42000: GOTO with no matching label: lab8
+#
+# Jump from handler to procedure code
+#
+CREATE or replace procedure f9(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+<<lab9>>
+if lim=-1 then
+res:=res||' -- goto end limit -1 --';
+goto lab9_end;
+end if;
+begin
+SELECT a INTO a FROM information_schema.tables LIMIT lim;
+EXCEPTION
+WHEN TOO_MANY_ROWS THEN
+begin
+res:=res||'--- too_many_rows cought ---';
+lim:=0;
+goto lab9;
+end;
+WHEN NO_DATA_FOUND THEN
+begin
+res:=res||'--- no_data_found cought ---';
+lim:=-1;
+goto lab9;
+end;
+end;
+res:=res||'error';
+<<lab9_end>>
+return ;
+END;
+$$
+SET @res='';
+CALL f9(2, @res);
+SELECT 'f9',@res;
+f9 @res
+f9 --- too_many_rows cought ------ no_data_found cought --- -- goto end limit -1 --
+CALL f9(0, @res);
+SELECT 'f9',@res;
+f9 @res
+f9 --- no_data_found cought --- -- goto end limit -1 --
+DROP PROCEDURE f9;
+#
+# Jump from handler to handling bloc
+CREATE or replace procedure f10(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+begin
+<<lab10>>
+SELECT a INTO a FROM information_schema.tables LIMIT lim;
+EXCEPTION
+WHEN TOO_MANY_ROWS THEN
+begin
+res:='--- too_many_rows cought ---';
+goto lab10;
+end;
+WHEN NO_DATA_FOUND THEN res:='--- no_data_found cought ---';
+end;
+return ;
+END;
+$$
+ERROR 42000: GOTO with no matching label: lab10
+#
+# Jump from cascaded block with handler
+#
+CREATE or replace procedure f11(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+<<lab11a>>
+begin
+SELECT a INTO a FROM information_schema.tables LIMIT lim;
+EXCEPTION
+WHEN TOO_MANY_ROWS THEN
+begin
+res:=res||'--- too_many_rows cought 1 ---';
+goto lab11b;
+end;
+WHEN NO_DATA_FOUND THEN
+begin
+res:=res||'--- no_data_found cought 1 ---';
+lim:=2;
+SELECT a INTO a FROM information_schema.tables LIMIT lim;
+EXCEPTION
+WHEN TOO_MANY_ROWS THEN
+begin
+res:=res||'--- too_many_rows cought 2 ---';
+goto lab11a;
+end;
+WHEN NO_DATA_FOUND THEN res:='--- no_data_found cought 2 ---';
+end;
+end;
+set res:=res||' error ';
+<<lab11b>>
+return ;
+END;
+$$
+SET @res='';
+CALL f11(0, @res);
+SELECT 'f11',@res;
+f11 @res
+f11 --- no_data_found cought 1 ------ too_many_rows cought 2 ------ too_many_rows cought 1 ---
+DROP PROCEDURE f11;
+#
+# Jump inside handler
+#
+CREATE or replace procedure f21(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+begin
+SELECT a INTO a FROM information_schema.tables LIMIT lim;
+EXCEPTION
+WHEN TOO_MANY_ROWS THEN
+begin
+<<retry>>
+lim:=lim-1;
+loop
+begin
+SELECT a INTO a FROM information_schema.tables LIMIT lim;
+EXCEPTION
+WHEN TOO_MANY_ROWS THEN
+begin
+lim:=lim-1;
+goto retry;
+end;
+end;
+exit ;
+end loop;
+end;
+end;
+res:=lim;
+return ;
+END;
+$$
+SET @res='';
+CALL f21(10, @res);
+SELECT 'f21',@res;
+f21 @res
+f21 1
+drop procedure f21;
+#
+# Jump beetween handler
+CREATE or replace procedure f22(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+res:='ok';
+begin
+SELECT a INTO a FROM information_schema.tables LIMIT lim;
+EXCEPTION
+WHEN TOO_MANY_ROWS THEN
+goto nodata ;
+WHEN NO_DATA_FOUND THEN
+begin
+<<nodata>>
+res:='error';
+end;
+end;
+return ;
+END;
+$$
+ERROR 42000: GOTO with no matching label: nodata
+#
+# Duplicate label in same bloc
+CREATE or replace procedure f12(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+<<lab12>>
+res:='error';
+<<lab12>>
+return ;
+END;
+$$
+ERROR 42000: Redefining label lab12
+#
+# Duplicate label in different block
+#
+CREATE or replace procedure f13(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+a:=0;
+<<lab13>>
+a:=a+1;
+begin
+<<lab13>>
+a:=a+1;
+if (a<10) then
+goto lab13;
+end if;
+end;
+res:=a;
+if (a=10) then
+goto lab13;
+end if;
+return ;
+END;
+$$
+SET @res='';
+CALL f13(0, @res);
+SELECT 'f13',@res;
+f13 @res
+f13 12
+DROP PROCEDURE f13;
+#
+# Jump outside unlabeled block
+#
+CREATE or replace procedure f14(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+a:=0;
+loop
+a:=a+1;
+if (a<10) then
+continue;
+end if;
+if (a>=lim) then
+goto lab14;
+end if;
+if (a>=20) then
+exit;
+end if;
+end loop;
+<<lab14>>
+res:=a;
+return ;
+END;
+$$
+SET @res='';
+CALL f14(15, @res);
+SELECT 'f14',@res;
+f14 @res
+f14 15
+CALL f14(8, @res);
+SELECT 'f14',@res;
+f14 @res
+f14 10
+CALL f14(25, @res);
+SELECT 'f14',@res;
+f14 @res
+f14 20
+DROP PROCEDURE f14;
+#
+# Jump inside/outside labeled block
+#
+CREATE or replace procedure f15(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+a:=0;
+<<looplabel>> loop
+<<beginlooplabel>>
+a:=a+1;
+if (a<10) then
+continue looplabel;
+end if;
+if (a>=lim) then
+goto lab15;
+end if;
+if (a>=20) then
+exit looplabel;
+end if;
+goto beginlooplabel;
+end loop;
+<<lab15>>
+res:=a;
+return ;
+END;
+$$
+SET @res='';
+CALL f15(15, @res);
+SELECT 'f15',@res;
+f15 @res
+f15 15
+CALL f15(8, @res);
+SELECT 'f15',@res;
+f15 @res
+f15 10
+CALL f15(25, @res);
+SELECT 'f15',@res;
+f15 @res
+f15 20
+DROP PROCEDURE f15;
+#
+# Jump from if / else
+#
+CREATE or replace procedure f16(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+if (lim<10) then
+goto lab16_1;
+else
+goto lab16_2;
+end if;
+<<lab16_1>>
+res:='if lab16_1';
+goto lab16_3;
+<<lab16_2>>
+res:='else lab16_2';
+goto lab16_3;
+res:='error lab16_3';
+<<lab16_3>>
+return ;
+END;
+$$
+SET @res='';
+CALL f16(15, @res);
+SELECT 'f16',@res;
+f16 @res
+f16 else lab16_2
+CALL f16(8, @res);
+SELECT 'f16',@res;
+f16 @res
+f16 if lab16_1
+DROP PROCEDURE f16;
+#
+# Jump with cursors
+#
+CREATE or replace procedure f17(lim INT, res OUT VARCHAR)
+AS
+v_a INT;
+v_b VARCHAR(10);
+CURSOR cur1 IS SELECT 1 FROM dual where 1=2;
+BEGIN
+OPEN cur1;
+LOOP
+FETCH cur1 INTO v_a;
+EXIT WHEN cur1%NOTFOUND;
+END LOOP;
+CLOSE cur1;
+<<lab17>>
+lim:=lim-1;
+begin
+declare
+CURSOR cur1 IS SELECT 1 FROM dual;
+CURSOR cur2 IS SELECT 1 FROM dual where 1=2;
+begin
+LOOP
+OPEN cur1;
+FETCH cur1 INTO v_a;
+EXIT WHEN cur1%NOTFOUND;
+res:=res||'-'||lim ;
+close cur1;
+if (lim>0) then
+goto lab17;
+else
+goto lab17_end;
+end if;
+END LOOP;
+end;
+<<lab17_end>>
+null;
+end;
+END;
+$$
+SET @res='';
+CALL f17(5, @res);
+SELECT 'f17',@res;
+f17 @res
+f17 -4-3-2-1-0
+DROP PROCEDURE f17;
+#
+# Jump outside case
+#
+CREATE or replace procedure f18(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+case lim
+when 1 then
+res:='case branch 18_1';
+goto lab18_1;
+res:='error';
+when 2 then
+res:='case branch 18_2';
+goto lab18_2;
+res:='error';
+else
+res:='default branch 18';
+end case;
+<<lab18_1>>
+null;
+<<lab18_2>>
+return ;
+END;
+$$
+SET @res='';
+CALL f18(0, @res);
+SELECT 'f18',@res;
+f18 @res
+f18 default branch 18
+CALL f18(1, @res);
+SELECT 'f18',@res;
+f18 @res
+f18 case branch 18_1
+CALL f18(2, @res);
+SELECT 'f18',@res;
+f18 @res
+f18 case branch 18_2
+DROP PROCEDURE f18;
+#
+# Jump inside/outside case block
+#
+CREATE or replace procedure f19(lim INT, res OUT VARCHAR)
+AS
+a INT;
+BEGIN
+a:=1;
+case lim
+when 1 then
+<<lab19_0>>
+a:=a+1;
+if (a<10) then
+goto lab19_0;
+else
+goto lab19_1;
+end if;
+res:='case branch 19_1';
+else
+res:='default branch 18';
+end case;
+goto lab19_end;
+<<lab19_1>>
+res:=a;
+<<lab19_end>>
+return ;
+END;
+$$
+SET @res='';
+CALL f19(1, @res);
+SELECT 'f19',@res;
+f19 @res
+f19 10
+DROP PROCEDURE f19;
+#
+# Jump outside labeled loop
+#
+CREATE OR REPLACE PROCEDURE f20(res OUT VARCHAR)
+AS
+a INT := 1;
+BEGIN
+<<lab>>
+FOR i IN a..10 LOOP
+IF i = 5 THEN
+a:= a+1;
+goto lab;
+END IF;
+END LOOP;
+res:=a;
+END;
+$$
+CALL f20(@res);
+SELECT 'f20',@res;
+f20 @res
+f20 6
+DROP PROCEDURE f20;
+#
+# Jump (continue) labeled loop
+#
+CREATE OR REPLACE PROCEDURE f23(res OUT VARCHAR)
+AS
+a INT := 1;
+BEGIN
+<<lab>>
+FOR i IN a..10 LOOP
+IF i = 5 THEN
+a:= a+1;
+continue lab;
+END IF;
+END LOOP;
+res:=a;
+END;
+$$
+CALL f23(@res);
+SELECT 'f23',@res;
+f23 @res
+f23 2
+DROP PROCEDURE f23;
+#
+# Two consecutive label (backward jump)
+#
+CREATE OR REPLACE PROCEDURE p24(action IN INT, res OUT varchar) AS
+a integer;
+BEGIN
+<<lab1>>
+<<lab2>>
+if (action = 1) then
+res:=res||' '||action;
+action:=2;
+goto lab1;
+end if;
+if (action = 2) then
+res:=res||' '||action;
+action:=3;
+goto lab2;
+end if;
+END;
+$$
+call p24(1,@res);
+select 'p24',@res;
+p24 @res
+p24 1 2
+DROP PROCEDURE p24;
+#
+# Two consecutive label (backward and forward jump)
+#
+CREATE OR REPLACE PROCEDURE p25(action IN INT, res OUT varchar) AS
+a integer;
+BEGIN
+if (action = 1) then
+res:=res||' '||action;
+action:=2;
+goto lab2;
+end if;
+goto lab_end;
+<<lab1>>
+<<lab2>>
+res:=res||' '||action;
+if (action = 2) then
+res:=res||' '||action;
+action:=3;
+goto lab1;
+end if;
+<<lab_end>>
+null;
+END;
+$$
+call p25(1,@res);
+select 'p25',@res;
+p25 @res
+p25 1 2 2 3
+DROP PROCEDURE p25;
+#
+# Two consecutive label, continue to wrong label
+CREATE OR REPLACE PROCEDURE p26(action IN INT, res OUT varchar) AS
+BEGIN
+<<lab1>>
+<<lab2>>
+FOR i IN 1..10 LOOP
+continue lab1;
+END LOOP;
+END;
+$$
+ERROR 42000: CONTINUE with no matching label: lab1
+#
+# Consecutive goto label and block label
+#
+CREATE OR REPLACE PROCEDURE p27(action IN INT, res OUT varchar) AS
+BEGIN
+res:='';
+<<lab1>>
+<<lab2>>
+FOR i IN 1..10 LOOP
+if (action = 1) then
+res:=res||' '||action||'-'||i;
+action:=2;
+continue lab2;
+end if;
+if (action = 2) then
+res:=res||' '||action||'-'||i;
+action:='3';
+goto lab2;
+end if;
+if (action = 3) then
+res:=res||' '||action||'-'||i;
+action:='4';
+goto lab1;
+end if;
+if (action = 4) then
+res:=res||' '||action||'-'||i;
+exit lab2;
+end if;
+END LOOP;
+END;
+$$
+call p27(1,@res);
+select 'p27',@res;
+p27 @res
+p27 1-1 2-2 3-1 4-1
+DROP PROCEDURE p27;
+# ----------------------
+# -- TEST IN FUNCTION --
+# ----------------------
+#
+# FUNCTION : Backward jump
+#
+CREATE or replace function func1()
+return varchar
+AS
+p2 varchar(10);
+BEGIN
+p2:='a';
+<<lab1>>
+if (p2='a') then
+p2:=p2||'b';
+goto lab1;
+end if;
+if (p2='ab') then
+p2:=p2||'c';
+end if;
+return p2;
+END;
+$$
+select 'func1',func1();
+func1 func1()
+func1 abc
+DROP function func1;
+#
+# FUNCTION : forward jump
+#
+CREATE or replace function func2()
+return varchar
+AS
+p2 varchar(10);
+BEGIN
+p2:='a';
+if (p2='a') then
+goto lab1;
+end if;
+p2:='b';
+<<lab1>>
+return p2;
+END;
+$$
+select 'func2',func2();
+func2 func2()
+func2 a
+DROP function func2;
+# ---------------------
+# -- TEST IN TRIGGER --
+# ---------------------
+#
+# TRIGGER : forward jump
+#
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+IF :NEW.a IS NULL
+THEN
+:NEW.a:= 15;
+goto end_trg;
+END IF;
+:NEW.a:= 10;
+<<end_trg>>
+null;
+END;
+$$
+insert into t1 values (1);
+insert into t1 values (null);
+SELECT * FROM t1;
+a
+10
+15
+DROP TRIGGER trg1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/sp-param.result b/mysql-test/suite/compat/oracle/r/sp-param.result
new file mode 100644
index 00000000000..4f4585c4570
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp-param.result
@@ -0,0 +1,132 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-10596 Allow VARCHAR and VARCHAR2 without length as a data type of routine parameters and in RETURN clause
+#
+CREATE FUNCTION f1(param CHAR) RETURN CHAR AS BEGIN RETURN param; END;;
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param CHAR) RETURN varchar(2000) CHARSET latin1
+AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT LENGTH(f1(REPEAT('a',2000)));;
+LENGTH(f1(REPEAT('a',2000)))
+2000
+CREATE TABLE t1 AS SELECT f1(REPEAT('a',2000)) AS a;;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" text DEFAULT NULL
+)
+DROP TABLE t1;
+DROP FUNCTION f1;
+CREATE FUNCTION f1(param NCHAR) RETURN NCHAR AS BEGIN RETURN param; END;;
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param NCHAR) RETURN varchar(2000) CHARSET utf8
+AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT LENGTH(f1(REPEAT('a',2000)));;
+LENGTH(f1(REPEAT('a',2000)))
+2000
+CREATE TABLE t1 AS SELECT f1(REPEAT('a',2000)) AS a;;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" text CHARACTER SET utf8 DEFAULT NULL
+)
+DROP TABLE t1;
+DROP FUNCTION f1;
+CREATE FUNCTION f1(param BINARY) RETURN BINARY AS BEGIN RETURN param; END;;
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param BINARY) RETURN varbinary(2000)
+AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT LENGTH(f1(REPEAT('a',2000)));;
+LENGTH(f1(REPEAT('a',2000)))
+2000
+CREATE TABLE t1 AS SELECT f1(REPEAT('a',2000)) AS a;;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" blob DEFAULT NULL
+)
+DROP TABLE t1;
+DROP FUNCTION f1;
+CREATE FUNCTION f1(param VARCHAR) RETURN VARCHAR AS BEGIN RETURN param; END;;
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param VARCHAR) RETURN varchar(4000) CHARSET latin1
+AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT LENGTH(f1(REPEAT('a',4000)));;
+LENGTH(f1(REPEAT('a',4000)))
+4000
+CREATE TABLE t1 AS SELECT f1(REPEAT('a',4000)) AS a;;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" text DEFAULT NULL
+)
+DROP TABLE t1;
+DROP FUNCTION f1;
+CREATE FUNCTION f1(param VARCHAR2) RETURN VARCHAR2 AS BEGIN RETURN param; END;;
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param VARCHAR2) RETURN varchar(4000) CHARSET latin1
+AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT LENGTH(f1(REPEAT('a',4000)));;
+LENGTH(f1(REPEAT('a',4000)))
+4000
+CREATE TABLE t1 AS SELECT f1(REPEAT('a',4000)) AS a;;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" text DEFAULT NULL
+)
+DROP TABLE t1;
+DROP FUNCTION f1;
+CREATE FUNCTION f1(param NVARCHAR) RETURN NVARCHAR AS BEGIN RETURN param; END;;
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param NVARCHAR) RETURN varchar(4000) CHARSET utf8
+AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT LENGTH(f1(REPEAT('a',4000)));;
+LENGTH(f1(REPEAT('a',4000)))
+4000
+CREATE TABLE t1 AS SELECT f1(REPEAT('a',4000)) AS a;;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" text CHARACTER SET utf8 DEFAULT NULL
+)
+DROP TABLE t1;
+DROP FUNCTION f1;
+CREATE FUNCTION f1(param VARBINARY) RETURN VARBINARY AS BEGIN RETURN param; END;;
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param VARBINARY) RETURN varbinary(4000)
+AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT LENGTH(f1(REPEAT('a',4000)));;
+LENGTH(f1(REPEAT('a',4000)))
+4000
+CREATE TABLE t1 AS SELECT f1(REPEAT('a',4000)) AS a;;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" blob DEFAULT NULL
+)
+DROP TABLE t1;
+DROP FUNCTION f1;
+CREATE FUNCTION f1(param RAW) RETURN RAW AS BEGIN RETURN param; END;;
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param RAW) RETURN varbinary(4000)
+AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT LENGTH(f1(REPEAT('a',4000)));;
+LENGTH(f1(REPEAT('a',4000)))
+4000
+CREATE TABLE t1 AS SELECT f1(REPEAT('a',4000)) AS a;;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" blob DEFAULT NULL
+)
+DROP TABLE t1;
+DROP FUNCTION f1;
diff --git a/mysql-test/suite/compat/oracle/r/sp-row.result b/mysql-test/suite/compat/oracle/r/sp-row.result
new file mode 100644
index 00000000000..86b6b9a530b
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp-row.result
@@ -0,0 +1,3072 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-10914 ROW data type for stored routine variables
+#
+#
+# ROW of ROWs is not supported yet
+#
+CREATE PROCEDURE p1()
+AS
+a ROW(a ROW(a INT));
+BEGIN
+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 'ROW(a INT));
+BEGIN
+END' at line 3
+#
+# Returning the entire ROW parameter from a function
+#
+CREATE FUNCTION f1(a ROW(a INT, b INT)) RETURN INT
+AS
+BEGIN
+RETURN a;
+END;
+$$
+SELECT f1(ROW(10,20));
+ERROR 21000: Operand should contain 1 column(s)
+DROP FUNCTION f1;
+#
+# ROW as an SP parameter
+#
+CREATE FUNCTION f1(a ROW(a INT,b INT)) RETURN INT
+AS
+BEGIN
+RETURN a.b;
+END;
+$$
+CREATE PROCEDURE p1()
+AS
+a ROW(a INT,b INT):=(11,21);
+BEGIN
+SELECT f1(a);
+END;
+$$
+SELECT f1(ROW(10,20));
+f1(ROW(10,20))
+20
+SELECT f1(10);
+ERROR 21000: Operand should contain 2 column(s)
+SELECT f1(ROW(10,20,30));
+ERROR 21000: Operand should contain 2 column(s)
+CALL p1();
+f1(a)
+21
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+CREATE PROCEDURE p1(a ROW(a INT,b INT))
+AS
+BEGIN
+SELECT a.a, a.b;
+END;
+$$
+CALL p1(ROW(10,20));
+a.a a.b
+10 20
+CALL p1(10);
+ERROR 21000: Operand should contain 2 column(s)
+CALL p1(ROW(10,20,30));
+ERROR 21000: Operand should contain 2 column(s)
+DROP PROCEDURE p1;
+#
+# ROW as an SP OUT parameter
+#
+CREATE PROCEDURE p1(a OUT ROW(a INT,b INT))
+AS
+BEGIN
+a.a:=10;
+a.b:=20;
+END;
+$$
+CREATE PROCEDURE p2
+AS
+a ROW(a INT,b INT):=(11,21);
+BEGIN
+CALL p1(a);
+SELECT a.a,a.b;
+END;
+$$
+CALL p2();
+a.a a.b
+10 20
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+#
+# ROW as an SP return value is not supported yet
+#
+CREATE FUNCTION p1() RETURN ROW(a INT)
+AS
+BEGIN
+RETURN NULL;
+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 'ROW(a INT)
+AS
+BEGIN
+RETURN NULL;
+END' at line 1
+#
+# Diplicate row field
+#
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT, a DOUBLE);
+BEGIN
+SELECT a.a;
+END;
+$$
+ERROR 42S21: Duplicate column name 'a'
+#
+# Bad scalar default value
+#
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT, b DOUBLE):= 1;
+BEGIN
+SELECT a.a;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP PROCEDURE p1;
+#
+# Bad ROW default value with a wrong number of fields
+#
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT, b DOUBLE):= ROW(1,2,3);
+BEGIN
+SELECT a.a;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP PROCEDURE p1;
+#
+# Scalar variable vs table alias cause no ambiguity
+#
+CREATE PROCEDURE p1()
+AS
+a INT;
+BEGIN
+-- a.x is a table column here (not a row variable field)
+SELECT a.x FROM a;
+SELECT a.x FROM t1 a;
+END;
+$$
+DROP PROCEDURE p1;
+#
+# Using the entire ROW variable in select list
+#
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT);
+BEGIN
+SELECT a;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT,b INT);
+BEGIN
+SELECT a;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+#
+# Using the entire ROW variable in functions
+#
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT);
+BEGIN
+SELECT COALESCE(a);
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT,b INT);
+BEGIN
+SELECT COALESCE(a);
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT);
+BEGIN
+SELECT a+1;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT,b INT);
+BEGIN
+SELECT a+1;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+#
+# Comparing the entire ROW to a scalar value
+#
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT,b INT);
+BEGIN
+SELECT a=1;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT,b INT);
+BEGIN
+SELECT 1=a;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+#
+# Passing the entire ROW to a stored function
+#
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+BEGIN
+RETURN a;
+END;
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT,b INT);
+BEGIN
+SELECT f1(a);
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+BEGIN
+RETURN a;
+END;
+CREATE PROCEDURE p1()
+AS
+a ROW (a INT);
+BEGIN
+SELECT f1(a);
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+#
+# Assigning a scalar value to a ROW variable with 1 column
+#
+CREATE OR REPLACE PROCEDURE p1
+AS
+rec ROW(a INT);
+BEGIN
+rec:=1;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+#
+# Assigning a scalar value to a ROW variable with 2 columns
+#
+CREATE OR REPLACE PROCEDURE p1
+AS
+rec ROW(a INT,b INT);
+BEGIN
+rec:=1;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP PROCEDURE p1;
+#
+# Assigning a ROW value to a ROW variable with different number of columns
+#
+CREATE OR REPLACE PROCEDURE p1
+AS
+rec ROW(a INT,b INT);
+BEGIN
+rec:=ROW(1,2,3);
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP PROCEDURE p1;
+#
+# Returning the entire ROW from a function is not supported yet
+# This syntax would be needed: SELECT f1().x FROM DUAL;
+#
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+rec ROW(a INT);
+BEGIN
+RETURN rec;
+END;
+$$
+SELECT f1(10);
+ERROR 21000: Operand should contain 1 column(s)
+DROP FUNCTION f1;
+#
+# Using the entire ROW in SELECT..CREATE
+#
+CREATE PROCEDURE p1
+AS
+rec ROW(a INT,b INT);
+BEGIN
+CREATE TABLE t1 AS SELECT rec;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 1 column(s)
+DROP PROCEDURE p1;
+#
+# Using the entire ROW in LIMIT
+#
+CREATE PROCEDURE p1()
+AS
+rec ROW(a INT);
+BEGIN
+rec.a:= '10';
+SELECT * FROM t1 LIMIT rec;
+END;
+$$
+ERROR HY000: A variable of a non-integer based type in LIMIT clause
+#
+# Setting ROW fields using a SET command
+#
+CREATE OR REPLACE PROCEDURE p1
+AS
+rec ROW(a INT,b DOUBLE,c VARCHAR(10));
+a INT;
+BEGIN
+SET @a= 10, rec.a=10, rec.b=20, rec.c= 'test', a= 5;
+SELECT rec.a, rec.b, rec.c, a;
+END;
+$$
+CALL p1();
+rec.a rec.b rec.c a
+10 20 test 5
+DROP PROCEDURE p1;
+#
+# Assigning a ROW variable from a ROW value
+#
+CREATE PROCEDURE p1
+AS
+rec ROW(a INT,b INT);
+BEGIN
+rec:=ROW(1,2);
+SELECT rec.a, rec.b;
+END;
+$$
+CALL p1();
+rec.a rec.b
+1 2
+DROP PROCEDURE p1;
+#
+# Assigning a ROW variable from another ROW value
+#
+CREATE PROCEDURE p1
+AS
+rec1 ROW(a INT,b INT);
+rec2 ROW(a INT,b INT);
+BEGIN
+rec1:=ROW(1,2);
+rec2:=rec1;
+SELECT rec2.a, rec2.b;
+END;
+$$
+CALL p1();
+rec2.a rec2.b
+1 2
+DROP PROCEDURE p1;
+#
+# Comparing a ROW variable to a ROW() function
+#
+CREATE OR REPLACE PROCEDURE p1
+AS
+rec ROW(a INT,b INT);
+BEGIN
+rec.a:= 1;
+rec.b:= 2;
+SELECT rec=(0,0), rec=ROW(0,0), (0,0)=rec, ROW(0,0)=rec;
+SELECT rec=(1,2), rec=ROW(1,2), (1,2)=rec, ROW(1,2)=rec;
+SELECT rec=(NULL,0), rec=ROW(NULL,0);
+SELECT rec=(NULL,2), rec=ROW(NULL,2);
+SELECT rec<>(0,0), rec<>ROW(0,0);
+SELECT rec<>(1,2), rec<>ROW(1,2);
+SELECT rec<>(NULL,0), rec<>ROW(NULL,0);
+SELECT rec<>(NULL,2), rec<>ROW(NULL,2);
+SELECT rec IN ((0,0)), rec IN (ROW(0,0));
+SELECT rec IN ((1,2)), rec IN (ROW(1,2));
+SELECT rec IN ((0,NULL),(1,2));
+SELECT rec NOT IN ((0,NULL),(1,1));
+SELECT rec NOT IN ((1,NULL),(1,1));
+END;
+$$
+CALL p1();
+rec=(0,0) rec=ROW(0,0) (0,0)=rec ROW(0,0)=rec
+0 0 0 0
+rec=(1,2) rec=ROW(1,2) (1,2)=rec ROW(1,2)=rec
+1 1 1 1
+rec=(NULL,0) rec=ROW(NULL,0)
+0 0
+rec=(NULL,2) rec=ROW(NULL,2)
+NULL NULL
+rec<>(0,0) rec<>ROW(0,0)
+1 1
+rec<>(1,2) rec<>ROW(1,2)
+0 0
+rec<>(NULL,0) rec<>ROW(NULL,0)
+1 1
+rec<>(NULL,2) rec<>ROW(NULL,2)
+NULL NULL
+rec IN ((0,0)) rec IN (ROW(0,0))
+0 0
+rec IN ((1,2)) rec IN (ROW(1,2))
+1 1
+rec IN ((0,NULL),(1,2))
+1
+rec NOT IN ((0,NULL),(1,1))
+1
+rec NOT IN ((1,NULL),(1,1))
+NULL
+DROP PROCEDURE p1;
+#
+# Comparing a ROW variable to another ROW variable
+#
+CREATE OR REPLACE PROCEDURE p1
+AS
+rec1,rec2,rec3 ROW(a INT,b INT);
+BEGIN
+rec1.a:= 1;
+rec1.b:= 2;
+rec2.a:= 11;
+rec2.b:= 12;
+rec3.a:= 11;
+rec3.b:= 12;
+SELECT rec1=rec2, rec2=rec1, rec2=rec3, rec3=rec2;
+END;
+$$
+CALL p1();
+rec1=rec2 rec2=rec1 rec2=rec3 rec3=rec2
+0 0 1 1
+DROP PROCEDURE p1;
+#
+# Referencing a non-existing row variable
+#
+CREATE PROCEDURE p1()
+AS
+BEGIN
+SET a.b=1;
+END;
+$$
+ERROR HY000: Unknown structured system variable or ROW routine variable 'a'
+CREATE PROCEDURE p1()
+AS
+BEGIN
+a.b:=1;
+END;
+$$
+ERROR HY000: Unknown structured system variable or ROW routine variable 'a'
+#
+# Referencing a non-existing row field
+#
+CREATE PROCEDURE p1()
+AS
+a ROW(a INT,b INT);
+BEGIN
+SELECT a.c FROM t1;
+END;
+$$
+ERROR HY000: Row variable 'a' does not have a field 'c'
+#
+# ROW and scalar variables with the same name shadowing each other
+#
+CREATE PROCEDURE p1()
+AS
+a ROW(a INT);
+BEGIN
+a.a:=100;
+DECLARE
+a INT:= 200;
+BEGIN
+SELECT a;
+DECLARE
+a ROW(a INT);
+BEGIN
+a.a:=300;
+SELECT a.a;
+END;
+SELECT a;
+END;
+SELECT a.a;
+END;
+$$
+CALL p1();
+a
+200
+a.a
+300
+a
+200
+a.a
+100
+DROP PROCEDURE p1;
+#
+# ROW with good default values
+#
+CREATE PROCEDURE p1()
+AS
+a ROW(a INT,b INT):= (10,20);
+b ROW(a INT,b INT):= (11,21);
+c ROW(a INT,b INT):= a;
+BEGIN
+SELECT a.a, a.b, b.a, b.b, c.a, c.b FROM DUAL;
+END;
+$$
+CALL p1;
+a.a a.b b.a b.b c.a c.b
+10 20 11 21 10 20
+DROP PROCEDURE p1;
+#
+# ROW in WHERE clause
+#
+CREATE TABLE t1 (a INT,b INT);
+INSERT INTO t1 VALUES (10,20);
+CREATE PROCEDURE p1()
+AS
+rec ROW(a INT,b INT):=ROW(10,20);
+BEGIN
+SELECT * FROM t1 WHERE rec=ROW(a,b);
+SELECT * FROM t1 WHERE ROW(a,b)=rec;
+SELECT * FROM t1 WHERE rec=ROW(10,20);
+SELECT * FROM t1 WHERE ROW(10,20)=rec;
+END;
+$$
+CALL p1();
+a b
+10 20
+a b
+10 20
+a b
+10 20
+a b
+10 20
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# ROW fields in WHERE clause
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+CREATE PROCEDURE p1()
+AS
+rec ROW(a INT);
+BEGIN
+rec.a:= 10;
+SELECT * FROM t1 WHERE a=rec.a;
+END;
+$$
+CALL p1();
+a
+10
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# ROW fields in HAVING clause
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+CREATE PROCEDURE p1()
+AS
+rec ROW(a INT);
+BEGIN
+rec.a:= 10;
+SELECT * FROM t1 HAVING a=rec.a;
+SELECT * FROM t1 HAVING MIN(a)=rec.a;
+END;
+$$
+CALL p1();
+a
+10
+a
+10
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# ROW fields in LIMIT clause
+#
+CREATE TABLE t1 (a INT);
+SELECT 1 FROM t1 LIMIT t1.a;
+ERROR 42000: Undeclared variable: t1
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+CREATE PROCEDURE p1()
+AS
+rec ROW(a INT);
+BEGIN
+rec.a:= 10;
+SELECT * FROM t1 LIMIT rec.a;
+END;
+$$
+CALL p1();
+a
+10
+20
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+rec ROW(a VARCHAR(10));
+BEGIN
+rec.a:= '10';
+SELECT * FROM t1 LIMIT rec.a;
+END;
+$$
+ERROR HY000: A variable of a non-integer based type in LIMIT clause
+#
+# ROW fields in select list
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+CREATE PROCEDURE p1()
+AS
+t1 ROW(a INT);
+BEGIN
+t1.a:= 10;
+SELECT t1.a, 'This is the variable t1.a value, rather than the column t1.a' AS comm FROM t1;
+SELECT t1.a, t2.a, t1.a+t2.a FROM t1 t2;
+END;
+$$
+CALL p1();
+t1.a comm
+10 This is the variable t1.a value, rather than the column t1.a
+10 This is the variable t1.a value, rather than the column t1.a
+t1.a a t1.a+t2.a
+10 10 20
+10 20 30
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# ROW fields as insert values
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+rec ROW(a INT, b VARCHAR(10));
+BEGIN
+rec.a:= 10;
+rec.b:= 'test';
+INSERT INTO t1 VALUES (rec.a, rec.b);
+END;
+$$
+CALL p1();
+SELECT * FROM t1;
+a b
+10 test
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# ROW fields as SP out parameters
+#
+CREATE PROCEDURE p1(a OUT INT, b OUT VARCHAR)
+AS
+BEGIN
+a:= 10;
+b:= 'test';
+END;
+$$
+CREATE PROCEDURE p2
+AS
+rec ROW(a INT, b VARCHAR(10));
+BEGIN
+CALL p1(rec.a, rec.b);
+SELECT rec.a, rec.b;
+END;
+$$
+CALL p2;
+rec.a rec.b
+10 test
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+#
+# ROW fields as dynamic SQL out parameters
+#
+CREATE PROCEDURE p1(a OUT INT, b OUT VARCHAR)
+AS
+BEGIN
+a:= 20;
+b:= 'test-dynamic-sql';
+END;
+$$
+CREATE PROCEDURE p2
+AS
+rec ROW(a INT, b VARCHAR(30));
+BEGIN
+EXECUTE IMMEDIATE 'CALL p1(?,?)' USING rec.a, rec.b;
+SELECT rec.a, rec.b;
+END;
+$$
+CALL p2;
+rec.a rec.b
+20 test-dynamic-sql
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+#
+# ROW fields as SELECT..INTO targets
+#
+CREATE PROCEDURE p1
+AS
+rec ROW(a INT, b VARCHAR(10));
+BEGIN
+SELECT 10,'test' INTO rec.a,rec.b;
+SELECT rec.a, rec.b;
+END;
+$$
+CALL p1;
+rec.a rec.b
+10 test
+DROP PROCEDURE p1;
+#
+# Implicit default NULL handling
+#
+CREATE PROCEDURE p1
+AS
+rec ROW(a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,0), e TIME, f DATETIME);
+BEGIN
+SELECT rec.a, rec.b, rec.c, rec.d, rec.e, rec.f FROM DUAL;
+END;
+$$
+CALL p1();
+rec.a rec.b rec.c rec.d rec.e rec.f
+NULL NULL NULL NULL NULL NULL
+DROP PROCEDURE p1;
+#
+# NULL handling
+#
+CREATE PROCEDURE p1
+AS
+rec1 ROW(a INT, b VARCHAR(10)):=(NULL,NULL);
+rec2 ROW(a INT, b VARCHAR(10)):=rec1;
+BEGIN
+SELECT rec1.a, rec1.b, rec2.a, rec2.b;
+rec1:= (10,20);
+rec2:= rec1;
+SELECT rec1.a, rec1.b, rec2.a, rec2.b;
+rec1:= (NULL,20);
+rec2:= rec1;
+SELECT rec1.a, rec1.b, rec2.a, rec2.b;
+rec1:= (10,NULL);
+rec2:= rec1;
+SELECT rec1.a, rec1.b, rec2.a, rec2.b;
+rec1:= (NULL,NULL);
+rec2:= rec1;
+SELECT rec1.a, rec1.b, rec2.a, rec2.b;
+END;
+$$
+CALL p1;
+rec1.a rec1.b rec2.a rec2.b
+NULL NULL NULL NULL
+rec1.a rec1.b rec2.a rec2.b
+10 20 10 20
+rec1.a rec1.b rec2.a rec2.b
+NULL 20 NULL 20
+rec1.a rec1.b rec2.a rec2.b
+10 NULL 10 NULL
+rec1.a rec1.b rec2.a rec2.b
+NULL NULL NULL NULL
+DROP PROCEDURE p1;
+#
+# Testing multiple ROW variable declarations
+# This makes sure that fill_field_definitions() is called only once
+# per a ROW field, so create length is not converted to internal length
+# multiple times.
+#
+CREATE PROCEDURE p1
+AS
+rec1, rec2, rec3 ROW(a VARCHAR(10) CHARACTER SET utf8);
+BEGIN
+CREATE TABLE t1 AS SELECT rec1.a, rec2.a, rec3.a;
+END;
+$$
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "rec1.a" varchar(10) CHARACTER SET utf8 DEFAULT NULL,
+ "rec2.a" varchar(10) CHARACTER SET utf8 DEFAULT NULL,
+ "rec3.a" varchar(10) CHARACTER SET utf8 DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# INT
+#
+CREATE PROCEDURE p1() AS var INT; rec ROW(var INT); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(1); rec ROW(var INT(1)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(2); rec ROW(var INT(2)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(3); rec ROW(var INT(3)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(4); rec ROW(var INT(4)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(5); rec ROW(var INT(5)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(6); rec ROW(var INT(6)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(7); rec ROW(var INT(7)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(8); rec ROW(var INT(8)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(9); rec ROW(var INT(9)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(10); rec ROW(var INT(10)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(11); rec ROW(var INT(11)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(11) DEFAULT NULL,
+ "rec.var" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(12); rec ROW(var INT(12)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(12) DEFAULT NULL,
+ "rec.var" int(12) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(13); rec ROW(var INT(13)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(13) DEFAULT NULL,
+ "rec.var" int(13) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(14); rec ROW(var INT(14)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(14) DEFAULT NULL,
+ "rec.var" int(14) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(20); rec ROW(var INT(20)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(20) DEFAULT NULL,
+ "rec.var" int(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var INT(21); rec ROW(var INT(21)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" int(21) DEFAULT NULL,
+ "rec.var" int(21) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# TINYINT
+#
+CREATE PROCEDURE p1() AS var TINYINT; rec ROW(var TINYINT); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(4) DEFAULT NULL,
+ "rec.var" tinyint(4) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(1); rec ROW(var TINYINT(1)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(4) DEFAULT NULL,
+ "rec.var" tinyint(4) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(2); rec ROW(var TINYINT(2)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(4) DEFAULT NULL,
+ "rec.var" tinyint(4) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(3); rec ROW(var TINYINT(3)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(4) DEFAULT NULL,
+ "rec.var" tinyint(4) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(4); rec ROW(var TINYINT(4)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(4) DEFAULT NULL,
+ "rec.var" tinyint(4) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(5); rec ROW(var TINYINT(5)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(5) DEFAULT NULL,
+ "rec.var" tinyint(5) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(6); rec ROW(var TINYINT(6)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(6) DEFAULT NULL,
+ "rec.var" tinyint(6) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(7); rec ROW(var TINYINT(7)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(7) DEFAULT NULL,
+ "rec.var" tinyint(7) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(8); rec ROW(var TINYINT(8)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(8) DEFAULT NULL,
+ "rec.var" tinyint(8) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(9); rec ROW(var TINYINT(9)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(9) DEFAULT NULL,
+ "rec.var" tinyint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(10); rec ROW(var TINYINT(10)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(10) DEFAULT NULL,
+ "rec.var" tinyint(10) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(11); rec ROW(var TINYINT(11)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(11) DEFAULT NULL,
+ "rec.var" tinyint(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(12); rec ROW(var TINYINT(12)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(12) DEFAULT NULL,
+ "rec.var" tinyint(12) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(13); rec ROW(var TINYINT(13)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(13) DEFAULT NULL,
+ "rec.var" tinyint(13) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(14); rec ROW(var TINYINT(14)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(14) DEFAULT NULL,
+ "rec.var" tinyint(14) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(20); rec ROW(var TINYINT(20)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(20) DEFAULT NULL,
+ "rec.var" tinyint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYINT(21); rec ROW(var TINYINT(21)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinyint(21) DEFAULT NULL,
+ "rec.var" tinyint(21) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# SMALLINT
+#
+CREATE PROCEDURE p1() AS var SMALLINT; rec ROW(var SMALLINT); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(6) DEFAULT NULL,
+ "rec.var" smallint(6) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(1); rec ROW(var SMALLINT(1)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(6) DEFAULT NULL,
+ "rec.var" smallint(6) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(2); rec ROW(var SMALLINT(2)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(6) DEFAULT NULL,
+ "rec.var" smallint(6) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(3); rec ROW(var SMALLINT(3)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(6) DEFAULT NULL,
+ "rec.var" smallint(6) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(4); rec ROW(var SMALLINT(4)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(6) DEFAULT NULL,
+ "rec.var" smallint(6) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(5); rec ROW(var SMALLINT(5)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(6) DEFAULT NULL,
+ "rec.var" smallint(6) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(6); rec ROW(var SMALLINT(6)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(6) DEFAULT NULL,
+ "rec.var" smallint(6) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(7); rec ROW(var SMALLINT(7)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(7) DEFAULT NULL,
+ "rec.var" smallint(7) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(8); rec ROW(var SMALLINT(8)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(8) DEFAULT NULL,
+ "rec.var" smallint(8) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(9); rec ROW(var SMALLINT(9)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(9) DEFAULT NULL,
+ "rec.var" smallint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(10); rec ROW(var SMALLINT(10)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(10) DEFAULT NULL,
+ "rec.var" smallint(10) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(11); rec ROW(var SMALLINT(11)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(11) DEFAULT NULL,
+ "rec.var" smallint(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(12); rec ROW(var SMALLINT(12)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(12) DEFAULT NULL,
+ "rec.var" smallint(12) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(13); rec ROW(var SMALLINT(13)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(13) DEFAULT NULL,
+ "rec.var" smallint(13) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(14); rec ROW(var SMALLINT(14)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(14) DEFAULT NULL,
+ "rec.var" smallint(14) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(20); rec ROW(var SMALLINT(20)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(20) DEFAULT NULL,
+ "rec.var" smallint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var SMALLINT(21); rec ROW(var SMALLINT(21)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" smallint(21) DEFAULT NULL,
+ "rec.var" smallint(21) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# MEDIUMINT
+#
+CREATE PROCEDURE p1() AS var MEDIUMINT; rec ROW(var MEDIUMINT); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(9) DEFAULT NULL,
+ "rec.var" mediumint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(1); rec ROW(var MEDIUMINT(1)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(9) DEFAULT NULL,
+ "rec.var" mediumint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(2); rec ROW(var MEDIUMINT(2)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(9) DEFAULT NULL,
+ "rec.var" mediumint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(3); rec ROW(var MEDIUMINT(3)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(9) DEFAULT NULL,
+ "rec.var" mediumint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(4); rec ROW(var MEDIUMINT(4)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(9) DEFAULT NULL,
+ "rec.var" mediumint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(5); rec ROW(var MEDIUMINT(5)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(9) DEFAULT NULL,
+ "rec.var" mediumint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(6); rec ROW(var MEDIUMINT(6)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(9) DEFAULT NULL,
+ "rec.var" mediumint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(7); rec ROW(var MEDIUMINT(7)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(9) DEFAULT NULL,
+ "rec.var" mediumint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(8); rec ROW(var MEDIUMINT(8)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(9) DEFAULT NULL,
+ "rec.var" mediumint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(9); rec ROW(var MEDIUMINT(9)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(9) DEFAULT NULL,
+ "rec.var" mediumint(9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(10); rec ROW(var MEDIUMINT(10)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(10) DEFAULT NULL,
+ "rec.var" mediumint(10) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(11); rec ROW(var MEDIUMINT(11)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(11) DEFAULT NULL,
+ "rec.var" mediumint(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(12); rec ROW(var MEDIUMINT(12)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(12) DEFAULT NULL,
+ "rec.var" mediumint(12) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(13); rec ROW(var MEDIUMINT(13)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(13) DEFAULT NULL,
+ "rec.var" mediumint(13) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(14); rec ROW(var MEDIUMINT(14)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(14) DEFAULT NULL,
+ "rec.var" mediumint(14) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(20); rec ROW(var MEDIUMINT(20)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(20) DEFAULT NULL,
+ "rec.var" mediumint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMINT(21); rec ROW(var MEDIUMINT(21)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumint(21) DEFAULT NULL,
+ "rec.var" mediumint(21) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# BIGINT
+#
+CREATE PROCEDURE p1() AS var BIGINT; rec ROW(var BIGINT); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(1); rec ROW(var BIGINT(1)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(2); rec ROW(var BIGINT(2)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(3); rec ROW(var BIGINT(3)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(4); rec ROW(var BIGINT(4)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(5); rec ROW(var BIGINT(5)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(6); rec ROW(var BIGINT(6)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(7); rec ROW(var BIGINT(7)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(8); rec ROW(var BIGINT(8)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(9); rec ROW(var BIGINT(9)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(10); rec ROW(var BIGINT(10)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(11); rec ROW(var BIGINT(11)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(12); rec ROW(var BIGINT(12)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(13); rec ROW(var BIGINT(13)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(14); rec ROW(var BIGINT(14)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(20); rec ROW(var BIGINT(20)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(20) DEFAULT NULL,
+ "rec.var" bigint(20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BIGINT(21); rec ROW(var BIGINT(21)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" bigint(21) DEFAULT NULL,
+ "rec.var" bigint(21) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# DOUBLE
+#
+CREATE PROCEDURE p1() AS var DOUBLE; rec ROW(var DOUBLE); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double DEFAULT NULL,
+ "rec.var" double DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,1); rec ROW(var DOUBLE(30,1)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,1) DEFAULT NULL,
+ "rec.var" double(30,1) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,2); rec ROW(var DOUBLE(30,2)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,2) DEFAULT NULL,
+ "rec.var" double(30,2) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,3); rec ROW(var DOUBLE(30,3)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,3) DEFAULT NULL,
+ "rec.var" double(30,3) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,4); rec ROW(var DOUBLE(30,4)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,4) DEFAULT NULL,
+ "rec.var" double(30,4) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,5); rec ROW(var DOUBLE(30,5)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,5) DEFAULT NULL,
+ "rec.var" double(30,5) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,6); rec ROW(var DOUBLE(30,6)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,6) DEFAULT NULL,
+ "rec.var" double(30,6) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,7); rec ROW(var DOUBLE(30,7)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,7) DEFAULT NULL,
+ "rec.var" double(30,7) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,8); rec ROW(var DOUBLE(30,8)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,8) DEFAULT NULL,
+ "rec.var" double(30,8) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,9); rec ROW(var DOUBLE(30,9)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,9) DEFAULT NULL,
+ "rec.var" double(30,9) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,10); rec ROW(var DOUBLE(30,10)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,10) DEFAULT NULL,
+ "rec.var" double(30,10) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,11); rec ROW(var DOUBLE(30,11)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,11) DEFAULT NULL,
+ "rec.var" double(30,11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,12); rec ROW(var DOUBLE(30,12)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,12) DEFAULT NULL,
+ "rec.var" double(30,12) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,13); rec ROW(var DOUBLE(30,13)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,13) DEFAULT NULL,
+ "rec.var" double(30,13) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,14); rec ROW(var DOUBLE(30,14)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,14) DEFAULT NULL,
+ "rec.var" double(30,14) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,20); rec ROW(var DOUBLE(30,20)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,20) DEFAULT NULL,
+ "rec.var" double(30,20) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DOUBLE(30,21); rec ROW(var DOUBLE(30,21)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" double(30,21) DEFAULT NULL,
+ "rec.var" double(30,21) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# VARCHAR
+#
+CREATE PROCEDURE p1() AS var CHAR; rec ROW(var CHAR); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" varchar(1) DEFAULT NULL,
+ "rec.var" varchar(1) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BINARY; rec ROW(var BINARY); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" varbinary(1) DEFAULT NULL,
+ "rec.var" varbinary(1) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var CHAR(1); rec ROW(var CHAR(1)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" varchar(1) DEFAULT NULL,
+ "rec.var" varchar(1) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var CHAR(10); rec ROW(var CHAR(10)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" varchar(10) DEFAULT NULL,
+ "rec.var" varchar(10) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var NCHAR(10); rec ROW(var NCHAR(10)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" varchar(10) CHARACTER SET utf8 DEFAULT NULL,
+ "rec.var" varchar(10) CHARACTER SET utf8 DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var BINARY(10); rec ROW(var BINARY(10)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" varbinary(10) DEFAULT NULL,
+ "rec.var" varbinary(10) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var VARBINARY(10); rec ROW(var VARBINARY(10)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" varbinary(10) DEFAULT NULL,
+ "rec.var" varbinary(10) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var VARCHAR(10); rec ROW(var VARCHAR(10)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" varchar(10) DEFAULT NULL,
+ "rec.var" varchar(10) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var VARCHAR(10) CHARACTER SET utf8; rec ROW(var VARCHAR(10) CHARACTER SET utf8); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" varchar(10) CHARACTER SET utf8 DEFAULT NULL,
+ "rec.var" varchar(10) CHARACTER SET utf8 DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var VARCHAR(10) CHARACTER SET utf8 COLLATE utf8_bin; rec ROW(var VARCHAR(10) CHARACTER SET utf8 COLLATE utf8_bin); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" varchar(10) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
+ "rec.var" varchar(10) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# TIME
+#
+CREATE PROCEDURE p1() AS var TIME; rec ROW(var TIME); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" time DEFAULT NULL,
+ "rec.var" time DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TIME(1); rec ROW(var TIME(1)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" time(1) DEFAULT NULL,
+ "rec.var" time(1) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TIME(2); rec ROW(var TIME(2)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" time(2) DEFAULT NULL,
+ "rec.var" time(2) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TIME(3); rec ROW(var TIME(3)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" time(3) DEFAULT NULL,
+ "rec.var" time(3) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TIME(4); rec ROW(var TIME(4)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" time(4) DEFAULT NULL,
+ "rec.var" time(4) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TIME(5); rec ROW(var TIME(5)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" time(5) DEFAULT NULL,
+ "rec.var" time(5) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TIME(6); rec ROW(var TIME(6)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" time(6) DEFAULT NULL,
+ "rec.var" time(6) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# DATETIME
+#
+CREATE PROCEDURE p1() AS var DATETIME; rec ROW(var DATETIME); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" datetime DEFAULT NULL,
+ "rec.var" datetime DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DATETIME(1); rec ROW(var DATETIME(1)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" datetime(1) DEFAULT NULL,
+ "rec.var" datetime(1) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DATETIME(2); rec ROW(var DATETIME(2)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" datetime(2) DEFAULT NULL,
+ "rec.var" datetime(2) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DATETIME(3); rec ROW(var DATETIME(3)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" datetime(3) DEFAULT NULL,
+ "rec.var" datetime(3) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DATETIME(4); rec ROW(var DATETIME(4)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" datetime(4) DEFAULT NULL,
+ "rec.var" datetime(4) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DATETIME(5); rec ROW(var DATETIME(5)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" datetime(5) DEFAULT NULL,
+ "rec.var" datetime(5) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var DATETIME(6); rec ROW(var DATETIME(6)); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" datetime(6) DEFAULT NULL,
+ "rec.var" datetime(6) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# LOB
+#
+CREATE PROCEDURE p1() AS var TEXT; rec ROW(var TEXT); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" text DEFAULT NULL,
+ "rec.var" text DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYTEXT; rec ROW(var TINYTEXT); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" tinytext DEFAULT NULL,
+ "rec.var" tinytext DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMTEXT; rec ROW(var MEDIUMTEXT); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumtext DEFAULT NULL,
+ "rec.var" mediumtext DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var LONGTEXT; rec ROW(var LONGTEXT); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" longtext DEFAULT NULL,
+ "rec.var" longtext DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TEXT CHARACTER SET utf8; rec ROW(var TEXT CHARACTER SET utf8); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" mediumtext CHARACTER SET utf8 DEFAULT NULL,
+ "rec.var" mediumtext CHARACTER SET utf8 DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var TINYTEXT CHARACTER SET utf8; rec ROW(var TINYTEXT CHARACTER SET utf8); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" text CHARACTER SET utf8 DEFAULT NULL,
+ "rec.var" text CHARACTER SET utf8 DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var MEDIUMTEXT CHARACTER SET utf8; rec ROW(var MEDIUMTEXT CHARACTER SET utf8); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" longtext CHARACTER SET utf8 DEFAULT NULL,
+ "rec.var" longtext CHARACTER SET utf8 DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1() AS var LONGTEXT CHARACTER SET utf8; rec ROW(var LONGTEXT CHARACTER SET utf8); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END;
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "var" longtext CHARACTER SET utf8 DEFAULT NULL,
+ "rec.var" longtext CHARACTER SET utf8 DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# End of MDEV-10914 ROW data type for stored routine variables
+#
+#
+# MDEV-12133 sql_mode=ORACLE: table%ROWTYPE in variable declarations
+#
+#
+# Referring to a table in a non-existing database
+#
+CREATE PROCEDURE p1()
+AS
+rec test2.t1%ROWTYPE;
+BEGIN
+NULL;
+END;
+$$
+CALL p1();
+ERROR 42S02: Table 'test2.t1' doesn't exist
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CALL p1();
+ERROR 42S02: Table 'test2.t1' doesn't exist
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Referring to a table in the current database
+#
+CREATE PROCEDURE p1()
+AS
+rec t1%ROWTYPE;
+BEGIN
+CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+$$
+CALL p1();
+ERROR 42S02: Table 'test.t1' doesn't exist
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CALL p1();
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "rec.a" int(11) DEFAULT NULL,
+ "rec.b" varchar(10) DEFAULT NULL,
+ "rec.c" double DEFAULT NULL,
+ "rec.d" decimal(10,0) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Referring to a table in an explicitly specified database
+#
+CREATE PROCEDURE p1()
+AS
+rec test.t1%ROWTYPE;
+BEGIN
+CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+$$
+CALL p1();
+ERROR 42S02: Table 'test.t1' doesn't exist
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CALL p1();
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "rec.a" int(11) DEFAULT NULL,
+ "rec.b" varchar(10) DEFAULT NULL,
+ "rec.c" double DEFAULT NULL,
+ "rec.d" decimal(10,0) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Referring to a view in the current database
+#
+CREATE PROCEDURE p1()
+AS
+rec v1%ROWTYPE;
+BEGIN
+CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+$$
+CALL p1();
+ERROR 42S02: Table 'test.v1' doesn't exist
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CREATE VIEW v1 AS SELECT * FROM t1;
+CALL p1();
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "rec.a" int(11) DEFAULT NULL,
+ "rec.b" varchar(10) DEFAULT NULL,
+ "rec.c" double DEFAULT NULL,
+ "rec.d" decimal(10,0) DEFAULT NULL
+)
+DROP VIEW v1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Referring to a view in an explicitly specified database
+#
+CREATE PROCEDURE p1()
+AS
+rec test.v1%ROWTYPE;
+BEGIN
+CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+$$
+CALL p1();
+ERROR 42S02: Table 'test.v1' doesn't exist
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CREATE VIEW v1 AS SELECT * FROM t1;
+CALL p1();
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "rec.a" int(11) DEFAULT NULL,
+ "rec.b" varchar(10) DEFAULT NULL,
+ "rec.c" double DEFAULT NULL,
+ "rec.d" decimal(10,0) DEFAULT NULL
+)
+DROP VIEW v1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Checking that all table%ROWTYPE fields are NULL by default
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE;
+BEGIN
+SELECT rec1.a, rec1.b, rec1.c, rec1.d;
+END;
+$$
+CALL p1();
+rec1.a rec1.b rec1.c rec1.d
+NULL NULL NULL NULL
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# A table%ROWTYPE variable with a ROW expression as a default
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE DEFAULT ROW(10,'bbb');
+BEGIN
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+rec1.a rec1.b
+10 bbb
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# A table%ROWTYPE variable with an incompatible ROW expression as a default
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE DEFAULT ROW(10,'bbb','ccc');
+BEGIN
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# A table%ROWTYPE variable with a ROW variable as a default
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+rec1 ROW(a INT, b VARCHAR(10)):= ROW(10,'bbb');
+rec2 t1%ROWTYPE DEFAULT rec1;
+BEGIN
+SELECT rec2.a, rec2.b;
+END;
+$$
+CALL p1();
+rec2.a rec2.b
+10 bbb
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# A ROW variable using a table%ROWTYPE variable as a default
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE := ROW(10,'bbb');
+rec2 ROW(a INT, b VARCHAR(10)):= rec1;
+BEGIN
+SELECT rec2.a, rec2.b;
+END;
+$$
+CALL p1();
+rec2.a rec2.b
+10 bbb
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Assigning table%ROWTYPE variables with a different column count
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE);
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE;
+rec2 t2%ROWTYPE;
+BEGIN
+rec2:=rec1;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE;
+rec2 t2%ROWTYPE;
+BEGIN
+rec1:=rec2;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 3 column(s)
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Assigning compatible table%ROWTYPE variables (equal number of fields)
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (x INT, y VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE;
+rec2 t2%ROWTYPE;
+BEGIN
+rec1.a:= 10;
+rec1.b:= 'bbb';
+rec2:=rec1;
+SELECT rec2.x, rec2.y;
+END;
+$$
+CALL p1();
+rec2.x rec2.y
+10 bbb
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Assigning between incompatible table%ROWTYPE and explicit ROW variables
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE;
+rec2 ROW(x INT,y INT,z INT);
+BEGIN
+rec2.x:= 10;
+rec2.y:= 20;
+rec2.z:= 30;
+rec1:= rec2;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Assigning between compatible table%ROWTYPE and explicit ROW variables
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE;
+rec2 ROW(x INT,y INT);
+BEGIN
+rec2.x:= 10;
+rec2.y:= 20;
+rec1:= rec2;
+SELECT rec1.a, rec1.b;
+rec1.a:= 11;
+rec1.b:= 21;
+rec2:= rec1;
+SELECT rec2.x, rec2.y;
+END;
+$$
+CALL p1();
+rec1.a rec1.b
+10 20
+rec2.x rec2.y
+11 21
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Assigning table%ROWTYPE from a ROW expression
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE;
+BEGIN
+rec1:= ROW(10,20);
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+rec1.a rec1.b
+10 20
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Fetching a cursor into a table%ROWTYPE variable with a wrong field count
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'bb1',111.111e2, 12.31);
+CREATE PROCEDURE p1()
+AS
+rec2 t2%ROWTYPE;
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+OPEN cur1;
+FETCH cur1 INTO rec2;
+CLOSE cur1;
+END;
+$$
+CALL p1();
+ERROR HY000: Incorrect number of FETCH variables
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Fetching a cursor into a table%ROWTYPE variable
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE TABLE t2 LIKE t1;
+INSERT INTO t1 VALUES (10,'bb1',111.111e2, 12.31);
+INSERT INTO t1 VALUES (20,'bb2',222.222e2, 12.32);
+INSERT INTO t1 VALUES (30,'bb3',333.333e2, 12.33);
+CREATE PROCEDURE p1()
+AS
+rec t1%ROWTYPE;
+CURSOR cur IS SELECT * FROM t1;
+BEGIN
+OPEN cur;
+LOOP
+FETCH cur INTO rec;
+EXIT WHEN cur%NOTFOUND;
+SELECT rec.a, rec.b, rec.c, rec.d;
+INSERT INTO t2 VALUES (rec.a, rec.b, rec.c, rec.d);
+END LOOP;
+CLOSE cur;
+END;
+$$
+CALL p1();
+rec.a rec.b rec.c rec.d
+10 bb1 11111.1 12.31
+rec.a rec.b rec.c rec.d
+20 bb2 22222.2 12.32
+rec.a rec.b rec.c rec.d
+30 bb3 33333.3 12.33
+SELECT * FROM t2;
+a b c d
+10 bb1 11111.1 12.31
+20 bb2 22222.2 12.32
+30 bb3 33333.3 12.33
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Fetching a cursor into a table%ROWTYPE variable with different column names
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (x INT, y VARCHAR(10));
+INSERT INTO t1 VALUES (10,'bbb');
+CREATE PROCEDURE p1()
+AS
+rec2 t2%ROWTYPE;
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+OPEN cur1;
+FETCH cur1 INTO rec2;
+SELECT rec2.x, rec2.y;
+CLOSE cur1;
+END;
+$$
+CALL p1();
+rec2.x rec2.y
+10 bbb
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# Fetching a cursor into a table%ROWTYPE variable, with truncation
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (a INT, b INT);
+INSERT INTO t1 VALUES (10,'11x');
+CREATE PROCEDURE p1()
+AS
+rec2 t2%ROWTYPE;
+CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+OPEN cur1;
+FETCH cur1 INTO rec2;
+SELECT rec2.a, rec2.b;
+CLOSE cur1;
+END;
+$$
+CALL p1();
+rec2.a rec2.b
+10 11
+Warnings:
+Warning 1265 Data truncated for column 'b' at row 1
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# table%ROWTYPE variables are not allowed in LIMIT
+#
+CREATE TABLE t1 (a INT, b INT);
+INSERT INTO t1 VALUES (1,2);
+CREATE PROCEDURE p1()
+AS
+rec1 t1%ROWTYPE:=(1,2);
+BEGIN
+SELECT * FROM t1 LIMIT rec1.a;
+END;
+$$
+ERROR HY000: A variable of a non-integer based type in LIMIT clause
+DROP TABLE t1;
+#
+# table%ROWTYPE variable fields as OUT parameters
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1(a OUT INT,b OUT VARCHAR(10))
+AS
+BEGIN
+a:=10;
+b:='bb';
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+rec1 t1%ROWTYPE;
+BEGIN
+CALL p1(rec1.a, rec1.b);
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p2();
+rec1.a rec1.b
+10 bb
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Passing the entire table%ROWTYPE variable
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1(a ROW(a INT, b VARCHAR(10)))
+AS
+BEGIN
+SELECT a.a, a.b;
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+rec1 t1%ROWTYPE:= ROW(10,'bb');
+BEGIN
+CALL p1(rec1);
+END;
+$$
+CALL p2();
+a.a a.b
+10 bb
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Passing the entire table%ROWTYPE variable as an OUT parameter
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1(a OUT ROW(a INT, b VARCHAR(10)))
+AS
+BEGIN
+a:= ROW(10,'bb');
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+rec1 t1%ROWTYPE;
+BEGIN
+CALL p1(rec1);
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p2();
+rec1.a rec1.b
+10 bb
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Assigning a table%ROWTYPE field to an OUT parameter
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1 (res IN OUT INTEGER)
+AS
+rec1 t1%ROWTYPE:=ROW(10,'b0');
+BEGIN
+res:=rec1.a;
+END;
+$$
+CALL p1(@res);
+SELECT @res;
+@res
+10
+SET @res=NULL;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Testing Item_splocal_row_field_by_name::print
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1
+AS
+rec t1%ROWTYPE:=ROW(10,'bb');
+BEGIN
+EXPLAIN EXTENDED SELECT rec.a, rec.b;
+END;
+$$
+CALL p1();
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select rec.a@0["a"] AS "rec.a",rec.b@0["b"] AS "rec.b"
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Non-existing field
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1
+AS
+rec t1%ROWTYPE;
+BEGIN
+SELECT rec.c;
+END;
+$$
+CALL p1();
+ERROR HY000: Row variable 'rec' does not have a field 'c'
+ALTER TABLE t1 ADD c INT;
+CALL p1();
+rec.c
+NULL
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Testing that field names are case insensitive
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE PROCEDURE p1
+AS
+rec t1%ROWTYPE:=ROW(10,'bb');
+BEGIN
+SELECT rec.A, rec.B;
+END;
+$$
+CALL p1();
+rec.A rec.B
+10 bb
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Testing that table%ROWTYPE uses temporary tables vs shadowed real tables
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TEMPORARY TABLE t1 (x INT, y VARCHAR(10));
+CREATE PROCEDURE p1
+AS
+rec t1%ROWTYPE:=ROW(10,'bb');
+BEGIN
+SELECT rec.A, rec.B;
+END;
+$$
+CALL p1();
+ERROR HY000: Row variable 'rec' does not have a field 'A'
+DROP TEMPORARY TABLE t1;
+CALL p1();
+rec.A rec.B
+10 bb
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Testing that the structure of table%ROWTYPE variables is determined at the very beginning and is not changed after ALTER
+#
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+BEGIN
+ALTER TABLE t1 ADD c INT;
+DECLARE
+rec t1%ROWTYPE; -- this will not have column "c"
+ BEGIN
+rec.c:=10;
+END;
+END;
+$$
+CALL p1();
+ERROR HY000: Row variable 'rec' does not have a field 'c'
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# MDEV-12291 Allow ROW variables as SELECT INTO targets
+#
+# ROW variable with a wrong column count
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+rec1 ROW(a INT, b VARCHAR(32), c DOUBLE);
+BEGIN
+SELECT * FROM t1 INTO rec1;
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+ERROR 21000: The used SELECT statements have a different number of columns
+DROP TABLE t1;
+DROP PROCEDURE p1;
+# Multiple ROW variables
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+rec1 ROW(a INT, b VARCHAR(32));
+BEGIN
+SELECT * FROM t1 INTO rec1, rec1;
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+# ROW variables working example
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+rec1 ROW(a INT, b VARCHAR(32));
+BEGIN
+SELECT * FROM t1 INTO rec1;
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+rec1.a rec1.b
+10 b10
+DROP TABLE t1;
+DROP PROCEDURE p1;
+# table%ROWTYPE variable with a wrong column count
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+rec1 t1%ROWTYPE;
+BEGIN
+SELECT 10,'a','b' FROM t1 INTO rec1;
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+ERROR 21000: The used SELECT statements have a different number of columns
+DROP TABLE t1;
+DROP PROCEDURE p1;
+# Multiple table%ROWTYPE variables
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+rec1 t1%ROWTYPE;
+BEGIN
+SELECT 10,'a' FROM t1 INTO rec1, rec1;
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+# table%ROWTYPE working example
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+rec1 t1%ROWTYPE;
+BEGIN
+SELECT * FROM t1 INTO rec1;
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+rec1.a rec1.b
+10 b10
+DROP TABLE t1;
+DROP PROCEDURE p1;
+# cursor%ROWTYPE variable with a wrong column count
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+CURSOR cur1 IS SELECT 10, 'b0', 'c0';
+rec1 cur1%ROWTYPE;
+BEGIN
+SELECT * FROM t1 INTO rec1;
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+ERROR 21000: The used SELECT statements have a different number of columns
+DROP TABLE t1;
+DROP PROCEDURE p1;
+# Multiple cursor%ROWTYPE variables
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+CURSOR cur1 IS SELECT * FROM t1;
+rec1 cur1%ROWTYPE;
+BEGIN
+SELECT * FROM t1 INTO rec1, rec1;
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+ERROR 21000: Operand should contain 2 column(s)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+# cursor%ROWTYPE working example
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+CREATE PROCEDURE p1 AS
+CURSOR cur1 IS SELECT * FROM t1;
+rec1 cur1%ROWTYPE;
+BEGIN
+SELECT * FROM t1 INTO rec1;
+SELECT rec1.a, rec1.b;
+END;
+$$
+CALL p1();
+rec1.a rec1.b
+10 b10
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# MDEV-12347 Valgrind reports invalid read errors in Item_field_row::element_index_by_name
+#
+CREATE TABLE t1 (a INT, b ENUM('b0','b1','b12','b3'));
+CREATE PROCEDURE p1 AS
+BEGIN
+DECLARE
+rec t1%ROWTYPE;
+BEGIN
+rec.b:='b0';
+SELECT rec.b;
+END;
+END;
+$$
+CALL p1();
+rec.b
+b0
+DROP TABLE t1;
+DROP PROCEDURE p1;
+CREATE TABLE t1 (a INT, b SET('b0','b1','b12','b3'));
+CREATE PROCEDURE p1 AS
+BEGIN
+DECLARE
+rec t1%ROWTYPE;
+BEGIN
+rec.b:='b0';
+SELECT rec.b;
+END;
+END;
+$$
+CALL p1();
+rec.b
+b0
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# MDEV-13273 Confusion between table alias and ROW type variable
+#
+CREATE TABLE t1 (c1 INT, c2 INT);
+INSERT INTO t1 VALUES (0,0);
+CREATE PROCEDURE p1
+AS
+a INT;
+b INT;
+BEGIN
+-- a.c1 is a table column
+SELECT a.c1 INTO b
+FROM t1 a
+WHERE a.c2 = 0;
+SELECT b;
+END;
+$$
+CALL p1;
+b
+0
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (c1 INT, c2 INT);
+INSERT INTO t1 VALUES (0,0);
+CREATE PROCEDURE p1
+AS
+a ROW (c1 INT, c2 INT) := ROW(101,102);
+b INT;
+BEGIN
+-- a.c1 is a ROW variable field
+SELECT a.c1 INTO b
+FROM t1 a
+WHERE a.c2 = 102;
+SELECT b;
+END;
+$$
+CALL p1;
+b
+101
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (c1 INT, c2 INT);
+INSERT INTO t1 VALUES (0,0);
+CREATE PROCEDURE p1
+AS
+a t1%ROWTYPE := ROW (10,20);
+b INT;
+BEGIN
+-- a.c1 is a ROW variable field
+SELECT a.c1 INTO b
+FROM t1 a
+WHERE a.c2 = 20;
+SELECT b;
+END;
+$$
+CALL p1;
+b
+10
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (c1 INT, c2 INT);
+INSERT INTO t1 VALUES (0,0);
+CREATE PROCEDURE p1
+AS
+CURSOR cur1 IS SELECT * FROM t1;
+a cur1%ROWTYPE := ROW (10,20);
+b INT;
+BEGIN
+-- a.c1 is a ROW variable field
+SELECT a.c1 INTO b
+FROM t1 a
+WHERE a.c2 = 20;
+SELECT b;
+END;
+$$
+CALL p1;
+b
+10
+DROP PROCEDURE p1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/sp-security.result b/mysql-test/suite/compat/oracle/r/sp-security.result
new file mode 100644
index 00000000000..b98ecaca972
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp-security.result
@@ -0,0 +1,288 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+#
+#
+# Initiation:
+# - creating database db1
+# - creating user user1 with access rights to db1
+#
+CREATE DATABASE db1;
+CREATE TABLE db1.t1 (a INT, b VARCHAR(10));
+CREATE USER user1;
+GRANT ALL PRIVILEGES ON test.* TO user1;
+connect conn1,localhost,user1,,test;
+SET sql_mode=ORACLE;
+SELECT database();
+database()
+test
+SELECT user();
+user()
+user1@localhost
+#
+# Making sure that user1 does not have privileges to db1.t1
+#
+SHOW CREATE TABLE db1.t1;
+ERROR 42000: SHOW command denied to user 'user1'@'localhost' for table 't1'
+SHOW FIELDS IN db1.t1;
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
+#
+# Trigger: using %TYPE with a table we don't have access to
+#
+CREATE TABLE test.t1 (a INT, b INT);
+INSERT INTO test.t1 (a,b) VALUES (10,20);
+SELECT * FROM t1;
+a b
+10 20
+CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
+BEGIN
+DECLARE b db1.t1.b%TYPE := 20;
+BEGIN
+:NEW.b := 10;
+END;
+END
+$$
+INSERT INTO t1 (a) VALUES (10);
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
+SELECT * FROM t1;
+a b
+10 20
+DROP TRIGGER tr1;
+DROP TABLE t1;
+#
+# Stored procedure: Using %TYPE for with a table that we don't have access to
+# DEFINER user1, SQL SECURITY DEFAULT
+#
+CREATE PROCEDURE p1()
+AS
+a db1.t1.a%TYPE := 10;
+BEGIN
+SELECT a;
+END;
+$$
+CALL p1;
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+a db1.t1%ROWTYPE;
+BEGIN
+SELECT a.a;
+END;
+$$
+CALL p1;
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
+DROP PROCEDURE p1;
+#
+# Stored procedure: Using %TYPE for with a table that we don't have access to
+# DEFINER root, SQL SECURITY INVOKER
+#
+connection default;
+CREATE PROCEDURE p1()
+SQL SECURITY INVOKER
+AS
+a db1.t1.a%TYPE := 10;
+BEGIN
+SELECT a;
+END;
+$$
+connection conn1;
+CALL p1;
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
+DROP PROCEDURE p1;
+connection default;
+CREATE PROCEDURE p1()
+SQL SECURITY INVOKER
+AS
+a db1.t1%ROWTYPE;
+BEGIN
+SELECT a.a;
+END;
+$$
+connection conn1;
+CALL p1;
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
+DROP PROCEDURE p1;
+#
+# Stored procedure: Using %TYPE for with a table that we don't have access to
+# DEFINER root, SQL SECURITY DEFINER
+#
+connection default;
+CREATE PROCEDURE p1()
+SQL SECURITY DEFINER
+AS
+a db1.t1.a%TYPE := 10;
+BEGIN
+SELECT a;
+END;
+$$
+connection conn1;
+CALL p1;
+a
+10
+DROP PROCEDURE p1;
+connection default;
+CREATE PROCEDURE p1()
+SQL SECURITY DEFINER
+AS
+a db1.t1%ROWTYPE;
+BEGIN
+a.a:= 10;
+SELECT a.a;
+END;
+$$
+connection conn1;
+CALL p1;
+a.a
+10
+DROP PROCEDURE p1;
+#
+# Stored function: Using %TYPE for with a table that we don't have access to
+# DEFINER user1, SQL SECURITY DEFAULT
+#
+CREATE TABLE t1 (a INT);
+CREATE FUNCTION f1() RETURN INT
+AS
+a db1.t1.a%TYPE:=0;
+BEGIN
+RETURN OCTET_LENGTH(a);
+END;
+$$
+SELECT f1();
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
+DROP FUNCTION f1;
+DROP TABLE t1;
+#
+# Stored function: Using %TYPE for with a table that we don't have access to
+# DEFINER root, SQL SECURITY INVOKER
+#
+connection default;
+CREATE TABLE t1 (a INT);
+CREATE FUNCTION f1() RETURN INT
+SQL SECURITY INVOKER
+AS
+a db1.t1.a%TYPE:=0;
+BEGIN
+RETURN OCTET_LENGTH(a);
+END;
+$$
+connection conn1;
+SELECT f1();
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
+DROP FUNCTION f1;
+DROP TABLE t1;
+#
+# Stored function: Using %TYPE for with a table that we don't have access to
+# DEFINER root, SQL SECURITY DEFINER
+#
+connection default;
+CREATE TABLE t1 (a INT);
+CREATE FUNCTION f1() RETURN INT
+SQL SECURITY DEFINER
+AS
+a db1.t1.a%TYPE:=0;
+BEGIN
+RETURN OCTET_LENGTH(a);
+END;
+$$
+connection conn1;
+SELECT f1();
+f1()
+1
+DROP FUNCTION f1;
+DROP TABLE t1;
+connection default;
+GRANT SELECT (a) ON db1.t1 TO user1;
+connection conn1;
+#
+# Making sure that user1 has access to db1.t1.a, but not to db1.t1.b
+#
+SHOW CREATE TABLE db1.t1;
+ERROR 42000: SHOW command denied to user 'user1'@'localhost' for table 't1'
+SHOW FIELDS IN db1.t1;
+Field Type Null Key Default Extra
+a int(11) YES NULL
+#
+# Trigger: Per-column privileges
+#
+CREATE TABLE test.t1 (a INT, b INT);
+INSERT INTO test.t1 (a,b) VALUES (10,20);
+SELECT * FROM t1;
+a b
+10 20
+CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
+BEGIN
+DECLARE a db1.t1.a%TYPE := 20;
+BEGIN
+:NEW.b := 10;
+END;
+END
+$$
+INSERT INTO t1 (a) VALUES (10);
+SELECT * FROM t1;
+a b
+10 20
+10 10
+DROP TRIGGER tr1;
+CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
+BEGIN
+DECLARE b db1.t1.b%TYPE := 20;
+BEGIN
+:NEW.b := 10;
+END;
+END
+$$
+INSERT INTO t1 (a) VALUES (10);
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for column 'b' in table 't1'
+SELECT * FROM t1;
+a b
+10 20
+10 10
+DROP TRIGGER tr1;
+DROP TABLE t1;
+#
+# Stored procedure: Per-column privileges
+# DEFINER user1, SQL SECURITY DEFAULT
+#
+CREATE PROCEDURE p1()
+AS
+a db1.t1.a%TYPE := 10;
+BEGIN
+SELECT a;
+END;
+$$
+CALL p1;
+a
+10
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+b db1.t1.b%TYPE := 10;
+BEGIN
+SELECT b;
+END;
+$$
+CALL p1;
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for column 'b' in table 't1'
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1()
+AS
+b db1.t1%ROWTYPE;
+BEGIN
+b.b:=10;
+SELECT b.b;
+END;
+$$
+CALL p1;
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for column 'b' in table 't1'
+DROP PROCEDURE p1;
+#
+# Clean up
+#
+disconnect conn1;
+connection default;
+DROP USER user1;
+DROP DATABASE db1;
+#
+# End of MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+#
diff --git a/mysql-test/suite/compat/oracle/r/sp.result b/mysql-test/suite/compat/oracle/r/sp.result
new file mode 100644
index 00000000000..a9158259f4a
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp.result
@@ -0,0 +1,2284 @@
+SET sql_mode=ORACLE;
+# Testing routines with no parameters
+CREATE FUNCTION f1 RETURN INT
+AS
+BEGIN
+RETURN 10;
+END;
+/
+SHOW CREATE FUNCTION f1;
+Function f1
+sql_mode PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER
+Create Function CREATE DEFINER="root"@"localhost" FUNCTION "f1"() RETURN int(11)
+AS
+BEGIN
+RETURN 10;
+END
+character_set_client latin1
+collation_connection latin1_swedish_ci
+Database Collation latin1_swedish_ci
+SELECT f1();
+f1()
+10
+DROP FUNCTION f1;
+CREATE PROCEDURE p1
+AS
+BEGIN
+SET @a=10;
+END;
+/
+SHOW CREATE PROCEDURE p1;
+Procedure p1
+sql_mode PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER
+Create Procedure CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
+AS
+BEGIN
+SET @a=10;
+END
+character_set_client latin1
+collation_connection latin1_swedish_ci
+Database Collation latin1_swedish_ci
+SET @a=0;
+CALL p1();
+SELECT @a;
+@a
+10
+DROP PROCEDURE p1;
+# Testing ":=" to set the default value of a variable
+CREATE FUNCTION f1 () RETURN NUMBER(10) AS
+a NUMBER(10) := 10;
+BEGIN
+DECLARE
+b NUMBER(10) DEFAULT 3;
+BEGIN
+RETURN a+b;
+END;
+END;
+/
+SELECT f1();
+f1()
+13
+DROP FUNCTION f1;
+# Testing labels
+CREATE FUNCTION f1 (a INT) RETURN CLOB AS
+BEGIN
+<<label1>>
+BEGIN
+IF a = 1 THEN
+LEAVE label1;
+END IF;
+RETURN 'IS NOT 1';
+END label1;
+RETURN 'IS 1';
+END;
+/
+SELECT f1(1);
+f1(1)
+IS 1
+SELECT f1(2);
+f1(2)
+IS NOT 1
+DROP FUNCTION f1;
+CREATE FUNCTION f1 (a INT) RETURN INT IS
+BEGIN
+<<label1>>
+LOOP
+IF a = 2 THEN
+LEAVE label1;
+END IF;
+SET a= a-1;
+END LOOP;
+RETURN a;
+END;
+/
+SELECT f1(4);
+f1(4)
+2
+DROP FUNCTION f1;
+CREATE FUNCTION f1 (a INT) RETURN INT AS
+BEGIN
+<<label1>>
+WHILE a>0 LOOP
+IF a = 2 THEN
+LEAVE label1;
+END IF;
+SET a= a-1;
+END LOOP label1;
+RETURN a;
+END;
+/
+SELECT f1(4);
+f1(4)
+2
+DROP FUNCTION f1;
+CREATE FUNCTION f1 (a INT) RETURN INT AS
+BEGIN
+<<label1>>
+REPEAT
+IF a = 2 THEN
+LEAVE label1;
+END IF;
+SET a= a-1;
+UNTIL a=0 END REPEAT;
+RETURN a;
+END;
+/
+SELECT f1(4);
+f1(4)
+2
+DROP FUNCTION f1;
+# Testing IN/OUT/INOUT
+CREATE PROCEDURE p1 (p1 IN VARCHAR2(10), p2 OUT VARCHAR2(10)) AS
+BEGIN
+SET p1='p1new';
+SET p2='p2new';
+END;
+/
+SET @p1='p1', @p2='p2';
+CALL p1(@p1, @p2);
+SELECT @p1, @p2;
+@p1 @p2
+p1 p2new
+DROP PROCEDURE p1;
+# Testing Oracle-style assigment
+CREATE PROCEDURE p1 (p1 OUT VARCHAR2(10)) AS
+BEGIN
+p1:= 'p1new';
+END;
+/
+SET @p1='p1';
+CALL p1(@p1);
+SELECT @p1;
+@p1
+p1new
+DROP PROCEDURE p1;
+# Testing that NULL is a valid statement
+CREATE PROCEDURE p1(a INT) AS
+BEGIN
+NULL;
+END;
+/
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1(a INT) AS
+a INT:=10;
+BEGIN
+IF a=10 THEN NULL; ELSE NULL; END IF;
+END;
+/
+DROP PROCEDURE p1;
+# Testing that (some) keyword_sp are allowed in Oracle-style assignments
+CREATE PROCEDURE p1 (action OUT INT) AS BEGIN action:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (clob OUT INT) AS BEGIN clob:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (enum OUT INT) AS BEGIN enum:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (via OUT INT) AS BEGIN via:=10; END;/
+DROP PROCEDURE p1/
+# Testing keyword_directly_assignable
+CREATE PROCEDURE p1 (ascii OUT INT) AS BEGIN ascii:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (backup OUT INT) AS BEGIN backup:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (binlog OUT INT) AS BEGIN binlog:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (byte OUT INT) AS BEGIN byte:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (cache OUT INT) AS BEGIN cache:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (checksum OUT INT) AS BEGIN checksum:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (checkpoint OUT INT) AS BEGIN checkpoint:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (column_add OUT INT) AS BEGIN column_add:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (column_check OUT INT) AS BEGIN column_check:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (column_create OUT INT) AS BEGIN column_create:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (column_delete OUT INT) AS BEGIN column_delete:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (column_get OUT INT) AS BEGIN column_get:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (deallocate OUT INT) AS BEGIN deallocate:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (examined OUT INT) AS BEGIN examined:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (execute OUT INT) AS BEGIN execute:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (flush OUT INT) AS BEGIN flush:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (format OUT INT) AS BEGIN format:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (get OUT INT) AS BEGIN get:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (help OUT INT) AS BEGIN help:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (host OUT INT) AS BEGIN host:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (install OUT INT) AS BEGIN install:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (option OUT INT) AS BEGIN option:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (options OUT INT) AS BEGIN options:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (owner OUT INT) AS BEGIN owner:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (parser OUT INT) AS BEGIN parser:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (port OUT INT) AS BEGIN port:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (prepare OUT INT) AS BEGIN prepare:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (remove OUT INT) AS BEGIN remove:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (reset OUT INT) AS BEGIN reset:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (restore OUT INT) AS BEGIN restore:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (security OUT INT) AS BEGIN security:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (server OUT INT) AS BEGIN server:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (signed OUT INT) AS BEGIN signed:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (socket OUT INT) AS BEGIN socket:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (slave OUT INT) AS BEGIN slave:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (slaves OUT INT) AS BEGIN slaves:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (soname OUT INT) AS BEGIN soname:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (start OUT INT) AS BEGIN start:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (stop OUT INT) AS BEGIN stop:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (stored OUT INT) AS BEGIN stored:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (unicode OUT INT) AS BEGIN unicode:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (uninstall OUT INT) AS BEGIN uninstall:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (upgrade OUT INT) AS BEGIN upgrade:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (wrapper OUT INT) AS BEGIN wrapper:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (xa OUT INT) AS BEGIN xa:=10; END;/
+DROP PROCEDURE p1/
+# Testing that keyword_directly_not_assignable does not work in :=
+CREATE PROCEDURE p1 (commit OUT INT) AS BEGIN commit:=10; 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 ':=10; END' at line 1
+CREATE PROCEDURE p1 (rollback OUT INT) AS BEGIN rollback:=10; 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 ':=10; END' at line 1
+CREATE PROCEDURE p1 (shutdown OUT INT) AS BEGIN shutdown:=10; 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 ':=10; END' at line 1
+# Testing that keyword_directly_not_assignable works in SET statements.
+CREATE PROCEDURE p1 (contains OUT INT) AS BEGIN SET contains=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (language OUT INT) AS BEGIN SET language=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (no OUT INT) AS BEGIN SET no=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (charset OUT INT) AS BEGIN SET charset=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (do OUT INT) AS BEGIN SET do=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (repair OUT INT) AS BEGIN SET repair=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (handler OUT INT) AS BEGIN SET handler=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (open OUT INT) AS BEGIN SET open=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (close OUT INT) AS BEGIN SET close=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (savepoint OUT INT) AS BEGIN SET savepoint=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (truncate OUT INT) AS BEGIN SET truncate=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (begin OUT INT) AS BEGIN SET begin=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (end OUT INT) AS BEGIN SET end=10; END;/
+DROP PROCEDURE p1/
+# Testing that keyword_directly_not_assignable works in table/column names
+CREATE TABLE contains (contains INT);
+DROP TABLE contains;
+CREATE TABLE language (language INT);
+DROP TABLE language;
+CREATE TABLE no (no INT);
+DROP TABLE no;
+CREATE TABLE charset (charset INT);
+DROP TABLE charset;
+CREATE TABLE do (do INT);
+DROP TABLE do;
+CREATE TABLE repair (repair INT);
+DROP TABLE repair;
+CREATE TABLE handler (handler INT);
+DROP TABLE handler;
+CREATE TABLE open (open INT);
+DROP TABLE open;
+CREATE TABLE close (close INT);
+DROP TABLE close;
+CREATE TABLE savepoint (savepoint INT);
+DROP TABLE savepoint;
+CREATE TABLE truncate (truncate INT);
+DROP TABLE truncate;
+CREATE TABLE begin (begin INT);
+DROP TABLE begin;
+CREATE TABLE end (end INT);
+DROP TABLE end;
+# Testing ELSIF
+CREATE FUNCTION f1(a INT) RETURN CLOB
+AS
+BEGIN
+IF a=1 THEN RETURN 'a is 1';
+ELSIF a=2 THEN RETURN 'a is 2';
+ELSE RETURN 'a is unknown';
+END IF;
+END;
+/
+SELECT f1(2) FROM DUAL;
+f1(2)
+a is 2
+DROP FUNCTION f1;
+# Testing top-level declarations
+CREATE PROCEDURE p1 (p1 OUT VARCHAR2(10))
+AS
+p2 VARCHAR(10);
+BEGIN
+p2:='p1new';
+p1:=p2;
+END;
+/
+SET @p1='p1';
+CALL p1(@p1);
+SELECT @p1;
+@p1
+p1new
+DROP PROCEDURE p1;
+CREATE FUNCTION f1 (p1 VARCHAR2(10)) RETURN VARCHAR(20)
+AS
+p2 VARCHAR(10);
+BEGIN
+p2:='new';
+RETURN CONCAT(p1, p2);
+END;
+/
+SET @p1='p1';
+SELECT f1(@p1);
+f1(@p1)
+p1new
+DROP FUNCTION f1;
+# Testing non-top declarations
+CREATE PROCEDURE p1 (p1 OUT VARCHAR2(10))
+AS
+BEGIN
+DECLARE
+p2 VARCHAR(10);
+BEGIN
+p2:='p1new';
+p1:=p2;
+END;
+DECLARE
+t1 VARCHAR(10);
+t2 VARCHAR(10);
+BEGIN
+END;
+END;
+/
+SET @p1='p1';
+CALL p1(@p1);
+SELECT @p1;
+@p1
+p1new
+DROP PROCEDURE p1;
+CREATE FUNCTION f1 (p1 VARCHAR2(10)) RETURN VARCHAR(20)
+AS
+BEGIN
+DECLARE
+p2 VARCHAR(10);
+BEGIN
+p2:='new';
+RETURN CONCAT(p1, p2);
+END;
+DECLARE
+t1 VARCHAR(10);
+t2 VARCHAR(10);
+BEGIN
+END;
+END;
+/
+SET @p1='p1';
+SELECT f1(@p1);
+f1(@p1)
+p1new
+DROP FUNCTION f1;
+# Testing exceptions
+CREATE TABLE t1 (c1 INT);
+CREATE PROCEDURE sp1 (p1 IN VARCHAR2(20), p2 OUT VARCHAR2(30))
+IS
+v1 INT;
+BEGIN
+SELECT c1 INTO v1 FROM t1;
+p2 := p1;
+EXCEPTION
+WHEN NOT FOUND THEN
+BEGIN
+p2 := 'def';
+END;
+END;
+/
+CALL sp1('abc', @a);
+SELECT @a;
+@a
+def
+DROP PROCEDURE sp1;
+DROP TABLE t1;
+CREATE PROCEDURE sp1 (v IN OUT INT, error IN INT)
+IS
+BEGIN
+SIGNAL SQLSTATE '45000' SET MYSQL_ERRNO=error, MESSAGE_TEXT='User defined error!';
+v:= 223;
+EXCEPTION
+WHEN 30001 THEN
+BEGIN
+v:= 113;
+END;
+END;
+/
+SET @v=10;
+CALL sp1(@v, 30001);
+CALL sp1(@v, 30002);
+ERROR 45000: User defined error!
+SELECT @v;
+@v
+113
+DROP PROCEDURE sp1;
+CREATE PROCEDURE sp1 (v IN OUT INT, error IN INT)
+IS
+BEGIN
+BEGIN
+BEGIN
+SIGNAL SQLSTATE '45000' SET MYSQL_ERRNO=error, MESSAGE_TEXT='User defined error!';
+v:= 223;
+EXCEPTION
+WHEN 30001 THEN
+BEGIN
+v:= 113;
+END;
+END;
+END;
+END;
+/
+SET @v=10;
+CALL sp1(@v, 30001);
+SELECT @v;
+@v
+113
+SET @v=10;
+CALL sp1(@v, 30002);
+ERROR 45000: User defined error!
+SELECT @v;
+@v
+10
+DROP PROCEDURE sp1;
+#
+# Testing EXIT statement
+#
+CREATE FUNCTION f1 RETURN INT
+IS
+i INT := 0;
+BEGIN
+EXIT;
+END;
+/
+ERROR 42000: EXIT with no matching label:
+CREATE FUNCTION f1 RETURN INT
+IS
+i INT := 0;
+BEGIN
+<<lable1>>
+BEGIN
+<<label2>>
+LOOP
+EXIT label1;
+END LOOP;
+END;
+END;
+/
+ERROR 42000: EXIT with no matching label: label1
+CREATE FUNCTION f1 RETURN INT
+IS
+i INT := 0;
+BEGIN
+LOOP
+LOOP
+i:= i + 1;
+IF i >= 5 THEN
+EXIT;
+END IF;
+END LOOP;
+i:= i + 100;
+EXIT;
+END LOOP;
+RETURN i;
+END;
+/
+SELECT f1() FROM DUAL;
+f1()
+105
+DROP FUNCTION f1;
+CREATE FUNCTION f1 RETURN INT
+IS
+i INT := 0;
+BEGIN
+<<label1>>
+LOOP
+<<label2>>
+LOOP
+i:= i + 1;
+IF i >= 5 THEN
+EXIT label2;
+END IF;
+END LOOP;
+i:= i + 100;
+EXIT;
+END LOOP;
+RETURN i;
+END;
+/
+SELECT f1() FROM DUAL;
+f1()
+105
+DROP FUNCTION f1;
+CREATE FUNCTION f1 RETURN INT
+IS
+i INT := 0;
+BEGIN
+<<label1>>
+LOOP
+<<label2>>
+LOOP
+i:= i + 1;
+IF i >= 5 THEN
+EXIT label1;
+END IF;
+END LOOP;
+i:= i + 100;
+EXIT;
+END LOOP;
+RETURN i;
+END;
+/
+SELECT f1() FROM DUAL;
+f1()
+5
+DROP FUNCTION f1;
+CREATE FUNCTION f1 RETURN INT
+IS
+i INT := 0;
+BEGIN
+LOOP
+i:= i + 1;
+EXIT WHEN i >=5;
+END LOOP;
+RETURN i;
+END;
+/
+SELECT f1() FROM DUAL;
+f1()
+5
+DROP FUNCTION f1;
+CREATE FUNCTION f1 RETURN INT
+IS
+i INT := 0;
+BEGIN
+<<label1>>
+LOOP
+<<label2>>
+LOOP
+i:= i + 1;
+EXIT label2 WHEN i >= 5;
+END LOOP;
+i:= i + 100;
+EXIT;
+END LOOP;
+RETURN i;
+END;
+/
+SELECT f1() FROM DUAL;
+f1()
+105
+DROP FUNCTION f1;
+CREATE FUNCTION f1 RETURN INT
+IS
+i INT := 0;
+BEGIN
+<<label1>>
+LOOP
+<<label2>>
+LOOP
+i:= i + 1;
+EXIT label1 WHEN i >= 5;
+END LOOP;
+i:= i + 100;
+EXIT;
+END LOOP;
+RETURN i;
+END;
+/
+SELECT f1() FROM DUAL;
+f1()
+5
+DROP FUNCTION f1;
+# Testing CURSOR declaration
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+CREATE FUNCTION f1 RETURN INT
+AS
+v_a INT:=10;
+CURSOR c IS SELECT a FROM t1;
+BEGIN
+OPEN c;
+FETCH c INTO v_a;
+CLOSE c;
+RETURN v_a;
+EXCEPTION
+WHEN OTHERS THEN RETURN -1;
+END;
+/
+SELECT f1() FROM DUAL;
+f1()
+1
+DROP FUNCTION f1;
+DROP TABLE t1;
+# Testing RETURN in procedures
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+BEGIN
+RETURN 10;
+END;
+/
+ERROR 42000: RETURN is only allowed in a FUNCTION
+CREATE FUNCTION f1 (a INT) RETURN INT
+AS
+BEGIN
+RETURN;
+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 ';
+END' at line 4
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+BEGIN
+IF a < 10 THEN
+BEGIN
+a:= a - 1;
+RETURN;
+END;
+END IF;
+a:= a + 1;
+EXCEPTION
+WHEN OTHERS THEN RETURN;
+END;
+/
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+@v
+11
+SET @v=9;
+CALL p1(@v);
+SELECT @v;
+@v
+8
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+BEGIN
+DROP TABLE t1_non_existent;
+EXCEPTION
+WHEN OTHERS THEN
+BEGIN
+a:= 100;
+RETURN;
+END;
+END;
+/
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+@v
+100
+DROP PROCEDURE p1;
+# Testing WHILE loop
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+i INT:= 1;
+j INT:= 3;
+BEGIN
+WHILE i<=j
+LOOP
+a:= a + i;
+i:= i + 1;
+END LOOP;
+END;
+/
+SET @v=0;
+CALL p1(@v);
+SELECT @v;
+@v
+6
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+i INT:= 1;
+j INT:= 3;
+BEGIN
+<<label>>
+WHILE i<=j
+LOOP
+a:= a + i;
+i:= i + 1;
+END LOOP label;
+END;
+/
+SET @v=0;
+CALL p1(@v);
+SELECT @v;
+@v
+6
+DROP PROCEDURE p1;
+# Testing the FOR loop statement
+CREATE TABLE t1 (a INT);
+FOR i IN 1..3
+LOOP
+INSERT INTO t1 VALUES (i);
+END LOOP;
+/
+SELECT * FROM t1;
+a
+1
+2
+3
+DROP TABLE t1;
+CREATE FUNCTION f1 (lower_bound INT, upper_bound INT, lim INT) RETURN INT
+AS
+total INT := 0;
+BEGIN
+FOR i IN lower_bound . . upper_bound
+LOOP
+NULL
+END LOOP;
+RETURN total;
+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 '. upper_bound
+LOOP
+NULL
+END LOOP;
+RETURN total;
+END' at line 5
+CREATE FUNCTION f1 (lower_bound INT, upper_bound INT, lim INT) RETURN INT
+AS
+total INT := 0;
+BEGIN
+FOR i IN lower_bound .. upper_bound
+LOOP
+total:= total + i;
+IF i = lim THEN
+EXIT;
+END IF;
+-- Bounds are calculated only once.
+-- The below assignments have no effect on the loop condition
+lower_bound:= 900;
+upper_bound:= 1000;
+END LOOP;
+RETURN total;
+END;
+/
+SELECT f1(1, 3, 100) FROM DUAL;
+f1(1, 3, 100)
+6
+SELECT f1(1, 3, 2) FROM DUAL;
+f1(1, 3, 2)
+3
+DROP FUNCTION f1;
+CREATE FUNCTION f1 RETURN INT
+AS
+total INT := 0;
+BEGIN
+FOR i IN 1 .. 5
+LOOP
+total:= total + 1000;
+FOR j IN 1 .. 5
+LOOP
+total:= total + 1;
+IF j = 3 THEN
+EXIT; -- End the internal loop
+END IF;
+END LOOP;
+END LOOP;
+RETURN total;
+END;
+/
+SELECT f1() FROM DUAL;
+f1()
+5015
+DROP FUNCTION f1;
+CREATE FUNCTION f1 (a INT, b INT) RETURN INT
+AS
+total INT := 0;
+BEGIN
+FOR i IN REVERSE a..1
+LOOP
+total:= total + i;
+IF i = b THEN
+EXIT;
+END IF;
+END LOOP;
+RETURN total;
+END
+/
+SELECT f1(3, 100) FROM DUAL;
+f1(3, 100)
+6
+SELECT f1(3, 2) FROM DUAL;
+f1(3, 2)
+5
+DROP FUNCTION f1;
+# Testing labeled FOR LOOP statement
+CREATE FUNCTION f1 (a INT, limita INT, b INT, limitb INT) RETURN INT
+AS
+total INT := 0;
+BEGIN
+<<la>>
+FOR ia IN 1 .. a
+LOOP
+total:= total + 1000;
+<<lb>>
+FOR ib IN 1 .. b
+LOOP
+total:= total + 1;
+EXIT lb WHEN ib = limitb;
+EXIT la WHEN ia = limita;
+END LOOP lb;
+END LOOP la;
+RETURN total;
+END;
+/
+SELECT f1(1, 1, 1, 1) FROM DUAL;
+f1(1, 1, 1, 1)
+1001
+SELECT f1(1, 2, 1, 2) FROM DUAL;
+f1(1, 2, 1, 2)
+1001
+SELECT f1(2, 1, 2, 1) FROM DUAL;
+f1(2, 1, 2, 1)
+2002
+SELECT f1(2, 1, 2, 2) FROM DUAL;
+f1(2, 1, 2, 2)
+1001
+SELECT f1(2, 2, 2, 2) FROM DUAL;
+f1(2, 2, 2, 2)
+2003
+SELECT f1(2, 3, 2, 3) FROM DUAL;
+f1(2, 3, 2, 3)
+2004
+DROP FUNCTION f1;
+# Testing labeled ITERATE in a labeled FOR LOOP statement
+CREATE FUNCTION f1 (a INT, b INT, blim INT) RETURN INT
+AS
+total INT := 0;
+BEGIN
+<<la>>
+FOR ia IN 1 .. a
+LOOP
+total:= total + 1000;
+DECLARE
+ib INT:= 1;
+BEGIN
+WHILE ib <= b
+LOOP
+IF ib > blim THEN
+ITERATE la;
+END IF;
+ib:= ib + 1;
+total:= total + 1;
+END LOOP;
+END;
+END LOOP la;
+RETURN total;
+END;
+/
+SELECT f1(3,3,0), f1(3,3,1), f1(3,3,2), f1(3,3,3), f1(3,3,4) FROM DUAL;
+f1(3,3,0) f1(3,3,1) f1(3,3,2) f1(3,3,3) f1(3,3,4)
+3000 3003 3006 3009 3009
+DROP FUNCTION f1;
+# Testing CONTINUE statement
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+total INT:= 0;
+BEGIN
+FOR i IN 1 .. a
+LOOP
+IF i=5 THEN
+CONTINUE;
+END IF;
+total:= total + 1;
+END LOOP;
+RETURN total;
+END;
+/
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+f1(3) f1(4) f1(5) f1(6)
+3 4 4 5
+DROP FUNCTION f1;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+total INT:= 0;
+BEGIN
+<<lj>>
+FOR j IN 1 .. 2
+LOOP
+FOR i IN 1 .. a
+LOOP
+IF i=5 THEN
+CONTINUE lj;
+END IF;
+total:= total + 1;
+END LOOP;
+END LOOP;
+RETURN total;
+END;
+/
+SELECT f1(3), f1(4), f1(5) FROM DUAL;
+f1(3) f1(4) f1(5)
+6 8 8
+DROP FUNCTION f1;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+total INT:= 0;
+BEGIN
+<<lj>>
+FOR j IN 1 .. 2
+LOOP
+FOR i IN 1 .. a
+LOOP
+CONTINUE lj WHEN i=5;
+total:= total + 1;
+END LOOP;
+END LOOP;
+RETURN total;
+END;
+/
+SELECT f1(3), f1(4), f1(5) FROM DUAL;
+f1(3) f1(4) f1(5)
+6 8 8
+DROP FUNCTION f1;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+total INT:= 0;
+i INT:= 1;
+BEGIN
+WHILE i <= a
+LOOP
+i:= i + 1;
+IF i=6 THEN
+CONTINUE;
+END IF;
+total:= total + 1;
+END LOOP;
+RETURN total;
+END;
+/
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+f1(3) f1(4) f1(5) f1(6)
+3 4 4 5
+DROP FUNCTION f1;
+#
+# Testing behaviour of unknown identifiers in EXIT and CONTINUE statements
+#
+CREATE PROCEDURE p1
+AS
+BEGIN
+LOOP
+EXIT WHEN unknown_ident IS NULL;
+END LOOP;
+END$$
+CALL p1;
+ERROR 42S22: Unknown column 'unknown_ident' in 'field list'
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+BEGIN
+<<label>>
+LOOP
+EXIT label WHEN unknown_ident IS NULL;
+END LOOP;
+END$$
+CALL p1;
+ERROR 42S22: Unknown column 'unknown_ident' in 'field list'
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+BEGIN
+LOOP
+CONTINUE WHEN unknown_ident IS NULL;
+END LOOP;
+END$$
+CALL p1;
+ERROR 42S22: Unknown column 'unknown_ident' in 'field list'
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1
+AS
+BEGIN
+<<label>>
+LOOP
+CONTINUE label WHEN unknown_ident IS NULL;
+END LOOP;
+END$$
+CALL p1;
+ERROR 42S22: Unknown column 'unknown_ident' in 'field list'
+DROP PROCEDURE p1;
+#
+# MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT
+#
+EXPLAIN EXTENDED SELECT sql%rowcount;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select SQL%ROWCOUNT AS "sql%rowcount"
+CREATE TABLE t1 AS SELECT SQL%ROWCOUNT;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "SQL%ROWCOUNT" bigint(21) NOT NULL
+)
+DROP TABLE t1;
+#
+# UPDATE
+#
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1
+AS
+BEGIN
+UPDATE t1 SET a=30;
+SELECT SQL%ROWCOUNT;
+END;
+$$
+CALL p1();
+SQL%ROWCOUNT
+0
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+CREATE PROCEDURE p1
+AS
+BEGIN
+UPDATE t1 SET a=30;
+SELECT SQL%ROWCOUNT;
+END;
+$$
+CALL p1();
+SQL%ROWCOUNT
+2
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# DELETE
+#
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1
+AS
+BEGIN
+DELETE FROM t1;
+SELECT SQL%ROWCOUNT;
+END;
+$$
+CALL p1();
+SQL%ROWCOUNT
+0
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+CREATE PROCEDURE p1
+AS
+BEGIN
+DELETE FROM t1;
+SELECT SQL%ROWCOUNT;
+END;
+$$
+CALL p1();
+SQL%ROWCOUNT
+2
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# SELECT ... INTO var FROM ... - one row found
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+CREATE PROCEDURE p1
+AS
+va INT;
+BEGIN
+SELECT a INTO va FROM t1 LIMIT 1;
+SELECT SQL%ROWCOUNT;
+END;
+$$
+CALL p1();
+SQL%ROWCOUNT
+1
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# SELECT ... INTO var FROM ... - no rows found
+#
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1
+AS
+va INT;
+BEGIN
+SELECT a INTO va FROM t1;
+SELECT SQL%ROWCOUNT;
+END;
+$$
+CALL p1();
+SQL%ROWCOUNT
+0
+Warnings:
+Warning 1329 No data - zero rows fetched, selected, or processed
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1
+AS
+va INT;
+BEGIN
+SELECT a INTO va FROM t1;
+SELECT SQL%ROWCOUNT;
+EXCEPTION
+WHEN NO_DATA_FOUND THEN SELECT SQL%ROWCOUNT||' (EXCEPTION)';
+END;
+$$
+CALL p1();
+SQL%ROWCOUNT||' (EXCEPTION)'
+0 (EXCEPTION)
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# SELECT ... INTO var FROM ... - multiple rows found
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+CREATE PROCEDURE p1
+AS
+va INT:=1;
+BEGIN
+SELECT a INTO va FROM t1;
+SELECT SQL%ROWCOUNT;
+EXCEPTION
+WHEN TOO_MANY_ROWS THEN SELECT SQL%ROWCOUNT||' (EXCEPTION) va='||va;
+END;
+$$
+CALL p1();
+SQL%ROWCOUNT||' (EXCEPTION) va='||va
+1 (EXCEPTION) va=10
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# INSERT INTO t2 SELECT ...
+#
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+CREATE PROCEDURE p1
+AS
+BEGIN
+INSERT INTO t2 SELECT * FROM t1;
+SELECT SQL%ROWCOUNT;
+END;
+$$
+CALL p1();
+SQL%ROWCOUNT
+2
+DROP PROCEDURE p1;
+DROP TABLE t1, t2;
+#
+# End of MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT
+#
+#
+# MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+#
+#
+# Missing table
+#
+CREATE PROCEDURE p1
+AS
+a t1.a%TYPE;
+BEGIN
+NULL;
+END;
+$$
+CALL p1();
+ERROR 42S02: Table 'test.t1' doesn't exist
+DROP PROCEDURE p1;
+#
+# Missing column
+#
+CREATE TABLE t1 (b INT);
+CREATE PROCEDURE p1
+AS
+a t1.a%TYPE;
+BEGIN
+NULL;
+END;
+$$
+CALL p1();
+ERROR 42S22: Unknown column 'a' in 't1'
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# One %TYPE variable
+#
+CREATE TABLE t1 (a INT);
+CREATE PROCEDURE p1
+AS
+a t1.a%TYPE;
+BEGIN
+a:= 123;
+SELECT a;
+END;
+$$
+CALL p1();
+a
+123
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Two %TYPE variables, with a truncation warning on assignment
+#
+CREATE TABLE t1 (a TINYINT, b INT);
+CREATE PROCEDURE p1
+AS
+a t1.a%TYPE;
+b t1.b%TYPE;
+BEGIN
+a:= 200;
+b:= 200;
+SELECT a, b;
+END;
+$$
+CALL p1();
+a b
+127 200
+Warnings:
+Warning 1264 Out of range value for column 'a' at row 1
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# %TYPE variables for fields with various attributes
+#
+CREATE TABLE t1 (
+id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
+a TINYINT NOT NULL,
+b INT NOT NULL,
+ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+UNIQUE(a)
+);
+CREATE PROCEDURE p1
+AS
+id t1.id%TYPE;
+a t1.a%TYPE;
+b t1.b%TYPE;
+ts t1.ts%TYPE;
+BEGIN
+SELECT id, a, b, ts;
+CREATE TABLE t2 AS SELECT id, a, b, ts;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+$$
+CALL p1();
+id a b ts
+NULL NULL NULL NULL
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "id" int(11) DEFAULT NULL,
+ "a" tinyint(4) DEFAULT NULL,
+ "b" int(11) DEFAULT NULL,
+ "ts" timestamp NULL DEFAULT NULL
+)
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# %TYPE + virtual columns
+#
+CREATE TABLE t1 (
+a INT NOT NULL,
+b VARCHAR(32),
+c INT AS (a + 10) VIRTUAL,
+d VARCHAR(5) AS (left(b,5)) PERSISTENT
+);
+CREATE PROCEDURE p1
+AS
+c t1.c%TYPE;
+d t1.d%TYPE;
+BEGIN
+SELECT c, d;
+CREATE TABLE t2 AS SELECT c, d;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+$$
+CALL p1();
+c d
+NULL NULL
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "c" int(11) DEFAULT NULL,
+ "d" varchar(5) DEFAULT NULL
+)
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# %TYPE + the ZEROFILL attribute
+#
+CREATE TABLE t1 (
+dz DECIMAL(10,3) ZEROFILL
+);
+CREATE PROCEDURE p1
+AS
+dzr t1.dz%TYPE := 10;
+dzt DECIMAL(10,3) ZEROFILL := 10;
+BEGIN
+SELECT dzr, dzt;
+CREATE TABLE t2 AS SELECT dzr,dzt;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+$$
+CALL p1();
+dzr dzt
+0000010.000 0000010.000
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "dzr" decimal(10,3) unsigned DEFAULT NULL,
+ "dzt" decimal(10,3) unsigned DEFAULT NULL
+)
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Temporary tables shadow real tables for %TYPE purposes
+#
+CREATE TABLE t1 (a VARCHAR(10));
+INSERT INTO t1 VALUES ('t1');
+CREATE TEMPORARY TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+CREATE PROCEDURE p1
+AS
+a t1.a%TYPE:=11;
+BEGIN
+CREATE TABLE t2 AS SELECT a;
+END;
+$$
+#
+# Should use INT(11) as %TYPE, as in the temporary table
+#
+CALL p1();
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "a" int(11) DEFAULT NULL
+)
+SELECT * FROM t2;
+a
+11
+DROP TABLE t2;
+SELECT * FROM t1;
+a
+10
+DROP TEMPORARY TABLE t1;
+SELECT * FROM t1;
+a
+t1
+#
+# Should use VARCHAR(10) as %TYPE, as in the real table
+#
+CALL p1();
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "a" varchar(10) DEFAULT NULL
+)
+SELECT * FROM t2;
+a
+11
+DROP TABLE t2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# t1.a%TYPE searches for "t1" in the current database
+#
+CREATE TABLE t1 (a VARCHAR(10));
+CREATE DATABASE test1;
+CREATE TABLE test1.t1 (a INT);
+CREATE PROCEDURE p1
+AS
+a t1.a%TYPE:=11;
+BEGIN
+CREATE TABLE test.t2 AS SELECT a;
+END;
+$$
+#
+# This interprets t1.a%TYPE as VARCHAR(10), as in test.t1.a
+#
+USE test;
+CALL test.p1();
+SHOW CREATE TABLE test.t2;
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "a" varchar(10) DEFAULT NULL
+)
+DROP TABLE test.t2;
+#
+# This interprets t1.a%TYPE as INT, as in test1.t1.a
+#
+USE test1;
+CALL test.p1();
+SHOW CREATE TABLE test.t2;
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "a" int(11) DEFAULT NULL
+)
+DROP TABLE test.t2;
+#
+# Error if there is no an active database
+#
+DROP DATABASE test1;
+CALL test.p1();
+ERROR 3D000: No database selected
+USE test;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# A reference to a table in a non-existing database
+#
+CREATE PROCEDURE p1
+AS
+a test1.t1.a%TYPE;
+BEGIN
+CREATE TABLE t1 AS SELECT a;
+END;
+$$
+CALL p1;
+ERROR 42S02: Table 'test1.t1' doesn't exist
+DROP PROCEDURE p1;
+#
+# A reference to a table in a different database
+#
+CREATE TABLE t1(a INT);
+CREATE DATABASE test1;
+CREATE TABLE test1.t1 (a VARCHAR(10));
+CREATE PROCEDURE p1
+AS
+a t1.a%TYPE;
+b test1.t1.a%TYPE;
+BEGIN
+CREATE TABLE t2 AS SELECT a,b;
+END;
+$$
+CALL p1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "a" int(11) DEFAULT NULL,
+ "b" varchar(10) DEFAULT NULL
+)
+DROP PROCEDURE p1;
+DROP TABLE t2;
+DROP DATABASE test1;
+DROP TABLE t1;
+#
+# Using a table before it appears in a %TYPE declaration + multiple %TYPE declarations
+#
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 (a,b) VALUES (10,'b10');
+CREATE PROCEDURE p1
+AS
+BEGIN
+INSERT INTO t1 (a,b) VALUES (11, 'b11');
+SELECT * FROM t1;
+DECLARE
+va t1.a%TYPE:= 30;
+vb t1.b%TYPE:= 'b30';
+BEGIN
+INSERT INTO t1 (a,b) VALUES (12,'b12');
+SELECT * FROM t1;
+INSERT INTO t1 (a,b) VALUES (va, vb);
+SELECT * FROM t1;
+END;
+DECLARE
+va t1.a%TYPE:= 40;
+vb t1.b%TYPE:= 'b40';
+BEGIN
+INSERT INTO t1 (a,b) VALUES (va,vb);
+SELECT * FROM t1;
+END;
+END;
+$$
+CALL p1;
+a b
+10 b10
+11 b11
+a b
+10 b10
+11 b11
+12 b12
+a b
+10 b10
+11 b11
+12 b12
+30 b30
+a b
+10 b10
+11 b11
+12 b12
+30 b30
+40 b40
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# %TYPE variables + TABLE vs VIEW
+#
+CREATE TABLE t1 (
+bit6 BIT(6),
+bit7 BIT(7),
+bit8 BIT(8),
+i1 TINYINT,
+i2 SMALLINT,
+i3 MEDIUMINT,
+i4 INT,
+i8 BIGINT,
+ff FLOAT,
+fd DOUBLE,
+cc CHAR(10),
+cv VARCHAR(10),
+cvu VARCHAR(10) CHARACTER SET utf8,
+t1 TINYTEXT,
+t2 TEXT,
+t3 MEDIUMTEXT,
+t4 LONGTEXT,
+enum1 ENUM('a','b','c'),
+set1 SET('a','b','c'),
+blob1 TINYBLOB,
+blob2 BLOB,
+blob3 MEDIUMBLOB,
+blob4 LONGBLOB,
+yy YEAR,
+dd DATE,
+tm0 TIME,
+tm3 TIME(3),
+tm6 TIME(6),
+dt0 DATETIME,
+dt3 DATETIME(3),
+dt6 DATETIME(6),
+ts0 TIMESTAMP,
+ts3 TIMESTAMP(3),
+ts6 TIMESTAMP(6),
+dc100 DECIMAL(10,0),
+dc103 DECIMAL(10,3),
+dc209 DECIMAL(20,9)
+);
+CREATE PROCEDURE p1(command enum('create','select'))
+AS
+bit6 t1.bit6%TYPE := 0x30;
+bit7 t1.bit7%TYPE := 0x41;
+bit8 t1.bit8%TYPE := 0x7E;
+i1 t1.i1%TYPE := 11;
+i2 t1.i2%TYPE := 12;
+i3 t1.i3%TYPE := 13;
+i4 t1.i4%TYPE := 14;
+i8 t1.i8%TYPE := 18;
+ff t1.ff%TYPE := 21;
+fd t1.fd%TYPE := 22;
+cc t1.cc%TYPE := 'char';
+cv t1.cv%TYPE := 'varchar';
+cvu t1.cvu%TYPE := 'varcharu8';
+t1 t1.t1%TYPE := 'text1';
+t2 t1.t2%TYPE := 'text2';
+t3 t1.t3%TYPE := 'text3';
+t4 t1.t4%TYPE := 'text4';
+enum1 t1.enum1%TYPE := 'b';
+set1 t1.set1%TYPE := 'a,c';
+blob1 t1.blob1%TYPE := 'blob1';
+blob2 t1.blob2%TYPE := 'blob2';
+blob3 t1.blob3%TYPE := 'blob3';
+blob4 t1.blob4%TYPE := 'blob4';
+yy t1.yy%TYPE := 2001;
+dd t1.dd%TYPE := '2001-01-01';
+tm0 t1.tm0%TYPE := '00:00:01';
+tm3 t1.tm3%TYPE := '00:00:03.333';
+tm6 t1.tm6%TYPE := '00:00:06.666666';
+dt0 t1.dt0%TYPE := '2001-01-01 00:00:01';
+dt3 t1.dt3%TYPE := '2001-01-03 00:00:01.333';
+dt6 t1.dt6%TYPE := '2001-01-06 00:00:01.666666';
+ts0 t1.ts0%TYPE := '2002-01-01 00:00:01';
+ts3 t1.ts3%TYPE := '2002-01-03 00:00:01.333';
+ts6 t1.ts6%TYPE := '2002-01-06 00:00:01.666666';
+dc100 t1.dc100%TYPE := 10;
+dc103 t1.dc103%TYPE := 10.123;
+dc209 t1.dc209%TYPE := 10.123456789;
+BEGIN
+CASE
+WHEN command='create' THEN
+CREATE TABLE t2 AS SELECT
+bit6, bit7, bit8,
+i1,i2,i3,i4,i8,
+ff,fd, dc100, dc103, dc209,
+cc,cv,cvu,
+t1,t2,t3,t4,
+enum1, set1,
+blob1, blob2, blob3, blob4,
+dd, yy,
+tm0, tm3, tm6,
+dt0, dt3, dt6,
+ts0, ts3, ts6;
+WHEN command='select' THEN
+SELECT
+bit6, bit7, bit8,
+i1,i2,i3,i4,i8,
+ff,fd, dc100, dc103, dc209,
+cc,cv,cvu,
+t1,t2,t3,t4,
+enum1, set1,
+blob1, blob2, blob3, blob4,
+dd, yy,
+tm0, tm3, tm6,
+dt0, dt3, dt6,
+ts0, ts3, ts6;
+END CASE;
+END;
+$$
+#
+# TABLE
+#
+CALL p1('create');
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "bit6" bit(6) DEFAULT NULL,
+ "bit7" bit(7) DEFAULT NULL,
+ "bit8" bit(8) DEFAULT NULL,
+ "i1" tinyint(4) DEFAULT NULL,
+ "i2" smallint(6) DEFAULT NULL,
+ "i3" mediumint(9) DEFAULT NULL,
+ "i4" int(11) DEFAULT NULL,
+ "i8" bigint(20) DEFAULT NULL,
+ "ff" float DEFAULT NULL,
+ "fd" double DEFAULT NULL,
+ "dc100" decimal(10,0) DEFAULT NULL,
+ "dc103" decimal(10,3) DEFAULT NULL,
+ "dc209" decimal(20,9) DEFAULT NULL,
+ "cc" varchar(10) DEFAULT NULL,
+ "cv" varchar(10) DEFAULT NULL,
+ "cvu" varchar(10) CHARACTER SET utf8 DEFAULT NULL,
+ "t1" tinytext DEFAULT NULL,
+ "t2" text DEFAULT NULL,
+ "t3" mediumtext DEFAULT NULL,
+ "t4" longtext DEFAULT NULL,
+ "enum1" varchar(1) DEFAULT NULL,
+ "set1" varchar(5) DEFAULT NULL,
+ "blob1" tinyblob DEFAULT NULL,
+ "blob2" longblob DEFAULT NULL,
+ "blob3" mediumblob DEFAULT NULL,
+ "blob4" longblob DEFAULT NULL,
+ "dd" datetime DEFAULT NULL,
+ "yy" year(4) DEFAULT NULL,
+ "tm0" time DEFAULT NULL,
+ "tm3" time(3) DEFAULT NULL,
+ "tm6" time(6) DEFAULT NULL,
+ "dt0" datetime DEFAULT NULL,
+ "dt3" datetime(3) DEFAULT NULL,
+ "dt6" datetime(6) DEFAULT NULL,
+ "ts0" timestamp NULL DEFAULT NULL,
+ "ts3" timestamp(3) NULL DEFAULT NULL,
+ "ts6" timestamp(6) NULL DEFAULT NULL
+)
+SELECT * FROM t2;
+bit6 0
+bit7 A
+bit8 ~
+i1 11
+i2 12
+i3 13
+i4 14
+i8 18
+ff 21
+fd 22
+dc100 10
+dc103 10.123
+dc209 10.123456789
+cc char
+cv varchar
+cvu varcharu8
+t1 text1
+t2 text2
+t3 text3
+t4 text4
+enum1 b
+set1 a,c
+blob1 blob1
+blob2 blob2
+blob3 blob3
+blob4 blob4
+dd 2001-01-01 00:00:00
+yy 2001
+tm0 00:00:01
+tm3 00:00:03.333
+tm6 00:00:06.666666
+dt0 2001-01-01 00:00:01
+dt3 2001-01-03 00:00:01.333
+dt6 2001-01-06 00:00:01.666666
+ts0 2002-01-01 00:00:01
+ts3 2002-01-03 00:00:01.333
+ts6 2002-01-06 00:00:01.666666
+DROP TABLE t2;
+CALL p1('select');
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def bit6 bit6 16 6 1 Y 32 0 63
+def bit7 bit7 16 7 1 Y 32 0 63
+def bit8 bit8 16 8 1 Y 32 0 63
+def i1 i1 1 4 2 Y 32768 0 63
+def i2 i2 2 6 2 Y 32768 0 63
+def i3 i3 9 9 2 Y 32768 0 63
+def i4 i4 3 11 2 Y 32768 0 63
+def i8 i8 8 20 2 Y 32768 0 63
+def ff ff 4 12 2 Y 32768 31 63
+def fd fd 5 22 2 Y 32768 31 63
+def dc100 dc100 246 11 2 Y 32768 0 63
+def dc103 dc103 246 12 6 Y 32768 3 63
+def dc209 dc209 246 22 12 Y 32768 9 63
+def cc cc 254 10 4 Y 0 0 8
+def cv cv 253 10 7 Y 0 0 8
+def cvu cvu 253 10 9 Y 0 0 8
+def t1 t1 252 255 5 Y 16 0 8
+def t2 t2 252 65535 5 Y 16 0 8
+def t3 t3 252 16777215 5 Y 16 0 8
+def t4 t4 252 4294967295 5 Y 16 0 8
+def enum1 enum1 254 1 1 Y 256 0 8
+def set1 set1 254 5 3 Y 2048 0 8
+def blob1 blob1 252 255 5 Y 144 0 63
+def blob2 blob2 252 4294967295 5 Y 144 0 63
+def blob3 blob3 252 16777215 5 Y 144 0 63
+def blob4 blob4 252 4294967295 5 Y 144 0 63
+def dd dd 12 19 19 Y 128 0 63
+def yy yy 13 4 4 Y 32864 0 63
+def tm0 tm0 11 10 8 Y 128 0 63
+def tm3 tm3 11 14 12 Y 128 3 63
+def tm6 tm6 11 17 15 Y 128 6 63
+def dt0 dt0 12 19 19 Y 128 0 63
+def dt3 dt3 12 23 23 Y 128 3 63
+def dt6 dt6 12 26 26 Y 128 6 63
+def ts0 ts0 7 19 19 Y 9376 0 63
+def ts3 ts3 7 23 23 Y 160 3 63
+def ts6 ts6 7 26 26 Y 160 6 63
+bit6 0
+bit7 A
+bit8 ~
+i1 11
+i2 12
+i3 13
+i4 14
+i8 18
+ff 21
+fd 22
+dc100 10
+dc103 10.123
+dc209 10.123456789
+cc char
+cv varchar
+cvu varcharu8
+t1 text1
+t2 text2
+t3 text3
+t4 text4
+enum1 b
+set1 a,c
+blob1 blob1
+blob2 blob2
+blob3 blob3
+blob4 blob4
+dd 2001-01-01 00:00:00
+yy 2001
+tm0 00:00:01
+tm3 00:00:03.333
+tm6 00:00:06.666666
+dt0 2001-01-01 00:00:01
+dt3 2001-01-03 00:00:01.333
+dt6 2001-01-06 00:00:01.666666
+ts0 2002-01-01 00:00:01
+ts3 2002-01-03 00:00:01.333
+ts6 2002-01-06 00:00:01.666666
+#
+# VIEW
+#
+ALTER TABLE t1 RENAME t0;
+CREATE VIEW t1 AS SELECT * FROM t0;
+CALL p1('create');
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "bit6" bit(6) DEFAULT NULL,
+ "bit7" bit(7) DEFAULT NULL,
+ "bit8" bit(8) DEFAULT NULL,
+ "i1" tinyint(4) DEFAULT NULL,
+ "i2" smallint(6) DEFAULT NULL,
+ "i3" mediumint(9) DEFAULT NULL,
+ "i4" int(11) DEFAULT NULL,
+ "i8" bigint(20) DEFAULT NULL,
+ "ff" float DEFAULT NULL,
+ "fd" double DEFAULT NULL,
+ "dc100" decimal(10,0) DEFAULT NULL,
+ "dc103" decimal(10,3) DEFAULT NULL,
+ "dc209" decimal(20,9) DEFAULT NULL,
+ "cc" varchar(10) DEFAULT NULL,
+ "cv" varchar(10) DEFAULT NULL,
+ "cvu" varchar(10) CHARACTER SET utf8 DEFAULT NULL,
+ "t1" tinytext DEFAULT NULL,
+ "t2" text DEFAULT NULL,
+ "t3" mediumtext DEFAULT NULL,
+ "t4" longtext DEFAULT NULL,
+ "enum1" varchar(1) DEFAULT NULL,
+ "set1" varchar(5) DEFAULT NULL,
+ "blob1" tinyblob DEFAULT NULL,
+ "blob2" longblob DEFAULT NULL,
+ "blob3" mediumblob DEFAULT NULL,
+ "blob4" longblob DEFAULT NULL,
+ "dd" datetime DEFAULT NULL,
+ "yy" year(4) DEFAULT NULL,
+ "tm0" time DEFAULT NULL,
+ "tm3" time(3) DEFAULT NULL,
+ "tm6" time(6) DEFAULT NULL,
+ "dt0" datetime DEFAULT NULL,
+ "dt3" datetime(3) DEFAULT NULL,
+ "dt6" datetime(6) DEFAULT NULL,
+ "ts0" timestamp NULL DEFAULT NULL,
+ "ts3" timestamp(3) NULL DEFAULT NULL,
+ "ts6" timestamp(6) NULL DEFAULT NULL
+)
+SELECT * FROM t2;
+bit6 0
+bit7 A
+bit8 ~
+i1 11
+i2 12
+i3 13
+i4 14
+i8 18
+ff 21
+fd 22
+dc100 10
+dc103 10.123
+dc209 10.123456789
+cc char
+cv varchar
+cvu varcharu8
+t1 text1
+t2 text2
+t3 text3
+t4 text4
+enum1 b
+set1 a,c
+blob1 blob1
+blob2 blob2
+blob3 blob3
+blob4 blob4
+dd 2001-01-01 00:00:00
+yy 2001
+tm0 00:00:01
+tm3 00:00:03.333
+tm6 00:00:06.666666
+dt0 2001-01-01 00:00:01
+dt3 2001-01-03 00:00:01.333
+dt6 2001-01-06 00:00:01.666666
+ts0 2002-01-01 00:00:01
+ts3 2002-01-03 00:00:01.333
+ts6 2002-01-06 00:00:01.666666
+DROP TABLE t2;
+CALL p1('select');
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def bit6 bit6 16 6 1 Y 32 0 63
+def bit7 bit7 16 7 1 Y 32 0 63
+def bit8 bit8 16 8 1 Y 32 0 63
+def i1 i1 1 4 2 Y 32768 0 63
+def i2 i2 2 6 2 Y 32768 0 63
+def i3 i3 9 9 2 Y 32768 0 63
+def i4 i4 3 11 2 Y 32768 0 63
+def i8 i8 8 20 2 Y 32768 0 63
+def ff ff 4 12 2 Y 32768 31 63
+def fd fd 5 22 2 Y 32768 31 63
+def dc100 dc100 246 11 2 Y 32768 0 63
+def dc103 dc103 246 12 6 Y 32768 3 63
+def dc209 dc209 246 22 12 Y 32768 9 63
+def cc cc 254 10 4 Y 0 0 8
+def cv cv 253 10 7 Y 0 0 8
+def cvu cvu 253 10 9 Y 0 0 8
+def t1 t1 252 255 5 Y 16 0 8
+def t2 t2 252 65535 5 Y 16 0 8
+def t3 t3 252 16777215 5 Y 16 0 8
+def t4 t4 252 4294967295 5 Y 16 0 8
+def enum1 enum1 254 1 1 Y 256 0 8
+def set1 set1 254 5 3 Y 2048 0 8
+def blob1 blob1 252 255 5 Y 144 0 63
+def blob2 blob2 252 4294967295 5 Y 144 0 63
+def blob3 blob3 252 16777215 5 Y 144 0 63
+def blob4 blob4 252 4294967295 5 Y 144 0 63
+def dd dd 12 19 19 Y 128 0 63
+def yy yy 13 4 4 Y 32864 0 63
+def tm0 tm0 11 10 8 Y 128 0 63
+def tm3 tm3 11 14 12 Y 128 3 63
+def tm6 tm6 11 17 15 Y 128 6 63
+def dt0 dt0 12 19 19 Y 128 0 63
+def dt3 dt3 12 23 23 Y 128 3 63
+def dt6 dt6 12 26 26 Y 128 6 63
+def ts0 ts0 7 19 19 Y 160 0 63
+def ts3 ts3 7 23 23 Y 160 3 63
+def ts6 ts6 7 26 26 Y 160 6 63
+bit6 0
+bit7 A
+bit8 ~
+i1 11
+i2 12
+i3 13
+i4 14
+i8 18
+ff 21
+fd 22
+dc100 10
+dc103 10.123
+dc209 10.123456789
+cc char
+cv varchar
+cvu varcharu8
+t1 text1
+t2 text2
+t3 text3
+t4 text4
+enum1 b
+set1 a,c
+blob1 blob1
+blob2 blob2
+blob3 blob3
+blob4 blob4
+dd 2001-01-01 00:00:00
+yy 2001
+tm0 00:00:01
+tm3 00:00:03.333
+tm6 00:00:06.666666
+dt0 2001-01-01 00:00:01
+dt3 2001-01-03 00:00:01.333
+dt6 2001-01-06 00:00:01.666666
+ts0 2002-01-01 00:00:01
+ts3 2002-01-03 00:00:01.333
+ts6 2002-01-06 00:00:01.666666
+DROP VIEW t1;
+DROP TABLE t0;
+DROP PROCEDURE p1;
+#
+# VIEW with subqueries
+#
+CREATE TABLE t1 (a INT,b INT);
+INSERT INTO t1 VALUES (10,1),(20,2),(30,3),(40,4);
+SELECT AVG(a) FROM t1;
+AVG(a)
+25.0000
+CREATE VIEW v1 AS SELECT a,1 as b FROM t1 WHERE a>(SELECT AVG(a) FROM t1) AND b>(SELECT 1);
+SELECT * FROM v1;
+a b
+30 1
+40 1
+CREATE PROCEDURE p1
+AS
+a v1.a%TYPE := 10;
+b v1.b%TYPE := 1;
+BEGIN
+SELECT a,b;
+END;
+$$
+CALL p1;
+a b
+10 1
+DROP PROCEDURE p1;
+CREATE FUNCTION f1 RETURN INT
+AS
+a v1.a%TYPE := 10;
+b v1.b%TYPE := 1;
+BEGIN
+RETURN a+b;
+END;
+$$
+SELECT f1();
+f1()
+11
+DROP FUNCTION f1;
+DROP VIEW v1;
+DROP TABLE t1;
+#
+# %TYPE variables + INFORMATION_SCHEMA
+#
+CREATE PROCEDURE p1
+AS
+tables_table_name INFORMATION_SCHEMA.TABLES.TABLE_NAME%TYPE;
+tables_table_rows INFORMATION_SCHEMA.TABLES.TABLE_ROWS%TYPE;
+processlist_info INFORMATION_SCHEMA.PROCESSLIST.INFO%TYPE;
+processlist_info_binary INFORMATION_SCHEMA.PROCESSLIST.INFO_BINARY%TYPE;
+BEGIN
+CREATE TABLE t1 AS SELECT
+tables_table_name,
+tables_table_rows,
+processlist_info,
+processlist_info_binary;
+END;
+$$
+CALL p1();
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "tables_table_name" varchar(64) CHARACTER SET utf8 DEFAULT NULL,
+ "tables_table_rows" bigint(21) unsigned DEFAULT NULL,
+ "processlist_info" longtext CHARACTER SET utf8 DEFAULT NULL,
+ "processlist_info_binary" blob DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# %TYPE + Table structure change
+# Data type for both a0 and a1 is chosen in the very beginning
+#
+CREATE PROCEDURE p1
+AS
+a0 t1.a%TYPE;
+BEGIN
+ALTER TABLE t1 MODIFY a VARCHAR(10); -- This does not affect a1
+DECLARE
+a1 t1.a%TYPE;
+BEGIN
+CREATE TABLE t2 AS SELECT a0, a1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+END
+$$
+CREATE TABLE t1 (a INT);
+CALL p1;
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "a0" int(11) DEFAULT NULL,
+ "a1" int(11) DEFAULT NULL
+)
+DROP TABLE t1;
+DROP PROCEDURE p1;
+#
+# %TYPE in parameters
+#
+CREATE TABLE t1 (a VARCHAR(10));
+CREATE DATABASE test1;
+CREATE TABLE test1.t1 (b SMALLINT);
+CREATE PROCEDURE p1(a t1.a%TYPE, b test1.t1.b%TYPE)
+AS
+BEGIN
+CREATE TABLE t2 AS SELECT a, b;
+END;
+$$
+CALL p1('test', 123);
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE "t2" (
+ "a" varchar(10) DEFAULT NULL,
+ "b" smallint(6) DEFAULT NULL
+)
+SELECT * FROM t2;
+a b
+test 123
+DROP TABLE t2;
+DROP PROCEDURE p1;
+DROP TABLE test1.t1;
+DROP DATABASE test1;
+DROP TABLE t1;
+#
+# %TYPE in a stored function variables and arguments
+#
+CREATE TABLE t1 (a INT);
+SET sql_mode=ORACLE;
+CREATE FUNCTION f1 (prm t1.a%TYPE) RETURN INT
+AS
+a t1.a%TYPE:= prm;
+BEGIN
+RETURN a;
+END;
+$$
+SELECT f1(20);
+f1(20)
+20
+DROP FUNCTION f1;
+DROP TABLE t1;
+#
+# %TYPE in function RETURN clause is not supported yet
+#
+CREATE FUNCTION f1 RETURN t1.a%TYPE
+AS
+BEGIN
+RETURN 0;
+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 't1.a%TYPE
+AS
+BEGIN
+RETURN 0;
+END' at line 1
+#
+# End of MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+#
+#
+# MDEV-12089 sql_mode=ORACLE: Understand optional routine name after the END keyword
+#
+CREATE FUNCTION f1 RETURN INT AS
+BEGIN
+RETURN 10;
+END f1;
+$$
+DROP FUNCTION f1;
+CREATE FUNCTION test.f1 RETURN INT AS
+BEGIN
+RETURN 10;
+END test.f1;
+$$
+DROP FUNCTION f1;
+CREATE FUNCTION test.f1 RETURN INT AS
+BEGIN
+RETURN 10;
+END test2.f1;
+$$
+ERROR HY000: END identifier 'test2.f1' does not match 'test.f1'
+CREATE FUNCTION test.f1 RETURN INT AS
+BEGIN
+RETURN 10;
+END test.f2;
+$$
+ERROR HY000: END identifier 'test.f2' does not match 'test.f1'
+CREATE FUNCTION f1 RETURN INT AS
+BEGIN
+RETURN 10;
+END test.f2;
+$$
+ERROR HY000: END identifier 'test.f2' does not match 'test.f1'
+CREATE FUNCTION f1 RETURN INT AS
+BEGIN
+RETURN 10;
+END test2.f1;
+$$
+ERROR HY000: END identifier 'test2.f1' does not match 'test.f1'
+CREATE PROCEDURE p1 AS
+BEGIN
+NULL;
+END p1;
+$$
+DROP PROCEDURE p1;
+CREATE PROCEDURE test.p1 AS
+BEGIN
+NULL;
+END test.p1;
+$$
+DROP PROCEDURE p1;
+CREATE PROCEDURE test.p1 AS
+BEGIN
+NULL;
+END test2.p1;
+$$
+ERROR HY000: END identifier 'test2.p1' does not match 'test.p1'
+CREATE PROCEDURE test.p1 AS
+BEGIN
+NULL;
+END test.p2;
+$$
+ERROR HY000: END identifier 'test.p2' does not match 'test.p1'
+CREATE PROCEDURE p1 AS
+BEGIN
+NULL;
+END test.p2;
+$$
+ERROR HY000: END identifier 'test.p2' does not match 'test.p1'
+CREATE PROCEDURE p1 AS
+BEGIN
+NULL;
+END test2.p1;
+$$
+ERROR HY000: END identifier 'test2.p1' does not match 'test.p1'
+#
+# MDEV-12107 sql_mode=ORACLE: Inside routines the CALL keywoard is optional
+#
+CREATE OR REPLACE PROCEDURE p1(a INT) AS
+BEGIN
+SELECT 'This is p1' AS "comment";
+END;
+/
+CREATE OR REPLACE PROCEDURE p2 AS
+BEGIN
+SELECT 'This is p2' AS "comment";
+END;
+/
+BEGIN
+p1(10);
+p2;
+test.p1(10);
+test.p2;
+END;
+/
+comment
+This is p1
+comment
+This is p2
+comment
+This is p1
+comment
+This is p2
+CREATE PROCEDURE p3 AS
+BEGIN
+p1(10);
+p2;
+test.p1(10);
+test.p2;
+END
+/
+CALL p3;
+comment
+This is p1
+comment
+This is p2
+comment
+This is p1
+comment
+This is p2
+DROP PROCEDURE p3;
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+#
+# MDEV-12854 Synchronize CREATE..SELECT data type and result set metadata data type for INT functions
+#
+SELECT SQL%ROWCOUNT;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def SQL%ROWCOUNT 8 21 1 N 32897 0 63
+SQL%ROWCOUNT
+0
diff --git a/mysql-test/suite/compat/oracle/r/trigger.result b/mysql-test/suite/compat/oracle/r/trigger.result
new file mode 100644
index 00000000000..f77a56546fa
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/trigger.result
@@ -0,0 +1,100 @@
+set sql_mode=ORACLE;
+:NEW.a := 1;
+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 'a := 1' at line 1
+:OLD.a := 1;
+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 'a := 1' at line 1
+:OLa.a := 1;
+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 'a := 1' at line 1
+SELECT :NEW.a;
+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 'a' at line 1
+SELECT :OLD.a;
+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 'a' at line 1
+SELECT :OLa.a;
+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 'a' at line 1
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW NEW.a:= 10;
+INSERT INTO t1 VALUES ();
+SELECT * FROM t1;
+a
+10
+DROP TRIGGER tr1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW :NEW.a:= 10;
+INSERT INTO t1 VALUES ();
+SELECT * FROM t1;
+a
+10
+DROP TRIGGER tr1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+IF :NEW.a IS NULL
+THEN
+:NEW.a:= 10;
+END IF;
+END;
+/
+INSERT INTO t1 VALUES (NULL);
+SELECT * FROM t1;
+a
+10
+DROP TRIGGER tr1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+IF :OLD.a IS NULL
+THEN
+:NEW.a:= 10;
+END IF;
+END;
+/
+INSERT INTO t1 VALUES (NULL);
+UPDATE t1 SET a=NULL;
+SELECT * FROM t1;
+a
+10
+DROP TRIGGER tr1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b INT, c INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1
+FOR EACH ROW
+DECLARE
+cnt INT := 0;
+BEGIN
+IF :NEW.a IS NULL THEN cnt:=cnt+1; END IF;
+IF :NEW.b IS NULL THEN cnt:=cnt+1; END IF;
+IF :NEW.c IS NULL THEN :NEW.c:=cnt; END IF;
+END;
+/
+INSERT INTO t1 VALUES ();
+INSERT INTO t1 VALUES (1, NULL, NULL);
+INSERT INTO t1 VALUES (NULL, 1, NULL);
+INSERT INTO t1 VALUES (1, 1, NULL);
+SELECT * FROM t1;
+a b c
+NULL NULL 2
+1 NULL 1
+NULL 1 1
+1 1 0
+DROP TABLE t1;
+#
+# MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+#
+CREATE TABLE t1 (a INT, b INT, total INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1
+FOR EACH ROW
+DECLARE
+va t1.a%TYPE:= :NEW.a;
+vb t1.b%TYPE:= :NEW.b;
+BEGIN
+:NEW.total:= va + vb;
+END;
+$$
+INSERT INTO t1 (a,b) VALUES (10, 20);
+SELECT * FROM t1;
+a b total
+10 20 30
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/truncate.result b/mysql-test/suite/compat/oracle/r/truncate.result
new file mode 100644
index 00000000000..f04ce09a4f8
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/truncate.result
@@ -0,0 +1,10 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-10588 sql_mode=ORACLE: TRUNCATE TABLE t1 [ {DROP|REUSE} STORAGE ]
+#
+CREATE TABLE t1 (a INT);
+TRUNCATE TABLE t1 REUSE STORAGE;
+TRUNCATE TABLE t1 DROP STORAGE;
+DROP TABLE t1;
+CREATE TABLE reuse (reuse INT);
+DROP TABLE reuse;
diff --git a/mysql-test/suite/compat/oracle/r/type_blob.result b/mysql-test/suite/compat/oracle/r/type_blob.result
new file mode 100644
index 00000000000..fe0a78e6ceb
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/type_blob.result
@@ -0,0 +1,8 @@
+SET sql_mode=ORACLE;
+CREATE TABLE t1 (a BLOB);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" longblob DEFAULT NULL
+)
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/type_clob.result b/mysql-test/suite/compat/oracle/r/type_clob.result
new file mode 100644
index 00000000000..f96572ea277
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/type_clob.result
@@ -0,0 +1,15 @@
+SET sql_mode=ORACLE;
+CREATE TABLE clob (clob INT);
+SHOW CREATE TABLE clob;
+Table Create Table
+clob CREATE TABLE "clob" (
+ "clob" int(11) DEFAULT NULL
+)
+DROP TABLE clob;
+CREATE TABLE t1 (a CLOB);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" longtext DEFAULT NULL
+)
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/type_date.result b/mysql-test/suite/compat/oracle/r/type_date.result
new file mode 100644
index 00000000000..0989fc593d2
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/type_date.result
@@ -0,0 +1,8 @@
+SET sql_mode=ORACLE;
+CREATE TABLE t1 (a DATE);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" datetime DEFAULT NULL
+)
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/type_number.result b/mysql-test/suite/compat/oracle/r/type_number.result
new file mode 100644
index 00000000000..c0848fdccf9
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/type_number.result
@@ -0,0 +1,15 @@
+SET sql_mode=ORACLE;
+CREATE TABLE t1 (a NUMBER);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" double DEFAULT NULL
+)
+DROP TABLE t1;
+CREATE TABLE t1 (a NUMBER(10,2));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" decimal(10,2) DEFAULT NULL
+)
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/type_raw.result b/mysql-test/suite/compat/oracle/r/type_raw.result
new file mode 100644
index 00000000000..1698c96d5b4
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/type_raw.result
@@ -0,0 +1,15 @@
+SET sql_mode=ORACLE;
+CREATE TABLE raw (raw INT);
+SHOW CREATE TABLE raw;
+Table Create Table
+raw CREATE TABLE "raw" (
+ "raw" int(11) DEFAULT NULL
+)
+DROP TABLE raw;
+CREATE TABLE t1 (a RAW(10));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" varbinary(10) DEFAULT NULL
+)
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/type_varchar.result b/mysql-test/suite/compat/oracle/r/type_varchar.result
new file mode 100644
index 00000000000..906e16867cd
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/type_varchar.result
@@ -0,0 +1,9 @@
+SET sql_mode=ORACLE;
+#
+# MDEV-11275 sql_mode=ORACLE: CAST(..AS VARCHAR(N))
+#
+SELECT CAST(123 AS VARCHAR(10)) FROM DUAL;
+CAST(123 AS VARCHAR(10))
+123
+SELECT CAST(123 AS VARCHAR) FROM DUAL;
+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 ') FROM DUAL' at line 1
diff --git a/mysql-test/suite/compat/oracle/r/type_varchar2.result b/mysql-test/suite/compat/oracle/r/type_varchar2.result
new file mode 100644
index 00000000000..5030cfbaa0a
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/type_varchar2.result
@@ -0,0 +1,23 @@
+SET sql_mode=ORACLE;
+CREATE TABLE varchar2 (varchar2 INT);
+SHOW CREATE TABLE varchar2;
+Table Create Table
+varchar2 CREATE TABLE "varchar2" (
+ "varchar2" int(11) DEFAULT NULL
+)
+DROP TABLE varchar2;
+CREATE TABLE t1 (a VARCHAR2(10));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "a" varchar(10) DEFAULT NULL
+)
+DROP TABLE t1;
+#
+# MDEV-11275 sql_mode=ORACLE: CAST(..AS VARCHAR(N))
+#
+SELECT CAST(123 AS VARCHAR2(10)) FROM DUAL;
+CAST(123 AS VARCHAR2(10))
+123
+SELECT CAST(123 AS VARCHAR2) FROM DUAL;
+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 ') FROM DUAL' at line 1
diff --git a/mysql-test/suite/compat/oracle/r/variables.result b/mysql-test/suite/compat/oracle/r/variables.result
new file mode 100644
index 00000000000..a7067d7b3fd
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/variables.result
@@ -0,0 +1,39 @@
+SET sql_mode=oracle;
+#
+# MDEV-10411 Providing compatibility for basic PL/SQL constructs
+# Part 6: Assignment operator
+#
+max_sort_length:=1030;
+SELECT @@max_sort_length;
+@@max_sort_length
+1030
+max_sort_length:=DEFAULT;
+#
+# Testing that SP variables shadow global variables in assignments
+#
+CREATE PROCEDURE p1
+AS
+BEGIN
+max_sort_length:=1030;
+DECLARE
+max_sort_length INT DEFAULT 1031;
+BEGIN
+SELECT @@max_sort_length, max_sort_length;
+max_sort_length:=1032;
+SELECT @@max_sort_length, max_sort_length;
+END;
+SELECT @@max_sort_length;
+max_sort_length:= DEFAULT;
+END;
+$$
+CALL p1();
+@@max_sort_length max_sort_length
+1030 1031
+@@max_sort_length max_sort_length
+1030 1032
+@@max_sort_length
+1030
+DROP PROCEDURE p1;
+#
+# End of MDEV-10411 Providing compatibility for basic PL/SQL constructs (part 6)
+#
diff --git a/mysql-test/suite/compat/oracle/t/binlog_stm_ps.test b/mysql-test/suite/compat/oracle/t/binlog_stm_ps.test
new file mode 100644
index 00000000000..996ef574413
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/binlog_stm_ps.test
@@ -0,0 +1,37 @@
+--source include/not_embedded.inc
+--source include/have_binlog_format_statement.inc
+
+--disable_query_log
+reset master; # get rid of previous tests binlog
+--enable_query_log
+
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-10801 sql_mode: dynamic SQL placeholders
+--echo #
+
+CREATE TABLE t1 (a INT, b INT);
+SET @a=10, @b=20;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (?,?)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:a,:b)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:aaa,:bbb)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:"a",:"b")';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:"aaa",:"bbb")';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:1,:2)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:222,:111)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:0,:65535)';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (:65535,:0)';
+EXECUTE stmt USING @a, @b;
+SELECT * FROM t1;
+--let $binlog_file = LAST
+source include/show_binlog_events.inc;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/binlog_stm_sp.test b/mysql-test/suite/compat/oracle/t/binlog_stm_sp.test
new file mode 100644
index 00000000000..065c43eb274
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/binlog_stm_sp.test
@@ -0,0 +1,196 @@
+--source include/not_embedded.inc
+--source include/have_binlog_format_statement.inc
+
+--disable_query_log
+call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
+reset master; # get rid of previous tests binlog
+--enable_query_log
+
+
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-10914 ROW data type for stored routine variables
+--echo #
+
+CREATE TABLE t1 (a INT, b INT);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec ROW(a INT,b INT);
+BEGIN
+ rec.a:=100;
+ rec.b:=200;
+ INSERT INTO t1 VALUES (rec.a,rec.b);
+ INSERT INTO t1 VALUES (10, rec=ROW(100,200));
+ INSERT INTO t1 VALUES (10, ROW(100,200)=rec);
+ INSERT INTO t1 SELECT 10, 20 FROM DUAL WHERE rec=ROW(100,200);
+ INSERT INTO t1 SELECT 10, 21 FROM DUAL WHERE ROW(100,200)=rec;
+ rec.a:=NULL;
+ INSERT INTO t1 VALUES (11, rec=ROW(100,200));
+ INSERT INTO t1 VALUES (11, rec=ROW(100,201));
+ INSERT INTO t1 VALUES (11, ROW(100,200)=rec);
+ INSERT INTO t1 VALUES (11, ROW(100,201)=rec);
+ INSERT INTO t1 SELECT 11, 20 FROM DUAL WHERE rec=ROW(100,200);
+ INSERT INTO t1 SELECT 11, 21 FROM DUAL WHERE ROW(100,200)=rec;
+ rec.b:=NULL;
+ INSERT INTO t1 VALUES (12, rec=ROW(100,200));
+ INSERT INTO t1 VALUES (12, ROW(100,200)=rec);
+ INSERT INTO t1 SELECT 12, 20 FROM DUAL WHERE rec=ROW(100,200);
+ INSERT INTO t1 SELECT 12, 21 FROM DUAL WHERE ROW(100,200)=rec;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+--let $binlog_file = LAST
+source include/show_binlog_events.inc;
+
+
+--echo #
+--echo # Testing ROW fields in LIMIT
+--echo #
+
+FLUSH LOGS;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(10);
+CREATE TABLE t2 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a INT:= 1;
+ rec ROW(a INT);
+BEGIN
+ rec.a:= 1;
+ INSERT INTO t2 SELECT 1 FROM t1 LIMIT a;
+ INSERT INTO t2 SELECT 2 FROM t1 LIMIT rec.a;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1,t2;
+DROP PROCEDURE p1;
+--let $binlog_file = LAST
+source include/show_binlog_events.inc;
+
+
+--echo #
+--echo # End of MDEV-10914 ROW data type for stored routine variables
+--echo #
+
+
+--echo #
+--echo # MDEV-12133 sql_mode=ORACLE: table%ROWTYPE in variable declarations
+--echo #
+
+CREATE TABLE t1 (a INT, b INT);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec t1%ROWTYPE;
+BEGIN
+ rec.a:=100;
+ rec.b:=200;
+ SELECT rec=ROW(100,200) AS true1, ROW(100,200)=rec AS true2;
+ INSERT INTO t1 VALUES (rec.a,rec.b);
+ INSERT INTO t1 VALUES (10, rec=ROW(100,200));
+ INSERT INTO t1 VALUES (10, ROW(100,200)=rec);
+ INSERT INTO t1 SELECT 10, 20 FROM DUAL WHERE rec=ROW(100,200);
+ INSERT INTO t1 SELECT 10, 21 FROM DUAL WHERE ROW(100,200)=rec;
+ rec.a:=NULL;
+ INSERT INTO t1 VALUES (11, rec=ROW(100,200));
+ INSERT INTO t1 VALUES (11, rec=ROW(100,201));
+ INSERT INTO t1 VALUES (11, ROW(100,200)=rec);
+ INSERT INTO t1 VALUES (11, ROW(100,201)=rec);
+ INSERT INTO t1 SELECT 11, 20 FROM DUAL WHERE rec=ROW(100,200);
+ INSERT INTO t1 SELECT 11, 21 FROM DUAL WHERE ROW(100,200)=rec;
+ rec.b:=NULL;
+ INSERT INTO t1 VALUES (12, rec=ROW(100,200));
+ INSERT INTO t1 VALUES (12, ROW(100,200)=rec);
+ INSERT INTO t1 SELECT 12, 20 FROM DUAL WHERE rec=ROW(100,200);
+ INSERT INTO t1 SELECT 12, 21 FROM DUAL WHERE ROW(100,200)=rec;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+--let $binlog_file = LAST
+source include/show_binlog_events.inc;
+
+
+--echo #
+--echo # MDEV-12291 Allow ROW variables as SELECT INTO targets
+--echo #
+
+FLUSH LOGS;
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10, 'b10');
+CREATE TABLE t2 LIKE t1;
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec1 ROW(a INT, b VARCHAR(32));
+BEGIN
+ SELECT * INTO rec1 FROM t1;
+ INSERT INTO t2 VALUES (rec1.a, rec1.b);
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+--let $binlog_file = LAST
+source include/show_binlog_events.inc;
+
+
+FLUSH LOGS;
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10, 'b10');
+CREATE TABLE t2 LIKE t1;
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec1 t1%ROWTYPE;
+BEGIN
+ SELECT * INTO rec1 FROM t1;
+ INSERT INTO t2 VALUES (rec1.a, rec1.b);
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+--let $binlog_file = LAST
+source include/show_binlog_events.inc;
+
+
+FLUSH LOGS;
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10, 'b10');
+CREATE TABLE t2 LIKE t1;
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+ rec1 cur1%ROWTYPE;
+BEGIN
+ SELECT * INTO rec1 FROM t1;
+ INSERT INTO t2 VALUES (rec1.a, rec1.b);
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+--let $binlog_file = LAST
+source include/show_binlog_events.inc;
diff --git a/mysql-test/suite/compat/oracle/t/exception.test b/mysql-test/suite/compat/oracle/t/exception.test
new file mode 100644
index 00000000000..6448a6ef627
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/exception.test
@@ -0,0 +1,457 @@
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # sql_mode=ORACLE: Predefined exceptions: TOO_MANY_ROWS, NO_DATA_FOUND, DUP_VAL_ON_INDEX
+--echo #
+
+--echo #
+--echo # Testing NO_DATA_FOUND and TOO_MANY_ROWS
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+DELIMITER $$;
+CREATE PROCEDURE p1(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ SELECT a INTO a FROM t1 LIMIT lim;
+EXCEPTION
+ WHEN TOO_MANY_ROWS THEN res:='--- too_many_rows cought ---';
+ WHEN NO_DATA_FOUND THEN res:='--- no_data_found cought ---';
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL p1(0, @res);
+SELECT @res;
+CALL p1(2, @res);
+SELECT @res;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing DUP_VAL_ON_INDEX
+--echo #
+
+CREATE TABLE t1 (a INT PRIMARY KEY);
+DELIMITER $$;
+CREATE PROCEDURE p1(res OUT VARCHAR)
+AS
+BEGIN
+ INSERT INTO t1 VALUES (10);
+ INSERT INTO t1 VALUES (10);
+EXCEPTION
+ WHEN DUP_VAL_ON_INDEX THEN res:='--- dup_val_on_index cought ---';
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL p1(@res);
+SELECT @res;
+SELECT * FROM t1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-10840 sql_mode=ORACLE: RAISE statement for predefined exceptions
+--echo #
+
+--echo #
+--echo # RAISE outside of an SP context
+--echo #
+
+--error ER_SP_COND_MISMATCH
+RAISE NO_DATA_FOUND;
+--error ER_SP_COND_MISMATCH
+RAISE INVALID_CURSOR;
+--error ER_SP_COND_MISMATCH
+RAISE DUP_VAL_ON_INDEX;
+--error ER_SP_COND_MISMATCH
+RAISE TOO_MANY_ROWS;
+
+--error ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER
+RAISE;
+
+
+--echo #
+--echo # RAISE for an undefinite exception
+--echo #
+
+DELIMITER $$;
+--error ER_SP_COND_MISMATCH
+CREATE PROCEDURE p1
+AS
+BEGIN
+ RAISE xxx;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # RAISE for predefined exceptions
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ RAISE no_data_found;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ RAISE invalid_cursor;
+END;
+$$
+DELIMITER ;$$
+--error ER_SP_CURSOR_NOT_OPEN
+CALL p1();
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ RAISE dup_val_on_index;
+END;
+$$
+DELIMITER ;$$
+--error ER_DUP_ENTRY
+CALL p1();
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ raise too_many_rows;
+END;
+$$
+DELIMITER ;$$
+--error ER_TOO_MANY_ROWS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # RAISE with no exception name (resignal)
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+BEGIN
+ RAISE;
+END;
+$$
+DELIMITER ;$$
+--error ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER
+CALL p1();
+DROP PROCEDURE p1;
+
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+DELIMITER $$;
+CREATE PROCEDURE p1(lim INT)
+AS
+ a INT;
+BEGIN
+ SELECT a INTO a FROM t1 LIMIT lim;
+EXCEPTION
+ WHEN TOO_MANY_ROWS THEN RAISE;
+ WHEN NO_DATA_FOUND THEN RAISE;
+END;
+$$
+DELIMITER ;$$
+CALL p1(0);
+--error ER_TOO_MANY_ROWS
+CALL p1(2);
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+DELIMITER $$;
+CREATE PROCEDURE p1(lim INT)
+AS
+ a INT;
+BEGIN
+ SELECT a INTO a FROM t1 LIMIT lim;
+EXCEPTION
+ WHEN OTHERS THEN RAISE;
+END;
+$$
+DELIMITER ;$$
+CALL p1(0);
+--error ER_TOO_MANY_ROWS
+CALL p1(2);
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a INT;
+ CURSOR c IS SELECT a FROM t1;
+BEGIN
+ FETCH c INTO a;
+EXCEPTION
+ WHEN INVALID_CURSOR THEN RAISE;
+END;
+$$
+DELIMITER ;$$
+--error ER_SP_CURSOR_NOT_OPEN
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a INT;
+ CURSOR c IS SELECT a FROM t1;
+BEGIN
+ FETCH c INTO a;
+EXCEPTION
+ WHEN OTHERS THEN RAISE;
+END;
+$$
+DELIMITER ;$$
+--error ER_SP_CURSOR_NOT_OPEN
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing that warning-alike errors are caught by OTHERS
+--echo #
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE FUNCTION f1 RETURN VARCHAR
+AS
+ a INT:=10;
+BEGIN
+ SELECT a INTO a FROM t1;
+ RETURN 'OK';
+EXCEPTION
+ WHEN OTHERS THEN RETURN 'Exception';
+END;
+$$
+DELIMITER ;$$
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # End of MDEV-10840 sql_mode=ORACLE: RAISE statement for predefined exceptions
+--echo #
+
+
+--echo #
+--echo # MDEV-10587 sql_mode=ORACLE: User defined exceptions
+--echo #
+
+--echo #
+--echo # Checking that duplicate WHEN clause is not allowed
+--echo #
+
+DELIMITER $$;
+--error ER_SP_DUP_HANDLER
+CREATE FUNCTION f1() RETURN VARCHAR
+AS
+ e EXCEPTION;
+BEGIN
+ RETURN 'Got no exceptions';
+EXCEPTION
+ WHEN e THEN RETURN 'Got exception e';
+ WHEN e THEN RETURN 'Got exception e';
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # Checking that raised user exceptions are further caught by name
+--echo #
+
+DELIMITER $$;
+CREATE FUNCTION f1(c VARCHAR) RETURN VARCHAR
+AS
+ e EXCEPTION;
+ f EXCEPTION;
+BEGIN
+ IF c = 'e' THEN RAISE e; END IF;
+ IF c = 'f' THEN RAISE f; END IF;
+ RETURN 'Got no exceptions';
+EXCEPTION
+ WHEN e THEN RETURN 'Got exception e';
+END;
+$$
+DELIMITER ;$$
+SELECT f1('');
+SELECT f1('e');
+--error ER_SIGNAL_EXCEPTION
+SELECT f1('f');
+DROP FUNCTION f1;
+
+
+--echo #
+--echo # Checking that raised user exceptions are further caught by OTHERS
+--echo #
+
+DELIMITER $$;
+CREATE FUNCTION f1(c VARCHAR) RETURN VARCHAR
+AS
+ e EXCEPTION;
+ f EXCEPTION;
+BEGIN
+ IF c = 'e' THEN RAISE e; END IF;
+ IF c = 'f' THEN RAISE f; END IF;
+ RETURN 'Got no exceptions';
+EXCEPTION
+ WHEN OTHERS THEN RETURN 'Got some exception';
+END;
+$$
+DELIMITER ;$$
+SELECT f1('');
+SELECT f1('e');
+SELECT f1('f');
+DROP FUNCTION f1;
+
+
+--echo #
+--echo # Checking that 'WHEN e .. WHEN f' does not produce ER_SP_DUP_HANDLER
+--echo #
+
+DELIMITER $$;
+CREATE FUNCTION f1(c VARCHAR) RETURN VARCHAR
+AS
+ e EXCEPTION;
+ f EXCEPTION;
+ a VARCHAR(64):='';
+BEGIN
+ BEGIN
+ IF c = 'e' THEN RAISE e; END IF;
+ IF c = 'f' THEN RAISE f; END IF;
+ EXCEPTION
+ WHEN e THEN BEGIN a:='Got EXCEPTION1/e; '; RAISE e; END;
+ WHEN f THEN BEGIN a:='Got EXCEPTION1/f; '; RAISE f; END;
+ END;
+ RETURN 'Got no exceptions';
+EXCEPTION
+ WHEN OTHERS THEN RETURN a || 'Got EXCEPTION2/OTHERS;';
+END;
+$$
+DELIMITER ;$$
+SELECT f1('');
+SELECT f1('e');
+SELECT f1('f');
+DROP FUNCTION f1;
+
+
+--echo #
+--echo # Checking that resignaled user exceptions are further caught by name
+--echo #
+DELIMITER $$;
+CREATE FUNCTION f1(c VARCHAR) RETURN VARCHAR
+AS
+ e EXCEPTION;
+ f EXCEPTION;
+ a VARCHAR(64):='';
+BEGIN
+ BEGIN
+ IF c = 'e' THEN RAISE e; END IF;
+ IF c = 'f' THEN RAISE f; END IF;
+ EXCEPTION
+ WHEN e THEN BEGIN a:='Got EXCEPTION1/e; '; RAISE; END;
+ WHEN f THEN BEGIN a:='Got EXCEPTION1/f; '; RAISE; END;
+ END;
+ RETURN 'Got no exceptions';
+EXCEPTION
+ WHEN e THEN RETURN a || 'Got EXCEPTION2/e;';
+END;
+$$
+DELIMITER ;$$
+SELECT f1('');
+SELECT f1('e');
+--error ER_SIGNAL_EXCEPTION
+SELECT f1('f');
+DROP FUNCTION f1;
+
+
+--echo #
+--echo # Checking that resignaled user exceptions are further caught by OTHERS
+--echo #
+
+DELIMITER $$;
+CREATE FUNCTION f1(c VARCHAR) RETURN VARCHAR
+AS
+ e EXCEPTION;
+ f EXCEPTION;
+ a VARCHAR(64):='';
+BEGIN
+ BEGIN
+ IF c = 'e' THEN RAISE e; END IF;
+ IF c = 'f' THEN RAISE f; END IF;
+ EXCEPTION
+ WHEN e THEN BEGIN a:='Got EXCEPTION1/e; '; RAISE; END;
+ WHEN f THEN BEGIN a:='Got EXCEPTION1/f; '; RAISE; END;
+ END;
+ RETURN 'Got no exceptions';
+EXCEPTION
+ WHEN OTHERS THEN RETURN a || 'Got EXCEPTION2/OTHERS;';
+END;
+$$
+DELIMITER ;$$
+SELECT f1('');
+SELECT f1('e');
+SELECT f1('f');
+DROP FUNCTION f1;
+
+
+--echo #
+--echo # End of MDEV-10587 sql_mode=ORACLE: User defined exceptions
+--echo #
+
+--echo #
+--echo # MDEV-12088 sql_mode=ORACLE: Do not require BEGIN..END in multi-statement exception handlers in THEN clause
+--echo #
+CREATE TABLE t1 (a INT PRIMARY KEY);
+INSERT INTO t1 VALUES (10),(20),(30);
+DELIMITER $$;
+CREATE PROCEDURE p1(a INT) AS
+BEGIN
+ INSERT INTO t1 (a) VALUES (a);
+EXCEPTION
+ WHEN DUP_VAL_ON_INDEX THEN
+ a:= a+1;
+ INSERT INTO t1 VALUES (a);
+ WHEN OTHERS THEN
+ NULL;
+ NULL;
+END;
+$$
+DELIMITER ;$$
+CALL p1(30);
+SELECT * FROM t1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/func_case.test b/mysql-test/suite/compat/oracle/t/func_case.test
new file mode 100644
index 00000000000..d5e0d650975
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/func_case.test
@@ -0,0 +1,9 @@
+#
+# Testing CASE and its abbreviations
+#
+
+SET sql_mode=ORACLE;
+
+SELECT NVL(NULL, 'a'), NVL('a', 'b');
+
+SELECT NVL2(NULL, 'a', 'b'), NVL2('a', 'b', 'c');
diff --git a/mysql-test/suite/compat/oracle/t/func_concat.test b/mysql-test/suite/compat/oracle/t/func_concat.test
new file mode 100644
index 00000000000..e1d8a5c477f
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/func_concat.test
@@ -0,0 +1,116 @@
+#
+# Testing CONCAT with null values
+#
+
+SET sql_mode=ORACLE;
+
+EXPLAIN EXTENDED SELECT 'a'||'b'||'c';
+EXPLAIN EXTENDED SELECT CONCAT('a'||'b'||'c');
+
+SELECT '' || '';
+SELECT '' || 'b';
+SELECT '' || NULL;
+SELECT 'a' || '';
+SELECT 'a' || 'b';
+SELECT 'a' || NULL;
+SELECT NULL || '';
+SELECT NULL || 'b';
+SELECT NULL || NULL;
+
+SELECT '' || '' || '';
+SELECT '' || '' || 'c';
+SELECT '' || '' || NULL;
+SELECT '' || 'b' || '';
+SELECT '' || 'b' || 'c';
+SELECT '' || 'b' || NULL;
+SELECT '' || NULL || '';
+SELECT '' || NULL || 'c';
+SELECT '' || NULL || NULL;
+
+SELECT 'a' || '' || '';
+SELECT 'a' || '' || 'c';
+SELECT 'a' || '' || NULL;
+SELECT 'a' || 'b' || '';
+SELECT 'a' || 'b' || 'c';
+SELECT 'a' || 'b' || NULL;
+SELECT 'a' || NULL || '';
+SELECT 'a' || NULL || 'c';
+SELECT 'a' || NULL || NULL;
+
+SELECT NULL || '' || '';
+SELECT NULL || '' || 'c';
+SELECT NULL || '' || NULL;
+SELECT NULL || 'b' || '';
+SELECT NULL || 'b' || 'c';
+SELECT NULL || 'b' || NULL;
+SELECT NULL || NULL || '';
+SELECT NULL || NULL || 'c';
+SELECT NULL || NULL || NULL;
+
+CREATE TABLE t1 (a VARCHAR(10), b VARCHAR(10), c VARCHAR(10));
+
+INSERT INTO t1 VALUES ('', '', '');
+INSERT INTO t1 VALUES ('', '', 'c');
+INSERT INTO t1 VALUES ('', '', NULL);
+INSERT INTO t1 VALUES ('', 'b', '');
+INSERT INTO t1 VALUES ('', 'b', 'c');
+INSERT INTO t1 VALUES ('', 'b', NULL);
+INSERT INTO t1 VALUES ('', NULL, '');
+INSERT INTO t1 VALUES ('', NULL, 'c');
+INSERT INTO t1 VALUES ('', NULL, NULL);
+
+INSERT INTO t1 VALUES ('a', '', '');
+INSERT INTO t1 VALUES ('a', '', 'c');
+INSERT INTO t1 VALUES ('a', '', NULL);
+INSERT INTO t1 VALUES ('a', 'b', '');
+INSERT INTO t1 VALUES ('a', 'b', 'c');
+INSERT INTO t1 VALUES ('a', 'b', NULL);
+INSERT INTO t1 VALUES ('a', NULL, '');
+INSERT INTO t1 VALUES ('a', NULL, 'c');
+INSERT INTO t1 VALUES ('a', NULL, NULL);
+
+INSERT INTO t1 VALUES (NULL, '', '');
+INSERT INTO t1 VALUES (NULL, '', 'c');
+INSERT INTO t1 VALUES (NULL, '', NULL);
+INSERT INTO t1 VALUES (NULL, 'b', '');
+INSERT INTO t1 VALUES (NULL, 'b', 'c');
+INSERT INTO t1 VALUES (NULL, 'b', NULL);
+INSERT INTO t1 VALUES (NULL, NULL, '');
+INSERT INTO t1 VALUES (NULL, NULL, 'c');
+INSERT INTO t1 VALUES (NULL, NULL, NULL);
+
+SELECT LENGTH(a||b||c), a||b||c FROM t1 ORDER BY a,b,c;
+SELECT LENGTH(CONCAT(a||b||c)), CONCAT(a||b||c) FROM t1 ORDER BY a,b,c;
+
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-12478 CONCAT function inside view casts values incorrectly with Oracle sql_mode
+--echo #
+
+SET sql_mode=ORACLE;
+CREATE VIEW v1 AS SELECT 'foo'||NULL||'bar' AS test;
+SHOW CREATE VIEW v1;
+SELECT * FROM v1;
+SET sql_mode=DEFAULT;
+SHOW CREATE VIEW v1;
+SELECT * FROM v1;
+DROP VIEW v1;
+
+SET sql_mode=DEFAULT;
+CREATE VIEW v1 AS SELECT CONCAT('foo',NULL,'bar') AS test;
+SHOW CREATE VIEW v1;
+SELECT * FROM v1;
+SET sql_mode=ORACLE;
+SHOW CREATE VIEW v1;
+SELECT * FROM v1;
+DROP VIEW v1;
+
+SET sql_mode=DEFAULT;
+CREATE VIEW v1 AS SELECT '0'||'1' AS test;
+SHOW CREATE VIEW v1;
+SELECT * FROM v1;
+SET sql_mode=ORACLE;
+SHOW CREATE VIEW v1;
+SELECT * FROM v1;
+DROP VIEW v1;
diff --git a/mysql-test/suite/compat/oracle/t/func_decode.test b/mysql-test/suite/compat/oracle/t/func_decode.test
new file mode 100644
index 00000000000..ae05cb2c3d1
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/func_decode.test
@@ -0,0 +1,21 @@
+SET sql_mode=ORACLE;
+
+--error ER_PARSE_ERROR
+SELECT DECODE(10);
+--error ER_PARSE_ERROR
+SELECT DECODE(10,10);
+
+SELECT DECODE(10,10,'x10');
+SELECT DECODE(11,10,'x10');
+
+SELECT DECODE(10,10,'x10','def');
+SELECT DECODE(11,10,'x10','def');
+
+SELECT DECODE(10,10,'x10',11,'x11','def');
+SELECT DECODE(11,10,'x10',11,'x11','def');
+SELECT DECODE(12,10,'x10',11,'x11','def');
+
+EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11','def');
+
+CREATE TABLE decode (decode int);
+DROP TABLE decode;
diff --git a/mysql-test/suite/compat/oracle/t/func_length.test b/mysql-test/suite/compat/oracle/t/func_length.test
new file mode 100644
index 00000000000..7b76d33a02f
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/func_length.test
@@ -0,0 +1,18 @@
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-12783 sql_mode=ORACLE: Functions LENGTH() and LENGTHB()
+--echo #
+#
+# Testing LENGTH / LENGTHB
+#
+# LENGTH : return the length of char
+# LENGTHB : return the length of byte
+
+
+SELECT LENGTH(null), LENGTH('a'), LENGTH(123);
+SELECT LENGTHB(null), LENGTHB('a'), LENGTHB(123);
+
+SELECT LENGTH(_utf8 0xC39F), LENGTH(CHAR(14844588 USING utf8));
+SELECT LENGTHB(_utf8 0xC39F), LENGTHB(CHAR(14844588 USING utf8));
+EXPLAIN EXTENDED SELECT LENGTH('a'), LENGTHB('a');
diff --git a/mysql-test/suite/compat/oracle/t/func_misc.test b/mysql-test/suite/compat/oracle/t/func_misc.test
new file mode 100644
index 00000000000..c5b42134f89
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/func_misc.test
@@ -0,0 +1,346 @@
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-10578 sql_mode=ORACLE: SP control functions SQLCODE, SQLERRM
+--echo #
+
+--echo #
+--echo # Using SQLCODE and SQLERRM outside of an SP
+--echo #
+
+--error ER_BAD_FIELD_ERROR
+SELECT SQLCODE;
+
+--error ER_BAD_FIELD_ERROR
+SELECT SQLERRM;
+
+CREATE TABLE t1 (SQLCODE INT, SQLERRM VARCHAR(10));
+INSERT INTO t1 VALUES (10, 'test');
+SELECT SQLCODE, SQLERRM FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Normal SQLCODE and SQLERRM usage
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(stmt VARCHAR)
+AS
+BEGIN
+ EXECUTE IMMEDIATE stmt;
+ SELECT 'Error1: ' || SQLCODE || ' ' || SQLERRM;
+EXCEPTION
+ WHEN OTHERS THEN
+ SELECT 'Error2: ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+CALL p1('SELECT 1');
+CALL p1('xxx');
+CALL p1('SELECT 1');
+DROP PROCEDURE p1;
+
+--echo #
+--echo # SQLCODE and SQLERRM hidden by local variables
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ sqlcode INT:= 10;
+ sqlerrm VARCHAR(64) := 'test';
+BEGIN
+ SELECT 'Error: ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ sqlcode INT;
+ sqlerrm VARCHAR(64);
+BEGIN
+ SQLCODE:= 10;
+ sqlerrm:= 'test';
+ SELECT 'Error: ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # SQLCODE and SQLERRM hidden by parameters
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(sqlcode INT, sqlerrm VARCHAR)
+AS
+BEGIN
+ SELECT 'Error: ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+CALL p1(10, 'test');
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # SQLCODE and SQLERRM in CREATE..SELECT
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ CREATE TABLE t1 AS SELECT SQLCODE, SQLERRM;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # SQLCODE and SQLERRM in EXPLAIN EXTENDED SELECT
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ EXPLAIN EXTENDED SELECT SQLCode, SQLErrm;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+
+
+
+--echo #
+--echo # Warning-alike errors in stored functions
+--echo #
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE FUNCTION f1 RETURN VARCHAR
+AS
+ a INT;
+BEGIN
+ SELECT a INTO a FROM t1;
+ RETURN 'No exception ' || SQLCODE || ' ' || SQLERRM;
+EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ RETURN 'Exception ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE FUNCTION f1 RETURN VARCHAR
+AS
+ a INT;
+BEGIN
+ SELECT a INTO a FROM t1;
+ RETURN 'No exception ' || SQLCODE || ' ' || SQLERRM;
+EXCEPTION
+ WHEN OTHERS THEN
+ RETURN 'Exception ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Warning-alike errors in stored procedures
+--echo #
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1(res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ SELECT a INTO a FROM t1;
+ res:= 'No exception ' || SQLCODE || ' ' || SQLERRM;
+EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ res:= 'Exception ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+CALL p1(@a);
+SELECT @a;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1(res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ SELECT a INTO a FROM t1;
+ res:= 'No exception ' || SQLCODE || ' ' || SQLERRM;
+EXCEPTION
+ WHEN OTHERS THEN
+ res:= 'Exception ' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+CALL p1(@a);
+SELECT @a;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SQLCODE and SQLERRM are cleared on RETURN
+--echo #
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE FUNCTION f1 RETURN VARCHAR
+AS
+ a INT:=10;
+BEGIN
+ SELECT a INTO a FROM t1;
+ RETURN 'Value=' || a;
+EXCEPTION
+ WHEN NO_DATA_FOUND THEN RETURN 'Exception|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CREATE FUNCTION f2 RETURN VARCHAR
+AS
+ a VARCHAR(128);
+BEGIN
+ RETURN f1() || '|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+SELECT f1() FROM DUAL;
+SELECT f2() FROM DUAL;
+DROP TABLE t1;
+DROP FUNCTION f2;
+DROP FUNCTION f1;
+
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE FUNCTION f1 RETURN VARCHAR
+AS
+ a INT:=10;
+BEGIN
+ SELECT a INTO a FROM t1;
+ RETURN 'Value=' || a;
+EXCEPTION
+ WHEN OTHERS THEN RETURN 'Exception|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CREATE FUNCTION f2 RETURN VARCHAR
+AS
+ a VARCHAR(128);
+BEGIN
+ RETURN f1() || '|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+SELECT f1() FROM DUAL;
+SELECT f2() FROM DUAL;
+DROP TABLE t1;
+DROP FUNCTION f2;
+DROP FUNCTION f1;
+
+
+--echo #
+--echo # SQLCODE and SQLERRM are cleared on a return from a PROCEDURE
+--echo #
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1(res OUT VARCHAR)
+AS
+ a INT:=10;
+BEGIN
+ SELECT a INTO a FROM t1;
+ res:='Value=' || a;
+EXCEPTION
+ WHEN NO_DATA_FOUND THEN res:='Exception|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CREATE FUNCTION f2 RETURN VARCHAR
+AS
+ res VARCHAR(128);
+BEGIN
+ CALL p1(res);
+ RETURN res || '|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+SELECT f2() FROM DUAL;
+DROP FUNCTION f2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1(res OUT VARCHAR)
+AS
+ a INT:=10;
+BEGIN
+ SELECT a INTO a FROM t1;
+ res:='Value=' || a;
+EXCEPTION
+ WHEN OTHERS THEN res:='Exception|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+CREATE FUNCTION f2 RETURN VARCHAR
+AS
+ res VARCHAR(128);
+BEGIN
+ CALL p1(res);
+ RETURN res || '|' || SQLCODE || ' ' || SQLERRM;
+END;
+$$
+DELIMITER ;$$
+SELECT f2() FROM DUAL;
+DROP FUNCTION f2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # End of MDEV-10578 sql_mode=ORACLE: SP control functions SQLCODE, SQLERRM
+--echo #
+
+--echo #
+--echo # MDEV-12854 Synchronize CREATE..SELECT data type and result set metadata data type for INT functions
+--echo #
+
+--enable_metadata
+--disable_ps_protocol
+DELIMITER $$;
+BEGIN
+ SELECT SQLCODE;
+END
+$$
+DELIMITER ;$$
+--enable_ps_protocol
+--disable_metadata
diff --git a/mysql-test/suite/compat/oracle/t/misc.test b/mysql-test/suite/compat/oracle/t/misc.test
new file mode 100644
index 00000000000..d939b20f8a0
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/misc.test
@@ -0,0 +1,10 @@
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-12086 sql_mode=ORACLE: allow SELECT UNIQUE as a synonym for SELECT DISTINCT
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20),(20),(30),(30),(30);
+SELECT UNIQUE a FROM t1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/ps.test b/mysql-test/suite/compat/oracle/t/ps.test
new file mode 100644
index 00000000000..08bb957c33f
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/ps.test
@@ -0,0 +1,266 @@
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-10801 sql_mode: dynamic SQL placeholders
+--echo #
+
+SET @a=10, @b=20;
+PREPARE stmt FROM 'SELECT ?,?';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'SELECT :a,:b';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'SELECT :aaa,:bbb';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'SELECT :"a",:"b"';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'SELECT :"aaa",:"bbb"';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'SELECT :1,:2';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'SELECT :222,:111';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'SELECT :0,:65535';
+EXECUTE stmt USING @a, @b;
+PREPARE stmt FROM 'SELECT :65535,:0';
+EXECUTE stmt USING @a, @b;
+
+--echo #
+--echo # MDEV-10709 Expressions as parameters to Dynamic SQL
+--echo #
+
+--echo #
+--echo # Testing disallowed expressions in USING
+--echo #
+
+PREPARE stmt FROM 'SELECT :1 FROM DUAL';
+--error ER_PARSE_ERROR
+EXECUTE stmt USING (SELECT 1);
+DEALLOCATE PREPARE stmt;
+
+DELIMITER $$;
+CREATE FUNCTION f1() RETURN VARCHAR
+AS
+BEGIN
+ RETURN 'test';
+END;
+$$
+DELIMITER ;$$
+PREPARE stmt FROM 'SELECT ? FROM DUAL';
+--error ER_SUBQUERIES_NOT_SUPPORTED
+EXECUTE stmt USING f1();
+DEALLOCATE PREPARE stmt;
+DROP FUNCTION f1;
+
+--echo #
+--echo # Using a user variable as a EXECUTE..USING out parameter
+--echo #
+
+DELIMITER /;
+CREATE PROCEDURE p1(a OUT INT)
+AS
+BEGIN
+ a:= 10;
+END;
+/
+DELIMITER ;/
+SET @a=1;
+CALL p1(@a);
+SELECT @a;
+SET @a=2;
+PREPARE stmt FROM 'CALL p1(?)';
+EXECUTE stmt USING @a;
+SELECT @a;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Using an SP variable as a EXECUTE..USING out parameter
+--echo #
+
+DELIMITER /;
+CREATE PROCEDURE p1 (a OUT INT)
+AS
+BEGIN
+ a:=10;
+END;
+/
+CREATE PROCEDURE p2 (a OUT INT)
+AS
+BEGIN
+ PREPARE stmt FROM 'CALL p1(?)';
+ EXECUTE stmt USING a;
+END;
+/
+DELIMITER ;/
+SET @a= 1;
+CALL p2(@a);
+SELECT @a;
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Using a trigger field as a EXECUTE..USING out parameter
+--echo #
+DELIMITER /;
+CREATE PROCEDURE p1 (a OUT INT)
+AS
+BEGIN
+ a:= 10;
+END;
+/
+DELIMITER ;/
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW CALL p1(:NEW.a);
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Testing re-prepare on a table metadata update between PREPARE and EXECUTE
+--echo #
+
+CREATE TABLE t1 (a INT);
+DELIMITER /;
+CREATE PROCEDURE p1(a IN INT)
+AS
+BEGIN
+ INSERT INTO t1 VALUES (a);
+END;
+/
+DELIMITER ;/
+PREPARE stmt FROM 'CALL p1(?)';
+EXECUTE stmt USING 10;
+SELECT * FROM t1;
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW NEW.a:=NEW.a+1;
+EXECUTE stmt USING 20;
+SELECT * FROM t1;
+DEALLOCATE PREPARE stmt;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--echo #
+--echo # End of MDEV-10709 Expressions as parameters to Dynamic SQL
+--echo #
+
+--echo #
+--echo # MDEV-10585 EXECUTE IMMEDIATE statement
+--echo #
+
+--echo #
+--echo # Testing disallowed expressions in USING
+--echo #
+
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE 'SELECT :1 FROM DUAL' USING (SELECT 1);
+
+DELIMITER $$;
+CREATE FUNCTION f1() RETURN VARCHAR
+AS
+BEGIN
+ RETURN 'test';
+END;
+$$
+DELIMITER ;$$
+--error ER_SUBQUERIES_NOT_SUPPORTED
+EXECUTE IMMEDIATE 'SELECT ? FROM DUAL' USING f1();
+DROP FUNCTION f1;
+
+
+--echo #
+--echo # Testing simple expressions
+--echo #
+
+EXECUTE IMMEDIATE 'SELECT :1 FROM DUAL' USING 10;
+
+
+--echo #
+--echo # MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
+--echo #
+
+--echo #
+--echo # Testing erroneous and diallowed prepare source
+--echo #
+
+--error ER_CANT_AGGREGATE_2COLLATIONS
+EXECUTE IMMEDIATE _latin1'SELECT 1 AS c FROM ' || _latin2 'DUAL';
+--error ER_CANT_AGGREGATE_2COLLATIONS
+PREPARE stmt FROM _latin1'SELECT 1 AS c FROM ' || _latin2 'DUAL';
+
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE (SELECT 'SELECT 1');
+--error ER_PARSE_ERROR
+PREPARE stmt FROM (SELECT 'SELECT 1');
+
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE a;
+--error ER_BAD_FIELD_ERROR
+PREPARE stmt FROM a;
+
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE NULL;
+--error ER_PARSE_ERROR
+PREPARE stmt FROM NULL;
+
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE COALESCE(NULL);
+--error ER_PARSE_ERROR
+PREPARE stmt FROM COALESCE(NULL);
+
+DELIMITER $$;
+CREATE FUNCTION f1() RETURN VARCHAR
+AS
+BEGIN
+ RETURN 't1';
+END;
+$$
+DELIMITER ;$$
+--error ER_SUBQUERIES_NOT_SUPPORTED
+EXECUTE IMMEDIATE f1();
+--error ER_SUBQUERIES_NOT_SUPPORTED
+PREPARE stmt FROM f1();
+DROP FUNCTION f1;
+
+--echo #
+--echo # Testing user variables in prepare source
+--echo #
+
+SET @table_name='DUAL';
+EXECUTE IMMEDIATE 'SELECT 1 AS a FROM ' || @table_name;
+PREPARE stmt FROM 'SELECT 1 AS a FROM ' || @table_name;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+--echo #
+--echo # Testing SP parameters and variables in prepare source
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(table_name VARCHAR)
+AS
+BEGIN
+ EXECUTE IMMEDIATE 'SELECT 1 AS c FROM '|| table_name;
+END;
+$$
+DELIMITER ;$$
+CALL p1('DUAL');
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ table_name VARCHAR(64):='DUAL';
+BEGIN
+ EXECUTE IMMEDIATE 'SELECT 1 AS c FROM ' || table_name;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # End of MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
+--echo #
diff --git a/mysql-test/suite/compat/oracle/t/sequence.test b/mysql-test/suite/compat/oracle/t/sequence.test
new file mode 100644
index 00000000000..719c4bcd45b
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sequence.test
@@ -0,0 +1,43 @@
+--source include/have_binlog_format_row.inc
+
+SET sql_mode=ORACLE;
+
+CREATE SEQUENCE s1;
+SHOW CREATE SEQUENCE s1;
+SELECT s1.currval;
+SELECT s1.nextval;
+SELECT s1.nextval;
+SELECT s1.nextval;
+EXPLAIN EXTENDED SELECT s1.nextval;
+SELECT nextval(s1);
+EXPLAIN EXTENDED SELECT s1.currval;
+SELECT lastval(s1);
+DROP SEQUENCE s1;
+
+
+CREATE SEQUENCE s1;
+CREATE VIEW v1 AS SELECT s1.nextval AS a;
+SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='v1';
+SELECT * FROM v1;
+SHOW CREATE VIEW v1;
+DROP VIEW v1;
+DROP SEQUENCE s1;
+
+
+CREATE SEQUENCE s1;
+CREATE VIEW v1 AS SELECT s1.currval AS a;
+SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='v1';
+SELECT * FROM v1;
+SHOW CREATE VIEW v1;
+DROP VIEW v1;
+DROP SEQUENCE s1;
+
+--echo #
+--echo # MDEV-12533 sql_mode=ORACLE: Add support for database qualified sequence names in NEXTVAL and CURRVAL
+--echo #
+CREATE SEQUENCE s1;
+SELECT test.s1.nextval;
+SELECT test.s1.currval;
+SELECT .s1.nextval;
+SELECT .s1.currval;
+DROP SEQUENCE s1;
diff --git a/mysql-test/suite/compat/oracle/t/sp-anonymous.test b/mysql-test/suite/compat/oracle/t/sp-anonymous.test
new file mode 100644
index 00000000000..ac61e8ace2e
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-anonymous.test
@@ -0,0 +1,244 @@
+--source include/have_innodb.inc
+
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-10655 Anonymous blocks
+--echo #
+
+--echo # Testing BEGIN NOT ATOMIC with no declarations
+DELIMITER /;
+BEGIN NOT ATOMIC
+ SELECT 1 AS a;
+END
+/
+DELIMITER ;/
+
+--echo # Testing BEGIN NOT ATOMIC with declarations
+--echo # DECLARE starts a new block and thus must be followed by BEGIN .. END
+DELIMITER /;
+BEGIN NOT ATOMIC
+ DECLARE
+ i INT DEFAULT 5;
+ x INT DEFAULT 10;
+ BEGIN
+ <<label>>
+ WHILE i > 3 LOOP
+ i:= i - 1;
+ SELECT i;
+ END LOOP label;
+ END;
+END
+/
+DELIMITER ;/
+
+
+--echo # Anonymous blocks with no declarations and no exceptions
+
+DELIMITER $$;
+BEGIN
+ SELECT 1 AS a;
+END
+$$
+DELIMITER ;$$
+
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+BEGIN
+ INSERT INTO t1 VALUES(20);
+ INSERT INTO t1 VALUES(30);
+ ROLLBACK;
+END;
+$$
+DELIMITER ;$$
+SELECT * FROM t1;
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+BEGIN
+ INSERT INTO t1 VALUES(20);
+ INSERT INTO t1 VALUES(30);
+END;
+$$
+DELIMITER ;$$
+ROLLBACK;
+SELECT * FROM t1;
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+BEGIN
+ INSERT INTO t1 VALUES(20);
+ INSERT INTO t1 VALUES(30);
+ COMMIT;
+END;
+$$
+DELIMITER ;$$
+SELECT * FROM t1;
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+BEGIN
+ INSERT INTO t1 VALUES(20);
+ INSERT INTO t1 VALUES(30);
+END;
+$$
+DELIMITER ;$$
+COMMIT;
+SELECT * FROM t1;
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+--error ER_DUP_ENTRY
+BEGIN
+ INSERT INTO t1 VALUES(20);
+ INSERT INTO t1 VALUES(20);
+END;
+$$
+DELIMITER ;$$
+COMMIT;
+SELECT * FROM t1;
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+
+
+--echo # Anonymous blocks with no declarations, with exceptions
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+BEGIN
+ INSERT INTO t1 VALUES(20);
+ INSERT INTO t1 VALUES(20);
+EXCEPTION
+ WHEN DUP_VAL_ON_INDEX THEN NULL;
+END;
+$$
+DELIMITER ;$$
+COMMIT;
+SELECT * FROM t1;
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+
+
+--echo # Anonymous blocks with declarations, with no exceptions
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+DECLARE
+ a20 INT:=20;
+ a30 INT:=30;
+BEGIN
+ INSERT INTO t1 VALUES(a20);
+ INSERT INTO t1 VALUES(a30);
+ ROLLBACK;
+END;
+$$
+DELIMITER ;$$
+SELECT * FROM t1;
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+DECLARE
+ a20 INT:=20;
+ a30 INT:=30;
+BEGIN
+ INSERT INTO t1 VALUES(a20);
+ INSERT INTO t1 VALUES(a30);
+END;
+$$
+DELIMITER ;$$
+ROLLBACK;
+SELECT * FROM t1;
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+DECLARE
+ a20 INT:=20;
+ a30 INT:=30;
+BEGIN
+ INSERT INTO t1 VALUES(a20);
+ INSERT INTO t1 VALUES(a30);
+ COMMIT;
+END;
+$$
+DELIMITER ;$$
+SELECT * FROM t1;
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+DECLARE
+ a20 INT:=20;
+ a30 INT:=30;
+BEGIN
+ INSERT INTO t1 VALUES(a20);
+ INSERT INTO t1 VALUES(a30);
+END;
+$$
+DELIMITER ;$$
+COMMIT;
+SELECT * FROM t1;
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
+
+
+--echo # Anonymous blocks with declarations, with exceptions
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+DECLARE
+ a20 INT:=20;
+BEGIN
+ INSERT INTO t1 VALUES(a20);
+ INSERT INTO t1 VALUES(a20);
+EXCEPTION
+ WHEN DUP_VAL_ON_INDEX THEN NULL;
+END;
+$$
+DELIMITER ;$$
+COMMIT;
+SELECT * FROM t1;
+DROP TABLE t1;
+SET AUTOCOMMIT=DEFAULT;
diff --git a/mysql-test/suite/compat/oracle/t/sp-code.test b/mysql-test/suite/compat/oracle/t/sp-code.test
new file mode 100644
index 00000000000..9a1f64e54b4
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-code.test
@@ -0,0 +1,1057 @@
+-- source include/have_debug.inc
+
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # Testing exceptions in the top-level blocks
+--echo #
+
+--echo # No HANDLER declarations, no exceptions
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+AS
+BEGIN
+ RETURN 10;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1();
+DROP FUNCTION f1;
+
+--echo # No HANDLER declarations, no code, no exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 ()
+IS
+BEGIN
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo # No HANDLER declarations, no code, some exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+EXCEPTION
+ WHEN 1002 THEN v:=225;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+
+--echo # No HANDLER declarations, some code, some exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+ v:=224;
+EXCEPTION
+ WHEN 1002 THEN v:=225;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+
+--echo # Some HANDLER declarations, no code, no exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+ EXIT HANDLER FOR 1000
+ BEGIN
+ v:=123;
+ END;
+BEGIN
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+
+--echo # Some HANDLER declarations, no code, some exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+ EXIT HANDLER FOR 1000
+ BEGIN
+ v:=123;
+ END;
+BEGIN
+EXCEPTION
+ WHEN 1002 THEN v:=225;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+
+--echo # Some HANDLER declarations, some code, no exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+ EXIT HANDLER FOR 1000
+ BEGIN
+ v:=123;
+ END;
+BEGIN
+ v:=223;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+--echo # Some HANDLER declarations, some code, some exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT VARCHAR2(20))
+IS
+ EXIT HANDLER FOR 1000
+ BEGIN
+ v:=123;
+ END;
+ CONTINUE HANDLER FOR 1001
+ BEGIN
+ SET v=223;
+ END;
+BEGIN
+ v:= 1;
+EXCEPTION
+ WHEN 1002 THEN SET v=225;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Testing EXCEPTIONS in internal blocks
+--echo #
+
+--echo # No HANDLER declarations, no code, no exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+ v:=123;
+ BEGIN
+ END;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+--echo # No HANDLER declarations, no code, some exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+ v:=123;
+ BEGIN
+ EXCEPTION
+ WHEN 20002 THEN v:=335;
+ END;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+--echo # No HANDLER declarations, some code, no exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+ v:=123;
+ BEGIN
+ v:=223;
+ END;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+--echo # No HANDLER declarations, some code, some exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+ v:=123;
+ BEGIN
+ v:=223;
+ EXCEPTION
+ WHEN 20002 THEN v:=335;
+ END;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+--echo # Some HANDLER declarations, no code, no exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+ v:=123;
+ DECLARE
+ EXIT HANDLER FOR 1000
+ BEGIN
+ v:=323;
+ END;
+ BEGIN
+ END;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+--echo # Some HANDLER declarations, no code, some exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+ v:=123;
+ DECLARE
+ EXIT HANDLER FOR 1000
+ BEGIN
+ v:=323;
+ END;
+ BEGIN
+ EXCEPTION
+ WHEN 20002 THEN v:=335;
+ END;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+--echo # Some HANDLER declarations, some code, no exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+ v:=123;
+ DECLARE
+ EXIT HANDLER FOR 1000
+ BEGIN
+ v:=323;
+ END;
+ BEGIN
+ v:= 324;
+ END;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+--echo # Some HANDLER declarations, some code, some exceptions
+DELIMITER /;
+CREATE PROCEDURE p1 (v IN OUT INT)
+IS
+BEGIN
+ v:=123;
+ DECLARE
+ EXIT HANDLER FOR 1000
+ BEGIN
+ v:=323;
+ END;
+ BEGIN
+ v:= 324;
+ EXCEPTION WHEN 2002 THEN v:= 325;
+ END;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+--echo #
+--echo # Testing EXIT statement
+--echo #
+
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+IS
+ i INT := 0;
+BEGIN
+ LOOP
+ i:= i + 1;
+ IF i >= 5 THEN
+ EXIT;
+ END IF;
+ END LOOP;
+ RETURN i;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+IS
+ i INT := 0;
+BEGIN
+ LOOP
+ i:= i + 1;
+ EXIT WHEN i >=5;
+ END LOOP;
+ RETURN i;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+IS
+ i INT := 0;
+BEGIN
+ LOOP
+ BEGIN
+ i:= i + 1;
+ IF i >= 5 THEN
+ EXIT;
+ END IF;
+ EXCEPTION
+ WHEN OTHERS THEN i:= 1000;
+ END;
+ END LOOP;
+ RETURN i;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE PROCEDURE p1(a IN OUT INT)
+IS
+ i INT := 0;
+BEGIN
+ LOOP
+ LOOP
+ BEGIN
+ i:= i + 1;
+ IF i >=5 THEN
+ EXIT;
+ END IF;
+ EXCEPTION
+ WHEN OTHERS THEN a:=1000;
+ END;
+ END LOOP;
+ i:= i + 100;
+ EXIT;
+ END LOOP;
+ a:= i;
+EXCEPTION
+ WHEN OTHERS THEN a:=11;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+set @v= 10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+
+--echo # Testing RETURN in procedures
+DELIMITER /;
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+BEGIN
+ IF a < 10 THEN
+ BEGIN
+ a:= a + 1;
+ RETURN;
+ END;
+ END IF;
+ a:= 200;
+EXCEPTION
+ WHEN OTHERS THEN
+ BEGIN
+ a:= 100;
+ RETURN;
+ END;
+END;
+/
+DELIMITER ;/
+SHOW PROCEDURE CODE p1;
+DROP PROCEDURE p1;
+
+
+--echo # Testing FOR loop statement
+DELIMITER /;
+CREATE FUNCTION f1 (a INT, b INT) RETURN INT
+AS
+ total INT := 0;
+BEGIN
+ FOR i IN 1 .. a
+ LOOP
+ total:= total + i;
+ IF i = b THEN
+ EXIT;
+ END IF;
+ END LOOP;
+ RETURN total;
+END
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1(3, 100) FROM DUAL;
+SELECT f1(3, 2) FROM DUAL;
+DROP FUNCTION f1;
+
+DELIMITER /;
+CREATE FUNCTION f1 (a INT, b INT) RETURN INT
+AS
+ total INT := 0;
+BEGIN
+ FOR i IN REVERSE a..1
+ LOOP
+ total:= total + i;
+ IF i = b THEN
+ EXIT;
+ END IF;
+ END LOOP;
+ RETURN total;
+END
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1(3, 100) FROM DUAL;
+SELECT f1(3, 2) FROM DUAL;
+DROP FUNCTION f1;
+
+
+--echo # Testing labeled FOR LOOP statement
+
+DELIMITER /;
+CREATE FUNCTION f1 (a INT, limita INT, b INT, limitb INT) RETURN INT
+AS
+ total INT := 0;
+BEGIN
+ <<la>>
+ FOR ia IN 1 .. a
+ LOOP
+ total:= total + 1000;
+ <<lb>>
+ FOR ib IN 1 .. b
+ LOOP
+ total:= total + 1;
+ EXIT lb WHEN ib = limitb;
+ EXIT la WHEN ia = limita;
+ END LOOP lb;
+ END LOOP la;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1(2, 1, 2, 2) FROM DUAL;
+SELECT f1(2, 2, 2, 2) FROM DUAL;
+SELECT f1(2, 3, 2, 3) FROM DUAL;
+DROP FUNCTION f1;
+
+
+--echo # Testing labeled ITERATE in a labeled FOR LOOP
+
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ total INT:= 0;
+BEGIN
+ <<li>>
+ FOR i IN 1 .. a
+ LOOP
+ total:= total + 1000;
+ IF i = 5 THEN
+ ITERATE li;
+ END IF;
+ total:= total + 1;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ total INT:= 0;
+BEGIN
+ <<li>>
+ FOR i IN 1 .. a
+ LOOP
+ FOR j IN 1 .. 2
+ LOOP
+ total:= total + 1000;
+ IF i = 5 THEN
+ ITERATE li;
+ END IF;
+ total:= total + 1;
+ END LOOP;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ total INT:= 0;
+BEGIN
+ <<lj>>
+ FOR j IN 1 .. 2
+ LOOP
+ <<li>>
+ FOR i IN 1 .. a
+ LOOP
+ total:= total + 1000;
+ IF i = 5 THEN
+ ITERATE li;
+ END IF;
+ total:= total + 1;
+ END LOOP;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+DROP FUNCTION f1;
+
+
+--echo # Testing CONTINUE statement
+
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ total INT:= 0;
+BEGIN
+ FOR i IN 1 .. a
+ LOOP
+ CONTINUE WHEN i=5;
+ total:= total + 1;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SHOW FUNCTION CODE f1;
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+DROP FUNCTION f1;
+
+--echo #
+--echo # Start of MDEV-10597 Cursors with parameters
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(arg_value_a VARCHAR, arg_value_b VARCHAR,
+ arg_pattern_a VARCHAR, arg_pattern_b VARCHAR)
+AS
+ v_a VARCHAR(10);
+ v_b VARCHAR(20);
+ CURSOR c (p_value_a VARCHAR,
+ p_value_b VARCHAR,
+ p_pattern_a VARCHAR,
+ p_pattern_b VARCHAR,
+ p_limit_a INT,
+ p_limit_b INT,
+ p_unused TEXT) IS
+ (SELECT p_value_a, p_value_b FROM DUAL
+ WHERE p_value_a LIKE p_pattern_a LIMIT p_limit_a)
+ UNION
+ (SELECT p_value_b, p_value_a FROM DUAL
+ WHERE p_value_b LIKE p_pattern_b LIMIT p_limit_b);
+BEGIN
+ OPEN c(arg_value_a, (SELECT arg_value_b),
+ arg_pattern_a, arg_pattern_b, 100, 101, 'x');
+ LOOP
+ FETCH c INTO v_a, v_b;
+ EXIT WHEN c%NOTFOUND;
+ SELECT v_a, v_b;
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1('aaa','bbb','aaa','bbb');
+SHOW PROCEDURE CODE p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # End of MDEV-10597 Cursors with parameters
+--echo #
+
+
+--echo #
+--echo # MDEV-10914 ROW data type for stored routine variables
+--echo #
+DELIMITER $$;
+CREATE FUNCTION f1() RETURN INT
+AS
+ a ROW(a INT, b INT);
+BEGIN
+ a.b:= 200;
+ RETURN a.b;
+END;
+$$
+DELIMITER ;$$
+SHOW FUNCTION CODE f1;
+SELECT f1();
+DROP FUNCTION f1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10));
+BEGIN
+ rec:= ROW(10,20.123456,30.123,'test');
+ SELECT rec.a, rec.b, rec.c, rec.d;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+CALL p1;
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10)) :=
+ ROW(10,20.123456,30.123,'test');
+BEGIN
+ SELECT rec.a, rec.b, rec.c, rec.d;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+CALL p1;
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec1 ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10));
+ rec2 ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10));
+BEGIN
+ rec1:= ROW(10,20.123456,30.123,'test');
+ rec2:= rec1;
+ SELECT rec2.a, rec2.b, rec2.c, rec2.d;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+CALL p1;
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec1 ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10)) :=
+ ROW(10,20.123456,30.123,'test');
+ rec2 ROW(a INT,b DOUBLE,c DECIMAL(10,3),d VARCHAR(10)) := rec1;
+BEGIN
+ SELECT rec2.a, rec2.b, rec2.c, rec2.d;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+CALL p1;
+DROP PROCEDURE p1;
+
+--echo #
+--echo # End of MDEV-10914 ROW data type for stored routine variables
+--echo #
+
+--echo #
+--echo # MDEV-12133 sql_mode=ORACLE: table%ROWTYPE in variable declarations
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE;
+BEGIN
+ rec1.a:= 10;
+ rec1.b:= 'bbb';
+ rec1.c:= 10e2;
+ rec1.d:= 10.12;
+ rec1.c:= rec1.d;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-12011 sql_mode=ORACLE: cursor%ROWTYPE in variable declarations
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+ CURSOR cur2 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1,rec2 cur1%ROWTYPE;
+ rec3 cur2%ROWTYPE;
+ BEGIN
+ rec1.a:= 10;
+ rec1.b:= 'bbb';
+ END;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-10581 sql_mode=ORACLE: Explicit cursor FOR LOOP
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR cur0 IS SELECT 10 AS a, 'b0' AS b;
+ CURSOR cur1 IS SELECT 10 AS a, 'b0' AS b;
+ CURSOR cur2 IS SELECT 10 AS a, 'b0' AS b;
+BEGIN
+ FOR rec1 IN cur1
+ LOOP
+ SELECT rec1.a, rec1.b;
+ rec1.a:= 11;
+ rec1.b:= 'b1';
+ SELECT rec1.a, rec1.b;
+ END LOOP;
+ FOR rec0 IN cur0
+ LOOP
+ rec0.a:= 10;
+ rec0.b:='b0';
+ END LOOP;
+ FOR rec2 IN cur2
+ LOOP
+ rec2.a:= 10;
+ rec2.b:='b0';
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR cur0 IS SELECT 10 AS a, 'b0' AS b;
+BEGIN
+ FOR rec0 IN cur0
+ LOOP
+ DECLARE
+ CURSOR cur1 IS SELECT 11 AS a, 'b1' AS b;
+ BEGIN
+ rec0.a:= 11;
+ rec0.b:= 'b0';
+ FOR rec1 IN cur1
+ LOOP
+ rec1.a:= 11;
+ rec1.b:= 'b1';
+ DECLARE
+ CURSOR cur2 IS SELECT 12 AS a, 'b2' AS b;
+ BEGIN
+ FOR rec2 IN cur2
+ LOOP
+ rec2.a:=12;
+ rec2.b:='b2';
+ END LOOP;
+ END;
+ END LOOP;
+ END;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # MDEV-12098 sql_mode=ORACLE: Implicit cursor FOR loop
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ FOR rec1 IN (SELECT 11 AS a, 'b1' AS b)
+ LOOP
+ SELECT rec1.a, rec1.b;
+ rec1.a:= 11;
+ rec1.b:= 'b1';
+ SELECT rec1.a, rec1.b;
+ END LOOP;
+ FOR rec0 IN (SELECT 10 AS a, 'b0' AS b)
+ LOOP
+ rec0.a:= 10;
+ rec0.b:='b0';
+ END LOOP;
+ FOR rec2 IN (SELECT 12 AS a, 'b2' AS b)
+ LOOP
+ rec2.a:= 10;
+ rec2.b:='b0';
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ FOR rec0 IN (SELECT 10 AS a, 'b0' AS b)
+ LOOP
+ rec0.a:= 11;
+ rec0.b:= 'b0';
+ FOR rec1 IN (SELECT 11 AS a, 'b1' AS b)
+ LOOP
+ rec1.a:= 11;
+ rec1.b:= 'b1';
+ FOR rec2 IN (SELECT 12 AS a, 'b2' AS b)
+ LOOP
+ rec2.a:=12;
+ rec2.b:='b2';
+ END LOOP;
+ END LOOP;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE 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;
+
+
+--echo #
+--echo # MDEV-12441 Variables declared after cursors with parameters lose values
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1() AS
+ x0 INT:=100;
+ CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+ x1 INT:=101;
+BEGIN
+ OPEN cur(10,11);
+ CLOSE cur;
+ SELECT x0, x1;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+CALL p1();
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1() AS
+ x0 INT:=100;
+ CURSOR cur0(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+ x1 INT:=101;
+ CURSOR cur1(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+ x2 INT:=102;
+ CURSOR cur2(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+ x3 INT:=103;
+BEGIN
+ OPEN cur0(0,1);
+ CLOSE cur0;
+ SELECT x0, x1, x2, x3;
+ OPEN cur1(10,11);
+ CLOSE cur1;
+ SELECT x0, x1, x2, x3;
+ OPEN cur2(20,21);
+ CLOSE cur2;
+ SELECT x0, x1, x2, x3;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+CALL p1();
+DROP PROCEDURE p1;
+
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1() AS
+ x0 INT:=100;
+ CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+ x1 t1.a%TYPE:=101;
+BEGIN
+ OPEN cur(10,11);
+ CLOSE cur;
+ SELECT x0, x1;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1() AS
+ x0 INT:=100;
+ CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+ x1 ROW(a INT,b INT):=ROW(101,102);
+BEGIN
+ OPEN cur(10,11);
+ CLOSE cur;
+ SELECT x0, x1.a, x1.b;
+END;
+$$
+DELIMITER ;$$
+SHOW PROCEDURE CODE p1;
+CALL p1();
+DROP PROCEDURE p1;
diff --git a/mysql-test/suite/compat/oracle/t/sp-cursor-decl.test b/mysql-test/suite/compat/oracle/t/sp-cursor-decl.test
new file mode 100644
index 00000000000..21683dd4220
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-cursor-decl.test
@@ -0,0 +1,295 @@
+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;
+
+
+--echo #
+--echo # MDEV-12916 Wrong column data type for an INT field of a cursor-anchored ROW variable
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a INT DEFAULT 10;
+ CURSOR cur1 IS SELECT a;
+ rec1 cur1%ROWTYPE;
+BEGIN
+ CREATE TABLE t1 AS SELECT rec1.a;
+ SHOW CREATE TABLE t1;
+ DROP TABLE t1;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
diff --git a/mysql-test/suite/compat/oracle/t/sp-cursor-rowtype.test b/mysql-test/suite/compat/oracle/t/sp-cursor-rowtype.test
new file mode 100644
index 00000000000..3c37a732d8c
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-cursor-rowtype.test
@@ -0,0 +1,1424 @@
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-12011 sql_mode=ORACLE: cursor%ROWTYPE in variable declarations
+--echo #
+
+--echo #
+--echo # A complete working example
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+CREATE TABLE t2 LIKE t1;
+INSERT INTO t1 VALUES (10,'b10');
+INSERT INTO t1 VALUES (20,'b20');
+INSERT INTO t1 VALUES (30,'b30');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ CURSOR c IS SELECT a,b FROM t1;
+BEGIN
+ DECLARE
+ rec c%ROWTYPE;
+ BEGIN
+ OPEN c;
+ LOOP
+ FETCH c INTO rec;
+ EXIT WHEN c%NOTFOUND;
+ SELECT 'rec=(' || rec.a ||','|| rec.b||')' AS c FROM dual;
+ INSERT INTO t2 VALUES (rec.a, rec.b);
+ END LOOP;
+ CLOSE c;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t2;
+DROP PROCEDURE p1;
+DROP TABLE t2;
+DROP TABLE t1;
+
+
+--echo #
+--echo # cursor%ROWTYPE referring to a table in a non-existing database
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur IS SELECT * FROM tes2.t1;
+BEGIN
+ DECLARE
+ rec cur%ROWTYPE;
+ BEGIN
+ NULL;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1();
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+--error ER_NO_SUCH_TABLE
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # cursor%ROWTYPE referring to a table in the current database
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec cur%ROWTYPE;
+ BEGIN
+ CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1();
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CALL p1();
+DROP TABLE t1;
+--error ER_NO_SUCH_TABLE
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # cursor%ROWTYPE referring to a table in an explicitly specified database
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur IS SELECT * FROM test.t1;
+BEGIN
+ DECLARE
+ rec cur%ROWTYPE;
+ BEGIN
+ CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1();
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Cursor%ROWTYPE referring to a view in the current database
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur IS SELECT * FROM v1;
+BEGIN
+ DECLARE
+ rec cur%ROWTYPE;
+ BEGIN
+ CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1();
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CREATE VIEW v1 AS SELECT * FROM t1;
+CALL p1();
+DROP VIEW v1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # cursor%ROWTYPE referring to a view in an explicitly specified database
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur IS SELECT * FROM test.v1;
+BEGIN
+ DECLARE
+ rec cur%ROWTYPE;
+ BEGIN
+ CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1();
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CREATE VIEW v1 AS SELECT * FROM t1;
+CALL p1();
+DROP VIEW v1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Checking that all cursor%ROWTYPE fields are NULL by default
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE;
+ BEGIN
+ SELECT rec1.a, rec1.b, rec1.c, rec1.d;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # A cursor%ROWTYPE variable with a ROW expression as a default
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE := ROW(10,'bbb');
+ BEGIN
+ SELECT rec1.a, rec1.b;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # A cursor%ROWTYPE variable with an incompatible ROW expression as a default
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE := ROW(10,'bbb','ccc');
+ BEGIN
+ SELECT rec1.a, rec1.b;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # A cursor%ROWTYPE variable with a ROW variable as a default
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 ROW(a INT, b VARCHAR(10)):= ROW(10,'bbb');
+ rec2 cur%ROWTYPE := rec1;
+ BEGIN
+ SELECT rec2.a, rec2.b;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # A ROW variable using a cursor%ROWTYPE variable as a default
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE := ROW(10,'bbb');
+ rec2 ROW(a INT, b VARCHAR(10)):= rec1;
+ BEGIN
+ SELECT rec2.a, rec2.b;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning cursor%ROWTYPE variables with a different column count
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE);
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+ CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE;
+ rec2 cur2%ROWTYPE;
+ BEGIN
+ rec2:=rec1;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+ CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE;
+ rec2 cur2%ROWTYPE;
+ BEGIN
+ rec1:=rec2;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning compatible cursor%ROWTYPE variables (equal number of fields)
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (x INT, y VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+ CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE;
+ rec2 cur2%ROWTYPE;
+ BEGIN
+ rec1.a:= 10;
+ rec1.b:= 'bbb';
+ rec2:=rec1;
+ SELECT rec2.x, rec2.y;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning between incompatible cursor%ROWTYPE and explicit ROW variables
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE;
+ rec2 ROW(x INT,y INT,z INT);
+ BEGIN
+ rec2.x:= 10;
+ rec2.y:= 20;
+ rec2.z:= 30;
+ rec1:= rec2;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning between compatible cursor%ROWTYPE and explicit ROW variables
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE;
+ rec2 ROW(x INT,y INT);
+ BEGIN
+ rec2.x:= 10;
+ rec2.y:= 20;
+ rec1:= rec2;
+ SELECT rec1.a, rec1.b;
+ rec1.a:= 11;
+ rec1.b:= 21;
+ rec2:= rec1;
+ SELECT rec2.x, rec2.y;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning cursor%ROWTYPE from a ROW expression
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE;
+ BEGIN
+ rec1:= ROW(10,20);
+ SELECT rec1.a, rec1.b;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Fetching a cursor into a cursor%ROWTYPE variable with a wrong field count
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'bb1',111.111e2, 12.31);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+ CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+ DECLARE
+ rec2 cur2%ROWTYPE;
+ BEGIN
+ OPEN cur1;
+ FETCH cur1 INTO rec2;
+ CLOSE cur1;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_SP_WRONG_NO_OF_FETCH_ARGS
+CALL p1();
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Fetching a cursor into a cursor%ROWTYPE variable
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE TABLE t2 LIKE t1;
+INSERT INTO t1 VALUES (10,'bb1',111.111e2, 12.31);
+INSERT INTO t1 VALUES (20,'bb2',222.222e2, 12.32);
+INSERT INTO t1 VALUES (30,'bb3',333.333e2, 12.33);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec cur%ROWTYPE;
+ BEGIN
+ OPEN cur;
+ LOOP
+ FETCH cur INTO rec;
+ EXIT WHEN cur%NOTFOUND;
+ SELECT rec.a, rec.b, rec.c, rec.d;
+ INSERT INTO t2 VALUES (rec.a, rec.b, rec.c, rec.d);
+ END LOOP;
+ CLOSE cur;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t2;
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Fetching a cursor into a cursor%ROWTYPE variable, cur%ROWTYPE declared inside the LOOP
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE TABLE t2 LIKE t1;
+INSERT INTO t1 VALUES (10,'bb1',111.111e2, 12.31);
+INSERT INTO t1 VALUES (20,'bb2',222.222e2, 12.32);
+INSERT INTO t1 VALUES (30,'bb3',333.333e2, 12.33);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur IS SELECT * FROM t1;
+BEGIN
+ OPEN cur;
+ LOOP
+ DECLARE
+ rec cur%ROWTYPE;
+ BEGIN
+ FETCH cur INTO rec;
+ EXIT WHEN cur%NOTFOUND;
+ SELECT rec.a, rec.b, rec.c, rec.d;
+ INSERT INTO t2 VALUES (rec.a, rec.b, rec.c, rec.d);
+ END;
+ END LOOP;
+ CLOSE cur;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t2;
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Fetching a cursor into a cursor%ROWTYPE variable with different column names
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (x INT, y VARCHAR(10));
+INSERT INTO t1 VALUES (10,'bbb');
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+ CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+ DECLARE
+ rec2 cur2%ROWTYPE;
+ BEGIN
+ OPEN cur1;
+ FETCH cur1 INTO rec2;
+ SELECT rec2.x, rec2.y;
+ CLOSE cur1;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Fetching a cursor into a cursor%ROWTYPE variable, with truncation
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (a INT, b INT);
+INSERT INTO t1 VALUES (10,'11x');
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+ CURSOR cur2 IS SELECT * FROM t2;
+BEGIN
+ DECLARE
+ rec2 cur2%ROWTYPE;
+ BEGIN
+ OPEN cur1;
+ FETCH cur1 INTO rec2;
+ SELECT rec2.a, rec2.b;
+ CLOSE cur1;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # cursor%ROWTYPE variables are not allowed in LIMIT
+--echo #
+CREATE TABLE t1 (a INT, b INT);
+INSERT INTO t1 VALUES (1,2);
+DELIMITER $$;
+--error ER_WRONG_SPVAR_TYPE_IN_LIMIT
+CREATE PROCEDURE p1()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE:=(1,2);
+ BEGIN
+ SELECT * FROM t1 LIMIT rec1.a;
+ END;
+END;
+$$
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+--echo #
+--echo # cursor%ROWTYPE variable fields as OUT parameters
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1(a OUT INT,b OUT VARCHAR(10))
+AS
+BEGIN
+ a:=10;
+ b:='bb';
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE;
+ BEGIN
+ CALL p1(rec1.a, rec1.b);
+ SELECT rec1.a, rec1.b;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p2();
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Passing the entire cursor%ROWTYPE variable
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1(a ROW(a INT, b VARCHAR(10)))
+AS
+BEGIN
+ SELECT a.a, a.b;
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+ CURSOR cur IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur%ROWTYPE:= ROW(10,'bb');
+ BEGIN
+ CALL p1(rec1);
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p2();
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Passing the entire cursor%ROWTYPE variable as an OUT parameter
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1(a OUT ROW(a INT, b VARCHAR(10)))
+AS
+BEGIN
+ a:= ROW(10,'bb');
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+ CURSOR cur IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur%ROWTYPE;
+ BEGIN
+ CALL p1(rec1);
+ SELECT rec1.a, rec1.b;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p2();
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Assigning a cursor%ROWTYPE field to an OUT parameter
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1 (res IN OUT INTEGER)
+AS
+ a INT:=10;
+ CURSOR cur1 IS SELECT a FROM DUAL;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE;
+ BEGIN
+ OPEN cur1;
+ FETCH cur1 INTO rec1;
+ CLOSE cur1;
+ res:=rec1.a;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1(@res);
+SELECT @res;
+SET @res=NULL;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Testing Item_splocal_row_field_by_name::print
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec cur1%ROWTYPE:=ROW(10,'bb');
+ BEGIN
+ EXPLAIN EXTENDED SELECT rec.a, rec.b;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Run time error in the cursor statement
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR cur1 IS SELECT
+ 10 AS a,
+ CONCAT(_latin1'a' COLLATE latin1_bin,
+ _latin1'a' COLLATE latin1_swedish_ci) AS b;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE;
+ BEGIN
+ OPEN cur1;
+ FETCH cur1 INTO rec1;
+ CLOSE cur1;
+ SELECT a,b;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_CANT_AGGREGATE_2COLLATIONS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+
+--echo #
+--echo # Non-existing field
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec cur1%ROWTYPE;
+ BEGIN
+ SELECT rec.c;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD
+CALL p1();
+ALTER TABLE t1 ADD c INT;
+#
+# The below ALTER is needed as a workaround to call sp_cache_invalidate()
+# Please remove it after fixing MDEV-12166
+#
+ALTER PROCEDURE p1 COMMENT 'test';
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that field names are case insensitive
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR cur IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec cur%ROWTYPE:=ROW(10,'bb');
+ BEGIN
+ SELECT rec.A, rec.B;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that cursor%ROWTYPE uses temporary tables vs shadowed real tables
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TEMPORARY TABLE t1 (x INT, y VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR cur IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec cur%ROWTYPE:=ROW(10,'bb');
+ BEGIN
+ SELECT rec.A, rec.B;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD
+CALL p1();
+DROP TEMPORARY TABLE t1;
+#
+# The below ALTER is needed as a workaround to call sp_cache_invalidate()
+# Please remove it after fixing MDEV-12166
+#
+ALTER PROCEDURE p1 COMMENT 'test';
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that the structure of cursor%ROWTYPE variables is determined at the CURSOR instantiation time
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ CURSOR cur IS SELECT * FROM t1;
+BEGIN
+ DROP TABLE t1;
+ CREATE TABLE t1 (a INT, b VARCHAR(32), c INT);
+ DECLARE
+ rec cur%ROWTYPE; -- This has a column "c"
+ BEGIN
+ rec.c:=10;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ CURSOR cur IS SELECT * FROM t1;
+BEGIN
+ DECLARE
+ rec cur%ROWTYPE; -- This does not have a column "c"
+ BEGIN
+ DROP TABLE t1;
+ CREATE TABLE t1 (a INT, b VARCHAR(32), c INT);
+ rec.c:=10;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Duplicate field nams in a cursor referenced by %ROWTYPE
+--echo #
+
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ CURSOR cur IS SELECT * FROM t1, t2;
+BEGIN
+ DECLARE
+ rec cur%ROWTYPE;
+ BEGIN
+ SELECT rec.a;
+ rec.a:=10;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_DUP_FIELDNAME
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t2;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Tricky field names a cursor referenced by %ROWTYPE
+--echo #
+
+SET NAMES utf8;
+CREATE TABLE t1 (a VARCHAR(10));
+INSERT INTO t1 VALUES ('a');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ CURSOR cur IS SELECT a, CONCAT(a,'a'), CONCAT(a,'ö') FROM t1;
+BEGIN
+ DECLARE
+ rec cur%ROWTYPE;
+ BEGIN
+ OPEN cur;
+ FETCH cur INTO rec;
+ CLOSE cur;
+ SELECT rec.a, rec."CONCAT(a,'a')", rec."CONCAT(a,'ö')";
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+SET NAMES latin1;
+
+
+--echo #
+--echo # Using definitions recursively (cursor%ROWTYPE variables in another cursor SELECT)
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'b1'),(20,'b2'),(30,'b3');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ CURSOR cur1 IS SELECT a,b FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE:=ROW(0,'b0');
+ CURSOR cur2 IS SELECT rec1.a AS a, rec1.b AS b FROM t1;
+ BEGIN
+ DECLARE
+ rec2 cur2%ROWTYPE;
+ BEGIN
+ OPEN cur2;
+ LOOP
+ FETCH cur2 INTO rec2;
+ EXIT WHEN cur2%NOTFOUND;
+ SELECT rec2.a, rec2.b;
+ END LOOP;
+ CLOSE cur2;
+ END;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing queries with auto-generated Items.
+--echo # An instance of Item_func_conv_charset is created during the below SELECT query.
+--echo # We check here that during an implicit cursor OPEN
+--echo # done in sp_instr_cursor_copy_struct::exec_core()
+--echo # all temporary Items are created on a proper memory root and are safely destroyed.
+--echo #
+
+CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1, b VARCHAR(10) CHARACTER SET utf8);
+INSERT INTO t1 VALUES (0xFF, 'a');
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR cur1 IS SELECT CONCAT(a,b) AS c FROM t1;
+BEGIN
+ DECLARE
+ rec1 cur1%ROWTYPE;
+ BEGIN
+ OPEN cur1;
+ FETCH cur1 INTO rec1;
+ CLOSE cur1;
+ SELECT HEX(rec1.c);
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-10581 sql_mode=ORACLE: Explicit cursor FOR LOOP
+--echo #
+
+--echo # IN followed by a non-identifier
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+CREATE PROCEDURE p1 AS
+ CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+ FOR rec IN 10
+ LOOP
+ NULL;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo # IN followed by a quoted identifier: table.column
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+CREATE PROCEDURE p1 AS
+ CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+ FOR rec IN c1.c2
+ LOOP
+ NULL;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo # IN followed by a quoted identifier: .table.column
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+CREATE PROCEDURE p1 AS
+ CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+ FOR rec IN .c1.c2
+ LOOP
+ NULL;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo # IN followed by a quoted identifier: schema.table.column
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+CREATE PROCEDURE p1 AS
+ CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+ FOR rec IN c1.c2.c3
+ LOOP
+ NULL;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo # IN followed by an unknown cursor name
+
+DELIMITER $$;
+--error ER_SP_CURSOR_MISMATCH
+CREATE PROCEDURE p1 AS
+ CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+ FOR rec IN c2
+ LOOP
+ NULL;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo # Make sure "rec" shadows other declarations outside the loop
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10, 'b0');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ rec INT:=10;
+ CURSOR c1 IS SELECT a,b FROM t1;
+BEGIN
+ FOR rec IN c1
+ LOOP
+ SELECT rec.a;
+ END LOOP;
+ SELECT rec;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo # Make sure "rec" is not visible after END LOOP
+
+DELIMITER $$;
+--error ER_UNKNOWN_STRUCTURED_VARIABLE
+CREATE PROCEDURE p1 AS
+ CURSOR c1 IS SELECT 'test' AS a FROM DUAL;
+BEGIN
+ FOR rec IN c1
+ LOOP
+ NULL;
+ END LOOP;
+ rec.a:= 10;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo # Make sure that duplicate column names are not allowed
+
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ CURSOR cur IS SELECT 'a' AS a, 'A' as a;
+BEGIN
+ FOR rec IN cur
+ LOOP
+ NULL;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+--error ER_DUP_FIELDNAME
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo # A complete working example
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'b0');
+INSERT INTO t1 VALUES (11,'b1');
+INSERT INTO t1 VALUES (12,'b2');
+CREATE TABLE t2 LIKE t1;
+CREATE TABLE t3 LIKE t1;
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ CURSOR cur IS SELECT a, b FROM t1;
+BEGIN
+ FOR rec IN cur
+ LOOP
+ SELECT rec.a, rec.b;
+ INSERT INTO t2 VALUES (rec.a, rec.b);
+ rec.a:= rec.a + 1000;
+ rec.b:= 'b' || rec.b;
+ INSERT INTO t3 VALUES (rec.a, rec.b);
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t2;
+SELECT * FROM t3;
+DROP PROCEDURE p1;
+DROP TABLE t3;
+DROP TABLE t2;
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-12314 Implicit cursor FOR LOOP for cursors with parameters
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b0');
+INSERT INTO t1 VALUES (11,'b1');
+INSERT INTO t1 VALUES (12,'b2');
+DELIMITER $$;
+CREATE PROCEDURE p1(pa INT, pb VARCHAR(32)) AS
+ CURSOR cur(va INT, vb VARCHAR(32)) IS
+ SELECT a, b FROM t1 WHERE a=va AND b=vb;
+BEGIN
+ FOR rec IN cur(pa,pb)
+ LOOP
+ SELECT rec.a, rec.b;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+CALL p1(10,'B0');
+CALL p1(11,'B1');
+CALL p1(12,'B2');
+CALL p1(12,'non-existing');
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # MDEV-12098 sql_mode=ORACLE: Implicit cursor FOR loop
+--echo #
+
+--echo # Parse error in the cursor SELECT statement
+DELIMITER $$;
+--error ER_PARSE_ERROR
+CREATE PROCEDURE p1 AS
+BEGIN
+ FOR rec IN (SELECT a, b FROM)
+ LOOP
+ SELECT rec.a, rec.b;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo # Make sure "rec" is not visible after END LOOP
+
+DELIMITER $$;
+--error ER_UNKNOWN_STRUCTURED_VARIABLE
+CREATE PROCEDURE p1 AS
+BEGIN
+ FOR rec IN (SELECT 'test' AS a)
+ LOOP
+ NULL;
+ END LOOP;
+ rec.a:= 10;
+END;
+$$
+DELIMITER ;$$
+
+--echo # Make sure "rec" is not visible inside the SELECT statement
+
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+BEGIN
+ FOR rec IN (SELECT rec)
+ LOOP
+ NULL;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+--error ER_BAD_FIELD_ERROR
+CALL p1;
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+BEGIN
+ FOR rec IN (SELECT rec.a)
+ LOOP
+ NULL;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+--error ER_UNKNOWN_TABLE
+CALL p1;
+DROP PROCEDURE p1;
+
+--echo # Totally confusing name mixture
+
+CREATE TABLE rec (rec INT);
+INSERT INTO rec VALUES (10);
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+BEGIN
+ FOR rec IN (SELECT rec FROM rec)
+ LOOP
+ SELECT rec.rec;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+DROP TABLE rec;
+
+
+--echo # Make sure that duplicate column names are not allowed
+
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+BEGIN
+ FOR rec IN (SELECT 'a' AS a, 'A' as a)
+ LOOP
+ NULL;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+--error ER_DUP_FIELDNAME
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo # A complete working example
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'b0');
+INSERT INTO t1 VALUES (11,'b1');
+INSERT INTO t1 VALUES (12,'b2');
+CREATE TABLE t2 LIKE t1;
+CREATE TABLE t3 LIKE t1;
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+BEGIN
+ FOR rec IN (SELECT a, b FROM t1)
+ LOOP
+ SELECT rec.a, rec.b;
+ INSERT INTO t2 VALUES (rec.a, rec.b);
+ rec.a:= rec.a + 1000;
+ rec.b:= 'b'|| rec.b;
+ INSERT INTO t3 VALUES (rec.a, rec.b);
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t2;
+SELECT * FROM t3;
+DROP PROCEDURE p1;
+DROP TABLE t3;
+DROP TABLE t2;
+DROP TABLE t1;
+
+
+--echo # A combination of explicit and implicit cursors
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'b1');
+INSERT INTO t1 VALUES (11,'b2');
+INSERT INTO t1 VALUES (12,'b3');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+BEGIN
+ FOR rec1 IN (SELECT a, b FROM t1)
+ LOOP
+ DECLARE
+ CURSOR cur2 IS SELECT a+1000 AS a, 'bb'||b AS b FROM t1 WHERE a=rec1.a AND b=rec1.b;
+ BEGIN
+ SELECT rec1.a, rec1.b;
+ FOR rec2 IN cur2
+ LOOP
+ SELECT rec2.a, rec2.b;
+ END LOOP;
+ END;
+ END LOOP;
+ FOR rec1 IN (SELECT a,b FROM t1)
+ LOOP
+ FOR rec2 IN (SELECT a+2000 AS a,'bbb'||b AS b FROM t1 WHERE a=rec1.a AND b=rec1.b)
+ LOOP
+ SELECT rec2.a, rec2.b;
+ END LOOP;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/sp-cursor.test b/mysql-test/suite/compat/oracle/t/sp-cursor.test
new file mode 100644
index 00000000000..5a8b7b69f67
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-cursor.test
@@ -0,0 +1,954 @@
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-10582 sql_mode=ORACLE: explicit cursor attributes %ISOPEN, %ROWCOUNT, %FOUND, %NOTFOUND
+--echo #
+
+
+--echo #
+--echo # Cursor attributes outside of an SP context
+--echo #
+
+--error ER_SP_CURSOR_MISMATCH
+SELECT c%ISOPEN;
+--error ER_SP_CURSOR_MISMATCH
+SELECT c%FOUND;
+--error ER_SP_CURSOR_MISMATCH
+SELECT c%NOTFOUND;
+--error ER_SP_CURSOR_MISMATCH
+SELECT c%ROWCOUNT;
+
+
+--echo #
+--echo # Undefinite cursor attributes
+--echo #
+
+DELIMITER $$;
+--error ER_SP_CURSOR_MISMATCH
+CREATE PROCEDURE p1
+AS
+BEGIN
+ SELECT c%ISOPEN;
+END;
+$$
+--error ER_SP_CURSOR_MISMATCH
+CREATE PROCEDURE p1
+AS
+BEGIN
+ SELECT c%ROWCOUNT;
+END;
+$$
+--error ER_SP_CURSOR_MISMATCH
+CREATE PROCEDURE p1
+AS
+BEGIN
+ SELECT c%FOUND;
+END;
+$$
+--error ER_SP_CURSOR_MISMATCH
+CREATE PROCEDURE p1
+AS
+BEGIN
+ SELECT c%NOTFOUND;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # Not opened cursor attributes %FOUND, %NOTFOUND, %ROWCOUNT
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+ SELECT c%ROWCOUNT;
+END;
+$$
+DELIMITER ;$$
+--error ER_SP_CURSOR_NOT_OPEN
+CALL p1;
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+ SELECT c%FOUND;
+END;
+$$
+DELIMITER ;$$
+--error ER_SP_CURSOR_NOT_OPEN
+CALL p1;
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+ SELECT c%NOTFOUND;
+END;
+$$
+DELIMITER ;$$
+--error ER_SP_CURSOR_NOT_OPEN
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Not opened cursor attributes %FOUND, %NOTFOUND, %ROWCOUNT with INVALID_CURSOR exception
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+ SELECT c%ROWCOUNT;
+EXCEPTION
+ WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+ SELECT c%FOUND;
+EXCEPTION
+ WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+ SELECT c%NOTFOUND;
+EXCEPTION
+ WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # print()
+--echo #
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR c IS SELECT * FROM t1 ORDER BY a;
+BEGIN
+ EXPLAIN EXTENDED SELECT c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Declared data type of the attributes
+--echo #
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR c IS SELECT * FROM t1 ORDER BY a;
+BEGIN
+ OPEN c;
+ CREATE TABLE t2 AS SELECT c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Core functionality
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+INSERT INTO t1 VALUES (30);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a INT:=0;
+ CURSOR c IS SELECT * FROM t1 ORDER BY a;
+BEGIN
+ SELECT a, c%ISOPEN;
+ OPEN c;
+ /*
+ After OPEN and before FETCH:
+ - %ROWCOUNT returns 0
+ - %FOUND and %NOTFOUND return NULL
+ */
+ SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+ FETCH c INTO a;
+ SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+ FETCH c INTO a;
+ SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+ FETCH c INTO a;
+ SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+ FETCH c INTO a;
+ SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+ CLOSE c;
+ SELECT a, c%ISOPEN;
+ /*
+ After reopen and before FETCH:
+ - %ROWCOUNT returns 0
+ - %FOUND and %NOTFOUND return NULL
+ */
+ OPEN c;
+ SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+ FETCH c INTO a;
+ SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # %NOTFOUND as a loop exit condition
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+INSERT INTO t1 VALUES (30);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a INT:=0;
+ CURSOR c IS SELECT * FROM t1 ORDER BY a;
+BEGIN
+ OPEN c;
+ LOOP
+ FETCH c INTO a;
+ EXIT WHEN c%NOTFOUND;
+ SELECT a;
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # %FOUND as a loop exit condition
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+INSERT INTO t1 VALUES (30);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a INT:=0;
+ CURSOR c IS SELECT * FROM t1 ORDER BY a;
+BEGIN
+ OPEN c;
+ LOOP
+ FETCH c INTO a;
+ EXIT WHEN NOT c%FOUND;
+ SELECT a;
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--echo #
+--echo # End of MDEV-10582 sql_mode=ORACLE: explicit cursor attributes %ISOPEN, %ROWCOUNT, %FOUND, %NOTFOUND
+--echo #
+
+--echo #
+--echo # MDEV-10597 Cursors with parameters
+--echo #
+
+--echo #
+--echo # OPEN with a wrong number of parameters
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+--error ER_WRONG_PARAMCOUNT_TO_CURSOR
+CREATE PROCEDURE p1(a_a INT,a_b VARCHAR)
+AS
+ v_a INT;
+ v_b VARCHAR(10);
+ CURSOR c (p_a INT, p_b VARCHAR) IS SELECT * FROM t1 WHERE a=p_a;
+BEGIN
+ OPEN c(a_a);
+ LOOP
+ FETCH c INTO v_a, v_b;
+ EXIT WHEN c%NOTFOUND;
+ DBMS_OUTPUT.PUT_LINE('Fetched a record a='||TO_CHAR(v_a)||' b='||v_b);
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+--echo #
+--echo # Cursor parameters are not visible outside of the cursor
+--echo #
+
+DELIMITER $$;
+--error ER_UNKNOWN_SYSTEM_VARIABLE
+CREATE PROCEDURE p1(a_a INT)
+AS
+ v_a INT;
+ CURSOR c (p_a INT) IS SELECT a FROM t1 WHERE a=p_a;
+BEGIN
+ OPEN c(a_a);
+ p_a:=10;
+END;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--error ER_UNKNOWN_SYSTEM_VARIABLE
+CREATE PROCEDURE p1(a_a INT)
+AS
+ v_a INT;
+ CURSOR c (p_a INT) IS SELECT a FROM t1 WHERE a=p_a;
+BEGIN
+ p_a:=10;
+ OPEN c(a_a);
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # Cursor parameter shadowing a local variable
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+DELIMITER $$;
+CREATE PROCEDURE p1(a INT)
+AS
+ v_a INT:=NULL;
+ p_a INT:=NULL;
+ CURSOR c (p_a VARCHAR2) IS SELECT a FROM t1 WHERE p_a IS NOT NULL;
+BEGIN
+ OPEN c(a);
+ FETCH c INTO v_a;
+ IF c%NOTFOUND THEN
+ BEGIN
+ SELECT 'No records found' AS msg;
+ RETURN;
+ END;
+ END IF;
+ CLOSE c;
+ SELECT 'Fetched a record a='||v_a AS msg;
+ INSERT INTO t1 VALUES (v_a);
+END;
+$$
+DELIMITER ;$$
+CALL p1(1);
+SELECT * FROM t1;
+CALL p1(NULL);
+SELECT * FROM t1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Parameters in SELECT list
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a_a INT, a_b VARCHAR)
+AS
+ v_a INT;
+ v_b VARCHAR(10);
+ CURSOR c (p_a INT, p_b VARCHAR) IS SELECT p_a,p_b FROM DUAL;
+BEGIN
+ FOR i IN 0..1
+ LOOP
+ OPEN c(a_a + i,a_b);
+ LOOP
+ FETCH c INTO v_a, v_b;
+ EXIT WHEN c%NOTFOUND;
+ SELECT 'Fetched a record a=' || v_a || ' b=' || v_b AS msg;
+ END LOOP;
+ CLOSE c;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+CALL p1(1,'b1');
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Parameters in SELECT list + UNION
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a_a INT, a_b VARCHAR)
+AS
+ v_a INT;
+ v_b VARCHAR(10);
+ CURSOR c (p_a INT, p_b VARCHAR) IS
+ SELECT p_a,p_b FROM DUAL
+ UNION ALL
+ SELECT p_a+1,p_b||'b' FROM DUAL;
+BEGIN
+ OPEN c(a_a,a_b);
+ LOOP
+ FETCH c INTO v_a, v_b;
+ EXIT WHEN c%NOTFOUND;
+ SELECT 'Fetched a record a=' || v_a || ' b=' || v_b AS msg;
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1(1,'b1');
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Parameters in SELECT list + type conversion + warnings
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a_a VARCHAR)
+AS
+ v_a INT;
+ CURSOR c (p_a INT) IS SELECT p_a FROM DUAL;
+BEGIN
+ OPEN c(a_a);
+ LOOP
+ FETCH c INTO v_a;
+ EXIT WHEN c%NOTFOUND;
+ SELECT 'Fetched a record a=' || v_a AS msg;
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1('1b');
+CALL p1('b1');
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # One parameter in SELECT list + subselect
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a_a VARCHAR)
+AS
+ v_a VARCHAR(10);
+ CURSOR c (p_a VARCHAR) IS
+ SELECT p_a FROM DUAL UNION SELECT REVERSE(p_a) FROM DUAL;
+BEGIN
+ OPEN c((SELECT a_a));
+ LOOP
+ FETCH c INTO v_a;
+ EXIT WHEN c%NOTFOUND;
+ SELECT v_a;
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1('ab');
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Two parameters in SELECT list + subselect
+--echo #
+
+SET sql_mode=ORACLE;
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ v_a VARCHAR(10);
+ v_b VARCHAR(20);
+ CURSOR c (p_a VARCHAR, p_b VARCHAR) IS
+ SELECT p_a, p_b FROM DUAL
+ UNION
+ SELECT p_b, p_a FROM DUAL;
+BEGIN
+ OPEN c((SELECT 'aaa'),(SELECT 'bbb'));
+ LOOP
+ FETCH c INTO v_a, v_b;
+ EXIT WHEN c%NOTFOUND;
+ SELECT v_a, v_b;
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Two parameters in SELECT list + two parameters in WHERE + subselects
+--echo #
+
+SET sql_mode=ORACLE;
+DELIMITER $$;
+CREATE PROCEDURE p1(a_a VARCHAR, a_b VARCHAR)
+AS
+ v_a VARCHAR(10);
+ v_b VARCHAR(20);
+ CURSOR c (value_a VARCHAR, value_b VARCHAR,
+ pattern_a VARCHAR, pattern_b VARCHAR) IS
+ SELECT value_a, value_b FROM DUAL WHERE value_a LIKE pattern_a
+ UNION
+ SELECT value_b, value_a FROM DUAL WHERE value_b LIKE pattern_b;
+BEGIN
+ OPEN c((SELECT 'aaa'),(SELECT 'bbb'),(SELECT a_a),(SELECT a_b));
+ LOOP
+ FETCH c INTO v_a, v_b;
+ EXIT WHEN c%NOTFOUND;
+ SELECT v_a, v_b;
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1('%','%');
+CALL p1('aaa','xxx');
+CALL p1('xxx','bbb');
+CALL p1('xxx','xxx');
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Parameters in SELECT list + stored function
+--echo #
+
+DELIMITER $$;
+CREATE FUNCTION f1 (a VARCHAR) RETURN VARCHAR
+AS
+BEGIN
+ RETURN a || 'y';
+END;
+$$
+CREATE PROCEDURE p1(a_a VARCHAR)
+AS
+ v_a VARCHAR(10);
+ v_b VARCHAR(10);
+ CURSOR c (p_sel_a VARCHAR, p_cmp_a VARCHAR) IS
+ SELECT p_sel_a, p_cmp_a FROM DUAL;
+BEGIN
+ OPEN c(f1(a_a), f1(a_a));
+ LOOP
+ FETCH c INTO v_a, v_b;
+ EXIT WHEN c%NOTFOUND;
+ SELECT v_a;
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1('x');
+# A complex expression
+CALL p1(f1(COALESCE(NULL, f1('x'))));
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+
+
+--echo #
+--echo # One parameter in WHERE clause
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (1,'11');
+INSERT INTO t1 VALUES (1,'12');
+INSERT INTO t1 VALUES (2,'21');
+INSERT INTO t1 VALUES (2,'22');
+INSERT INTO t1 VALUES (3,'31');
+INSERT INTO t1 VALUES (3,'32');
+DELIMITER $$;
+CREATE PROCEDURE p1(a_a INT)
+AS
+ v_a INT;
+ v_b VARCHAR(10);
+ CURSOR c (p_a INT) IS SELECT a,b FROM t1 WHERE a=p_a;
+BEGIN
+ OPEN c(a_a);
+ LOOP
+ FETCH c INTO v_a, v_b;
+ EXIT WHEN c%NOTFOUND;
+ INSERT INTO t2 VALUES (v_a,v_b);
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1(1);
+SELECT * FROM t2;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Two parameters in WHERE clause
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (1,'11');
+INSERT INTO t1 VALUES (1,'12');
+INSERT INTO t1 VALUES (2,'21');
+INSERT INTO t1 VALUES (2,'22');
+INSERT INTO t1 VALUES (3,'31');
+INSERT INTO t1 VALUES (3,'32');
+DELIMITER $$;
+CREATE PROCEDURE p1(a_a INT, a_b VARCHAR)
+AS
+ v_a INT;
+ v_b VARCHAR(10);
+ CURSOR c (p_a INT, p_b VARCHAR) IS SELECT a,b FROM t1 WHERE a=p_a AND b=p_b;
+BEGIN
+ OPEN c(a_a, a_b);
+ LOOP
+ FETCH c INTO v_a, v_b;
+ EXIT WHEN c%NOTFOUND;
+ INSERT INTO t2 VALUES (v_a,v_b);
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1(1,'11');
+SELECT * FROM t2;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+
+--echo #
+--echo # Parameters in WHERE and HAVING clauses
+--echo #
+CREATE TABLE t1 (name VARCHAR(10), value INT);
+INSERT INTO t1 VALUES ('but',1);
+INSERT INTO t1 VALUES ('but',1);
+INSERT INTO t1 VALUES ('but',1);
+INSERT INTO t1 VALUES ('bin',1);
+INSERT INTO t1 VALUES ('bin',1);
+INSERT INTO t1 VALUES ('bot',1);
+DELIMITER $$;
+CREATE PROCEDURE p1 (arg_name_limit VARCHAR, arg_total_limit INT)
+AS
+ v_name VARCHAR(10);
+ v_total INT;
+-- +0 is needed to work around the bug MDEV-11081
+ CURSOR c(p_v INT) IS
+ SELECT name, SUM(value + p_v) + 0 AS total FROM t1
+ WHERE name LIKE arg_name_limit
+ GROUP BY name HAVING total>=arg_total_limit;
+BEGIN
+ FOR i IN 0..1
+ LOOP
+ OPEN c(i);
+ LOOP
+ FETCH c INTO v_name, v_total;
+ EXIT WHEN c%NOTFOUND;
+ SELECT v_name, v_total;
+ END LOOP;
+ CLOSE c;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+CALL p1('%', 2);
+CALL p1('b_t', 0);
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # One parameter in LIMIT clause
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (1,'b1');
+INSERT INTO t1 VALUES (2,'b2');
+INSERT INTO t1 VALUES (3,'b3');
+INSERT INTO t1 VALUES (4,'b4');
+INSERT INTO t1 VALUES (5,'b5');
+INSERT INTO t1 VALUES (6,'b6');
+DELIMITER $$;
+CREATE PROCEDURE p1(a_a INT)
+AS
+ v_a INT;
+ v_b VARCHAR(10);
+ CURSOR c (p_a INT) IS SELECT a,b FROM t1 ORDER BY a LIMIT p_a;
+BEGIN
+ CREATE TABLE t2 (a INT, b VARCHAR(10));
+ OPEN c(a_a);
+ LOOP
+ FETCH c INTO v_a, v_b;
+ EXIT WHEN c%NOTFOUND;
+ INSERT INTO t2 VALUES (v_a,v_b);
+ END LOOP;
+ CLOSE c;
+ SELECT * FROM t2;
+ DROP TABLE t2;
+END;
+$$
+DELIMITER ;$$
+CALL p1(1);
+CALL p1(3);
+CALL p1(6);
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # End of MDEV-10597 Cursors with parameters
+--echo #
+
+--echo #
+--echo # MDEV-12209 sql_mode=ORACLE: Syntax error in a OPEN cursor with parameters makes the server crash
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (1,'A');
+DELIMITER $$;
+--error ER_PARSE_ERROR
+CREATE PROCEDURE p1(a INT,b VARCHAR)
+AS
+ CURSOR c (p_a INT, p_b VARCHAR) IS SELECT * FROM t1 WHERE a=p_a;
+BEGIN
+ OPEN c(a+, b);
+ LOOP
+ FETCH c INTO a, b;
+ EXIT WHEN c%NOTFOUND;
+ SELECT a, b;
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10),c DATETIME(3));
+INSERT INTO t1 VALUES (1,'b1','2001-01-01 10:20:30.123');
+INSERT INTO t1 VALUES (2,'b2','2001-01-02 10:20:30.123');
+CREATE TABLE t2 LIKE t1;
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ v_a t1.a%TYPE;
+ v_b t1.b%TYPE;
+ v_c t1.c%TYPE;
+ CURSOR c IS SELECT a,b,c FROM t1;
+BEGIN
+ OPEN c;
+ LOOP
+ FETCH c INTO v_a, v_b, v_c;
+ EXIT WHEN c%NOTFOUND;
+ INSERT INTO t2 (a,b,c) VALUES (v_a, v_b, v_c);
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t2;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-12007 Allow ROW variables as a cursor FETCH target
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+INSERT INTO t1 VALUES (20,'b20');
+INSERT INTO t1 VALUES (30,'b30');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ rec ROW(a INT, b VARCHAR(32));
+ CURSOR c IS SELECT a,b FROM t1;
+BEGIN
+ OPEN c;
+ LOOP
+ FETCH c INTO rec;
+ EXIT WHEN c%NOTFOUND;
+ SELECT ('rec=(' || rec.a ||','|| rec.b||')') AS c;
+ END LOOP;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-12441 Variables declared after cursors with parameters lose values
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1() AS
+ x0 INT:=100;
+ CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+ x1 INT:=101;
+BEGIN
+ OPEN cur(10,11);
+ CLOSE cur;
+ SELECT x0, x1;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1() AS
+ x0 INT:=100;
+ CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+ x1 t1.a%TYPE:=101;
+BEGIN
+ OPEN cur(10,11);
+ CLOSE cur;
+ SELECT x0, x1;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1() AS
+ x0 INT:=100;
+ CURSOR cur(cp1 INT, cp2 INT) IS SELECT cp1+cp2;
+ x1 ROW(a INT,b INT):=ROW(101,102);
+BEGIN
+ OPEN cur(10,11);
+ CLOSE cur;
+ SELECT x0, x1.a, x1.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'Tbl-t1.b0');
+DELIMITER $$;
+CREATE PROCEDURE p1() AS
+ x0 INT:=100;
+ CURSOR cur(cp1 INT, cp2 INT) IS SELECT a,b FROM t1;
+ x1 t1%ROWTYPE:=ROW(101,'Var-x1.b0');
+BEGIN
+ SELECT x0, x1.a, x1.b;
+ OPEN cur(10,11);
+ FETCH cur INTO x1;
+ CLOSE cur;
+ SELECT x0, x1.a, x1.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'Tbl-t1.b0');
+DELIMITER $$;
+CREATE PROCEDURE p1() AS
+ x0 INT:=100;
+ CURSOR cur(cp1 INT, cp2 INT) IS SELECT a,b FROM t1;
+ x1 cur%ROWTYPE:=ROW(101,'Var-x1.b0');
+BEGIN
+ SELECT x0, x1.a, x1.b;
+ OPEN cur(10,11);
+ FETCH cur INTO x1;
+ CLOSE cur;
+ SELECT x0, x1.a, x1.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-12854 Synchronize CREATE..SELECT data type and result set metadata data type for INT functions
+--echo #
+
+--enable_metadata
+--disable_ps_protocol
+DELIMITER $$;
+DECLARE
+ CURSOR c IS SELECT 1 AS c FROM DUAL;
+BEGIN
+ OPEN c;
+ SELECT
+ c%ISOPEN,
+ c%NOTFOUND,
+ c%FOUND,
+ c%ROWCOUNT;
+ CLOSE c;
+END;
+$$
+DELIMITER ;$$
+--enable_ps_protocol
+--disable_metadata
diff --git a/mysql-test/suite/compat/oracle/t/sp-goto.test b/mysql-test/suite/compat/oracle/t/sp-goto.test
new file mode 100644
index 00000000000..df7f1132666
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-goto.test
@@ -0,0 +1,872 @@
+set sql_mode=oracle;
+--echo #
+--echo # MDEV-10697 sql_mode=ORACLE: GOTO statement
+--echo #
+
+--echo # matrice of tests in procedure
+--echo # |--------------------------------------------------------
+--echo # | | Same | Outside | to sub | No |
+--echo # | | block | one block | block | matching |
+--echo # | | | | | label |
+--echo # |--------------------------------------------------------
+--echo # | Forward jump | F1 | F3 | F5 | F7 |
+--echo # |--------------------------------------------------------
+--echo # | Backward jump | F2 | F4 | F6 | F8 |
+--echo # |--------------------------------------------------------
+--echo # Jump from handler to outside handling code block : F9
+--echo # Jump from handler to handling code block : F10 (forbidden)
+--echo # Jump inside handler : F21
+--echo # Jump between handler : F22 (forbidden)
+--echo # Jump from cascaded block with handler : F11
+--echo # Duplicate label in same block : F12 (forbidden)
+--echo # Duplicate label in different block : F13
+--echo # Jump outside unlabeled block : F14
+--echo # Jump inside/outside labeled block : F15
+--echo # Jump from if / else : F16
+--echo # Jump with cursors : F17
+--echo # Jump outside case : F18
+--echo # Jump inside/outside case block : F19
+--echo # Jump outside labeled loop : F20
+--echo # Jump (continue) labeled loop : F23
+--echo # Two consecutive label : P24
+--echo # Two consecutive label (backward and forward jump) : P25
+--echo # Two consecutive label, continue to wrong label : P26
+--echo # Consecutive goto label and block label : P27
+
+--echo # Test in function
+--echo # backward jump : func1
+--echo # forward jump : func2
+
+--echo # Test in trigger
+--echo # forward jump : trg1
+
+--echo #
+--echo # Forward jump in same block
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f1(p2 IN OUT VARCHAR)
+AS
+BEGIN
+ p2:='a';
+ goto lab1;
+<<lab1>>
+ goto lab2;
+ p2:='b';
+<<lab2>>
+ return ;
+END;
+$$
+
+DELIMITER ;$$
+call f1(@wp1);
+select 'f1',@wp1;
+DROP PROCEDURE f1;
+
+--echo #
+--echo # Backward jump in same block
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f2(p2 IN OUT VARCHAR)
+AS
+BEGIN
+ p2:='a';
+<<lab1>>
+ if (p2='b') then
+ return ;
+ end if;
+ p2:='b';
+ goto lab1;
+END;
+$$
+DELIMITER ;$$
+call f2(@wp1);
+select 'f2',@wp1;
+DROP PROCEDURE f2;
+
+--echo #
+--echo # Forward jump outside one block
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f3(p2 IN OUT VARCHAR)
+AS
+BEGIN
+ p2:='a';
+ if (p2='a') then
+ goto lab1;
+ end if;
+ p2:='c';
+<<lab1>>
+ return ;
+END;
+$$
+DELIMITER ;$$
+call f3(@wp1);
+select 'f3',@wp1;
+DROP PROCEDURE f3;
+
+--echo #
+--echo # Backward jump outside one block
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f4(p2 IN OUT VARCHAR)
+AS
+BEGIN
+ p2:='a';
+<<lab1>>
+ if (p2='a') then
+ p2:=p2||'b';
+ goto lab1;
+ end if;
+ if (p2='ab') then
+ p2:=p2||'c';
+ end if;
+ return ;
+END;
+$$
+DELIMITER ;$$
+call f4(@wp1);
+select 'f4',@wp1;
+DROP PROCEDURE f4;
+
+DELIMITER $$;
+--echo #
+--echo # Forward jump inside sub block
+--error ER_SP_LILABEL_MISMATCH
+CREATE or replace procedure f5(p2 IN OUT VARCHAR)
+AS
+BEGIN
+ p2:='a';
+goto lab5 ;
+ if (p2='a') then
+<<lab5>>
+ p2:=p2||'b';
+ end if;
+ return ;
+END;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--echo #
+--echo # Backward jump inside sub block
+--error ER_SP_LILABEL_MISMATCH
+CREATE or replace procedure f6(p2 IN OUT VARCHAR)
+AS
+BEGIN
+ p2:='a';
+ if (p2='a') then
+<<lab6>>
+ p2:=p2||'b';
+ return ;
+ end if;
+goto lab6 ;
+END;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--echo #
+--echo # Backward jump - missing label
+--error ER_SP_LILABEL_MISMATCH
+CREATE or replace procedure f7(p2 IN OUT VARCHAR)
+AS
+BEGIN
+<<lab>>
+ goto lab7 ;
+ return ;
+END;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--echo #
+--echo # Forward jump - missing label
+--error ER_SP_LILABEL_MISMATCH
+CREATE or replace procedure f8(p2 IN OUT VARCHAR)
+AS
+BEGIN
+ goto lab8 ;
+<<lab>>
+ return ;
+END;
+$$
+DELIMITER ;$$
+
+--echo #
+--echo # Jump from handler to procedure code
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f9(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+<<lab9>>
+ if lim=-1 then
+ res:=res||' -- goto end limit -1 --';
+ goto lab9_end;
+ end if;
+
+ begin
+ SELECT a INTO a FROM information_schema.tables LIMIT lim;
+ EXCEPTION
+ WHEN TOO_MANY_ROWS THEN
+ begin
+ res:=res||'--- too_many_rows cought ---';
+ lim:=0;
+ goto lab9;
+ end;
+ WHEN NO_DATA_FOUND THEN
+ begin
+ res:=res||'--- no_data_found cought ---';
+ lim:=-1;
+ goto lab9;
+ end;
+ end;
+ res:=res||'error';
+<<lab9_end>>
+ return ;
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL f9(2, @res);
+SELECT 'f9',@res;
+CALL f9(0, @res);
+SELECT 'f9',@res;
+DROP PROCEDURE f9;
+
+DELIMITER $$;
+--echo #
+--echo # Jump from handler to handling bloc
+--error ER_SP_LILABEL_MISMATCH
+CREATE or replace procedure f10(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ begin
+<<lab10>>
+ SELECT a INTO a FROM information_schema.tables LIMIT lim;
+ EXCEPTION
+ WHEN TOO_MANY_ROWS THEN
+ begin
+ res:='--- too_many_rows cought ---';
+ goto lab10;
+ end;
+ WHEN NO_DATA_FOUND THEN res:='--- no_data_found cought ---';
+ end;
+ return ;
+END;
+$$
+
+--echo #
+--echo # Jump from cascaded block with handler
+--echo #
+CREATE or replace procedure f11(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+<<lab11a>>
+ begin
+ SELECT a INTO a FROM information_schema.tables LIMIT lim;
+ EXCEPTION
+ WHEN TOO_MANY_ROWS THEN
+ begin
+ res:=res||'--- too_many_rows cought 1 ---';
+ goto lab11b;
+ end;
+ WHEN NO_DATA_FOUND THEN
+ begin
+ res:=res||'--- no_data_found cought 1 ---';
+ lim:=2;
+ SELECT a INTO a FROM information_schema.tables LIMIT lim;
+ EXCEPTION
+ WHEN TOO_MANY_ROWS THEN
+ begin
+ res:=res||'--- too_many_rows cought 2 ---';
+ goto lab11a;
+ end;
+ WHEN NO_DATA_FOUND THEN res:='--- no_data_found cought 2 ---';
+ end;
+ end;
+ set res:=res||' error ';
+<<lab11b>>
+ return ;
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL f11(0, @res);
+SELECT 'f11',@res;
+DROP PROCEDURE f11;
+
+DELIMITER $$;
+--echo #
+--echo # Jump inside handler
+--echo #
+CREATE or replace procedure f21(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ begin
+ SELECT a INTO a FROM information_schema.tables LIMIT lim;
+ EXCEPTION
+ WHEN TOO_MANY_ROWS THEN
+ begin
+ <<retry>>
+ lim:=lim-1;
+ loop
+ begin
+ SELECT a INTO a FROM information_schema.tables LIMIT lim;
+ EXCEPTION
+ WHEN TOO_MANY_ROWS THEN
+ begin
+ lim:=lim-1;
+ goto retry;
+ end;
+ end;
+ exit ;
+ end loop;
+ end;
+ end;
+ res:=lim;
+ return ;
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL f21(10, @res);
+SELECT 'f21',@res;
+drop procedure f21;
+
+DELIMITER $$;
+--echo #
+--echo # Jump beetween handler
+--error ER_SP_LILABEL_MISMATCH
+CREATE or replace procedure f22(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ res:='ok';
+ begin
+ SELECT a INTO a FROM information_schema.tables LIMIT lim;
+ EXCEPTION
+ WHEN TOO_MANY_ROWS THEN
+ goto nodata ;
+ WHEN NO_DATA_FOUND THEN
+ begin
+<<nodata>>
+ res:='error';
+ end;
+ end;
+ return ;
+END;
+$$
+DELIMITER ;$$
+
+
+DELIMITER $$;
+--echo #
+--echo # Duplicate label in same bloc
+--error 1309
+CREATE or replace procedure f12(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+<<lab12>>
+ res:='error';
+<<lab12>>
+ return ;
+END;
+$$
+DELIMITER ;$$
+
+--echo #
+--echo # Duplicate label in different block
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f13(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ a:=0;
+<<lab13>>
+ a:=a+1;
+ begin
+ <<lab13>>
+ a:=a+1;
+ if (a<10) then
+ goto lab13;
+ end if;
+ end;
+ res:=a;
+ if (a=10) then
+ goto lab13;
+ end if;
+ return ;
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL f13(0, @res);
+SELECT 'f13',@res;
+DROP PROCEDURE f13;
+
+
+--echo #
+--echo # Jump outside unlabeled block
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f14(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ a:=0;
+ loop
+ a:=a+1;
+ if (a<10) then
+ continue;
+ end if;
+ if (a>=lim) then
+ goto lab14;
+ end if;
+ if (a>=20) then
+ exit;
+ end if;
+ end loop;
+<<lab14>>
+ res:=a;
+ return ;
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL f14(15, @res);
+SELECT 'f14',@res;
+CALL f14(8, @res);
+SELECT 'f14',@res;
+CALL f14(25, @res);
+SELECT 'f14',@res;
+DROP PROCEDURE f14;
+
+--echo #
+--echo # Jump inside/outside labeled block
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f15(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ a:=0;
+ <<looplabel>> loop
+ <<beginlooplabel>>
+ a:=a+1;
+ if (a<10) then
+ continue looplabel;
+ end if;
+ if (a>=lim) then
+ goto lab15;
+ end if;
+ if (a>=20) then
+ exit looplabel;
+ end if;
+ goto beginlooplabel;
+ end loop;
+<<lab15>>
+ res:=a;
+ return ;
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL f15(15, @res);
+SELECT 'f15',@res;
+CALL f15(8, @res);
+SELECT 'f15',@res;
+CALL f15(25, @res);
+SELECT 'f15',@res;
+DROP PROCEDURE f15;
+
+--echo #
+--echo # Jump from if / else
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f16(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ if (lim<10) then
+ goto lab16_1;
+ else
+ goto lab16_2;
+ end if;
+<<lab16_1>>
+ res:='if lab16_1';
+ goto lab16_3;
+<<lab16_2>>
+ res:='else lab16_2';
+ goto lab16_3;
+ res:='error lab16_3';
+<<lab16_3>>
+ return ;
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL f16(15, @res);
+SELECT 'f16',@res;
+CALL f16(8, @res);
+SELECT 'f16',@res;
+DROP PROCEDURE f16;
+
+--echo #
+--echo # Jump with cursors
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f17(lim INT, res OUT VARCHAR)
+AS
+ v_a INT;
+ v_b VARCHAR(10);
+ CURSOR cur1 IS SELECT 1 FROM dual where 1=2;
+BEGIN
+ OPEN cur1;
+ LOOP
+ FETCH cur1 INTO v_a;
+ EXIT WHEN cur1%NOTFOUND;
+ END LOOP;
+ CLOSE cur1;
+ <<lab17>>
+ lim:=lim-1;
+ begin
+ declare
+ CURSOR cur1 IS SELECT 1 FROM dual;
+ CURSOR cur2 IS SELECT 1 FROM dual where 1=2;
+ begin
+ LOOP
+ OPEN cur1;
+ FETCH cur1 INTO v_a;
+ EXIT WHEN cur1%NOTFOUND;
+ res:=res||'-'||lim ;
+ close cur1;
+ if (lim>0) then
+ goto lab17;
+ else
+ goto lab17_end;
+ end if;
+ END LOOP;
+ end;
+ <<lab17_end>>
+ null;
+ end;
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL f17(5, @res);
+SELECT 'f17',@res;
+DROP PROCEDURE f17;
+
+--echo #
+--echo # Jump outside case
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f18(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ case lim
+ when 1 then
+ res:='case branch 18_1';
+ goto lab18_1;
+ res:='error';
+ when 2 then
+ res:='case branch 18_2';
+ goto lab18_2;
+ res:='error';
+ else
+ res:='default branch 18';
+ end case;
+<<lab18_1>>
+ null;
+<<lab18_2>>
+ return ;
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL f18(0, @res);
+SELECT 'f18',@res;
+CALL f18(1, @res);
+SELECT 'f18',@res;
+CALL f18(2, @res);
+SELECT 'f18',@res;
+DROP PROCEDURE f18;
+
+--echo #
+--echo # Jump inside/outside case block
+--echo #
+DELIMITER $$;
+CREATE or replace procedure f19(lim INT, res OUT VARCHAR)
+AS
+ a INT;
+BEGIN
+ a:=1;
+ case lim
+ when 1 then
+<<lab19_0>>
+ a:=a+1;
+ if (a<10) then
+ goto lab19_0;
+ else
+ goto lab19_1;
+ end if;
+ res:='case branch 19_1';
+ else
+ res:='default branch 18';
+ end case;
+ goto lab19_end;
+<<lab19_1>>
+ res:=a;
+<<lab19_end>>
+ return ;
+END;
+$$
+DELIMITER ;$$
+SET @res='';
+CALL f19(1, @res);
+SELECT 'f19',@res;
+DROP PROCEDURE f19;
+
+DELIMITER $$;
+--echo #
+--echo # Jump outside labeled loop
+--echo #
+CREATE OR REPLACE PROCEDURE f20(res OUT VARCHAR)
+AS
+ a INT := 1;
+BEGIN
+ <<lab>>
+ FOR i IN a..10 LOOP
+ IF i = 5 THEN
+ a:= a+1;
+ goto lab;
+ END IF;
+ END LOOP;
+ res:=a;
+END;
+$$
+DELIMITER ;$$
+CALL f20(@res);
+SELECT 'f20',@res;
+DROP PROCEDURE f20;
+
+DELIMITER $$;
+--echo #
+--echo # Jump (continue) labeled loop
+--echo #
+CREATE OR REPLACE PROCEDURE f23(res OUT VARCHAR)
+AS
+ a INT := 1;
+BEGIN
+ <<lab>>
+ FOR i IN a..10 LOOP
+ IF i = 5 THEN
+ a:= a+1;
+ continue lab;
+ END IF;
+ END LOOP;
+ res:=a;
+END;
+$$
+DELIMITER ;$$
+CALL f23(@res);
+SELECT 'f23',@res;
+DROP PROCEDURE f23;
+
+DELIMITER $$;
+--echo #
+--echo # Two consecutive label (backward jump)
+--echo #
+CREATE OR REPLACE PROCEDURE p24(action IN INT, res OUT varchar) AS
+ a integer;
+BEGIN
+ <<lab1>>
+ <<lab2>>
+ if (action = 1) then
+ res:=res||' '||action;
+ action:=2;
+ goto lab1;
+ end if;
+ if (action = 2) then
+ res:=res||' '||action;
+ action:=3;
+ goto lab2;
+ end if;
+END;
+$$
+DELIMITER ;$$
+call p24(1,@res);
+select 'p24',@res;
+DROP PROCEDURE p24;
+
+DELIMITER $$;
+--echo #
+--echo # Two consecutive label (backward and forward jump)
+--echo #
+CREATE OR REPLACE PROCEDURE p25(action IN INT, res OUT varchar) AS
+ a integer;
+BEGIN
+ if (action = 1) then
+ res:=res||' '||action;
+ action:=2;
+ goto lab2;
+ end if;
+ goto lab_end;
+ <<lab1>>
+ <<lab2>>
+ res:=res||' '||action;
+ if (action = 2) then
+ res:=res||' '||action;
+ action:=3;
+ goto lab1;
+ end if;
+<<lab_end>>
+ null;
+END;
+$$
+DELIMITER ;$$
+call p25(1,@res);
+select 'p25',@res;
+DROP PROCEDURE p25;
+
+
+DELIMITER $$;
+--echo #
+--echo # Two consecutive label, continue to wrong label
+--error ER_SP_LILABEL_MISMATCH
+CREATE OR REPLACE PROCEDURE p26(action IN INT, res OUT varchar) AS
+BEGIN
+ <<lab1>>
+ <<lab2>>
+ FOR i IN 1..10 LOOP
+ continue lab1;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--echo #
+--echo # Consecutive goto label and block label
+--echo #
+CREATE OR REPLACE PROCEDURE p27(action IN INT, res OUT varchar) AS
+BEGIN
+ res:='';
+ <<lab1>>
+ <<lab2>>
+ FOR i IN 1..10 LOOP
+ if (action = 1) then
+ res:=res||' '||action||'-'||i;
+ action:=2;
+ continue lab2;
+ end if;
+ if (action = 2) then
+ res:=res||' '||action||'-'||i;
+ action:='3';
+ goto lab2;
+ end if;
+ if (action = 3) then
+ res:=res||' '||action||'-'||i;
+ action:='4';
+ goto lab1;
+ end if;
+ if (action = 4) then
+ res:=res||' '||action||'-'||i;
+ exit lab2;
+ end if;
+ END LOOP;
+END;
+$$
+
+DELIMITER ;$$
+call p27(1,@res);
+select 'p27',@res;
+DROP PROCEDURE p27;
+
+--echo # ----------------------
+--echo # -- TEST IN FUNCTION --
+--echo # ----------------------
+
+--echo #
+--echo # FUNCTION : Backward jump
+--echo #
+DELIMITER $$;
+CREATE or replace function func1()
+return varchar
+AS
+ p2 varchar(10);
+BEGIN
+ p2:='a';
+<<lab1>>
+ if (p2='a') then
+ p2:=p2||'b';
+ goto lab1;
+ end if;
+ if (p2='ab') then
+ p2:=p2||'c';
+ end if;
+ return p2;
+END;
+$$
+DELIMITER ;$$
+select 'func1',func1();
+DROP function func1;
+
+--echo #
+--echo # FUNCTION : forward jump
+--echo #
+DELIMITER $$;
+CREATE or replace function func2()
+return varchar
+AS
+ p2 varchar(10);
+BEGIN
+ p2:='a';
+ if (p2='a') then
+ goto lab1;
+ end if;
+ p2:='b';
+<<lab1>>
+ return p2;
+END;
+$$
+DELIMITER ;$$
+select 'func2',func2();
+DROP function func2;
+
+--echo # ---------------------
+--echo # -- TEST IN TRIGGER --
+--echo # ---------------------
+
+--echo #
+--echo # TRIGGER : forward jump
+--echo #
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+ IF :NEW.a IS NULL
+ THEN
+ :NEW.a:= 15;
+ goto end_trg;
+ END IF;
+ :NEW.a:= 10;
+<<end_trg>>
+ null;
+END;
+$$
+DELIMITER ;$$
+insert into t1 values (1);
+insert into t1 values (null);
+SELECT * FROM t1;
+DROP TRIGGER trg1;
+DROP TABLE t1; \ No newline at end of file
diff --git a/mysql-test/suite/compat/oracle/t/sp-param.inc b/mysql-test/suite/compat/oracle/t/sp-param.inc
new file mode 100644
index 00000000000..35bce8accea
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-param.inc
@@ -0,0 +1,9 @@
+--eval CREATE FUNCTION f1(param $type) RETURN $type AS BEGIN RETURN param; END;
+SHOW CREATE FUNCTION f1;
+
+--eval SELECT LENGTH(f1(REPEAT('a',$length)));
+--eval CREATE TABLE t1 AS SELECT f1(REPEAT('a',$length)) AS a;
+
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+DROP FUNCTION f1;
diff --git a/mysql-test/suite/compat/oracle/t/sp-param.test b/mysql-test/suite/compat/oracle/t/sp-param.test
new file mode 100644
index 00000000000..23203317f50
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-param.test
@@ -0,0 +1,37 @@
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-10596 Allow VARCHAR and VARCHAR2 without length as a data type of routine parameters and in RETURN clause
+--echo #
+
+--let type = CHAR
+--let length = 2000
+--source sp-param.inc
+
+--let type = NCHAR
+--let length = 2000
+--source sp-param.inc
+
+--let type = BINARY
+--let length = 2000
+--source sp-param.inc
+
+--let type = VARCHAR
+--let length = 4000
+--source sp-param.inc
+
+--let type = VARCHAR2
+--let length = 4000
+--source sp-param.inc
+
+--let type = NVARCHAR
+--let length = 4000
+--source sp-param.inc
+
+--let type = VARBINARY
+--let length = 4000
+--source sp-param.inc
+
+--let type = RAW
+--let length = 4000
+--source sp-param.inc
diff --git a/mysql-test/suite/compat/oracle/t/sp-row-vs-var.inc b/mysql-test/suite/compat/oracle/t/sp-row-vs-var.inc
new file mode 100644
index 00000000000..14f6f7dfd44
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-row-vs-var.inc
@@ -0,0 +1,6 @@
+--let $query= CREATE PROCEDURE p1() AS var $type; rec ROW(var $type); BEGIN CREATE TABLE t1 AS SELECT var,rec.var FROM DUAL;END
+--eval $query
+CALL p1();
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
diff --git a/mysql-test/suite/compat/oracle/t/sp-row.test b/mysql-test/suite/compat/oracle/t/sp-row.test
new file mode 100644
index 00000000000..5d97bf02fa2
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-row.test
@@ -0,0 +1,2377 @@
+SET sql_mode=ORACLE;
+
+
+--echo #
+--echo # MDEV-10914 ROW data type for stored routine variables
+--echo #
+
+
+
+--echo #
+--echo # ROW of ROWs is not supported yet
+--echo #
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+CREATE PROCEDURE p1()
+AS
+ a ROW(a ROW(a INT));
+BEGIN
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # Returning the entire ROW parameter from a function
+--echo #
+# TODO: this should probably return an error at compile time
+DELIMITER $$;
+CREATE FUNCTION f1(a ROW(a INT, b INT)) RETURN INT
+AS
+BEGIN
+ RETURN a;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+SELECT f1(ROW(10,20));
+DROP FUNCTION f1;
+
+
+
+--echo #
+--echo # ROW as an SP parameter
+--echo #
+
+DELIMITER $$;
+CREATE FUNCTION f1(a ROW(a INT,b INT)) RETURN INT
+AS
+BEGIN
+ RETURN a.b;
+END;
+$$
+CREATE PROCEDURE p1()
+AS
+ a ROW(a INT,b INT):=(11,21);
+BEGIN
+ SELECT f1(a);
+END;
+$$
+DELIMITER ;$$
+SELECT f1(ROW(10,20));
+--error ER_OPERAND_COLUMNS
+SELECT f1(10);
+--error ER_OPERAND_COLUMNS
+SELECT f1(ROW(10,20,30));
+CALL p1();
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a ROW(a INT,b INT))
+AS
+BEGIN
+ SELECT a.a, a.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1(ROW(10,20));
+--error ER_OPERAND_COLUMNS
+CALL p1(10);
+--error ER_OPERAND_COLUMNS
+CALL p1(ROW(10,20,30));
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # ROW as an SP OUT parameter
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a OUT ROW(a INT,b INT))
+AS
+BEGIN
+ a.a:=10;
+ a.b:=20;
+END;
+$$
+CREATE PROCEDURE p2
+AS
+ a ROW(a INT,b INT):=(11,21);
+BEGIN
+ CALL p1(a);
+ SELECT a.a,a.b;
+END;
+$$
+DELIMITER ;$$
+CALL p2();
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # ROW as an SP return value is not supported yet
+--echo #
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+CREATE FUNCTION p1() RETURN ROW(a INT)
+AS
+BEGIN
+ RETURN NULL;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # Diplicate row field
+--echo #
+DELIMITER $$;
+--error ER_DUP_FIELDNAME
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT, a DOUBLE);
+BEGIN
+ SELECT a.a;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # Bad scalar default value
+--echo #
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT, b DOUBLE):= 1;
+BEGIN
+ SELECT a.a;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+--echo #
+--echo # Bad ROW default value with a wrong number of fields
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT, b DOUBLE):= ROW(1,2,3);
+BEGIN
+ SELECT a.a;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Scalar variable vs table alias cause no ambiguity
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a INT;
+BEGIN
+ -- a.x is a table column here (not a row variable field)
+ SELECT a.x FROM a;
+ SELECT a.x FROM t1 a;
+END;
+$$
+DELIMITER ;$$
+DROP PROCEDURE p1;
+
+--echo #
+--echo # Using the entire ROW variable in select list
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT);
+BEGIN
+ SELECT a;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT,b INT);
+BEGIN
+ SELECT a;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Using the entire ROW variable in functions
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT);
+BEGIN
+ SELECT COALESCE(a);
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT,b INT);
+BEGIN
+ SELECT COALESCE(a);
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT);
+BEGIN
+ SELECT a+1;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT,b INT);
+BEGIN
+ SELECT a+1;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Comparing the entire ROW to a scalar value
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT,b INT);
+BEGIN
+ SELECT a=1;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT,b INT);
+BEGIN
+ SELECT 1=a;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Passing the entire ROW to a stored function
+--echo #
+
+DELIMITER $$;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+BEGIN
+ RETURN a;
+END;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT,b INT);
+BEGIN
+ SELECT f1(a);
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+
+
+DELIMITER $$;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+BEGIN
+ RETURN a;
+END;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT);
+BEGIN
+ SELECT f1(a);
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+
+
+--echo #
+--echo # Assigning a scalar value to a ROW variable with 1 column
+--echo #
+
+DELIMITER $$;
+CREATE OR REPLACE PROCEDURE p1
+AS
+ rec ROW(a INT);
+BEGIN
+ rec:=1;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning a scalar value to a ROW variable with 2 columns
+--echo #
+
+DELIMITER $$;
+CREATE OR REPLACE PROCEDURE p1
+AS
+ rec ROW(a INT,b INT);
+BEGIN
+ rec:=1;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning a ROW value to a ROW variable with different number of columns
+--echo #
+
+DELIMITER $$;
+CREATE OR REPLACE PROCEDURE p1
+AS
+ rec ROW(a INT,b INT);
+BEGIN
+ rec:=ROW(1,2,3);
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+--echo #
+--echo # Returning the entire ROW from a function is not supported yet
+--echo # This syntax would be needed: SELECT f1().x FROM DUAL;
+--echo #
+DELIMITER $$;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ rec ROW(a INT);
+BEGIN
+ RETURN rec;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+SELECT f1(10);
+DROP FUNCTION f1;
+
+
+--echo #
+--echo # Using the entire ROW in SELECT..CREATE
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec ROW(a INT,b INT);
+BEGIN
+ CREATE TABLE t1 AS SELECT rec;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Using the entire ROW in LIMIT
+--echo #
+DELIMITER $$;
+--error ER_WRONG_SPVAR_TYPE_IN_LIMIT
+CREATE PROCEDURE p1()
+AS
+ rec ROW(a INT);
+BEGIN
+ rec.a:= '10';
+ SELECT * FROM t1 LIMIT rec;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # Setting ROW fields using a SET command
+--echo #
+DELIMITER $$;
+CREATE OR REPLACE PROCEDURE p1
+AS
+ rec ROW(a INT,b DOUBLE,c VARCHAR(10));
+ a INT;
+BEGIN
+ SET @a= 10, rec.a=10, rec.b=20, rec.c= 'test', a= 5;
+ SELECT rec.a, rec.b, rec.c, a;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning a ROW variable from a ROW value
+--echo #
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec ROW(a INT,b INT);
+BEGIN
+ rec:=ROW(1,2);
+ SELECT rec.a, rec.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning a ROW variable from another ROW value
+--echo #
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec1 ROW(a INT,b INT);
+ rec2 ROW(a INT,b INT);
+BEGIN
+ rec1:=ROW(1,2);
+ rec2:=rec1;
+ SELECT rec2.a, rec2.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Comparing a ROW variable to a ROW() function
+--echo #
+
+DELIMITER $$;
+CREATE OR REPLACE PROCEDURE p1
+AS
+ rec ROW(a INT,b INT);
+BEGIN
+ rec.a:= 1;
+ rec.b:= 2;
+ SELECT rec=(0,0), rec=ROW(0,0), (0,0)=rec, ROW(0,0)=rec;
+ SELECT rec=(1,2), rec=ROW(1,2), (1,2)=rec, ROW(1,2)=rec;
+ SELECT rec=(NULL,0), rec=ROW(NULL,0);
+ SELECT rec=(NULL,2), rec=ROW(NULL,2);
+ SELECT rec<>(0,0), rec<>ROW(0,0);
+ SELECT rec<>(1,2), rec<>ROW(1,2);
+ SELECT rec<>(NULL,0), rec<>ROW(NULL,0);
+ SELECT rec<>(NULL,2), rec<>ROW(NULL,2);
+ SELECT rec IN ((0,0)), rec IN (ROW(0,0));
+ SELECT rec IN ((1,2)), rec IN (ROW(1,2));
+ SELECT rec IN ((0,NULL),(1,2));
+ SELECT rec NOT IN ((0,NULL),(1,1));
+ SELECT rec NOT IN ((1,NULL),(1,1));
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Comparing a ROW variable to another ROW variable
+--echo #
+
+DELIMITER $$;
+CREATE OR REPLACE PROCEDURE p1
+AS
+ rec1,rec2,rec3 ROW(a INT,b INT);
+BEGIN
+ rec1.a:= 1;
+ rec1.b:= 2;
+ rec2.a:= 11;
+ rec2.b:= 12;
+ rec3.a:= 11;
+ rec3.b:= 12;
+ SELECT rec1=rec2, rec2=rec1, rec2=rec3, rec3=rec2;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Referencing a non-existing row variable
+--echo #
+DELIMITER $$;
+--error ER_UNKNOWN_STRUCTURED_VARIABLE
+CREATE PROCEDURE p1()
+AS
+BEGIN
+ SET a.b=1;
+END;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--error ER_UNKNOWN_STRUCTURED_VARIABLE
+CREATE PROCEDURE p1()
+AS
+BEGIN
+ a.b:=1;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # Referencing a non-existing row field
+--echo #
+DELIMITER $$;
+--error ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD
+CREATE PROCEDURE p1()
+AS
+ a ROW(a INT,b INT);
+BEGIN
+ SELECT a.c FROM t1;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # ROW and scalar variables with the same name shadowing each other
+--echo #
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW(a INT);
+BEGIN
+ a.a:=100;
+ DECLARE
+ a INT:= 200;
+ BEGIN
+ SELECT a;
+ DECLARE
+ a ROW(a INT);
+ BEGIN
+ a.a:=300;
+ SELECT a.a;
+ END;
+ SELECT a;
+ END;
+ SELECT a.a;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # ROW with good default values
+--echo #
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW(a INT,b INT):= (10,20);
+ b ROW(a INT,b INT):= (11,21);
+ c ROW(a INT,b INT):= a;
+BEGIN
+ SELECT a.a, a.b, b.a, b.b, c.a, c.b FROM DUAL;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # ROW in WHERE clause
+--echo #
+
+CREATE TABLE t1 (a INT,b INT);
+INSERT INTO t1 VALUES (10,20);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec ROW(a INT,b INT):=ROW(10,20);
+BEGIN
+ SELECT * FROM t1 WHERE rec=ROW(a,b);
+ SELECT * FROM t1 WHERE ROW(a,b)=rec;
+ SELECT * FROM t1 WHERE rec=ROW(10,20);
+ SELECT * FROM t1 WHERE ROW(10,20)=rec;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # ROW fields in WHERE clause
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec ROW(a INT);
+BEGIN
+ rec.a:= 10;
+ SELECT * FROM t1 WHERE a=rec.a;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # ROW fields in HAVING clause
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec ROW(a INT);
+BEGIN
+ rec.a:= 10;
+ SELECT * FROM t1 HAVING a=rec.a;
+ SELECT * FROM t1 HAVING MIN(a)=rec.a;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # ROW fields in LIMIT clause
+--echo #
+
+CREATE TABLE t1 (a INT);
+--error ER_SP_UNDECLARED_VAR
+SELECT 1 FROM t1 LIMIT t1.a;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec ROW(a INT);
+BEGIN
+ rec.a:= 10;
+ SELECT * FROM t1 LIMIT rec.a;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+--error ER_WRONG_SPVAR_TYPE_IN_LIMIT
+CREATE PROCEDURE p1()
+AS
+ rec ROW(a VARCHAR(10));
+BEGIN
+ rec.a:= '10';
+ SELECT * FROM t1 LIMIT rec.a;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # ROW fields in select list
+--echo #
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ t1 ROW(a INT);
+BEGIN
+ t1.a:= 10;
+ SELECT t1.a, 'This is the variable t1.a value, rather than the column t1.a' AS comm FROM t1;
+ SELECT t1.a, t2.a, t1.a+t2.a FROM t1 t2;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # ROW fields as insert values
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec ROW(a INT, b VARCHAR(10));
+BEGIN
+ rec.a:= 10;
+ rec.b:= 'test';
+ INSERT INTO t1 VALUES (rec.a, rec.b);
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # ROW fields as SP out parameters
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a OUT INT, b OUT VARCHAR)
+AS
+BEGIN
+ a:= 10;
+ b:= 'test';
+END;
+$$
+CREATE PROCEDURE p2
+AS
+ rec ROW(a INT, b VARCHAR(10));
+BEGIN
+ CALL p1(rec.a, rec.b);
+ SELECT rec.a, rec.b;
+END;
+$$
+DELIMITER ;$$
+CALL p2;
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+
+
+--echo #
+--echo # ROW fields as dynamic SQL out parameters
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a OUT INT, b OUT VARCHAR)
+AS
+BEGIN
+ a:= 20;
+ b:= 'test-dynamic-sql';
+END;
+$$
+CREATE PROCEDURE p2
+AS
+ rec ROW(a INT, b VARCHAR(30));
+BEGIN
+ EXECUTE IMMEDIATE 'CALL p1(?,?)' USING rec.a, rec.b;
+ SELECT rec.a, rec.b;
+END;
+$$
+DELIMITER ;$$
+CALL p2;
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+
+
+--echo #
+--echo # ROW fields as SELECT..INTO targets
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec ROW(a INT, b VARCHAR(10));
+BEGIN
+ SELECT 10,'test' INTO rec.a,rec.b;
+ SELECT rec.a, rec.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Implicit default NULL handling
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec ROW(a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,0), e TIME, f DATETIME);
+BEGIN
+ SELECT rec.a, rec.b, rec.c, rec.d, rec.e, rec.f FROM DUAL;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # NULL handling
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec1 ROW(a INT, b VARCHAR(10)):=(NULL,NULL);
+ rec2 ROW(a INT, b VARCHAR(10)):=rec1;
+BEGIN
+ SELECT rec1.a, rec1.b, rec2.a, rec2.b;
+
+ rec1:= (10,20);
+ rec2:= rec1;
+ SELECT rec1.a, rec1.b, rec2.a, rec2.b;
+
+ rec1:= (NULL,20);
+ rec2:= rec1;
+ SELECT rec1.a, rec1.b, rec2.a, rec2.b;
+
+ rec1:= (10,NULL);
+ rec2:= rec1;
+ SELECT rec1.a, rec1.b, rec2.a, rec2.b;
+
+ rec1:= (NULL,NULL);
+ rec2:= rec1;
+ SELECT rec1.a, rec1.b, rec2.a, rec2.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Testing multiple ROW variable declarations
+--echo # This makes sure that fill_field_definitions() is called only once
+--echo # per a ROW field, so create length is not converted to internal length
+--echo # multiple times.
+--echo #
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec1, rec2, rec3 ROW(a VARCHAR(10) CHARACTER SET utf8);
+BEGIN
+ CREATE TABLE t1 AS SELECT rec1.a, rec2.a, rec3.a;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+--echo #
+--echo # INT
+--echo #
+
+--let type=INT
+--source sp-row-vs-var.inc
+
+--let type=INT(1)
+--source sp-row-vs-var.inc
+
+--let type=INT(2)
+--source sp-row-vs-var.inc
+
+--let type=INT(3)
+--source sp-row-vs-var.inc
+
+--let type=INT(4)
+--source sp-row-vs-var.inc
+
+--let type=INT(5)
+--source sp-row-vs-var.inc
+
+--let type=INT(6)
+--source sp-row-vs-var.inc
+
+--let type=INT(7)
+--source sp-row-vs-var.inc
+
+--let type=INT(8)
+--source sp-row-vs-var.inc
+
+--let type=INT(9)
+--source sp-row-vs-var.inc
+
+--let type=INT(10)
+--source sp-row-vs-var.inc
+
+--let type=INT(11)
+--source sp-row-vs-var.inc
+
+--let type=INT(12)
+--source sp-row-vs-var.inc
+
+--let type=INT(13)
+--source sp-row-vs-var.inc
+
+--let type=INT(14)
+--source sp-row-vs-var.inc
+
+--let type=INT(20)
+--source sp-row-vs-var.inc
+
+--let type=INT(21)
+--source sp-row-vs-var.inc
+
+
+--echo #
+--echo # TINYINT
+--echo #
+
+--let type=TINYINT
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(1)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(2)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(3)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(4)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(5)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(6)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(7)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(8)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(9)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(10)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(11)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(12)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(13)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(14)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(20)
+--source sp-row-vs-var.inc
+
+--let type=TINYINT(21)
+--source sp-row-vs-var.inc
+
+--echo #
+--echo # SMALLINT
+--echo #
+
+--let type=SMALLINT
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(1)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(2)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(3)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(4)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(5)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(6)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(7)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(8)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(9)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(10)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(11)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(12)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(13)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(14)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(20)
+--source sp-row-vs-var.inc
+
+--let type=SMALLINT(21)
+--source sp-row-vs-var.inc
+
+
+--echo #
+--echo # MEDIUMINT
+--echo #
+
+--let type=MEDIUMINT
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(1)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(2)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(3)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(4)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(5)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(6)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(7)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(8)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(9)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(10)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(11)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(12)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(13)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(14)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(20)
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMINT(21)
+--source sp-row-vs-var.inc
+
+
+--echo #
+--echo # BIGINT
+--echo #
+
+--let type=BIGINT
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(1)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(2)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(3)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(4)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(5)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(6)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(7)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(8)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(9)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(10)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(11)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(12)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(13)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(14)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(20)
+--source sp-row-vs-var.inc
+
+--let type=BIGINT(21)
+--source sp-row-vs-var.inc
+
+
+--echo #
+--echo # DOUBLE
+--echo #
+
+--let type=DOUBLE
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,1)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,2)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,3)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,4)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,5)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,6)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,7)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,8)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,9)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,10)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,11)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,12)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,13)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,14)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,20)
+--source sp-row-vs-var.inc
+
+--let type=DOUBLE(30,21)
+--source sp-row-vs-var.inc
+
+--echo #
+--echo # VARCHAR
+--echo #
+
+--let type=CHAR
+--source sp-row-vs-var.inc
+
+--let type=BINARY
+--source sp-row-vs-var.inc
+
+--let type=CHAR(1)
+--source sp-row-vs-var.inc
+
+--let type=CHAR(10)
+--source sp-row-vs-var.inc
+
+--let type=NCHAR(10)
+--source sp-row-vs-var.inc
+
+--let type=BINARY(10)
+--source sp-row-vs-var.inc
+
+--let type=VARBINARY(10)
+--source sp-row-vs-var.inc
+
+--let type=VARCHAR(10)
+--source sp-row-vs-var.inc
+
+--let type=VARCHAR(10) CHARACTER SET utf8
+--source sp-row-vs-var.inc
+
+--let type=VARCHAR(10) CHARACTER SET utf8 COLLATE utf8_bin
+--source sp-row-vs-var.inc
+
+--echo #
+--echo # TIME
+--echo #
+
+--let type=TIME
+--source sp-row-vs-var.inc
+
+--let type=TIME(1)
+--source sp-row-vs-var.inc
+
+--let type=TIME(2)
+--source sp-row-vs-var.inc
+
+--let type=TIME(3)
+--source sp-row-vs-var.inc
+
+--let type=TIME(4)
+--source sp-row-vs-var.inc
+
+--let type=TIME(5)
+--source sp-row-vs-var.inc
+
+--let type=TIME(6)
+--source sp-row-vs-var.inc
+
+--echo #
+--echo # DATETIME
+--echo #
+
+--let type=DATETIME
+--source sp-row-vs-var.inc
+
+--let type=DATETIME(1)
+--source sp-row-vs-var.inc
+
+--let type=DATETIME(2)
+--source sp-row-vs-var.inc
+
+--let type=DATETIME(3)
+--source sp-row-vs-var.inc
+
+--let type=DATETIME(4)
+--source sp-row-vs-var.inc
+
+--let type=DATETIME(5)
+--source sp-row-vs-var.inc
+
+--let type=DATETIME(6)
+--source sp-row-vs-var.inc
+
+
+--echo #
+--echo # LOB
+--echo #
+
+--let type=TEXT
+--source sp-row-vs-var.inc
+
+--let type=TINYTEXT
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMTEXT
+--source sp-row-vs-var.inc
+
+--let type=LONGTEXT
+--source sp-row-vs-var.inc
+
+--let type=TEXT CHARACTER SET utf8
+--source sp-row-vs-var.inc
+
+--let type=TINYTEXT CHARACTER SET utf8
+--source sp-row-vs-var.inc
+
+--let type=MEDIUMTEXT CHARACTER SET utf8
+--source sp-row-vs-var.inc
+
+--let type=LONGTEXT CHARACTER SET utf8
+--source sp-row-vs-var.inc
+
+
+--echo #
+--echo # End of MDEV-10914 ROW data type for stored routine variables
+--echo #
+
+
+--echo #
+--echo # MDEV-12133 sql_mode=ORACLE: table%ROWTYPE in variable declarations
+--echo #
+
+--echo #
+--echo # Referring to a table in a non-existing database
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec test2.t1%ROWTYPE;
+BEGIN
+ NULL;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1();
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+--error ER_NO_SUCH_TABLE
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Referring to a table in the current database
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec t1%ROWTYPE;
+BEGIN
+ CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1();
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Referring to a table in an explicitly specified database
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec test.t1%ROWTYPE;
+BEGIN
+ CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1();
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Referring to a view in the current database
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec v1%ROWTYPE;
+BEGIN
+ CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1();
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CREATE VIEW v1 AS SELECT * FROM t1;
+CALL p1();
+DROP VIEW v1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Referring to a view in an explicitly specified database
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec test.v1%ROWTYPE;
+BEGIN
+ CREATE TABLE t2 AS SELECT rec.a, rec.b, rec.c, rec.d;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1();
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10));
+CREATE VIEW v1 AS SELECT * FROM t1;
+CALL p1();
+DROP VIEW v1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Checking that all table%ROWTYPE fields are NULL by default
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE;
+BEGIN
+ SELECT rec1.a, rec1.b, rec1.c, rec1.d;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # A table%ROWTYPE variable with a ROW expression as a default
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE DEFAULT ROW(10,'bbb');
+BEGIN
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # A table%ROWTYPE variable with an incompatible ROW expression as a default
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE DEFAULT ROW(10,'bbb','ccc');
+BEGIN
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # A table%ROWTYPE variable with a ROW variable as a default
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 ROW(a INT, b VARCHAR(10)):= ROW(10,'bbb');
+ rec2 t1%ROWTYPE DEFAULT rec1;
+BEGIN
+ SELECT rec2.a, rec2.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # A ROW variable using a table%ROWTYPE variable as a default
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE := ROW(10,'bbb');
+ rec2 ROW(a INT, b VARCHAR(10)):= rec1;
+BEGIN
+ SELECT rec2.a, rec2.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning table%ROWTYPE variables with a different column count
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE);
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE;
+ rec2 t2%ROWTYPE;
+BEGIN
+ rec2:=rec1;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP PROCEDURE p1;
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE;
+ rec2 t2%ROWTYPE;
+BEGIN
+ rec1:=rec2;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning compatible table%ROWTYPE variables (equal number of fields)
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (x INT, y VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE;
+ rec2 t2%ROWTYPE;
+BEGIN
+ rec1.a:= 10;
+ rec1.b:= 'bbb';
+ rec2:=rec1;
+ SELECT rec2.x, rec2.y;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning between incompatible table%ROWTYPE and explicit ROW variables
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE;
+ rec2 ROW(x INT,y INT,z INT);
+BEGIN
+ rec2.x:= 10;
+ rec2.y:= 20;
+ rec2.z:= 30;
+ rec1:= rec2;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning between compatible table%ROWTYPE and explicit ROW variables
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE;
+ rec2 ROW(x INT,y INT);
+BEGIN
+ rec2.x:= 10;
+ rec2.y:= 20;
+ rec1:= rec2;
+ SELECT rec1.a, rec1.b;
+ rec1.a:= 11;
+ rec1.b:= 21;
+ rec2:= rec1;
+ SELECT rec2.x, rec2.y;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Assigning table%ROWTYPE from a ROW expression
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE;
+BEGIN
+ rec1:= ROW(10,20);
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Fetching a cursor into a table%ROWTYPE variable with a wrong field count
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE TABLE t2 (a INT, b VARCHAR(10));
+INSERT INTO t1 VALUES (10,'bb1',111.111e2, 12.31);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec2 t2%ROWTYPE;
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ OPEN cur1;
+ FETCH cur1 INTO rec2;
+ CLOSE cur1;
+END;
+$$
+DELIMITER ;$$
+--error ER_SP_WRONG_NO_OF_FETCH_ARGS
+CALL p1();
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Fetching a cursor into a table%ROWTYPE variable
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10), c DOUBLE, d DECIMAL(10,2));
+CREATE TABLE t2 LIKE t1;
+INSERT INTO t1 VALUES (10,'bb1',111.111e2, 12.31);
+INSERT INTO t1 VALUES (20,'bb2',222.222e2, 12.32);
+INSERT INTO t1 VALUES (30,'bb3',333.333e2, 12.33);
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec t1%ROWTYPE;
+ CURSOR cur IS SELECT * FROM t1;
+BEGIN
+ OPEN cur;
+ LOOP
+ FETCH cur INTO rec;
+ EXIT WHEN cur%NOTFOUND;
+ SELECT rec.a, rec.b, rec.c, rec.d;
+ INSERT INTO t2 VALUES (rec.a, rec.b, rec.c, rec.d);
+ END LOOP;
+ CLOSE cur;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SELECT * FROM t2;
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+--echo #
+--echo # Fetching a cursor into a table%ROWTYPE variable with different column names
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (x INT, y VARCHAR(10));
+INSERT INTO t1 VALUES (10,'bbb');
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec2 t2%ROWTYPE;
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ OPEN cur1;
+ FETCH cur1 INTO rec2;
+ SELECT rec2.x, rec2.y;
+ CLOSE cur1;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Fetching a cursor into a table%ROWTYPE variable, with truncation
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TABLE t2 (a INT, b INT);
+INSERT INTO t1 VALUES (10,'11x');
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ rec2 t2%ROWTYPE;
+ CURSOR cur1 IS SELECT * FROM t1;
+BEGIN
+ OPEN cur1;
+ FETCH cur1 INTO rec2;
+ SELECT rec2.a, rec2.b;
+ CLOSE cur1;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # table%ROWTYPE variables are not allowed in LIMIT
+--echo #
+CREATE TABLE t1 (a INT, b INT);
+INSERT INTO t1 VALUES (1,2);
+DELIMITER $$;
+--error ER_WRONG_SPVAR_TYPE_IN_LIMIT
+CREATE PROCEDURE p1()
+AS
+ rec1 t1%ROWTYPE:=(1,2);
+BEGIN
+ SELECT * FROM t1 LIMIT rec1.a;
+END;
+$$
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+--echo #
+--echo # table%ROWTYPE variable fields as OUT parameters
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1(a OUT INT,b OUT VARCHAR(10))
+AS
+BEGIN
+ a:=10;
+ b:='bb';
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+ rec1 t1%ROWTYPE;
+BEGIN
+ CALL p1(rec1.a, rec1.b);
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+CALL p2();
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Passing the entire table%ROWTYPE variable
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1(a ROW(a INT, b VARCHAR(10)))
+AS
+BEGIN
+ SELECT a.a, a.b;
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+ rec1 t1%ROWTYPE:= ROW(10,'bb');
+BEGIN
+ CALL p1(rec1);
+END;
+$$
+DELIMITER ;$$
+CALL p2();
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Passing the entire table%ROWTYPE variable as an OUT parameter
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1(a OUT ROW(a INT, b VARCHAR(10)))
+AS
+BEGIN
+ a:= ROW(10,'bb');
+END;
+$$
+CREATE PROCEDURE p2()
+AS
+ rec1 t1%ROWTYPE;
+BEGIN
+ CALL p1(rec1);
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+CALL p2();
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Assigning a table%ROWTYPE field to an OUT parameter
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1 (res IN OUT INTEGER)
+AS
+ rec1 t1%ROWTYPE:=ROW(10,'b0');
+BEGIN
+ res:=rec1.a;
+END;
+$$
+DELIMITER ;$$
+CALL p1(@res);
+SELECT @res;
+SET @res=NULL;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing Item_splocal_row_field_by_name::print
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec t1%ROWTYPE:=ROW(10,'bb');
+BEGIN
+ EXPLAIN EXTENDED SELECT rec.a, rec.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--echo #
+--echo # Non-existing field
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec t1%ROWTYPE;
+BEGIN
+ SELECT rec.c;
+END;
+$$
+DELIMITER ;$$
+--error ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD
+CALL p1();
+ALTER TABLE t1 ADD c INT;
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that field names are case insensitive
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec t1%ROWTYPE:=ROW(10,'bb');
+BEGIN
+ SELECT rec.A, rec.B;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that table%ROWTYPE uses temporary tables vs shadowed real tables
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+CREATE TEMPORARY TABLE t1 (x INT, y VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ rec t1%ROWTYPE:=ROW(10,'bb');
+BEGIN
+ SELECT rec.A, rec.B;
+END;
+$$
+DELIMITER ;$$
+--error ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD
+CALL p1();
+DROP TEMPORARY TABLE t1;
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing that the structure of table%ROWTYPE variables is determined at the very beginning and is not changed after ALTER
+--echo #
+
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+BEGIN
+ ALTER TABLE t1 ADD c INT;
+ DECLARE
+ rec t1%ROWTYPE; -- this will not have column "c"
+ BEGIN
+ rec.c:=10;
+ END;
+END;
+$$
+DELIMITER ;$$
+--error ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # MDEV-12291 Allow ROW variables as SELECT INTO targets
+--echo #
+
+
+--echo # ROW variable with a wrong column count
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ rec1 ROW(a INT, b VARCHAR(32), c DOUBLE);
+BEGIN
+ SELECT * FROM t1 INTO rec1;
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+--error ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo # Multiple ROW variables
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ rec1 ROW(a INT, b VARCHAR(32));
+BEGIN
+ SELECT * FROM t1 INTO rec1, rec1;
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo # ROW variables working example
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ rec1 ROW(a INT, b VARCHAR(32));
+BEGIN
+ SELECT * FROM t1 INTO rec1;
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo # table%ROWTYPE variable with a wrong column count
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ rec1 t1%ROWTYPE;
+BEGIN
+ SELECT 10,'a','b' FROM t1 INTO rec1;
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+--error ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo # Multiple table%ROWTYPE variables
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ rec1 t1%ROWTYPE;
+BEGIN
+ SELECT 10,'a' FROM t1 INTO rec1, rec1;
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo # table%ROWTYPE working example
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ rec1 t1%ROWTYPE;
+BEGIN
+ SELECT * FROM t1 INTO rec1;
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo # cursor%ROWTYPE variable with a wrong column count
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ CURSOR cur1 IS SELECT 10, 'b0', 'c0';
+ rec1 cur1%ROWTYPE;
+BEGIN
+ SELECT * FROM t1 INTO rec1;
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+--error ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo # Multiple cursor%ROWTYPE variables
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ CURSOR cur1 IS SELECT * FROM t1;
+ rec1 cur1%ROWTYPE;
+BEGIN
+ SELECT * FROM t1 INTO rec1, rec1;
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo # cursor%ROWTYPE working example
+CREATE TABLE t1 (a INT, b VARCHAR(32));
+INSERT INTO t1 VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+ CURSOR cur1 IS SELECT * FROM t1;
+ rec1 cur1%ROWTYPE;
+BEGIN
+ SELECT * FROM t1 INTO rec1;
+ SELECT rec1.a, rec1.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # MDEV-12347 Valgrind reports invalid read errors in Item_field_row::element_index_by_name
+--echo #
+
+# An additional test for MDEV-12347, to make sure that
+# Column_definition::interval creates a permanent copy of TYPELIB on
+# the memory root when processing %ROWTYPE for a table with ENUM/SET column,
+# rather than reuses the TYPELIB from table->field[i], which is freed in the
+# end of sp_rcontext::resolve_table_rowtype_ref().
+
+CREATE TABLE t1 (a INT, b ENUM('b0','b1','b12','b3'));
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+BEGIN
+ DECLARE
+ rec t1%ROWTYPE;
+ BEGIN
+ rec.b:='b0';
+ SELECT rec.b;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+CREATE TABLE t1 (a INT, b SET('b0','b1','b12','b3'));
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+BEGIN
+ DECLARE
+ rec t1%ROWTYPE;
+ BEGIN
+ rec.b:='b0';
+ SELECT rec.b;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # MDEV-13273 Confusion between table alias and ROW type variable
+--echo #
+
+CREATE TABLE t1 (c1 INT, c2 INT);
+INSERT INTO t1 VALUES (0,0);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a INT;
+ b INT;
+BEGIN
+ -- a.c1 is a table column
+ SELECT a.c1 INTO b
+ FROM t1 a
+ WHERE a.c2 = 0;
+ SELECT b;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (c1 INT, c2 INT);
+INSERT INTO t1 VALUES (0,0);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a ROW (c1 INT, c2 INT) := ROW(101,102);
+ b INT;
+BEGIN
+ -- a.c1 is a ROW variable field
+ SELECT a.c1 INTO b
+ FROM t1 a
+ WHERE a.c2 = 102;
+ SELECT b;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (c1 INT, c2 INT);
+INSERT INTO t1 VALUES (0,0);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a t1%ROWTYPE := ROW (10,20);
+ b INT;
+BEGIN
+ -- a.c1 is a ROW variable field
+ SELECT a.c1 INTO b
+ FROM t1 a
+ WHERE a.c2 = 20;
+ SELECT b;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (c1 INT, c2 INT);
+INSERT INTO t1 VALUES (0,0);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ CURSOR cur1 IS SELECT * FROM t1;
+ a cur1%ROWTYPE := ROW (10,20);
+ b INT;
+BEGIN
+ -- a.c1 is a ROW variable field
+ SELECT a.c1 INTO b
+ FROM t1 a
+ WHERE a.c2 = 20;
+ SELECT b;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/sp-security.test b/mysql-test/suite/compat/oracle/t/sp-security.test
new file mode 100644
index 00000000000..1732c0b80db
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-security.test
@@ -0,0 +1,345 @@
+--source include/not_embedded.inc
+
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+--echo #
+
+
+--echo #
+--echo # Initiation:
+--echo # - creating database db1
+--echo # - creating user user1 with access rights to db1
+--echo #
+
+CREATE DATABASE db1;
+CREATE TABLE db1.t1 (a INT, b VARCHAR(10));
+
+CREATE USER user1;
+
+GRANT ALL PRIVILEGES ON test.* TO user1;
+
+connect (conn1,localhost,user1,,test);
+SET sql_mode=ORACLE;
+
+SELECT database();
+SELECT user();
+
+--echo #
+--echo # Making sure that user1 does not have privileges to db1.t1
+--echo #
+
+--error ER_TABLEACCESS_DENIED_ERROR
+SHOW CREATE TABLE db1.t1;
+--error ER_TABLEACCESS_DENIED_ERROR
+SHOW FIELDS IN db1.t1;
+
+
+--echo #
+--echo # Trigger: using %TYPE with a table we don't have access to
+--echo #
+CREATE TABLE test.t1 (a INT, b INT);
+INSERT INTO test.t1 (a,b) VALUES (10,20);
+SELECT * FROM t1;
+DELIMITER $$;
+CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
+BEGIN
+ DECLARE b db1.t1.b%TYPE := 20;
+ BEGIN
+ :NEW.b := 10;
+ END;
+END
+$$
+DELIMITER ;$$
+--error ER_TABLEACCESS_DENIED_ERROR
+INSERT INTO t1 (a) VALUES (10);
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Stored procedure: Using %TYPE for with a table that we don't have access to
+--echo # DEFINER user1, SQL SECURITY DEFAULT
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a db1.t1.a%TYPE := 10;
+BEGIN
+ SELECT a;
+END;
+$$
+DELIMITER ;$$
+--error ER_TABLEACCESS_DENIED_ERROR
+CALL p1;
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a db1.t1%ROWTYPE;
+BEGIN
+ SELECT a.a;
+END;
+$$
+DELIMITER ;$$
+--error ER_TABLEACCESS_DENIED_ERROR
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Stored procedure: Using %TYPE for with a table that we don't have access to
+--echo # DEFINER root, SQL SECURITY INVOKER
+--echo #
+
+connection default;
+DELIMITER $$;
+CREATE PROCEDURE p1()
+SQL SECURITY INVOKER
+AS
+ a db1.t1.a%TYPE := 10;
+BEGIN
+ SELECT a;
+END;
+$$
+DELIMITER ;$$
+connection conn1;
+--error ER_TABLEACCESS_DENIED_ERROR
+CALL p1;
+DROP PROCEDURE p1;
+
+
+connection default;
+DELIMITER $$;
+CREATE PROCEDURE p1()
+SQL SECURITY INVOKER
+AS
+ a db1.t1%ROWTYPE;
+BEGIN
+ SELECT a.a;
+END;
+$$
+DELIMITER ;$$
+connection conn1;
+--error ER_TABLEACCESS_DENIED_ERROR
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Stored procedure: Using %TYPE for with a table that we don't have access to
+--echo # DEFINER root, SQL SECURITY DEFINER
+--echo #
+
+connection default;
+DELIMITER $$;
+CREATE PROCEDURE p1()
+SQL SECURITY DEFINER
+AS
+ a db1.t1.a%TYPE := 10;
+BEGIN
+ SELECT a;
+END;
+$$
+DELIMITER ;$$
+connection conn1;
+CALL p1;
+DROP PROCEDURE p1;
+
+connection default;
+DELIMITER $$;
+CREATE PROCEDURE p1()
+SQL SECURITY DEFINER
+AS
+ a db1.t1%ROWTYPE;
+BEGIN
+ a.a:= 10;
+ SELECT a.a;
+END;
+$$
+DELIMITER ;$$
+connection conn1;
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Stored function: Using %TYPE for with a table that we don't have access to
+--echo # DEFINER user1, SQL SECURITY DEFAULT
+--echo #
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE FUNCTION f1() RETURN INT
+AS
+ a db1.t1.a%TYPE:=0;
+BEGIN
+ RETURN OCTET_LENGTH(a);
+END;
+$$
+DELIMITER ;$$
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT f1();
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Stored function: Using %TYPE for with a table that we don't have access to
+--echo # DEFINER root, SQL SECURITY INVOKER
+--echo #
+
+connection default;
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE FUNCTION f1() RETURN INT
+SQL SECURITY INVOKER
+AS
+ a db1.t1.a%TYPE:=0;
+BEGIN
+ RETURN OCTET_LENGTH(a);
+END;
+$$
+DELIMITER ;$$
+connection conn1;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT f1();
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Stored function: Using %TYPE for with a table that we don't have access to
+--echo # DEFINER root, SQL SECURITY DEFINER
+--echo #
+
+connection default;
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE FUNCTION f1() RETURN INT
+SQL SECURITY DEFINER
+AS
+ a db1.t1.a%TYPE:=0;
+BEGIN
+ RETURN OCTET_LENGTH(a);
+END;
+$$
+DELIMITER ;$$
+connection conn1;
+SELECT f1();
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+
+connection default;
+GRANT SELECT (a) ON db1.t1 TO user1;
+connection conn1;
+
+--echo #
+--echo # Making sure that user1 has access to db1.t1.a, but not to db1.t1.b
+--echo #
+
+--error ER_TABLEACCESS_DENIED_ERROR
+SHOW CREATE TABLE db1.t1;
+SHOW FIELDS IN db1.t1;
+
+--echo #
+--echo # Trigger: Per-column privileges
+--echo #
+CREATE TABLE test.t1 (a INT, b INT);
+INSERT INTO test.t1 (a,b) VALUES (10,20);
+SELECT * FROM t1;
+# %TYPE reference using a column we have access to
+DELIMITER $$;
+CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
+BEGIN
+ DECLARE a db1.t1.a%TYPE := 20;
+ BEGIN
+ :NEW.b := 10;
+ END;
+END
+$$
+DELIMITER ;$$
+INSERT INTO t1 (a) VALUES (10);
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+# %TYPE reference using a column that we don't have access to
+DELIMITER $$;
+CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
+BEGIN
+ DECLARE b db1.t1.b%TYPE := 20;
+ BEGIN
+ :NEW.b := 10;
+ END;
+END
+$$
+DELIMITER ;$$
+--error ER_COLUMNACCESS_DENIED_ERROR
+INSERT INTO t1 (a) VALUES (10);
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+
+
+
+--echo #
+--echo # Stored procedure: Per-column privileges
+--echo # DEFINER user1, SQL SECURITY DEFAULT
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a db1.t1.a%TYPE := 10;
+BEGIN
+ SELECT a;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ b db1.t1.b%TYPE := 10;
+BEGIN
+ SELECT b;
+END;
+$$
+DELIMITER ;$$
+--error ER_COLUMNACCESS_DENIED_ERROR
+CALL p1;
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ b db1.t1%ROWTYPE;
+BEGIN
+ b.b:=10;
+ SELECT b.b;
+END;
+$$
+DELIMITER ;$$
+--error ER_COLUMNACCESS_DENIED_ERROR
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Clean up
+--echo #
+disconnect conn1;
+connection default;
+
+DROP USER user1;
+DROP DATABASE db1;
+
+--echo #
+--echo # End of MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+--echo #
diff --git a/mysql-test/suite/compat/oracle/t/sp.test b/mysql-test/suite/compat/oracle/t/sp.test
new file mode 100644
index 00000000000..4717ebef8eb
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp.test
@@ -0,0 +1,2133 @@
+SET sql_mode=ORACLE;
+
+--echo # Testing routines with no parameters
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+AS
+BEGIN
+ RETURN 10;
+END;
+/
+DELIMITER ;/
+--vertical_results
+SHOW CREATE FUNCTION f1;
+--horizontal_results
+SELECT f1();
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ SET @a=10;
+END;
+/
+DELIMITER ;/
+--vertical_results
+SHOW CREATE PROCEDURE p1;
+--horizontal_results
+SET @a=0;
+CALL p1();
+SELECT @a;
+DROP PROCEDURE p1;
+
+--echo # Testing ":=" to set the default value of a variable
+DELIMITER /;
+CREATE FUNCTION f1 () RETURN NUMBER(10) AS
+ a NUMBER(10) := 10;
+BEGIN
+ DECLARE
+ b NUMBER(10) DEFAULT 3;
+ BEGIN
+ RETURN a+b;
+ END;
+END;
+/
+DELIMITER ;/
+SELECT f1();
+DROP FUNCTION f1;
+
+--echo # Testing labels
+
+DELIMITER /;
+CREATE FUNCTION f1 (a INT) RETURN CLOB AS
+BEGIN
+ <<label1>>
+ BEGIN
+ IF a = 1 THEN
+ LEAVE label1;
+ END IF;
+ RETURN 'IS NOT 1';
+ END label1;
+ RETURN 'IS 1';
+END;
+/
+DELIMITER ;/
+SELECT f1(1);
+SELECT f1(2);
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 (a INT) RETURN INT IS
+BEGIN
+ <<label1>>
+ LOOP
+ IF a = 2 THEN
+ LEAVE label1;
+ END IF;
+ SET a= a-1;
+ END LOOP;
+ RETURN a;
+END;
+/
+DELIMITER ;/
+SELECT f1(4);
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 (a INT) RETURN INT AS
+BEGIN
+ <<label1>>
+ WHILE a>0 LOOP
+ IF a = 2 THEN
+ LEAVE label1;
+ END IF;
+ SET a= a-1;
+ END LOOP label1;
+ RETURN a;
+END;
+/
+DELIMITER ;/
+SELECT f1(4);
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 (a INT) RETURN INT AS
+BEGIN
+ <<label1>>
+ REPEAT
+ IF a = 2 THEN
+ LEAVE label1;
+ END IF;
+ SET a= a-1;
+ UNTIL a=0 END REPEAT;
+ RETURN a;
+END;
+/
+DELIMITER ;/
+SELECT f1(4);
+DROP FUNCTION f1;
+
+--echo # Testing IN/OUT/INOUT
+
+DELIMITER /;
+CREATE PROCEDURE p1 (p1 IN VARCHAR2(10), p2 OUT VARCHAR2(10)) AS
+BEGIN
+ SET p1='p1new';
+ SET p2='p2new';
+END;
+/
+DELIMITER ;/
+SET @p1='p1', @p2='p2';
+CALL p1(@p1, @p2);
+SELECT @p1, @p2;
+DROP PROCEDURE p1;
+
+--echo # Testing Oracle-style assigment
+DELIMITER /;
+CREATE PROCEDURE p1 (p1 OUT VARCHAR2(10)) AS
+BEGIN
+ p1:= 'p1new';
+END;
+/
+DELIMITER ;/
+SET @p1='p1';
+CALL p1(@p1);
+SELECT @p1;
+DROP PROCEDURE p1;
+
+--echo # Testing that NULL is a valid statement
+DELIMITER /;
+CREATE PROCEDURE p1(a INT) AS
+BEGIN
+ NULL;
+END;
+/
+DELIMITER ;/
+DROP PROCEDURE p1;
+
+DELIMITER /;
+CREATE PROCEDURE p1(a INT) AS
+ a INT:=10;
+BEGIN
+ IF a=10 THEN NULL; ELSE NULL; END IF;
+END;
+/
+DELIMITER ;/
+DROP PROCEDURE p1;
+
+
+--echo # Testing that (some) keyword_sp are allowed in Oracle-style assignments
+DELIMITER /;
+CREATE PROCEDURE p1 (action OUT INT) AS BEGIN action:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (clob OUT INT) AS BEGIN clob:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (enum OUT INT) AS BEGIN enum:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (via OUT INT) AS BEGIN via:=10; END;/
+DROP PROCEDURE p1/
+DELIMITER ;/
+
+--echo # Testing keyword_directly_assignable
+DELIMITER /;
+CREATE PROCEDURE p1 (ascii OUT INT) AS BEGIN ascii:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (backup OUT INT) AS BEGIN backup:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (binlog OUT INT) AS BEGIN binlog:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (byte OUT INT) AS BEGIN byte:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (cache OUT INT) AS BEGIN cache:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (checksum OUT INT) AS BEGIN checksum:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (checkpoint OUT INT) AS BEGIN checkpoint:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (column_add OUT INT) AS BEGIN column_add:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (column_check OUT INT) AS BEGIN column_check:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (column_create OUT INT) AS BEGIN column_create:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (column_delete OUT INT) AS BEGIN column_delete:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (column_get OUT INT) AS BEGIN column_get:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (deallocate OUT INT) AS BEGIN deallocate:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (examined OUT INT) AS BEGIN examined:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (execute OUT INT) AS BEGIN execute:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (flush OUT INT) AS BEGIN flush:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (format OUT INT) AS BEGIN format:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (get OUT INT) AS BEGIN get:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (help OUT INT) AS BEGIN help:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (host OUT INT) AS BEGIN host:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (install OUT INT) AS BEGIN install:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (option OUT INT) AS BEGIN option:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (options OUT INT) AS BEGIN options:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (owner OUT INT) AS BEGIN owner:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (parser OUT INT) AS BEGIN parser:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (port OUT INT) AS BEGIN port:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (prepare OUT INT) AS BEGIN prepare:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (remove OUT INT) AS BEGIN remove:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (reset OUT INT) AS BEGIN reset:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (restore OUT INT) AS BEGIN restore:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (security OUT INT) AS BEGIN security:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (server OUT INT) AS BEGIN server:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (signed OUT INT) AS BEGIN signed:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (socket OUT INT) AS BEGIN socket:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (slave OUT INT) AS BEGIN slave:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (slaves OUT INT) AS BEGIN slaves:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (soname OUT INT) AS BEGIN soname:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (start OUT INT) AS BEGIN start:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (stop OUT INT) AS BEGIN stop:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (stored OUT INT) AS BEGIN stored:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (unicode OUT INT) AS BEGIN unicode:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (uninstall OUT INT) AS BEGIN uninstall:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (upgrade OUT INT) AS BEGIN upgrade:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (wrapper OUT INT) AS BEGIN wrapper:=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (xa OUT INT) AS BEGIN xa:=10; END;/
+DROP PROCEDURE p1/
+DELIMITER ;/
+
+
+--echo # Testing that keyword_directly_not_assignable does not work in :=
+DELIMITER /;
+--error ER_PARSE_ERROR
+CREATE PROCEDURE p1 (commit OUT INT) AS BEGIN commit:=10; END;/
+--error ER_PARSE_ERROR
+CREATE PROCEDURE p1 (rollback OUT INT) AS BEGIN rollback:=10; END;/
+--error ER_PARSE_ERROR
+CREATE PROCEDURE p1 (shutdown OUT INT) AS BEGIN shutdown:=10; END;/
+DELIMITER ;/
+
+
+--echo # Testing that keyword_directly_not_assignable works in SET statements.
+DELIMITER /;
+CREATE PROCEDURE p1 (contains OUT INT) AS BEGIN SET contains=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (language OUT INT) AS BEGIN SET language=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (no OUT INT) AS BEGIN SET no=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (charset OUT INT) AS BEGIN SET charset=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (do OUT INT) AS BEGIN SET do=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (repair OUT INT) AS BEGIN SET repair=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (handler OUT INT) AS BEGIN SET handler=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (open OUT INT) AS BEGIN SET open=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (close OUT INT) AS BEGIN SET close=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (savepoint OUT INT) AS BEGIN SET savepoint=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (truncate OUT INT) AS BEGIN SET truncate=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (begin OUT INT) AS BEGIN SET begin=10; END;/
+DROP PROCEDURE p1/
+CREATE PROCEDURE p1 (end OUT INT) AS BEGIN SET end=10; END;/
+DROP PROCEDURE p1/
+DELIMITER ;/
+
+--echo # Testing that keyword_directly_not_assignable works in table/column names
+CREATE TABLE contains (contains INT);
+DROP TABLE contains;
+CREATE TABLE language (language INT);
+DROP TABLE language;
+CREATE TABLE no (no INT);
+DROP TABLE no;
+CREATE TABLE charset (charset INT);
+DROP TABLE charset;
+CREATE TABLE do (do INT);
+DROP TABLE do;
+CREATE TABLE repair (repair INT);
+DROP TABLE repair;
+CREATE TABLE handler (handler INT);
+DROP TABLE handler;
+CREATE TABLE open (open INT);
+DROP TABLE open;
+CREATE TABLE close (close INT);
+DROP TABLE close;
+CREATE TABLE savepoint (savepoint INT);
+DROP TABLE savepoint;
+CREATE TABLE truncate (truncate INT);
+DROP TABLE truncate;
+CREATE TABLE begin (begin INT);
+DROP TABLE begin;
+CREATE TABLE end (end INT);
+DROP TABLE end;
+
+--echo # Testing ELSIF
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN CLOB
+AS
+BEGIN
+ IF a=1 THEN RETURN 'a is 1';
+ ELSIF a=2 THEN RETURN 'a is 2';
+ ELSE RETURN 'a is unknown';
+ END IF;
+END;
+/
+DELIMITER ;/
+SELECT f1(2) FROM DUAL;
+DROP FUNCTION f1;
+
+
+
+--echo # Testing top-level declarations
+DELIMITER /;
+CREATE PROCEDURE p1 (p1 OUT VARCHAR2(10))
+AS
+ p2 VARCHAR(10);
+BEGIN
+ p2:='p1new';
+ p1:=p2;
+END;
+/
+DELIMITER ;/
+SET @p1='p1';
+CALL p1(@p1);
+SELECT @p1;
+DROP PROCEDURE p1;
+
+DELIMITER /;
+CREATE FUNCTION f1 (p1 VARCHAR2(10)) RETURN VARCHAR(20)
+AS
+ p2 VARCHAR(10);
+BEGIN
+ p2:='new';
+ RETURN CONCAT(p1, p2);
+END;
+/
+DELIMITER ;/
+SET @p1='p1';
+SELECT f1(@p1);
+DROP FUNCTION f1;
+
+--echo # Testing non-top declarations
+
+DELIMITER /;
+CREATE PROCEDURE p1 (p1 OUT VARCHAR2(10))
+AS
+BEGIN
+ DECLARE
+ p2 VARCHAR(10);
+ BEGIN
+ p2:='p1new';
+ p1:=p2;
+ END;
+ DECLARE
+ t1 VARCHAR(10);
+ t2 VARCHAR(10);
+ BEGIN
+ END;
+END;
+/
+DELIMITER ;/
+SET @p1='p1';
+CALL p1(@p1);
+SELECT @p1;
+DROP PROCEDURE p1;
+
+DELIMITER /;
+CREATE FUNCTION f1 (p1 VARCHAR2(10)) RETURN VARCHAR(20)
+AS
+BEGIN
+ DECLARE
+ p2 VARCHAR(10);
+ BEGIN
+ p2:='new';
+ RETURN CONCAT(p1, p2);
+ END;
+ DECLARE
+ t1 VARCHAR(10);
+ t2 VARCHAR(10);
+ BEGIN
+ END;
+END;
+/
+DELIMITER ;/
+SET @p1='p1';
+SELECT f1(@p1);
+DROP FUNCTION f1;
+
+
+--echo # Testing exceptions
+
+CREATE TABLE t1 (c1 INT);
+
+DELIMITER /;
+
+CREATE PROCEDURE sp1 (p1 IN VARCHAR2(20), p2 OUT VARCHAR2(30))
+IS
+ v1 INT;
+BEGIN
+ SELECT c1 INTO v1 FROM t1;
+ p2 := p1;
+EXCEPTION
+ WHEN NOT FOUND THEN
+ BEGIN
+ p2 := 'def';
+ END;
+END;
+/
+
+DELIMITER ;/
+
+CALL sp1('abc', @a);
+SELECT @a;
+
+DROP PROCEDURE sp1;
+DROP TABLE t1;
+
+
+DELIMITER /;
+CREATE PROCEDURE sp1 (v IN OUT INT, error IN INT)
+IS
+BEGIN
+ SIGNAL SQLSTATE '45000' SET MYSQL_ERRNO=error, MESSAGE_TEXT='User defined error!';
+ v:= 223;
+EXCEPTION
+ WHEN 30001 THEN
+ BEGIN
+ v:= 113;
+ END;
+END;
+/
+DELIMITER ;/
+SET @v=10;
+CALL sp1(@v, 30001);
+--error 30002
+CALL sp1(@v, 30002);
+SELECT @v;
+DROP PROCEDURE sp1;
+
+
+DELIMITER /;
+CREATE PROCEDURE sp1 (v IN OUT INT, error IN INT)
+IS
+BEGIN
+ BEGIN
+ BEGIN
+ SIGNAL SQLSTATE '45000' SET MYSQL_ERRNO=error, MESSAGE_TEXT='User defined error!';
+ v:= 223;
+ EXCEPTION
+ WHEN 30001 THEN
+ BEGIN
+ v:= 113;
+ END;
+ END;
+ END;
+END;
+/
+DELIMITER ;/
+SET @v=10;
+CALL sp1(@v, 30001);
+SELECT @v;
+SET @v=10;
+--error 30002
+CALL sp1(@v, 30002);
+SELECT @v;
+DROP PROCEDURE sp1;
+
+
+--echo #
+--echo # Testing EXIT statement
+--echo #
+
+DELIMITER /;
+--error ER_SP_LILABEL_MISMATCH
+CREATE FUNCTION f1 RETURN INT
+IS
+ i INT := 0;
+BEGIN
+ EXIT;
+END;
+/
+DELIMITER ;/
+
+
+DELIMITER /;
+--error ER_SP_LILABEL_MISMATCH
+CREATE FUNCTION f1 RETURN INT
+IS
+ i INT := 0;
+BEGIN
+ <<lable1>>
+ BEGIN
+ <<label2>>
+ LOOP
+ EXIT label1;
+ END LOOP;
+ END;
+END;
+/
+DELIMITER ;/
+
+
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+IS
+ i INT := 0;
+BEGIN
+ LOOP
+ LOOP
+ i:= i + 1;
+ IF i >= 5 THEN
+ EXIT;
+ END IF;
+ END LOOP;
+ i:= i + 100;
+ EXIT;
+ END LOOP;
+ RETURN i;
+END;
+/
+DELIMITER ;/
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+IS
+ i INT := 0;
+BEGIN
+ <<label1>>
+ LOOP
+ <<label2>>
+ LOOP
+ i:= i + 1;
+ IF i >= 5 THEN
+ EXIT label2;
+ END IF;
+ END LOOP;
+ i:= i + 100;
+ EXIT;
+ END LOOP;
+ RETURN i;
+END;
+/
+DELIMITER ;/
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+IS
+ i INT := 0;
+BEGIN
+ <<label1>>
+ LOOP
+ <<label2>>
+ LOOP
+ i:= i + 1;
+ IF i >= 5 THEN
+ EXIT label1;
+ END IF;
+ END LOOP;
+ i:= i + 100;
+ EXIT;
+ END LOOP;
+ RETURN i;
+END;
+/
+DELIMITER ;/
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+IS
+ i INT := 0;
+BEGIN
+ LOOP
+ i:= i + 1;
+ EXIT WHEN i >=5;
+ END LOOP;
+ RETURN i;
+END;
+/
+DELIMITER ;/
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+IS
+ i INT := 0;
+BEGIN
+ <<label1>>
+ LOOP
+ <<label2>>
+ LOOP
+ i:= i + 1;
+ EXIT label2 WHEN i >= 5;
+ END LOOP;
+ i:= i + 100;
+ EXIT;
+ END LOOP;
+ RETURN i;
+END;
+/
+DELIMITER ;/
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+IS
+ i INT := 0;
+BEGIN
+ <<label1>>
+ LOOP
+ <<label2>>
+ LOOP
+ i:= i + 1;
+ EXIT label1 WHEN i >= 5;
+ END LOOP;
+ i:= i + 100;
+ EXIT;
+ END LOOP;
+ RETURN i;
+END;
+/
+DELIMITER ;/
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+
+
+--echo # Testing CURSOR declaration
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+AS
+ v_a INT:=10;
+ CURSOR c IS SELECT a FROM t1;
+BEGIN
+ OPEN c;
+ FETCH c INTO v_a;
+ CLOSE c;
+ RETURN v_a;
+EXCEPTION
+ WHEN OTHERS THEN RETURN -1;
+END;
+/
+DELIMITER ;/
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+
+--echo # Testing RETURN in procedures
+
+DELIMITER /;
+--error ER_SP_BADRETURN
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+BEGIN
+ RETURN 10;
+END;
+/
+DELIMITER ;/
+
+DELIMITER /;
+--error ER_PARSE_ERROR
+CREATE FUNCTION f1 (a INT) RETURN INT
+AS
+BEGIN
+ RETURN;
+END;
+/
+DELIMITER ;/
+
+DELIMITER /;
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+BEGIN
+ IF a < 10 THEN
+ BEGIN
+ a:= a - 1;
+ RETURN;
+ END;
+ END IF;
+ a:= a + 1;
+EXCEPTION
+ WHEN OTHERS THEN RETURN;
+END;
+/
+DELIMITER ;/
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+SET @v=9;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+DELIMITER /;
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+BEGIN
+ DROP TABLE t1_non_existent;
+EXCEPTION
+ WHEN OTHERS THEN
+ BEGIN
+ a:= 100;
+ RETURN;
+ END;
+END;
+/
+DELIMITER ;/
+SET @v=10;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+
+--echo # Testing WHILE loop
+
+DELIMITER /;
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+ i INT:= 1;
+ j INT:= 3;
+BEGIN
+ WHILE i<=j
+ LOOP
+ a:= a + i;
+ i:= i + 1;
+ END LOOP;
+END;
+/
+DELIMITER ;/
+SET @v=0;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+DELIMITER /;
+CREATE PROCEDURE p1 (a IN OUT INT)
+AS
+ i INT:= 1;
+ j INT:= 3;
+BEGIN
+ <<label>>
+ WHILE i<=j
+ LOOP
+ a:= a + i;
+ i:= i + 1;
+ END LOOP label;
+END;
+/
+DELIMITER ;/
+SET @v=0;
+CALL p1(@v);
+SELECT @v;
+DROP PROCEDURE p1;
+
+
+--echo # Testing the FOR loop statement
+
+CREATE TABLE t1 (a INT);
+DELIMITER /;
+FOR i IN 1..3
+LOOP
+ INSERT INTO t1 VALUES (i);
+END LOOP;
+/
+DELIMITER ;/
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+DELIMITER /;
+--error ER_PARSE_ERROR
+CREATE FUNCTION f1 (lower_bound INT, upper_bound INT, lim INT) RETURN INT
+AS
+ total INT := 0;
+BEGIN
+ FOR i IN lower_bound . . upper_bound
+ LOOP
+ NULL
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+
+
+DELIMITER /;
+CREATE FUNCTION f1 (lower_bound INT, upper_bound INT, lim INT) RETURN INT
+AS
+ total INT := 0;
+BEGIN
+ FOR i IN lower_bound .. upper_bound
+ LOOP
+ total:= total + i;
+ IF i = lim THEN
+ EXIT;
+ END IF;
+ -- Bounds are calculated only once.
+ -- The below assignments have no effect on the loop condition
+ lower_bound:= 900;
+ upper_bound:= 1000;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SELECT f1(1, 3, 100) FROM DUAL;
+SELECT f1(1, 3, 2) FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 RETURN INT
+AS
+ total INT := 0;
+BEGIN
+ FOR i IN 1 .. 5
+ LOOP
+ total:= total + 1000;
+ FOR j IN 1 .. 5
+ LOOP
+ total:= total + 1;
+ IF j = 3 THEN
+ EXIT; -- End the internal loop
+ END IF;
+ END LOOP;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SELECT f1() FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1 (a INT, b INT) RETURN INT
+AS
+ total INT := 0;
+BEGIN
+ FOR i IN REVERSE a..1
+ LOOP
+ total:= total + i;
+ IF i = b THEN
+ EXIT;
+ END IF;
+ END LOOP;
+ RETURN total;
+END
+/
+DELIMITER ;/
+SELECT f1(3, 100) FROM DUAL;
+SELECT f1(3, 2) FROM DUAL;
+DROP FUNCTION f1;
+
+
+--echo # Testing labeled FOR LOOP statement
+
+DELIMITER /;
+CREATE FUNCTION f1 (a INT, limita INT, b INT, limitb INT) RETURN INT
+AS
+ total INT := 0;
+BEGIN
+ <<la>>
+ FOR ia IN 1 .. a
+ LOOP
+ total:= total + 1000;
+ <<lb>>
+ FOR ib IN 1 .. b
+ LOOP
+ total:= total + 1;
+ EXIT lb WHEN ib = limitb;
+ EXIT la WHEN ia = limita;
+ END LOOP lb;
+ END LOOP la;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SELECT f1(1, 1, 1, 1) FROM DUAL;
+SELECT f1(1, 2, 1, 2) FROM DUAL;
+SELECT f1(2, 1, 2, 1) FROM DUAL;
+SELECT f1(2, 1, 2, 2) FROM DUAL;
+SELECT f1(2, 2, 2, 2) FROM DUAL;
+SELECT f1(2, 3, 2, 3) FROM DUAL;
+DROP FUNCTION f1;
+
+
+--echo # Testing labeled ITERATE in a labeled FOR LOOP statement
+
+DELIMITER /;
+CREATE FUNCTION f1 (a INT, b INT, blim INT) RETURN INT
+AS
+ total INT := 0;
+BEGIN
+ <<la>>
+ FOR ia IN 1 .. a
+ LOOP
+ total:= total + 1000;
+ DECLARE
+ ib INT:= 1;
+ BEGIN
+ WHILE ib <= b
+ LOOP
+ IF ib > blim THEN
+ ITERATE la;
+ END IF;
+ ib:= ib + 1;
+ total:= total + 1;
+ END LOOP;
+ END;
+ END LOOP la;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SELECT f1(3,3,0), f1(3,3,1), f1(3,3,2), f1(3,3,3), f1(3,3,4) FROM DUAL;
+DROP FUNCTION f1;
+
+
+--echo # Testing CONTINUE statement
+
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ total INT:= 0;
+BEGIN
+ FOR i IN 1 .. a
+ LOOP
+ IF i=5 THEN
+ CONTINUE;
+ END IF;
+ total:= total + 1;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ total INT:= 0;
+BEGIN
+ <<lj>>
+ FOR j IN 1 .. 2
+ LOOP
+ FOR i IN 1 .. a
+ LOOP
+ IF i=5 THEN
+ CONTINUE lj;
+ END IF;
+ total:= total + 1;
+ END LOOP;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SELECT f1(3), f1(4), f1(5) FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ total INT:= 0;
+BEGIN
+ <<lj>>
+ FOR j IN 1 .. 2
+ LOOP
+ FOR i IN 1 .. a
+ LOOP
+ CONTINUE lj WHEN i=5;
+ total:= total + 1;
+ END LOOP;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SELECT f1(3), f1(4), f1(5) FROM DUAL;
+DROP FUNCTION f1;
+
+
+DELIMITER /;
+CREATE FUNCTION f1(a INT) RETURN INT
+AS
+ total INT:= 0;
+ i INT:= 1;
+BEGIN
+ WHILE i <= a
+ LOOP
+ i:= i + 1;
+ IF i=6 THEN
+ CONTINUE;
+ END IF;
+ total:= total + 1;
+ END LOOP;
+ RETURN total;
+END;
+/
+DELIMITER ;/
+SELECT f1(3), f1(4), f1(5), f1(6) FROM DUAL;
+DROP FUNCTION f1;
+
+--echo #
+--echo # Testing behaviour of unknown identifiers in EXIT and CONTINUE statements
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ LOOP
+ EXIT WHEN unknown_ident IS NULL;
+ END LOOP;
+END$$
+DELIMITER ;$$
+--error ER_BAD_FIELD_ERROR
+CALL p1;
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ <<label>>
+ LOOP
+ EXIT label WHEN unknown_ident IS NULL;
+ END LOOP;
+END$$
+DELIMITER ;$$
+--error ER_BAD_FIELD_ERROR
+CALL p1;
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ LOOP
+ CONTINUE WHEN unknown_ident IS NULL;
+ END LOOP;
+END$$
+DELIMITER ;$$
+--error ER_BAD_FIELD_ERROR
+CALL p1;
+DROP PROCEDURE p1;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ <<label>>
+ LOOP
+ CONTINUE label WHEN unknown_ident IS NULL;
+ END LOOP;
+END$$
+DELIMITER ;$$
+--error ER_BAD_FIELD_ERROR
+CALL p1;
+DROP PROCEDURE p1;
+
+--echo #
+--echo # MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT
+--echo #
+
+EXPLAIN EXTENDED SELECT sql%rowcount;
+CREATE TABLE t1 AS SELECT SQL%ROWCOUNT;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+--echo #
+--echo # UPDATE
+--echo #
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ UPDATE t1 SET a=30;
+ SELECT SQL%ROWCOUNT;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ UPDATE t1 SET a=30;
+ SELECT SQL%ROWCOUNT;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # DELETE
+--echo #
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ DELETE FROM t1;
+ SELECT SQL%ROWCOUNT;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ DELETE FROM t1;
+ SELECT SQL%ROWCOUNT;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SELECT ... INTO var FROM ... - one row found
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ va INT;
+BEGIN
+ SELECT a INTO va FROM t1 LIMIT 1;
+ SELECT SQL%ROWCOUNT;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SELECT ... INTO var FROM ... - no rows found
+--echo #
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ va INT;
+BEGIN
+ SELECT a INTO va FROM t1;
+ SELECT SQL%ROWCOUNT;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ va INT;
+BEGIN
+ SELECT a INTO va FROM t1;
+ SELECT SQL%ROWCOUNT;
+EXCEPTION
+ WHEN NO_DATA_FOUND THEN SELECT SQL%ROWCOUNT||' (EXCEPTION)';
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SELECT ... INTO var FROM ... - multiple rows found
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ va INT:=1;
+BEGIN
+ SELECT a INTO va FROM t1;
+ SELECT SQL%ROWCOUNT;
+EXCEPTION
+ WHEN TOO_MANY_ROWS THEN SELECT SQL%ROWCOUNT||' (EXCEPTION) va='||va;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+
+--echo #
+--echo # INSERT INTO t2 SELECT ...
+--echo #
+
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (20);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ INSERT INTO t2 SELECT * FROM t1;
+ SELECT SQL%ROWCOUNT;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1, t2;
+
+--echo #
+--echo # End of MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT
+--echo #
+
+--echo #
+--echo # MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+--echo #
+
+--echo #
+--echo # Missing table
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a t1.a%TYPE;
+BEGIN
+ NULL;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1();
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # Missing column
+--echo #
+
+CREATE TABLE t1 (b INT);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a t1.a%TYPE;
+BEGIN
+ NULL;
+END;
+$$
+DELIMITER ;$$
+--error ER_BAD_FIELD_ERROR
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # One %TYPE variable
+--echo #
+
+CREATE TABLE t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a t1.a%TYPE;
+BEGIN
+ a:= 123;
+ SELECT a;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--echo #
+--echo # Two %TYPE variables, with a truncation warning on assignment
+--echo #
+
+CREATE TABLE t1 (a TINYINT, b INT);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a t1.a%TYPE;
+ b t1.b%TYPE;
+BEGIN
+ a:= 200;
+ b:= 200;
+ SELECT a, b;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # %TYPE variables for fields with various attributes
+--echo #
+
+CREATE TABLE t1 (
+ id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ a TINYINT NOT NULL,
+ b INT NOT NULL,
+ ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ UNIQUE(a)
+);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ id t1.id%TYPE;
+ a t1.a%TYPE;
+ b t1.b%TYPE;
+ ts t1.ts%TYPE;
+BEGIN
+ SELECT id, a, b, ts;
+ CREATE TABLE t2 AS SELECT id, a, b, ts;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # %TYPE + virtual columns
+--echo #
+
+#
+# TODO: Changing 'a + 10' to 'a mod 10' make it fail, because
+# it's Item::print() returns 'a % 10' which makes grammar conflict
+# with cursor attributes
+
+CREATE TABLE t1 (
+ a INT NOT NULL,
+ b VARCHAR(32),
+ c INT AS (a + 10) VIRTUAL,
+ d VARCHAR(5) AS (left(b,5)) PERSISTENT
+);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ c t1.c%TYPE;
+ d t1.d%TYPE;
+BEGIN
+ SELECT c, d;
+ CREATE TABLE t2 AS SELECT c, d;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # %TYPE + the ZEROFILL attribute
+--echo #
+
+CREATE TABLE t1 (
+ dz DECIMAL(10,3) ZEROFILL
+);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ dzr t1.dz%TYPE := 10;
+ dzt DECIMAL(10,3) ZEROFILL := 10;
+BEGIN
+ SELECT dzr, dzt;
+ CREATE TABLE t2 AS SELECT dzr,dzt;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Temporary tables shadow real tables for %TYPE purposes
+--echo #
+CREATE TABLE t1 (a VARCHAR(10));
+INSERT INTO t1 VALUES ('t1');
+CREATE TEMPORARY TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a t1.a%TYPE:=11;
+BEGIN
+ CREATE TABLE t2 AS SELECT a;
+END;
+$$
+DELIMITER ;$$
+--echo #
+--echo # Should use INT(11) as %TYPE, as in the temporary table
+--echo #
+CALL p1();
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+SELECT * FROM t1;
+DROP TEMPORARY TABLE t1;
+SELECT * FROM t1;
+--echo #
+--echo # Should use VARCHAR(10) as %TYPE, as in the real table
+--echo #
+CALL p1();
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # t1.a%TYPE searches for "t1" in the current database
+--echo #
+
+CREATE TABLE t1 (a VARCHAR(10));
+CREATE DATABASE test1;
+CREATE TABLE test1.t1 (a INT);
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a t1.a%TYPE:=11;
+BEGIN
+ CREATE TABLE test.t2 AS SELECT a;
+END;
+$$
+DELIMITER ;$$
+
+--echo #
+--echo # This interprets t1.a%TYPE as VARCHAR(10), as in test.t1.a
+--echo #
+
+USE test;
+CALL test.p1();
+SHOW CREATE TABLE test.t2;
+DROP TABLE test.t2;
+
+--echo #
+--echo # This interprets t1.a%TYPE as INT, as in test1.t1.a
+--echo #
+
+USE test1;
+CALL test.p1();
+SHOW CREATE TABLE test.t2;
+DROP TABLE test.t2;
+
+--echo #
+--echo # Error if there is no an active database
+--echo #
+
+DROP DATABASE test1;
+--error ER_NO_DB_ERROR
+CALL test.p1();
+
+USE test;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # A reference to a table in a non-existing database
+--echo #
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a test1.t1.a%TYPE;
+BEGIN
+ CREATE TABLE t1 AS SELECT a;
+END;
+$$
+DELIMITER ;$$
+--error ER_NO_SUCH_TABLE
+CALL p1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # A reference to a table in a different database
+--echo #
+CREATE TABLE t1(a INT);
+CREATE DATABASE test1;
+CREATE TABLE test1.t1 (a VARCHAR(10));
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a t1.a%TYPE;
+ b test1.t1.a%TYPE;
+BEGIN
+ CREATE TABLE t2 AS SELECT a,b;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+SHOW CREATE TABLE t2;
+DROP PROCEDURE p1;
+DROP TABLE t2;
+DROP DATABASE test1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Using a table before it appears in a %TYPE declaration + multiple %TYPE declarations
+--echo #
+CREATE TABLE t1 (a INT, b VARCHAR(10));
+INSERT INTO t1 (a,b) VALUES (10,'b10');
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ INSERT INTO t1 (a,b) VALUES (11, 'b11');
+ SELECT * FROM t1;
+ DECLARE
+ va t1.a%TYPE:= 30;
+ vb t1.b%TYPE:= 'b30';
+ BEGIN
+ INSERT INTO t1 (a,b) VALUES (12,'b12');
+ SELECT * FROM t1;
+ INSERT INTO t1 (a,b) VALUES (va, vb);
+ SELECT * FROM t1;
+ END;
+ DECLARE
+ va t1.a%TYPE:= 40;
+ vb t1.b%TYPE:= 'b40';
+ BEGIN
+ INSERT INTO t1 (a,b) VALUES (va,vb);
+ SELECT * FROM t1;
+ END;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # %TYPE variables + TABLE vs VIEW
+--echo #
+
+CREATE TABLE t1 (
+ bit6 BIT(6),
+ bit7 BIT(7),
+ bit8 BIT(8),
+ i1 TINYINT,
+ i2 SMALLINT,
+ i3 MEDIUMINT,
+ i4 INT,
+ i8 BIGINT,
+ ff FLOAT,
+ fd DOUBLE,
+ cc CHAR(10),
+ cv VARCHAR(10),
+ cvu VARCHAR(10) CHARACTER SET utf8,
+ t1 TINYTEXT,
+ t2 TEXT,
+ t3 MEDIUMTEXT,
+ t4 LONGTEXT,
+ enum1 ENUM('a','b','c'),
+ set1 SET('a','b','c'),
+ blob1 TINYBLOB,
+ blob2 BLOB,
+ blob3 MEDIUMBLOB,
+ blob4 LONGBLOB,
+ yy YEAR,
+ dd DATE,
+ tm0 TIME,
+ tm3 TIME(3),
+ tm6 TIME(6),
+ dt0 DATETIME,
+ dt3 DATETIME(3),
+ dt6 DATETIME(6),
+ ts0 TIMESTAMP,
+ ts3 TIMESTAMP(3),
+ ts6 TIMESTAMP(6),
+ dc100 DECIMAL(10,0),
+ dc103 DECIMAL(10,3),
+ dc209 DECIMAL(20,9)
+);
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1(command enum('create','select'))
+AS
+ bit6 t1.bit6%TYPE := 0x30;
+ bit7 t1.bit7%TYPE := 0x41;
+ bit8 t1.bit8%TYPE := 0x7E;
+ i1 t1.i1%TYPE := 11;
+ i2 t1.i2%TYPE := 12;
+ i3 t1.i3%TYPE := 13;
+ i4 t1.i4%TYPE := 14;
+ i8 t1.i8%TYPE := 18;
+ ff t1.ff%TYPE := 21;
+ fd t1.fd%TYPE := 22;
+ cc t1.cc%TYPE := 'char';
+ cv t1.cv%TYPE := 'varchar';
+ cvu t1.cvu%TYPE := 'varcharu8';
+ t1 t1.t1%TYPE := 'text1';
+ t2 t1.t2%TYPE := 'text2';
+ t3 t1.t3%TYPE := 'text3';
+ t4 t1.t4%TYPE := 'text4';
+ enum1 t1.enum1%TYPE := 'b';
+ set1 t1.set1%TYPE := 'a,c';
+ blob1 t1.blob1%TYPE := 'blob1';
+ blob2 t1.blob2%TYPE := 'blob2';
+ blob3 t1.blob3%TYPE := 'blob3';
+ blob4 t1.blob4%TYPE := 'blob4';
+ yy t1.yy%TYPE := 2001;
+ dd t1.dd%TYPE := '2001-01-01';
+ tm0 t1.tm0%TYPE := '00:00:01';
+ tm3 t1.tm3%TYPE := '00:00:03.333';
+ tm6 t1.tm6%TYPE := '00:00:06.666666';
+ dt0 t1.dt0%TYPE := '2001-01-01 00:00:01';
+ dt3 t1.dt3%TYPE := '2001-01-03 00:00:01.333';
+ dt6 t1.dt6%TYPE := '2001-01-06 00:00:01.666666';
+ ts0 t1.ts0%TYPE := '2002-01-01 00:00:01';
+ ts3 t1.ts3%TYPE := '2002-01-03 00:00:01.333';
+ ts6 t1.ts6%TYPE := '2002-01-06 00:00:01.666666';
+ dc100 t1.dc100%TYPE := 10;
+ dc103 t1.dc103%TYPE := 10.123;
+ dc209 t1.dc209%TYPE := 10.123456789;
+BEGIN
+ CASE
+ WHEN command='create' THEN
+ CREATE TABLE t2 AS SELECT
+ bit6, bit7, bit8,
+ i1,i2,i3,i4,i8,
+ ff,fd, dc100, dc103, dc209,
+ cc,cv,cvu,
+ t1,t2,t3,t4,
+ enum1, set1,
+ blob1, blob2, blob3, blob4,
+ dd, yy,
+ tm0, tm3, tm6,
+ dt0, dt3, dt6,
+ ts0, ts3, ts6;
+ WHEN command='select' THEN
+ SELECT
+ bit6, bit7, bit8,
+ i1,i2,i3,i4,i8,
+ ff,fd, dc100, dc103, dc209,
+ cc,cv,cvu,
+ t1,t2,t3,t4,
+ enum1, set1,
+ blob1, blob2, blob3, blob4,
+ dd, yy,
+ tm0, tm3, tm6,
+ dt0, dt3, dt6,
+ ts0, ts3, ts6;
+ END CASE;
+END;
+$$
+DELIMITER ;$$
+
+--echo #
+--echo # TABLE
+--echo #
+CALL p1('create');
+SHOW CREATE TABLE t2;
+--vertical_results
+SELECT * FROM t2;
+--horizontal_results
+DROP TABLE t2;
+
+--disable_ps_protocol
+--enable_metadata
+--vertical_results
+CALL p1('select');
+--horizontal_results
+--disable_metadata
+--enable_ps_protocol
+
+--echo #
+--echo # VIEW
+--echo #
+ALTER TABLE t1 RENAME t0;
+CREATE VIEW t1 AS SELECT * FROM t0;
+
+CALL p1('create');
+SHOW CREATE TABLE t2;
+--vertical_results
+SELECT * FROM t2;
+--horizontal_results
+DROP TABLE t2;
+
+--disable_ps_protocol
+--enable_metadata
+--vertical_results
+CALL p1('select');
+--horizontal_results
+--disable_metadata
+--enable_ps_protocol
+
+DROP VIEW t1;
+DROP TABLE t0;
+
+DROP PROCEDURE p1;
+
+--echo #
+--echo # VIEW with subqueries
+--echo #
+CREATE TABLE t1 (a INT,b INT);
+INSERT INTO t1 VALUES (10,1),(20,2),(30,3),(40,4);
+SELECT AVG(a) FROM t1;
+CREATE VIEW v1 AS SELECT a,1 as b FROM t1 WHERE a>(SELECT AVG(a) FROM t1) AND b>(SELECT 1);
+SELECT * FROM v1;
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a v1.a%TYPE := 10;
+ b v1.b%TYPE := 1;
+BEGIN
+ SELECT a,b;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+DELIMITER $$;
+CREATE FUNCTION f1 RETURN INT
+AS
+ a v1.a%TYPE := 10;
+ b v1.b%TYPE := 1;
+BEGIN
+ RETURN a+b;
+END;
+$$
+DELIMITER ;$$
+SELECT f1();
+DROP FUNCTION f1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # %TYPE variables + INFORMATION_SCHEMA
+--echo #
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ tables_table_name INFORMATION_SCHEMA.TABLES.TABLE_NAME%TYPE;
+ tables_table_rows INFORMATION_SCHEMA.TABLES.TABLE_ROWS%TYPE;
+ processlist_info INFORMATION_SCHEMA.PROCESSLIST.INFO%TYPE;
+ processlist_info_binary INFORMATION_SCHEMA.PROCESSLIST.INFO_BINARY%TYPE;
+BEGIN
+ CREATE TABLE t1 AS SELECT
+ tables_table_name,
+ tables_table_rows,
+ processlist_info,
+ processlist_info_binary;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # %TYPE + Table structure change
+--echo # Data type for both a0 and a1 is chosen in the very beginning
+--echo #
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+ a0 t1.a%TYPE;
+BEGIN
+ ALTER TABLE t1 MODIFY a VARCHAR(10); -- This does not affect a1
+ DECLARE
+ a1 t1.a%TYPE;
+ BEGIN
+ CREATE TABLE t2 AS SELECT a0, a1;
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+ END;
+END
+$$
+DELIMITER ;$$
+CREATE TABLE t1 (a INT);
+CALL p1;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # %TYPE in parameters
+--echo #
+CREATE TABLE t1 (a VARCHAR(10));
+CREATE DATABASE test1;
+CREATE TABLE test1.t1 (b SMALLINT);
+DELIMITER $$;
+CREATE PROCEDURE p1(a t1.a%TYPE, b test1.t1.b%TYPE)
+AS
+BEGIN
+ CREATE TABLE t2 AS SELECT a, b;
+END;
+$$
+DELIMITER ;$$
+CALL p1('test', 123);
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+DROP PROCEDURE p1;
+DROP TABLE test1.t1;
+DROP DATABASE test1;
+DROP TABLE t1;
+
+--echo #
+--echo # %TYPE in a stored function variables and arguments
+--echo #
+
+CREATE TABLE t1 (a INT);
+SET sql_mode=ORACLE;
+DELIMITER $$;
+CREATE FUNCTION f1 (prm t1.a%TYPE) RETURN INT
+AS
+ a t1.a%TYPE:= prm;
+BEGIN
+ RETURN a;
+END;
+$$
+DELIMITER ;$$
+SELECT f1(20);
+DROP FUNCTION f1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # %TYPE in function RETURN clause is not supported yet
+--echo #
+DELIMITER $$;
+--error ER_PARSE_ERROR
+CREATE FUNCTION f1 RETURN t1.a%TYPE
+AS
+BEGIN
+ RETURN 0;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # End of MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+--echo #
+
+
+--echo #
+--echo # MDEV-12089 sql_mode=ORACLE: Understand optional routine name after the END keyword
+--echo #
+
+DELIMITER $$;
+CREATE FUNCTION f1 RETURN INT AS
+BEGIN
+ RETURN 10;
+END f1;
+$$
+DELIMITER ;$$
+DROP FUNCTION f1;
+
+DELIMITER $$;
+CREATE FUNCTION test.f1 RETURN INT AS
+BEGIN
+ RETURN 10;
+END test.f1;
+$$
+DELIMITER ;$$
+DROP FUNCTION f1;
+
+DELIMITER $$;
+--error ER_END_IDENTIFIER_DOES_NOT_MATCH
+CREATE FUNCTION test.f1 RETURN INT AS
+BEGIN
+ RETURN 10;
+END test2.f1;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--error ER_END_IDENTIFIER_DOES_NOT_MATCH
+CREATE FUNCTION test.f1 RETURN INT AS
+BEGIN
+ RETURN 10;
+END test.f2;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--error ER_END_IDENTIFIER_DOES_NOT_MATCH
+CREATE FUNCTION f1 RETURN INT AS
+BEGIN
+ RETURN 10;
+END test.f2;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--error ER_END_IDENTIFIER_DOES_NOT_MATCH
+CREATE FUNCTION f1 RETURN INT AS
+BEGIN
+ RETURN 10;
+END test2.f1;
+$$
+DELIMITER ;$$
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1 AS
+BEGIN
+ NULL;
+END p1;
+$$
+DELIMITER ;$$
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE PROCEDURE test.p1 AS
+BEGIN
+ NULL;
+END test.p1;
+$$
+DELIMITER ;$$
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+--error ER_END_IDENTIFIER_DOES_NOT_MATCH
+CREATE PROCEDURE test.p1 AS
+BEGIN
+ NULL;
+END test2.p1;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--error ER_END_IDENTIFIER_DOES_NOT_MATCH
+CREATE PROCEDURE test.p1 AS
+BEGIN
+ NULL;
+END test.p2;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--error ER_END_IDENTIFIER_DOES_NOT_MATCH
+CREATE PROCEDURE p1 AS
+BEGIN
+ NULL;
+END test.p2;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--error ER_END_IDENTIFIER_DOES_NOT_MATCH
+CREATE PROCEDURE p1 AS
+BEGIN
+ NULL;
+END test2.p1;
+$$
+DELIMITER ;$$
+
+--echo #
+--echo # MDEV-12107 sql_mode=ORACLE: Inside routines the CALL keywoard is optional
+--echo #
+DELIMITER /;
+CREATE OR REPLACE PROCEDURE p1(a INT) AS
+BEGIN
+ SELECT 'This is p1' AS "comment";
+END;
+/
+CREATE OR REPLACE PROCEDURE p2 AS
+BEGIN
+ SELECT 'This is p2' AS "comment";
+END;
+/
+BEGIN
+ p1(10);
+ p2;
+ test.p1(10);
+ test.p2;
+END;
+/
+CREATE PROCEDURE p3 AS
+BEGIN
+ p1(10);
+ p2;
+ test.p1(10);
+ test.p2;
+END
+/
+DELIMITER ;/
+CALL p3;
+DROP PROCEDURE p3;
+DROP PROCEDURE p2;
+DROP PROCEDURE p1;
+
+
+--echo #
+--echo # MDEV-12854 Synchronize CREATE..SELECT data type and result set metadata data type for INT functions
+--echo #
+
+--enable_metadata
+--disable_ps_protocol
+SELECT SQL%ROWCOUNT;
+--enable_ps_protocol
+--disable_metadata
diff --git a/mysql-test/suite/compat/oracle/t/trigger.test b/mysql-test/suite/compat/oracle/t/trigger.test
new file mode 100644
index 00000000000..45affb2d6e8
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/trigger.test
@@ -0,0 +1,106 @@
+set sql_mode=ORACLE;
+
+--error ER_PARSE_ERROR
+:NEW.a := 1;
+--error ER_PARSE_ERROR
+:OLD.a := 1;
+--error ER_PARSE_ERROR
+:OLa.a := 1;
+
+--error ER_PARSE_ERROR
+SELECT :NEW.a;
+--error ER_PARSE_ERROR
+SELECT :OLD.a;
+--error ER_PARSE_ERROR
+SELECT :OLa.a;
+
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW NEW.a:= 10;
+INSERT INTO t1 VALUES ();
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW :NEW.a:= 10;
+INSERT INTO t1 VALUES ();
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+DELIMITER /;
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+ IF :NEW.a IS NULL
+ THEN
+ :NEW.a:= 10;
+ END IF;
+END;
+/
+DELIMITER ;/
+INSERT INTO t1 VALUES (NULL);
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INT);
+DELIMITER /;
+CREATE TRIGGER tr1 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+ IF :OLD.a IS NULL
+ THEN
+ :NEW.a:= 10;
+ END IF;
+END;
+/
+DELIMITER ;/
+INSERT INTO t1 VALUES (NULL);
+UPDATE t1 SET a=NULL;
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+
+
+
+CREATE TABLE t1 (a INT, b INT, c INT);
+DELIMITER /;
+CREATE TRIGGER tr1 BEFORE INSERT ON t1
+FOR EACH ROW
+DECLARE
+ cnt INT := 0;
+BEGIN
+ IF :NEW.a IS NULL THEN cnt:=cnt+1; END IF;
+ IF :NEW.b IS NULL THEN cnt:=cnt+1; END IF;
+ IF :NEW.c IS NULL THEN :NEW.c:=cnt; END IF;
+END;
+/
+DELIMITER ;/
+INSERT INTO t1 VALUES ();
+INSERT INTO t1 VALUES (1, NULL, NULL);
+INSERT INTO t1 VALUES (NULL, 1, NULL);
+INSERT INTO t1 VALUES (1, 1, NULL);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
+--echo #
+
+CREATE TABLE t1 (a INT, b INT, total INT);
+DELIMITER $$;
+CREATE TRIGGER tr1 BEFORE INSERT ON t1
+FOR EACH ROW
+DECLARE
+ va t1.a%TYPE:= :NEW.a;
+ vb t1.b%TYPE:= :NEW.b;
+BEGIN
+ :NEW.total:= va + vb;
+END;
+$$
+DELIMITER ;$$
+INSERT INTO t1 (a,b) VALUES (10, 20);
+SELECT * FROM t1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/truncate.test b/mysql-test/suite/compat/oracle/t/truncate.test
new file mode 100644
index 00000000000..ac540047e49
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/truncate.test
@@ -0,0 +1,16 @@
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-10588 sql_mode=ORACLE: TRUNCATE TABLE t1 [ {DROP|REUSE} STORAGE ]
+--echo #
+
+CREATE TABLE t1 (a INT);
+TRUNCATE TABLE t1 REUSE STORAGE;
+TRUNCATE TABLE t1 DROP STORAGE;
+DROP TABLE t1;
+
+# REUSE is actually a reserved word in Oracle.
+# But we don't reserve it for MDEV-10588
+
+CREATE TABLE reuse (reuse INT);
+DROP TABLE reuse;
diff --git a/mysql-test/suite/compat/oracle/t/type_blob.test b/mysql-test/suite/compat/oracle/t/type_blob.test
new file mode 100644
index 00000000000..2bfaa77560d
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/type_blob.test
@@ -0,0 +1,4 @@
+SET sql_mode=ORACLE;
+CREATE TABLE t1 (a BLOB);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/type_clob.test b/mysql-test/suite/compat/oracle/t/type_clob.test
new file mode 100644
index 00000000000..275e368b298
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/type_clob.test
@@ -0,0 +1,10 @@
+SET sql_mode=ORACLE;
+
+# CLOB is not a reserved word even in sql_mode=ORACLE
+CREATE TABLE clob (clob INT);
+SHOW CREATE TABLE clob;
+DROP TABLE clob;
+
+CREATE TABLE t1 (a CLOB);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/type_date.test b/mysql-test/suite/compat/oracle/t/type_date.test
new file mode 100644
index 00000000000..61f7aa53944
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/type_date.test
@@ -0,0 +1,4 @@
+SET sql_mode=ORACLE;
+CREATE TABLE t1 (a DATE);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/type_number.test b/mysql-test/suite/compat/oracle/t/type_number.test
new file mode 100644
index 00000000000..d8ea04ab333
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/type_number.test
@@ -0,0 +1,9 @@
+SET sql_mode=ORACLE;
+
+CREATE TABLE t1 (a NUMBER);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a NUMBER(10,2));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/type_raw.test b/mysql-test/suite/compat/oracle/t/type_raw.test
new file mode 100644
index 00000000000..3b54f5a3735
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/type_raw.test
@@ -0,0 +1,10 @@
+SET sql_mode=ORACLE;
+
+# RAW is not a reserved word even in sql_mode=ORACLE
+CREATE TABLE raw (raw INT);
+SHOW CREATE TABLE raw;
+DROP TABLE raw;
+
+CREATE TABLE t1 (a RAW(10));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/type_varchar.test b/mysql-test/suite/compat/oracle/t/type_varchar.test
new file mode 100644
index 00000000000..05691bfb8e6
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/type_varchar.test
@@ -0,0 +1,9 @@
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # MDEV-11275 sql_mode=ORACLE: CAST(..AS VARCHAR(N))
+--echo #
+
+SELECT CAST(123 AS VARCHAR(10)) FROM DUAL;
+--error ER_PARSE_ERROR
+SELECT CAST(123 AS VARCHAR) FROM DUAL;
diff --git a/mysql-test/suite/compat/oracle/t/type_varchar2.test b/mysql-test/suite/compat/oracle/t/type_varchar2.test
new file mode 100644
index 00000000000..bd0243713b6
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/type_varchar2.test
@@ -0,0 +1,19 @@
+SET sql_mode=ORACLE;
+
+# VARCHAR2 is not a reserved word even in sql_mode=ORACLE
+CREATE TABLE varchar2 (varchar2 INT);
+SHOW CREATE TABLE varchar2;
+DROP TABLE varchar2;
+
+CREATE TABLE t1 (a VARCHAR2(10));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-11275 sql_mode=ORACLE: CAST(..AS VARCHAR(N))
+--echo #
+
+SELECT CAST(123 AS VARCHAR2(10)) FROM DUAL;
+--error ER_PARSE_ERROR
+SELECT CAST(123 AS VARCHAR2) FROM DUAL;
diff --git a/mysql-test/suite/compat/oracle/t/variables.test b/mysql-test/suite/compat/oracle/t/variables.test
new file mode 100644
index 00000000000..4705cac11c0
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/variables.test
@@ -0,0 +1,38 @@
+SET sql_mode=oracle;
+
+--echo #
+--echo # MDEV-10411 Providing compatibility for basic PL/SQL constructs
+--echo # Part 6: Assignment operator
+--echo #
+
+max_sort_length:=1030;
+SELECT @@max_sort_length;
+max_sort_length:=DEFAULT;
+
+--echo #
+--echo # Testing that SP variables shadow global variables in assignments
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1
+AS
+BEGIN
+ max_sort_length:=1030;
+ DECLARE
+ max_sort_length INT DEFAULT 1031;
+ BEGIN
+ SELECT @@max_sort_length, max_sort_length;
+ max_sort_length:=1032;
+ SELECT @@max_sort_length, max_sort_length;
+ END;
+ SELECT @@max_sort_length;
+ max_sort_length:= DEFAULT;
+END;
+$$
+DELIMITER ;$$
+CALL p1();
+DROP PROCEDURE p1;
+
+--echo #
+--echo # End of MDEV-10411 Providing compatibility for basic PL/SQL constructs (part 6)
+--echo #