diff options
Diffstat (limited to 'mysql-test/suite/compat/oracle')
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 # |