diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
commit | 3f619478f796eddbba6e39502fe941b285dd97b1 (patch) | |
tree | e2c7b5777f728320e5b5542b6213fd3591ba51e2 /mysql-test/suite/compat/oracle/t | |
parent | Initial commit. (diff) | |
download | mariadb-upstream.tar.xz mariadb-upstream.zip |
Adding upstream version 1:10.11.6.upstream/1%10.11.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mysql-test/suite/compat/oracle/t')
83 files changed, 23848 insertions, 0 deletions
diff --git a/mysql-test/suite/compat/oracle/t/anonymous_derived.test b/mysql-test/suite/compat/oracle/t/anonymous_derived.test new file mode 100644 index 00000000..7a9ee216 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/anonymous_derived.test @@ -0,0 +1,56 @@ +--echo # +--echo # MDEV-19162: anonymous derived tables part +--echo # + +set @save_sql_mode=@@sql_mode; +set session sql_mode=ORACLE; + +--disable_ps_protocol +--enable_metadata +SELECT * FROM (SELECT 1 FROM DUAL), (SELECT 2 FROM DUAL); +--disable_metadata +--enable_ps_protocol +create table t1 (a int); +insert into t1 values (2),(3); +create table t2 (a int); +insert into t2 values (2),(3); +--disable_ps_protocol +--enable_metadata +select t1.a from t1, (select * from t2 where t2.a<= 2); +select t1.a, b from t1, (select a as b from t2 where t2.a<= 2); +select t1.a, b from t1, (select max(a) as b from t2); +--disable_metadata +--enable_ps_protocol +explain extended +select t1.a, b from t1, (select max(a) as b from t2); +--error ER_BAD_FIELD_ERROR +select * from (select tt.* from (select * from t1) as tt) where tt.a > 0; +select * from (select tt.* from (select * from t1) as tt) where a > 0; + +create view v1 as select t1.a, b from t1, (select max(a) as b from t2); + +select * from v1; + + +DELIMITER /; +create procedure p1 +as +begin + select t1.a, b from t1, (select max(a) as b from t2); +end/ +DELIMITER ;/ + +call p1; + +SET sql_mode=default; + +select * from v1; +show create view v1; + +call p1; +show create procedure p1; + +drop view v1; +drop procedure p1; +drop table t1,t2; +set session sql_mode=@save_sql_mode; diff --git a/mysql-test/suite/compat/oracle/t/binlog_ptr_mysqlbinlog-master.opt b/mysql-test/suite/compat/oracle/t/binlog_ptr_mysqlbinlog-master.opt new file mode 100644 index 00000000..8f0cc182 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/binlog_ptr_mysqlbinlog-master.opt @@ -0,0 +1 @@ +--flashback diff --git a/mysql-test/suite/compat/oracle/t/binlog_ptr_mysqlbinlog.test b/mysql-test/suite/compat/oracle/t/binlog_ptr_mysqlbinlog.test new file mode 100644 index 00000000..bda32af5 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/binlog_ptr_mysqlbinlog.test @@ -0,0 +1,117 @@ +# ==== Purpose ==== +# +# Test verifies that point in time recovery of binary log works when +# sql_mode='ORACLE'. +# +# BEGIN statement is printed in three places +# 1) "Gtid_log_event::print" +# 2) "Xid_log_event::print" if flashback is enabled +# 3) "Query_log_event::print" if flashback is enabled and engine is +# non-transacional. +# +# Test verifies all these cases. +# +# ==== References ==== +# +# MDEV-23108: Point in time recovery of binary log fails when sql_mode=ORACLE +# +--source include/have_log_bin.inc +--source include/have_innodb.inc + +let $MYSQLD_DATADIR= `select @@datadir`; +SET @@SQL_MODE = 'ORACLE'; + +--echo ########################################################################## +--echo # Test verifies Gtid_log_event/Xid_log_event specific print # +--echo ########################################################################## +CREATE TABLE tm (f INT) ENGINE=MYISAM; +INSERT INTO tm VALUES (10); + +CREATE TABLE t(f INT) ENGINE=INNODB; +INSERT INTO t VALUES (10); + +DELIMITER /; +CREATE OR REPLACE PROCEDURE simpleproc (param1 OUT INT) AS + BEGIN + SELECT COUNT(*) INTO param1 FROM t; + END; +/ +CREATE FUNCTION f1 RETURN INT +AS +BEGIN + RETURN 10; +END; +/ +DELIMITER ;/ + +FLUSH LOGS; +--echo ########################################################################## +--echo # Delete data from master so that it can be restored from binlog # +--echo ########################################################################## +DROP FUNCTION f1; +DROP PROCEDURE simpleproc; +DROP TABLE tm; +DROP TABLE t; + +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/test.sql +--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/test.sql + +--echo ########################################################################## +--echo # Post recovery using mysqlbinlog # +--echo ########################################################################## +SHOW TABLES; +SELECT * FROM tm; +SELECT * FROM t; +--horizontal_results +SELECT f1(); +CALL simpleproc(@a); +SELECT @a; + +--echo "***** Clean Up *****" +DROP TABLE t,tm; +DROP PROCEDURE simpleproc; +DROP FUNCTION f1; +--remove_file $MYSQLTEST_VARDIR/tmp/test.sql +RESET MASTER; + +--echo ########################################################################## +--echo # Test verifies Gtid_log_event/Xid_log_event/Qery_log_event # +--echo # specific print along with flashback option # +--echo ########################################################################## +CREATE TABLE tm(f INT) ENGINE=MYISAM; +INSERT INTO tm VALUES (10); +INSERT INTO tm VALUES (20); +CREATE TABLE t(f INT) ENGINE=INNODB; +INSERT INTO t VALUES (10); +INSERT INTO t VALUES (20); +--echo ########################################################################## +--echo # Initial data # +--echo ########################################################################## +SELECT * FROM tm; +SELECT * FROM t; +FLUSH LOGS; +DELETE FROM tm WHERE f=20; +DELETE FROM t WHERE f=20; +FLUSH LOGS; + +--echo ########################################################################## +--echo # Data after deletion # +--echo ########################################################################## +SELECT * FROM tm; +SELECT * FROM t; +--exec $MYSQL_BINLOG --flashback $MYSQLD_DATADIR/master-bin.000002 > $MYSQLTEST_VARDIR/tmp/test.sql + +--let SEARCH_FILE=$MYSQLTEST_VARDIR/tmp/test.sql +--let SEARCH_PATTERN=START TRANSACTION +--source include/search_pattern_in_file.inc +--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/test.sql + +--echo ########################################################################## +--echo # Data after recovery using flashback # +--echo ########################################################################## +SELECT * FROM tm; +SELECT * FROM t; + +--echo "***** Clean Up *****" +DROP TABLE t,tm; +--remove_file $MYSQLTEST_VARDIR/tmp/test.sql 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 00000000..f305f611 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/binlog_stm_ps.test @@ -0,0 +1,57 @@ +--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; + + +--echo # +--echo # MDEV-16095 Oracle-style placeholder inside GROUP BY..WITH ROLLUP breaks replication +--echo # + +FLUSH LOGS; +CREATE TABLE t1 (d DATE); +INSERT INTO t1 VALUES ('1985-05-13'),('1989-12-24'); +CREATE TABLE t2 (d DATE, c BIGINT); +DELIMITER $$; +BEGIN + EXECUTE IMMEDIATE 'INSERT INTO t2 SELECT d, COUNT(*) FROM t1 GROUP BY d, :param' USING 1; + EXECUTE IMMEDIATE 'INSERT INTO t2 SELECT d, COUNT(*) FROM t1 GROUP BY d, :param WITH ROLLUP' USING 1; +END; +$$ +DELIMITER ;$$ +DROP TABLE t1,t2; +--let $binlog_file = LAST +source include/show_binlog_events.inc; 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 00000000..e6f33cb1 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/binlog_stm_sp.test @@ -0,0 +1,219 @@ +--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; + + +--echo # +--echo # MDEV-16020 SP variables inside GROUP BY..WITH ROLLUP break replication +--echo # + +FLUSH LOGS; +CREATE TABLE t1 (d DATE); +INSERT INTO t1 VALUES ('1985-05-13'),('1989-12-24'); +CREATE TABLE t2 (d DATE, c BIGINT); +DELIMITER $$; +DECLARE + var INT; +BEGIN + INSERT INTO t2 SELECT d, COUNT(*) FROM t1 GROUP BY d, var; + INSERT INTO t2 SELECT d, COUNT(*) FROM t1 GROUP BY d, var WITH ROLLUP; +END; +$$ +DELIMITER ;$$ +DROP TABLE t1,t2; + +--let $binlog_file = LAST +source include/show_binlog_events.inc; diff --git a/mysql-test/suite/compat/oracle/t/binlog_stm_sp_package.test b/mysql-test/suite/compat/oracle/t/binlog_stm_sp_package.test new file mode 100644 index 00000000..577ff58d --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/binlog_stm_sp_package.test @@ -0,0 +1,158 @@ +--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; + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE IF NOT EXISTS p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY p1 AS + PROCEDURE p1 AS + BEGIN + NULL; + END; + FUNCTION f1 RETURN INT AS + BEGIN + RETURN 10; + END; +END; +$$ +DELIMITER ;$$ + +DROP PACKAGE BODY p1; +DROP PACKAGE p1; +DROP PACKAGE IF EXISTS p1; + +--echo # +--echo # Creating a package with a COMMENT clause +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 COMMENT 'package-p1-comment' AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY p1 COMMENT 'package-body-p1-comment' AS + PROCEDURE p1 AS + BEGIN + NULL; + END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE p1; + +--echo # +--echo # Creating a package with a different DEFINER +--echo # + +DELIMITER $$; +CREATE DEFINER=xxx@localhost PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE DEFINER=xxx@localhost PACKAGE BODY p1 AS + PROCEDURE p1 AS + BEGIN + NULL; + END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE p1; + + +--echo # +--echo # Creating a package with a different DEFINER, with SQL SECURITY INVOKER +--echo # + +DELIMITER $$; +CREATE DEFINER=xxx@localhost PACKAGE p1 SQL SECURITY INVOKER AS + PROCEDURE p1; +END; +$$ +CREATE DEFINER=xxx@localhost PACKAGE BODY p1 SQL SECURITY INVOKER AS + PROCEDURE p1 AS + BEGIN + NULL; + END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE p1; + + +--echo # +--echo # Creating a new package in a remote database +--echo # + +CREATE DATABASE test2; + +DELIMITER $$; +CREATE PACKAGE test2.test2 COMMENT 'package-test2-comment' AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PACKAGE BODY test2.test2 COMMENT 'package-body-test2-comment' AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END; + PROCEDURE p1 AS BEGIN SELECT f1(); END; +END; +$$ +DELIMITER ;$$ + +DROP PACKAGE BODY test2.test2; +DROP PACKAGE test2.test2; +DROP DATABASE test2; + + +--echo # +--echo # MDEV-13139 Package-wide variables in CREATE PACKAGE +--echo # + +CREATE TABLE t1 (a INT); +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY p1 AS + a INT:=0; + PROCEDURE p1 AS + BEGIN + INSERT INTO t1 VALUES (a); + a:=a+1; + END; +BEGIN + a:=10; +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT * FROM t1; +--source sp-cache-invalidate.inc +CALL p1.p1(); +CALL p1.p1(); +SELECT * FROM t1; +DROP PACKAGE p1; +DROP TABLE t1; + + +--let $binlog_file = LAST +source include/show_binlog_events.inc; diff --git a/mysql-test/suite/compat/oracle/t/column_compression.test b/mysql-test/suite/compat/oracle/t/column_compression.test new file mode 100644 index 00000000..01d4977b --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/column_compression.test @@ -0,0 +1,85 @@ +--source include/have_innodb.inc +--source include/have_csv.inc +--source include/have_normal_bzip.inc + +SET sql_mode=ORACLE; + +SET column_compression_zlib_wrap=true; +CREATE TABLE t1 (a BLOB COMPRESSED); +INSERT INTO t1 VALUES (REPEAT('a',10000)); +SELECT DATA_LENGTH<100 AS c FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test'; +DROP TABLE t1; + +--echo # +--echo # MDEV-17363 - Compressed columns cannot be restored from dump +--echo # + +--error ER_WRONG_FIELD_SPEC +CREATE TABLE t1(a INT NOT NULL COMPRESSED); +SHOW WARNINGS; + +CREATE TABLE t1( + a JSON COMPRESSED, + b VARCHAR(1000) COMPRESSED BINARY, + c NVARCHAR(1000) COMPRESSED BINARY, + d TINYTEXT COMPRESSED BINARY +); +SHOW CREATE TABLE t1; +DROP TABLE t1; + + +--echo # +--echo # VARCHAR and TEXT variants +--echo # + +--let type=VARCHAR(10) +--source include/column_compression_syntax_varchar.inc + +--let type=VARCHAR2(10) +--source include/column_compression_syntax_varchar.inc + +--let type=TINYTEXT +--source include/column_compression_syntax_varchar.inc + +--let type=TEXT +--source include/column_compression_syntax_varchar.inc + +--let type=MEDIUMTEXT +--source include/column_compression_syntax_varchar.inc + +--let type=LONGTEXT +--source include/column_compression_syntax_varchar.inc + + +--echo # +--echo # VARBINARY and BLOB variables +--echo # + +--let type=VARCHAR(10) +--source include/column_compression_syntax_varbinary.inc + +--let type=TINYBLOB +--source include/column_compression_syntax_varbinary.inc + +--let type=BLOB +--source include/column_compression_syntax_varbinary.inc + +--let type=MEDIUMBLOB +--source include/column_compression_syntax_varbinary.inc + +--let type=LONGBLOB +--source include/column_compression_syntax_varbinary.inc + + +--echo # +--echo # NVARCHAR +--echo # + +CREATE TABLE t1 (a NVARCHAR(10) COMPRESSED); +SHOW CREATE TABLE t1; +DROP TABLE t1; +--error ER_PARSE_ERROR +CREATE TABLE t1 (a NVARCHAR(10) COMPRESSED BINARY COMPRESSED); +--error ER_PARSE_ERROR +CREATE TABLE t1 (a NVARCHAR(10) COMPRESSED DEFAULT '' COMPRESSED); diff --git a/mysql-test/suite/compat/oracle/t/custom_aggregate_functions.test b/mysql-test/suite/compat/oracle/t/custom_aggregate_functions.test new file mode 100644 index 00000000..0affc4ef --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/custom_aggregate_functions.test @@ -0,0 +1,170 @@ +SET sql_mode=ORACLE; + +delimiter |; +--error ER_INVALID_AGGREGATE_FUNCTION +create aggregate function f1(x INT) return INT AS +begin + insert into t1(sal) values (x); + return x; +end| + +--error ER_NOT_AGGREGATE_FUNCTION +create function f1(x INT) return INT AS +begin + set x=5; + fetch group next row; +return x+1; +end | + +DELIMITER ;| + + +CREATE TABLE marks(stud_id INT, grade_count INT); +INSERT INTO marks VALUES (1,6), (2,4), (3,7), (4,5), (5,8); +SELECT * FROM marks; + +--echo # Using PL/SQL syntax: EXCEPTION WHEN NO_DATA_FOUND + +DELIMITER //; +CREATE AGGREGATE FUNCTION IF NOT EXISTS aggregate_count(x INT) RETURN INT AS + count_students INT DEFAULT 0; +BEGIN + LOOP + FETCH GROUP NEXT ROW; + IF x THEN + count_students:= count_students + 1; + END IF; + END LOOP; +EXCEPTION + WHEN NO_DATA_FOUND THEN + RETURN count_students; +END aggregate_count // +DELIMITER ;// +SELECT aggregate_count(stud_id) FROM marks; +DROP FUNCTION IF EXISTS aggregate_count; + + +--echo # Using SQL/PSM systax: CONTINUE HANDLER + +DELIMITER //; +CREATE AGGREGATE FUNCTION IF NOT EXISTS aggregate_count(x INT) RETURN INT AS + count_students INT DEFAULT 0; + CONTINUE HANDLER FOR NOT FOUND RETURN count_students; +BEGIN + LOOP + FETCH GROUP NEXT ROW; + IF x THEN + SET count_students= count_students + 1; + END IF; + END LOOP; +END // +DELIMITER ;// +SELECT aggregate_count(stud_id) FROM marks; +DROP FUNCTION IF EXISTS aggregate_count; + + +DROP TABLE marks; + + +--echo # +--echo # MDEV-18813 PROCEDURE and anonymous blocks silently ignore FETCH GROUP NEXT ROW +--echo # + + +DELIMITER $$; +--error ER_NOT_AGGREGATE_FUNCTION +CREATE PROCEDURE p1 AS +BEGIN + FETCH GROUP NEXT ROW; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_NOT_AGGREGATE_FUNCTION +BEGIN NOT ATOMIC + FETCH GROUP NEXT ROW; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_NOT_AGGREGATE_FUNCTION +CREATE DEFINER=root@localhost FUNCTION f1 RETURN INT AS +BEGIN + FETCH GROUP NEXT ROW; + RETURN 0; +END; +$$ +DELIMITER ;$$ + + +CREATE TABLE t1 (a INT); +--error ER_NOT_AGGREGATE_FUNCTION +CREATE TRIGGER tr1 + AFTER INSERT ON t1 FOR EACH ROW + FETCH GROUP NEXT ROW; +DROP TABLE t1; + + +--error ER_NOT_AGGREGATE_FUNCTION +CREATE EVENT ev1 + ON SCHEDULE EVERY 1 HOUR + STARTS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + ENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + INTERVAL 1 WEEK +DO FETCH GROUP NEXT ROW; + + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ + +--error ER_NOT_AGGREGATE_FUNCTION +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS + BEGIN + FETCH GROUP NEXT ROW; -- In a package procedure + END; + FUNCTION f1 RETURN INT AS + BEGIN + RETURN 0; + END; +END; +$$ + +--error ER_NOT_AGGREGATE_FUNCTION +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS + BEGIN + NULL; + END; + FUNCTION f1 RETURN INT AS + BEGIN + FETCH GROUP NEXT ROW; -- In a package function + RETURN 0; + END; +END; +$$ + +--error ER_NOT_AGGREGATE_FUNCTION +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS + BEGIN + NULL; + END; + FUNCTION f1 RETURN INT AS + BEGIN + RETURN 0; + END; +BEGIN + FETCH GROUP NEXT ROW; -- In a package executable section +END; +$$ + +DELIMITER ;$$ +DROP PACKAGE pkg1; diff --git a/mysql-test/suite/compat/oracle/t/empty_string_literal.test b/mysql-test/suite/compat/oracle/t/empty_string_literal.test new file mode 100644 index 00000000..3c612f72 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/empty_string_literal.test @@ -0,0 +1,8 @@ +USE test; +--echo # +--echo # MDEV-14013 : sql_mode=EMPTY_STRING_IS_NULL +--echo # + +set @mode='ORACLE,EMPTY_STRING_IS_NULL'; + +--source include/empty_string_literal.inc diff --git a/mysql-test/suite/compat/oracle/t/events.test b/mysql-test/suite/compat/oracle/t/events.test new file mode 100644 index 00000000..fb56af51 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/events.test @@ -0,0 +1,37 @@ +-- source include/not_embedded.inc + +set sql_mode='ORACLE'; + +--echo # +--echo # MDEV-16891 EVENTs created with SQL_MODE=ORACLE fail to execute +--echo # + +SET GLOBAL event_scheduler=off; + +SET sql_mode='ORACLE'; +CREATE TABLE t1 (a TIMESTAMP); +CREATE EVENT e1 + ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 MICROSECOND + DO INSERT INTO t1 VALUES(NOW()); +SET GLOBAL event_scheduler=on; + +let $wait_timeout = 10; +let $wait_condition = + SELECT COUNT(*) = 0 + FROM INFORMATION_SCHEMA.EVENTS + WHERE event_schema = 'test' AND event_name = 'e1'; +--source include/wait_condition.inc + +SELECT COUNT(*) FROM t1; +DROP TABLE t1; + +SET GLOBAL event_scheduler=off; + +--echo # +--echo # MDEV-28588 SIGSEGV in __memmove_avx_unaligned_erms, strmake_root +--echo # +CREATE EVENT ev ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO BEGIN END; +--vertical_results +SELECT EVENT_DEFINITION FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='test' AND EVENT_NAME='ev'; +--horizontal_results +DROP EVENT ev; 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 00000000..6448a6ef --- /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_add_months.test b/mysql-test/suite/compat/oracle/t/func_add_months.test new file mode 100644 index 00000000..ca9391ef --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_add_months.test @@ -0,0 +1,38 @@ +--echo Test for ADD_MONTHS + +CREATE TABLE t1(c1 int, c2 datetime, c3 date, c4 time, c5 timestamp); + +INSERT INTO t1 VALUES (1, '2011-11-12 12:10:11', '2011-11-12', '12:10:11', '2011-11-12 12:10:11'); +INSERT INTO t1 VALUES (2, '2021-11-12 00:23:12', '2021-11-12', '00:23:12', '2021-11-12 00:23:12'); +INSERT INTO t1 VALUES (3, '2011-01-22 16:45:45', '2011-01-22', '16:45:45', '2011-01-22 16:45:45'); +INSERT INTO t1 VALUES (4, '2031-05-12 04:11:34', '2031-05-12', '04:11:34', '2031-05-12 04:11:34'); +INSERT INTO t1 VALUES (5, '2031-09-02 08:15:22', '2031-09-02', '08:15:22', '2031-09-02 08:15:22'); +INSERT INTO t1 VALUES (6, '0000-09-02 00:00:00', '0000-09-02', '00:00:00', '1980-09-02 00:00:00'); +INSERT INTO t1 VALUES (7, '9999-09-02', '9999-09-02', '00:00:00', '1980-09-02'); + +# some normal case +SELECT c1, ADD_MONTHS(c2, 2), ADD_MONTHS(c3, 2), ADD_MONTHS(c5, 2) FROM t1; +SELECT c1, ADD_MONTHS(c2, 15), ADD_MONTHS(c3, 200), ADD_MONTHS(c5, 2000) FROM t1; +SELECT c1, ADD_MONTHS(c2, 0), ADD_MONTHS(c3, -200), ADD_MONTHS(c5, -2) FROM t1; +SELECT c1, ADD_MONTHS(c2, -15), ADD_MONTHS(c3, -111), ADD_MONTHS(c5, 2) FROM t1; + +# for time type, it will be overflow +SELECT ADD_MONTHS(c4, 11) FROM t1 WHERE c1 = 1; + +UPDATE t1 SET c2=ADD_MONTHS(c2, 2); +SELECT c2 FROM t1; + +EXPLAIN EXTENDED SELECT c1, ADD_MONTHS(c2, -15) FROM t1 WHERE c1 = 1; + +# string type can be convert to datetime type +SELECT ADD_MONTHS("2000-10-10", 12); +SELECT ADD_MONTHS("2000:10:10", 12); + +# number type can not be convert datetime type +SELECT ADD_MONTHS(2000, 12); + +# last day of the month +SELECT ADD_MONTHS('2011-01-31', 1), ADD_MONTHS('2012-01-31', 1), ADD_MONTHS('2012-01-31', 2), ADD_MONTHS('2012-01-31', 3); +SELECT ADD_MONTHS('2011-01-30', 1), ADD_MONTHS('2012-01-30', 1), ADD_MONTHS('2012-01-30', 2), ADD_MONTHS('2012-01-30', 3); + +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 00000000..d5e0d650 --- /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 00000000..5a613242 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_concat.test @@ -0,0 +1,184 @@ +# +# 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; + + +--echo # +--echo # MDEV-16186 Concatenation operator || returns wrong results in sql_mode=ORACLE +--echo # + +# Concatenation operator || has the same precedence with + +# (stronger than << and weaker than * ^) + +SELECT -1<<1||1 AS a FROM DUAL; +SELECT -1||0<<1 AS a FROM DUAL; + +EXPLAIN EXTENDED SELECT -1<<1||1 AS a FROM DUAL; +EXPLAIN EXTENDED SELECT -1||0<<1 AS a FROM DUAL; + +SELECT -1+1||1 AS a FROM DUAL; +SELECT -1||0+1 AS a FROM DUAL; + +EXPLAIN EXTENDED SELECT -1+1||1 AS a FROM DUAL; +EXPLAIN EXTENDED SELECT -1||0+1 AS a FROM DUAL; + +SELECT 1*1||-1 AS a FROM DUAL; +SELECT 1||1*-1 AS a FROM DUAL; + +EXPLAIN EXTENDED SELECT 1*1||-1 AS a FROM DUAL; +EXPLAIN EXTENDED SELECT 1||1*-1 AS a FROM DUAL; + +SELECT -1^1||1 AS a FROM DUAL; +SELECT -1||0^1 AS a FROM DUAL; + +EXPLAIN EXTENDED SELECT -1^1||1 AS a FROM DUAL; +EXPLAIN EXTENDED SELECT -1||0^1 AS a FROM DUAL; + + +--echo # +--echo # MDEV-17359 Concatenation operator || in like expression failed in sql_mode=ORACLE +--echo # + +SELECT 'abc' LIKE 'a'||'%'; +EXPLAIN EXTENDED SELECT 'abc' LIKE 'a'||'%'; + +SELECT 'x' FROM DUAL WHERE 11 LIKE 1||1; +SELECT 'x' FROM DUAL WHERE 1||1 LIKE 11; +SELECT 'x' FROM DUAL WHERE 1||1 LIKE 1||1; + +CREATE TABLE t1 (c1 VARCHAR(10),c2 VARCHAR(10), ord INTEGER); +INSERT INTO t1 VALUES ('a', 'ab' ,1); +INSERT INTO t1 VALUES ('ab', 'ab', 2); +INSERT INTO t1 VALUES ('abc', 'ab', 3); + +SELECT c1 FROM t1 WHERE c1 LIKE '%'||'b' ORDER BY ord; +EXPLAIN EXTENDED SELECT c1 FROM t1 WHERE c1 LIKE '%'||'b' ORDER BY ord; + +SELECT c1 FROM t1 WHERE c1 LIKE c2||'%'||'c' ORDER BY ord; +EXPLAIN EXTENDED SELECT c1 FROM t1 WHERE c1 LIKE c2||'%'||'c' ORDER BY ord; + +SELECT 'x' FROM t1 WHERE c1||c2 LIKE 'aa%'; +EXPLAIN EXTENDED SELECT 'x' FROM t1 WHERE c1||c2 LIKE 'aa%'; + +SELECT 'x' FROM t1 WHERE c1||c2 LIKE c2||c1; +EXPLAIN EXTENDED SELECT 'x' FROM t1 WHERE c1||c2 LIKE c2||c1; + +CREATE VIEW v1 AS SELECT c1, c2, c1 LIKE c2||'_' FROM t1 ORDER BY ord; +SELECT * FROM v1; +EXPLAIN EXTENDED SELECT * FROM v1; + +DROP VIEW v1; +DROP TABLE t1; 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 00000000..b8be7178 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_decode.test @@ -0,0 +1,98 @@ +SET sql_mode=ORACLE; + +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT DECODE(10); +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +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; + + +--echo # +--echo # MDEV-13863 sql_mode=ORACLE: DECODE does not treat two NULLs as equivalent +--echo # + +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT DECODE(10); +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT DECODE(10,10); + +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT DECODE_ORACLE(10); +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT DECODE_ORACLE(10,10); + + +EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11'); +EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11','def'); +EXPLAIN EXTENDED SELECT DECODE_ORACLE(12,10,'x10',11,'x11'); +EXPLAIN EXTENDED SELECT DECODE_ORACLE(12,10,'x10',11,'x11','def'); + +CREATE TABLE t1 (a INT); +CREATE VIEW v1 AS + SELECT + DECODE(a,1,'x1',NULL,'xNULL') AS d1, + DECODE(a,1,'x1',NULL,'xNULL','xELSE') AS d2, + DECODE_ORACLE(a,1,'x1',NULL,'xNULL') AS d3, + DECODE_ORACLE(a,1,'x1',NULL,'xNULL','xELSE') AS d4 + FROM t1; +SHOW CREATE VIEW v1; +DROP VIEW v1; +DROP TABLE t1; + +SELECT DECODE(TIME'10:20:31','10:20:31','then1','10:20:32','then2','def'); +SELECT DECODE(TIME'10:20:32','10:20:31','then1','10:20:32','then2','def'); +SELECT DECODE(TIME'10:20:33','10:20:31','then1',NULL,'then2NULL','10:20:33','then3','def'); +SELECT DECODE(NULL,TIME'10:20:31','then1',NULL,'then2NULL','10:20:33','then3','def'); + +SELECT DECODE(TIMESTAMP'2001-01-01 10:20:31','2001-01-01 10:20:31','then1','2001-01-01 10:20:32','then2','def'); +SELECT DECODE(TIMESTAMP'2001-01-01 10:20:32','2001-01-01 10:20:31','then1','2001-01-01 10:20:32','then2','def'); +SELECT DECODE(TIMESTAMP'2001-01-01 10:20:33','2001-01-01 10:20:31','then1',NULL,'then2NULL','2001-01-01 10:20:33','then3','def'); +SELECT DECODE(NULL,TIMESTAMP'2001-01-01 10:20:31','then1',NULL,'then2NULL','2001-01-01 10:20:33','then3','def'); + +SELECT DECODE('w1','w1','then1','w2','then2','def'); +SELECT DECODE('w2','w1','then1','w2','then2','def'); +SELECT DECODE('w3','w1','then1',NULL,'then2NULL','w3','then3','def'); +SELECT DECODE(NULL,'w1','then1',NULL,'then2NULL','w3','then3','def'); + +SELECT DECODE(1,1,'then1',2,'then2','def'); +SELECT DECODE(2,1,'then1',2,'then2','def'); +SELECT DECODE(3,1,'then1',NULL,'then2NULL',3,'then3','def'); +SELECT DECODE(NULL,1,'then1',NULL,'then2NULL',3,'then3','def'); +SELECT DECODE(CAST(NULL AS SIGNED),1,'then1',NULL,'then2NULL',3,'then3','def'); + +SELECT DECODE(1.0,1.0,'then1',2.0,'then2','def'); +SELECT DECODE(2.0,1.0,'then1',2.0,'then2','def'); +SELECT DECODE(3.0,1.0,'then1',NULL,'then2NULL',3.0,'then3','def'); +SELECT DECODE(NULL,1.0,'then1',NULL,'then2NULL',3.0,'then3','def'); +SELECT DECODE(CAST(NULL AS DECIMAL),1.0,'then1',NULL,'then2NULL',3.0,'then3','def'); + +SELECT DECODE(1e0,1e0,'then1',2e0,'then2','def'); +SELECT DECODE(2e0,1e0,'then1',2e0,'then2','def'); +SELECT DECODE(3e0,1e0,'then1',NULL,'then2NULL',3e0,'then3','def'); +SELECT DECODE(NULL,1e0,'then1',NULL,'then2NULL',3e0,'then3','def'); +SELECT DECODE(CAST(NULL AS DOUBLE),1e0,'then1',NULL,'then2NULL',3e0,'then3','def'); + +SELECT DECODE(NULL,NULL,1,2) FROM DUAL; +SELECT DECODE(NULL,10,10,NULL,1,2) FROM DUAL; + +SELECT DECODE_ORACLE(NULL,NULL,1,2) FROM DUAL; +SELECT DECODE_ORACLE(NULL,10,10,NULL,1,2) FROM DUAL; + +CREATE OR REPLACE TABLE t1 (a VARCHAR(10) DEFAULT NULL); +INSERT INTO t1 VALUES (NULL),(1); +SELECT a, DECODE(a,NULL,1,2) FROM t1; +DROP TABLE t1; 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 00000000..7b76d33a --- /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 00000000..c5b42134 --- /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/func_pad.test b/mysql-test/suite/compat/oracle/t/func_pad.test new file mode 100644 index 00000000..bc33a9fa --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_pad.test @@ -0,0 +1,31 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-15739 - sql_mode=ORACLE: Make LPAD and RPAD return NULL instead of empty string +--echo # + +SELECT RPAD('a',0), RPAD('abc',1), RPAD('abc',2) ; +SELECT RPAD('a',0,'.'), RPAD('abc',1,'.'), RPAD('abc',2,'.') ; +SELECT LPAD('a',0), LPAD('abc',1), LPAD('abc',2) ; +SELECT LPAD('a',0,'.'), LPAD('abc',1,'.'), LPAD('abc',2,'.') ; + +CREATE TABLE t1 (c1 VARCHAR(10),c2 INTEGER, c3 VARCHAR(10), ord INTEGER); +INSERT INTO t1 VALUES ('a',1,null,1); +INSERT INTO t1 VALUES ('a',null,'.',2); +INSERT INTO t1 VALUES (null,1,'.',3); +INSERT INTO t1 VALUES ('a',-1,'.',4); +INSERT INTO t1 VALUES ('a',0,'.',5); +INSERT INTO t1 VALUES ('a',1,'.',6); +INSERT INTO t1 VALUES ('a',2,'.',7); + +SELECT LPAD(c1,c2,c3), LPAD(c1,c2) FROM t1 ORDER BY ord; +SELECT RPAD(c1,c2,c3), RPAD(c1,c2) FROM t1 ORDER BY ord; + +EXPLAIN EXTENDED SELECT RPAD('a',0,'.'), LPAD('a',0,'.'), LPAD(c1,c2,c3), LPAD(c1,c2), RPAD(c1,c2,c3), RPAD(c1,c2) FROM t1 ORDER BY ord; + +CREATE VIEW v1 AS SELECT RPAD('a',0,'.') AS "C1", LPAD('a',0,'.') AS "C2", LPAD(c1,c2,c3) AS "C3", LPAD(c1,c2) AS "C4", RPAD(c1,c2,c3) AS "C5", RPAD(c1,c2) AS "C6" FROM t1 ORDER BY ord; +SHOW CREATE VIEW v1; +SELECT * FROM v1; +SELECT c1||'-'||c2||'-'||c3||'-'||c4||'-'||c5||'-'||c6 FROM v1; +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/suite/compat/oracle/t/func_replace.test b/mysql-test/suite/compat/oracle/t/func_replace.test new file mode 100644 index 00000000..0028f7d2 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_replace.test @@ -0,0 +1,22 @@ +# +# Testing replace with null args +# + +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-13003 - Oracle compatibility : Replace function +--echo # + +SELECT REPLACE(null,'a','b') ; +SELECT REPLACE('ab',null,'b') ; +SELECT REPLACE('ab','a',null) ; +SELECT REPLACE('ab',null,null) ; +SELECT REPLACE('aaa','a',null) ; + +EXPLAIN EXTENDED SELECT REPLACE('ab','a',null) ; + +CREATE VIEW v1 AS SELECT REPLACE('ab','a',null) ; +SHOW CREATE VIEW v1; +SELECT * FROM v1; +DROP VIEW v1; diff --git a/mysql-test/suite/compat/oracle/t/func_substr.test b/mysql-test/suite/compat/oracle/t/func_substr.test new file mode 100644 index 00000000..b661dfd3 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_substr.test @@ -0,0 +1,47 @@ +--echo # +--echo # MDEV-14012 - sql_mode=Oracle: substr(): treat position 0 as position 1 +--echo # MDEV-10574 - sql_mode=Oracle: return null instead of empty string +--echo # + +SET sql_mode=ORACLE; +SELECT SUBSTR('abc',2,1),SUBSTR('abc',1,1), SUBSTR('abc',0,1) FROM dual; +SELECT SUBSTR('abc',2),SUBSTR('abc',1), SUBSTR('abc',0) FROM dual; +SELECT SUBSTR(null,2,1),SUBSTR(null,1), SUBSTR(null,0) FROM dual; +SELECT SUBSTR('abc',-2),SUBSTR('abc',-1), SUBSTR('abc',-0) FROM dual; +SELECT SUBSTR('abc',-2,1),SUBSTR('abc',-1,1), SUBSTR('abc',-0,1) FROM dual; +SELECT SUBSTR('abc',null) FROM dual; +SELECT SUBSTR('abc',2,null),SUBSTR('abc',1,null), SUBSTR('abc',0,null) FROM dual; +SELECT SUBSTR('abc',2,0),SUBSTR('abc',1,0), SUBSTR('abc',0,0) FROM dual; +SELECT SUBSTR('abc',2,-1),SUBSTR('abc',1,-1), SUBSTR('abc',0,-1) FROM dual; +SELECT SUBSTR(SPACE(0),1) FROM DUAL; + +CREATE TABLE t1 (c1 VARCHAR(10),start INTEGER, length INTEGER); +INSERT INTO t1 VALUES ('abc', 1, 1); +INSERT INTO t1 VALUES ('abc', 0, 1); +INSERT INTO t1 VALUES (null, 1, 1); +INSERT INTO t1 VALUES (null, 0, 1); +INSERT INTO t1 VALUES ('abc', 1, 0); +INSERT INTO t1 VALUES ('abc', 0, 0); +INSERT INTO t1 VALUES (null, 1, 0); +INSERT INTO t1 VALUES (null, 0, 0); +INSERT INTO t1 VALUES ('abc', 1, -1); +INSERT INTO t1 VALUES ('abc', 0, -1); +INSERT INTO t1 VALUES (null, 1, -1); +INSERT INTO t1 VALUES (null, 0, -1); +INSERT INTO t1 VALUES (SPACE(0), 0, 1); + +SELECT SUBSTR(c1,start,length) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c1 VARCHAR(10) NOT NULL); +CREATE TABLE t2 AS SELECT SUBSTR(C1,1,1) AS C1 from t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + +EXPLAIN EXTENDED SELECT SUBSTR('abc',2,1) ; + +CREATE VIEW v1 AS SELECT SUBSTR('abc',2,1) ; +SHOW CREATE VIEW v1; +SELECT * FROM v1; +DROP VIEW v1; diff --git a/mysql-test/suite/compat/oracle/t/func_time.test b/mysql-test/suite/compat/oracle/t/func_time.test new file mode 100644 index 00000000..c1174f7f --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_time.test @@ -0,0 +1,25 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-16152 Expressions with INTERVAL return bad results in some cases +--echo # + +SELECT TIMESTAMP'2001-01-01 10:20:30' - INTERVAL '10' YEAR AS c1, + -INTERVAL '10' YEAR + TIMESTAMP'2001-01-01 10:20:30' AS c2; + +SELECT TIMESTAMP'2001-01-01 10:20:30' + INTERVAL '10' YEAR AS c1, + INTERVAL '10' YEAR + TIMESTAMP'2001-01-01 10:20:30' AS c2, + +INTERVAL '10' YEAR + TIMESTAMP'2001-01-01 10:20:30' AS c3; + +EXPLAIN EXTENDED SELECT + TIMESTAMP'2001-01-01 10:20:30' - INTERVAL '10' YEAR AS c1, + -INTERVAL '10' YEAR + TIMESTAMP'2001-01-01 10:20:30' AS c2; + +EXPLAIN EXTENDED SELECT + TIMESTAMP'2001-01-01 10:20:30' + INTERVAL '10' YEAR AS c1, + INTERVAL '10' YEAR + TIMESTAMP'2001-01-01 10:20:30' AS c2, + +INTERVAL '10' YEAR + TIMESTAMP'2001-01-01 10:20:30' AS c3; diff --git a/mysql-test/suite/compat/oracle/t/func_to_char.test b/mysql-test/suite/compat/oracle/t/func_to_char.test new file mode 100644 index 00000000..7a403215 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_to_char.test @@ -0,0 +1,236 @@ +############################################################## +# testcase for TO_CHAR() function for oracle +# Part of MDEV-20017 Implement TO_CHAR() Oracle compatible function +############################################################## + +# Save sql_mode +set @save_sql_mode=@@sql_mode; + +--echo # +--echo # test for datetime +--echo # + +CREATE TABLE t_to_char1(c0 int, c1 date, c2 time, c3 datetime); + +INSERT INTO t_to_char1 VALUES (1, '1000-1-1', '00:00:00', '1000-1-1 00:00:00'); +INSERT INTO t_to_char1 VALUES (2, '9999-12-31', '23:59:59', '9999-12-31 23:59:59'); +INSERT INTO t_to_char1 VALUES (3, '2021-01-03', '08:30:00', '2021-01-03 08:30:00'); +INSERT INTO t_to_char1 VALUES (4, '2021-07-03', '18:30:00', '2021-07-03 18:30:00'); + +CREATE TABLE t_to_char2(c1 timestamp); +INSERT INTO t_to_char2 VALUES ('1980-01-11 04:50:39'); +INSERT INTO t_to_char2 VALUES ('2000-11-11 12:50:00'); +INSERT INTO t_to_char2 VALUES ('2030-11-11 18:20:10'); + +# test for timestamp +SELECT TO_CHAR(c1, 'YYYY-MM-DD') FROM t_to_char2; +SELECT TO_CHAR(c1, 'HH24-MI-SS') FROM t_to_char2; + +# test full output format +--echo # +--echo # test YYYY/YY/MM/DD/HH/HH24/MI/SS +--echo # +SELECT TO_CHAR(c1, 'YYYY-MM-DD') AS C1, TO_CHAR(c2, 'HH:MI:SS') AS C2, TO_CHAR(c3, 'YY-MM-DD HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'yyyy-mm-dd') AS C1, TO_CHAR(c2, 'hh:mi:ss') AS C2, TO_CHAR(c3, 'yy-mm-dd hh24:mi:ss') AS C3 FROM t_to_char1; + +--echo # +--echo # test YYY/Y/MON/DD/DY/HH/HH12/MI/SS +--echo # +SELECT TO_CHAR(c1, 'YYY-MON-DD') AS C1, TO_CHAR(c2, 'HH12:MI:SS') AS C2, TO_CHAR(c3, 'Y-MONTH-DY HH:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'yyy-Mon-Dd') AS C1, TO_CHAR(c2, 'Hh12:mi:Ss') AS C2, TO_CHAR(c3, 'y-Month-Dy Hh:Mi:Ss') AS C3 FROM t_to_char1; + +--echo # +--echo # test RRRR/RR/DAY +--echo # +SELECT TO_CHAR(c1, 'RRRR-MM-DD') AS C1, TO_CHAR(c2, 'HH:MI:SS') AS C2, TO_CHAR(c3, 'RRRR-MM-DD HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'RR-MM-DD') AS C1, TO_CHAR(c2, 'HH:MI:SS') AS C2, TO_CHAR(c3, 'YY-MM-DD HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'Rrrr-Mm-Dd') AS C1, TO_CHAR(c2, 'hh:mi:ss') AS C2, TO_CHAR(c3, 'Rrrr-mm-dd Hh24:mi:ss') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'rr-mm-dd') AS C1, TO_CHAR(c2, 'hh:mi:ss') AS C2, TO_CHAR(c3, 'yy-mm-dd hh24:Mi:ss') AS C3 FROM t_to_char1; + +--echo # +--echo # test AD/A.D./BC/B.C./AM/A.M./PM/P.M. +--echo # +SELECT TO_CHAR(c1, 'ADYYYY-MM-DD') AS C1, TO_CHAR(c2, 'HH:MI:SS') AS C2, TO_CHAR(c3, 'AD.YYYY-MM-DD HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'A.D.YYYY-MM-DD') AS C1, TO_CHAR(c2, 'HH:MI:SS') AS C2, TO_CHAR(c3, 'A.D..YYYY-MM-DD HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'ADYYYY-MM-DD') AS C1, TO_CHAR(c2, 'HH:MI:SS') AS C2, TO_CHAR(c3, 'AD.YYYY-MM-DD HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'A.D.YYYY-MM-DD') AS C1, TO_CHAR(c2, 'HH:MI:SS') AS C2, TO_CHAR(c3, 'A.D..YYYY-MM-DD HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'BCYYYY-MM-DD') AS C1, TO_CHAR(c2, 'HH:MI:SS') AS C2, TO_CHAR(c3, 'BCYYYY-MM-DD HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'B.C.YYYY-MM-DD') AS C1, TO_CHAR(c2, 'HH:MI:SS') AS C2, TO_CHAR(c3, 'B.C.YYYY-MM-DD HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'bcyyyy-mm-dd') AS C1, TO_CHAR(c2, 'hh:mi:ss') AS C2, TO_CHAR(c3, 'BcYYyy-MM-DD Hh24:mi:sS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'b.c.yyyy-mm-dd') AS C1, TO_CHAR(c2, 'hh:mI:Ss') AS C2, TO_CHAR(c3, 'b.C.Yyyy-Mm-dd hH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'A.D.YYYY-MM-DD') AS C1, TO_CHAR(c2, 'PMHH:MI:SS') AS C2, TO_CHAR(c3, 'A.D..YYYY-MM-DD P.M.HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'A.D.YYYY-MM-DD') AS C1, TO_CHAR(c2, 'pmHH:MI:SS') AS C2, TO_CHAR(c3, 'A.D..YYYY-MM-DD p.m.HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'A.D.YYYY-MM-DD') AS C1, TO_CHAR(c2, 'AMHH:MI:SS') AS C2, TO_CHAR(c3, 'A.D..YYYY-MM-DD A.m.HH24:MI:SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'A.D.YYYY-MM-DD') AS C1, TO_CHAR(c2, 'amHH:MI:SS') AS C2, TO_CHAR(c3, 'A.D..YYYY-MM-DD a.M.HH24:MI:SS') AS C3 FROM t_to_char1; + +--echo # +--echo # test format without order +--echo # +SELECT TO_CHAR(c1, 'MM-YYYY-DD') AS C1, TO_CHAR(c2, 'HH:SS:MI') AS C2, TO_CHAR(c3, 'DD-YY-MM MI:SS:HH24') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'yyy-Dd-Mon') AS C1, TO_CHAR(c2, 'mi:Hh12:Ss') AS C2, TO_CHAR(c3, 'Ss:Hh:Mi Dy-y-Month') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'Dd-Mm-Rrrr') AS C1, TO_CHAR(c2, 'ss:hh:mi') AS C2, TO_CHAR(c3, 'ss:Rrrr-hh24-dd mon:mi') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'YYYYA.D.-MM-DD') AS C1, TO_CHAR(c2, 'HH:MI:SS') AS C2, TO_CHAR(c3, 'A.D..YYYY-MM-DD HH24:MI:SS') AS C3 FROM t_to_char1; + +--echo # +--echo # test for special characters +--echo # +SELECT TO_CHAR(c1, 'YYYYMMDD') AS C1, TO_CHAR(c2, 'HHMISS') AS C2, TO_CHAR(c3, 'YYMMDDHH24MISS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'YYYY!!MM@DD') AS C1, TO_CHAR(c2, 'HH#MI$SS') AS C2, TO_CHAR(c3, 'YY%MM^DD*HH24(MI)SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'YYYY_MM+DD') AS C1, TO_CHAR(c2, 'HH=MI{SS') AS C2, TO_CHAR(c3, 'YY}MMDDHH24MISS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'YYYY,MM.DD') AS C1, TO_CHAR(c2, 'HH/MI;SS') AS C2, TO_CHAR(c3, 'YY>MM<DD]HH24[MI\SS') AS C3 FROM t_to_char1; +SELECT TO_CHAR(c1, 'YYYY||||MM|DD') AS C1, TO_CHAR(c2, 'HH&|MI|&|SS') AS C2, TO_CHAR(c3, 'YY&&&\\MM|&&|DD HH24|| MI&||"abx"|SS') AS C3 FROM t_to_char1; +--error ER_STD_INVALID_ARGUMENT +SELECT TO_CHAR(c1, 'YYYY&MM-DD') FROM t_to_char1 where c0=1; +SELECT TO_CHAR(c1, 'YYYY"abx"MM"bsz"DD') AS C1 FROM t_to_char1; + +--echo # +--echo # test for other locale +--echo # +SET character_set_client='utf8'; +SET character_set_connection='utf8'; +SET character_set_results='utf8'; +SET lc_time_names='zh_TW'; +SELECT TO_CHAR(c1, 'YYYY-MON-DAY') FROM t_to_char1; +SET lc_time_names='de_DE'; +SELECT TO_CHAR(c1, 'YYYY-MON-DAY') FROM t_to_char1; +SET lc_time_names='en_US'; +SELECT TO_CHAR(c1, 'YYYY-MON-DAY') FROM t_to_char1; +SET lc_time_names='zh_CN'; +SELECT TO_CHAR(c1, 'YYYY-MON-DAY') FROM t_to_char1; + +--echo # +--echo # test for invalid format +--echo # + +--error ER_STD_INVALID_ARGUMENT +SELECT TO_CHAR(c1, 'YYYYaxMON-DAY') FROM t_to_char1 where c0 = 1; +--error ER_STD_INVALID_ARGUMENT +SELECT TO_CHAR(c1, 'YYYY\nMON-DAY') FROM t_to_char1 where c0 = 1; +--error ER_STD_INVALID_ARGUMENT +SELECT TO_CHAR(c1, 'YYYY\rMON-DAY') FROM t_to_char1 where c0 = 1; +--error ER_STD_INVALID_ARGUMENT +SELECT TO_CHAR(c1, 'YYYY分隔MON-DAY') FROM t_to_char1 where c0 = 1; +--error ER_STD_INVALID_ARGUMENT +SELECT TO_CHAR(c1, 'YYYY-分隔MON-DAY') FROM t_to_char1 where c0 = 1; +--error ER_STD_INVALID_ARGUMENT +select to_char(c3, 'YYYYxDDD') from t_to_char1 where c0 = 1; +--error ER_STD_INVALID_ARGUMENT +select to_char(c3, 'YYYY&DDD') from t_to_char1 where c0 = 1; +--error ER_STD_INVALID_ARGUMENT +select to_char(c3, 'xxYYYY-DD') from t_to_char1 where c0 = 1; + +SET character_set_client='latin1'; +SET character_set_connection='latin1'; +SET character_set_results='latin1'; +--echo # +--echo # test for unusual format +--echo # +select to_char(c3, 'YYYYYYYYYYYYYYY') from t_to_char1; +select to_char(c3, 'YYYYYYYYYYYYYYYDDDDDD') from t_to_char1; + +--echo # +--echo # oracle max length is 144 +--echo # + +--error ER_STD_INVALID_ARGUMENT +select to_char(c3, 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY') from t_to_char1 where c0 = 1; +CREATE TABLE t_f(c1 varchar(150)); +insert into t_f values('YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY-DD'); +select to_char('2000-11-11', c1) from t_f; +DROP TABLE t_f; +select to_char(c3, 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY-DD-MM') from t_to_char1 where c0 = 1; + +--echo # +--echo # now only support two parameter. +--echo # +select to_char(c3) from t_to_char1 where c0 =1; +select to_char(c3, "YYYY-MM-DD HH:MI:SS") from t_to_char1 where c0 =1; +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +select to_char(c3, "YYYY-MM-DD HH:MI:SS", "zh_CN") from t_to_char1 where c0 = 1; +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +select to_char(c3, "YYYY-MM-DD HH:MI:SS", "NLS_DATE_LANGUAGE = zh_CN") from t_to_char1 where c0 = 1; + +--echo # +--echo # oracle support format but mariadb does not support +--echo # +--error ER_STD_INVALID_ARGUMENT +select to_char(c3, 'DDD') from t_to_char1 where c0 = 1; +--error ER_STD_INVALID_ARGUMENT +select to_char(c3, 'D') from t_to_char1 where c0 = 1; +--error ER_STD_INVALID_ARGUMENT +select to_char(c3, 'DS') from t_to_char1 where c0 = 1; +--error ER_STD_INVALID_ARGUMENT +select to_char(c3, 'IY') from t_to_char1 where c0 = 1; +--error ER_STD_INVALID_ARGUMENT +select to_char(c3, 'IYYY') from t_to_char1 where c0 = 1; + +--echo # +--echo # test for first argument data type +--echo # +--error ER_STD_INVALID_ARGUMENT +select to_char(1, 'yyyy'); +--error ER_STD_INVALID_ARGUMENT +select to_char(1.1, 'yyyy'); +CREATE TABLE t_a(c1 int, c2 float, c3 decimal, c4 char(20), c5 varchar(20), c6 nchar(20), c7 nvarchar(20)); +insert into t_a VALUES (1, 3.2, 2002.02, '2000-11-11', '2000-11-11', '2000-11-11', '2000-11-11'); +--error ER_STD_INVALID_ARGUMENT +SELECT TO_CHAR(c1, 'YYYY') from t_a; +--error ER_STD_INVALID_ARGUMENT +SELECT TO_CHAR(c2, 'YYYY') from t_a; +--error ER_STD_INVALID_ARGUMENT +SELECT TO_CHAR(c3, 'YYYY') from t_a; +SELECT TO_CHAR(c4, 'YYYY') from t_a; +SELECT TO_CHAR(c5, 'YYYY') from t_a; +SELECT TO_CHAR(c6, 'YYYY') from t_a; +SELECT TO_CHAR(c7, 'YYYY') from t_a; +DROP TABLE t_a; + +CREATE TABLE t_b(c0 int, c1 char(20), c2 varchar(20), c3 nchar(20), c4 nvarchar(20)); +INSERT INTO t_b VALUES (1111, 'YYYY-MM-DD', 'YYYY-MM-DD', 'YYYY-MM-DD', 'YYYY-MM-DD'); +SELECT TO_CHAR('2000-11-11', c0) FROM t_b; +SELECT TO_CHAR('2000-11-11', c1) FROM t_b; +SELECT TO_CHAR('2000-11-11', c2) FROM t_b; +SELECT TO_CHAR('2000-11-11', c3) FROM t_b; +SELECT TO_CHAR('2000-11-11', c4) FROM t_b; +DROP TABLE t_b; + +EXPLAIN EXTENDED SELECT TO_CHAR(c1, 'YYYY-MM-DD') FROM t_to_char1; + +--echo # +--echo # test for time type with date format string +--echo # +SELECT TO_CHAR(c2, 'YYYY-MM-DD HH:MI:SS') from t_to_char1; +SELECT TO_CHAR(c2, 'YYYY-MON-DY HH:MI:SS') from t_to_char1; +SELECT TO_CHAR(c2, 'MON-YYYY-DY HH:MI:SS') from t_to_char1; +SELECT TO_CHAR(c2, 'YYYY-MONTH-DAY HH:MI:SS') from t_to_char1; + +DROP TABLE t_to_char1; +DROP TABLE t_to_char2; + + +--echo # +--echo # Test strict mode +--echo # + +create table t1 (a datetime, b int, f varchar(30)) engine=myisam; +insert into t1 values ("2021-01-24 19:22:10", 2014, "YYYY-MM-DD"); +insert into t1 values ("2021-01-24 19:22:10", 2014, "YYYY-MQ-DD"); +create table t2 (a varchar(30)) engine=myisam; +insert into t2 select to_char(a,f) from t1; +set @@sql_mode="STRICT_ALL_TABLES"; +--error ER_STD_INVALID_ARGUMENT +insert into t2 select to_char(a,f) from t1; +select * from t2; +drop table t1,t2; +set @local.sql_mode=@sql_mode; + +--echo # +--echo # MDEV-29152: Assertion failed ... upon TO_CHAR with wrong argument +--echo # + +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT TO_CHAR((VALUES('2022-12-12','2020-10-10'))); + +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT TO_CHAR((STR_TO_DATE('2023-01-01', '%d-%m-%Y'), 'YYYY-MM-DD') ); + diff --git a/mysql-test/suite/compat/oracle/t/func_trim.test b/mysql-test/suite/compat/oracle/t/func_trim.test new file mode 100644 index 00000000..153238fb --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/func_trim.test @@ -0,0 +1,77 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-15664 sql_mode=ORACLE: Make TRIM return NULL instead of empty string +--echo # + +SELECT TRIM('abc'), TRIM('abc ')||'.', '.'||TRIM(' abc ')||'.', TRIM(' '), TRIM(NULL), TRIM(SPACE(0)),TRIM(SPACE(10)) FROM dual; + +SELECT TRIM(TRAILING 'abc' FROM 'abc'); +SELECT TRIM(TRAILING 'abc' FROM 'abc '); +SELECT TRIM(TRAILING 'abc' FROM ' abc'); + +SELECT TRIM(LEADING 'abc' FROM 'abc'); +SELECT TRIM(LEADING 'abc' FROM 'abc '); +SELECT TRIM(LEADING 'abc' FROM ' abc'); + +SELECT TRIM(BOTH 'abc' FROM 'abc'); +SELECT TRIM(BOTH 'abc' FROM 'abc '); +SELECT TRIM(BOTH 'abc' FROM ' abc'); + +SELECT RTRIM('abc'), RTRIM('abc ')||'.', RTRIM(' abc ')||'.', RTRIM(' '), RTRIM(NULL), RTRIM(SPACE(0)),RTRIM(SPACE(10)) FROM dual; +SELECT LTRIM('abc'), LTRIM('abc '), LTRIM(' abc '), LTRIM(' '), LTRIM(NULL), LTRIM(SPACE(0)),LTRIM(SPACE(10)) FROM dual; + +CREATE TABLE t1 (c1 VARCHAR(10),ord INTEGER); +INSERT INTO t1 VALUES ('abc',1); +INSERT INTO t1 VALUES (SPACE(0),2); +INSERT INTO t1 VALUES ('',3); +INSERT INTO t1 VALUES (' ',4); +INSERT INTO t1 VALUES (' ',5); +INSERT INTO t1 VALUES (' a ',6); +INSERT INTO t1 VALUES ('aa',7); +INSERT INTO t1 VALUES ('aabb',8); +INSERT INTO t1 VALUES ('bbaa',9); +INSERT INTO t1 VALUES ('aabbaa',10); + +SELECT ord,'['||c1||']','.'||COALESCE(TRIM(LEADING 'a' FROM c1),'NULL')||'.' FROM t1 ORDER BY ord; +SELECT ord,'['||c1||']','.'||COALESCE(TRIM(TRAILING 'a' FROM c1),'NULL')||'.' FROM t1 ORDER BY ord; +SELECT ord,'['||c1||']','.'||COALESCE(TRIM(BOTH 'a' FROM c1),'NULL')||'.' FROM t1 ORDER BY ord; +SELECT ord,'['||c1||']',COALESCE(LTRIM(c1),'NULL') FROM t1 ORDER BY ord; +SELECT ord,'['||c1||']',COALESCE(RTRIM(c1),'NULL')||'.' FROM t1 ORDER BY ord; + +EXPLAIN EXTENDED SELECT TRIM('abc'), + TRIM(BOTH 'a' FROM 'abc'), + TRIM(LEADING 'a' FROM 'abc'), + TRIM(TRAILING 'a' FROM 'abc') ; + +EXPLAIN EXTENDED SELECT RTRIM('abc'), + LTRIM('abc'); + + +CREATE VIEW v1 AS SELECT ord,TRIM('abc'),RTRIM('abc'),LTRIM('abc'), + '['||c1||']', + TRIM(LEADING 'a' FROM c1), + TRIM(TRAILING 'a' FROM c1), + TRIM(BOTH 'a' FROM c1), + LTRIM(c1), + RTRIM(c1) + FROM t1 ORDER BY ord ; +SHOW CREATE VIEW v1; +SELECT * FROM v1; +DROP VIEW v1; + +DROP TABLE t1; + +CREATE TABLE t1 (c1 VARCHAR(10) NOT NULL); +CREATE TABLE t2 AS SELECT TRIM(LEADING 'a' FROM c1) AS C1, + TRIM(TRAILING 'a' FROM c1) AS C2, + TRIM(BOTH 'a' FROM c1) AS C3, + LTRIM(c1) AS C4, + RTRIM(c1) AS C5 + FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + +CREATE TABLE trim_oracle (trim_oracle int); +DROP TABLE trim_oracle; diff --git a/mysql-test/suite/compat/oracle/t/gis-debug.test b/mysql-test/suite/compat/oracle/t/gis-debug.test new file mode 100644 index 00000000..6053e546 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/gis-debug.test @@ -0,0 +1,31 @@ +--source include/have_geometry.inc +--source include/have_debug.inc + +SET sql_mode=ORACLE; + +--echo # +--echo # Start of 10.5 tests +--echo # + +--echo # +--echo # MDEV-19994 Add class Function_collection +--echo # + +SET SESSION debug_dbug="+d,make_item_func_call_native_simulate_not_found"; +--error ER_PARSE_ERROR +SELECT CONTAINS(POINT(1,1),POINT(1,1)); +--error ER_PARSE_ERROR +SELECT WITHIN(POINT(1,1),POINT(1,1)); +SET SESSION debug_dbug="-d,make_item_func_call_native_simulate_not_found"; + +--echo # +--echo # MDEV-20009 Add CAST(expr AS pluggable_type) +--echo # + +SET SESSION debug_dbug="+d,emulate_geometry_create_typecast_item"; +SELECT AsText(CAST('POINT(0 0)' AS GEOMETRY)); +SET SESSION debug_dbug="-d,emulate_geometry_create_typecast_item"; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/mysql-test/suite/compat/oracle/t/gis.test b/mysql-test/suite/compat/oracle/t/gis.test new file mode 100644 index 00000000..cb1b8690 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/gis.test @@ -0,0 +1,76 @@ +-- source include/have_geometry.inc + +SET sql_mode=ORACLE; + + +SELECT CONTAINS(POINT(1,1), POINT(1,1)); +SELECT CONTAINS(POINT(1,1), POINT(0,0)); + +SELECT WITHIN(POINT(1,1), POINT(1,1)); +SELECT WITHIN(POINT(1,1), POINT(0,0)); + +--echo # +--echo # Start of 10.5 tests +--echo # + +--echo # +--echo # MDEV-19994 Add class Function_collection +--echo # + +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT CONTAINS(); +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT CONTAINS(POINT(1,1)); +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT CONTAINS(POINT(1,1), POINT(1,1), POINT(1,1)); + +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT WITHIN(); +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT WITHIN(POINT(1,1)); +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT WITHIN(POINT(1,1), POINT(1,1), POINT(1,1)); + +--echo # +--echo # MDEV-20009 Add CAST(expr AS pluggable_type) +--echo # + +--error ER_UNKNOWN_OPERATOR +SELECT CAST(1 AS GEOMETRY); +--error ER_UNKNOWN_OPERATOR +SELECT CAST(1 AS GEOMETRYCOLLECTION); +--error ER_UNKNOWN_OPERATOR +SELECT CAST(1 AS POINT); +--error ER_UNKNOWN_OPERATOR +SELECT CAST(1 AS LINESTRING); +--error ER_UNKNOWN_OPERATOR +SELECT CAST(1 AS POLYGON); +--error ER_UNKNOWN_OPERATOR +SELECT CAST(1 AS MULTIPOINT); +--error ER_UNKNOWN_OPERATOR +SELECT CAST(1 AS MULTILINESTRING); +--error ER_UNKNOWN_OPERATOR +SELECT CAST(1 AS MULTIPOLYGON); + + +--error ER_UNKNOWN_OPERATOR +SELECT CONVERT(1, GEOMETRY); +--error ER_UNKNOWN_OPERATOR +SELECT CONVERT(1, GEOMETRYCOLLECTION); +--error ER_UNKNOWN_OPERATOR +SELECT CONVERT(1, POINT); +--error ER_UNKNOWN_OPERATOR +SELECT CONVERT(1, LINESTRING); +--error ER_UNKNOWN_OPERATOR +SELECT CONVERT(1, POLYGON); +--error ER_UNKNOWN_OPERATOR +SELECT CONVERT(1, MULTIPOINT); +--error ER_UNKNOWN_OPERATOR +SELECT CONVERT(1, MULTILINESTRING); +--error ER_UNKNOWN_OPERATOR +SELECT CONVERT(1, MULTIPOLYGON); + + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/mysql-test/suite/compat/oracle/t/information_schema_parameters.test b/mysql-test/suite/compat/oracle/t/information_schema_parameters.test new file mode 100644 index 00000000..c13a5910 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/information_schema_parameters.test @@ -0,0 +1,127 @@ + +--echo # +--echo # MDEV-15416 Crash when reading I_S.PARAMETERS +--echo # + +--echo # Create in sql_mode=ORACLE, display in sql_mode=ORACLE and sql_mode=DEFAULT + +SET sql_mode=ORACLE; +DELIMITER $$; +CREATE PROCEDURE p1(a0 t1.a%TYPE, + a1 test.t1.a%TYPE, + b0 t1%ROWTYPE, + b1 test.t1%ROWTYPE, + d ROW(a INT,b DOUBLE)) +AS +BEGIN + NULL; +END; +$$ +DELIMITER ;$$ +--vertical_results +SET sql_mode=ORACLE; +SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='p1'; +SET sql_mode=DEFAULT; +SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='p1'; +--horizontal_results +DROP PROCEDURE p1; + + +SET sql_mode=ORACLE; +DELIMITER $$; +CREATE FUNCTION f1(a0 t1.a%TYPE, + a1 test.t1.a%TYPE, + b0 t1%ROWTYPE, + b1 test.t1%ROWTYPE, + d ROW(a INT,b DOUBLE)) + RETURN INT +AS +BEGIN + RETURN 0; +END; +$$ +DELIMITER ;$$ +--vertical_results +SET sql_mode=ORACLE; +SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='f1'; +SET sql_mode=DEFAULT; +SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='f1'; +--horizontal_results +DROP FUNCTION f1; + + +--echo # Create in sql_mode=DEFAULT, display in sql_mode=DEFAULT and sql_mode=ORACLE + +SET sql_mode=DEFAULT; +DELIMITER $$; +CREATE PROCEDURE p1(a0 TYPE OF t1.a, + a1 TYPE OF test.t1.a, + b0 ROW TYPE OF t1, + b1 ROW TYPE OF test.t1, + d ROW(a INT,b DOUBLE)) +BEGIN +END; +$$ +DELIMITER ;$$ +--vertical_results +SET sql_mode=DEFAULT; +SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='p1'; +SET sql_mode=ORACLE; +SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='p1'; +--horizontal_results +DROP PROCEDURE p1; + + +SET sql_mode=DEFAULT; +DELIMITER $$; +CREATE FUNCTION f1(a0 TYPE OF t1.a, + a1 TYPE OF test.t1.a, + b0 ROW TYPE OF t1, + b1 ROW TYPE OF test.t1, + d ROW(a INT,b DOUBLE)) + RETURNS INT +BEGIN + RETURN 0; +END; +$$ +DELIMITER ;$$ +--vertical_results +SET sql_mode=DEFAULT; +SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='f1'; +SET sql_mode=ORACLE; +SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='f1'; +--horizontal_results +DROP FUNCTION f1; + +--echo # +--echo # MDEV 18092 Query with the table I_S.PARAMETERS stop working +--echo # after a package is created +--echo # + +SET sql_mode=ORACLE; + +CREATE DATABASE db1_mdev18092; +USE db1_mdev18092; + +DELIMITER $$; + +CREATE PROCEDURE p1(a INT) +AS BEGIN + NULL; +END; +$$ + +CREATE OR REPLACE PACKAGE employee_tools AS + FUNCTION getSalary(eid INT) RETURN DECIMAL(10,2); + PROCEDURE raiseSalary(eid INT, amount DECIMAL(10,2)); + PROCEDURE raiseSalaryStd(eid INT); + PROCEDURE hire(ename TEXT, esalary DECIMAL(10,2)); +END; +$$ +DELIMITER ;$$ + +--vertical_results +SELECT *, '---------------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_SCHEMA='db1_mdev18092'; +--horizontal_results + +DROP DATABASE db1_mdev18092; diff --git a/mysql-test/suite/compat/oracle/t/keywords.test b/mysql-test/suite/compat/oracle/t/keywords.test new file mode 100644 index 00000000..0768633b --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/keywords.test @@ -0,0 +1,29 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-17363 Compressed columns cannot be restored from dump +--echo # In sql_mode=ORACLE, COMPRESSED is still valid both as an SP label +--echo # and an SP variable name. +--echo # + +DELIMITER $$; +BEGIN + IF TRUE THEN + GOTO compressed; + END IF; + SELECT 'This should not be reached' AS warn; +<<compressed>> + BEGIN + SELECT 1 AS a; + END; +END +$$ +DELIMITER ;$$ + +DELIMITER $$; +DECLARE compressed INT DEFAULT 1; +BEGIN + SELECT compressed; +END +$$ +DELIMITER ;$$ diff --git a/mysql-test/suite/compat/oracle/t/minus.test b/mysql-test/suite/compat/oracle/t/minus.test new file mode 100644 index 00000000..cbaf4227 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/minus.test @@ -0,0 +1,44 @@ +CREATE TABLE tx1 (c1 int, c2 varchar(30)); +CREATE TABLE tx2 (c1 int, c2 varchar(30)); +CREATE TABLE tx3 (c1 int, c2 varchar(30)); +INSERT INTO tx1 VALUES (1, 'jim'); +INSERT INTO tx1 VALUES (2, 'menny'); +INSERT INTO tx1 VALUES (3, 'linda'); + +INSERT INTO tx2 VALUES (1, 'jim'); +INSERT INTO tx2 VALUES (2, 'kris'); +INSERT INTO tx2 VALUES (3, 'shory'); + +INSERT INTO tx3 VALUES (1, 'jim'); +INSERT INTO tx3 VALUES (2, 'kris'); +INSERT INTO tx3 VALUES (3, 'linda'); + +--echo # +--echo # test when sql_mode is not oracle +--echo # + +SELECT c2 FROM tx1 EXCEPT SELECT c2 from tx2; +--error 1064 +SELECT c2 FROM tx1 MINUS SELECT c2 from tx2; + +# MINUS should not be a reserved word +create table MINUS (a int); +drop table MINUS; + +--echo # +--echo # test when sql_mode is oracle +--echo # + +SET sql_mode=ORACLE; +SELECT c2 FROM tx1 MINUS SELECT c2 from tx2; +SELECT c2 FROM tx1 MINUS SELECT c2 from tx2 MINUS SELECT c2 from tx3; +SELECT c2 FROM tx1 MINUS SELECT c2 from tx2 EXCEPT SELECT c2 from tx3; +SELECT c2 FROM tx1 MINUS SELECT c2 from tx2 UNION SELECT c2 from tx3; + +# MINUS should be a reserved word +--error ER_PARSE_ERROR +create table MINUS (a int); + +DROP TABLE tx1; +DROP TABLE tx2; +DROP TABLE tx3;
\ No newline at end of file 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 00000000..b3fdfdf3 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/misc.test @@ -0,0 +1,38 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # Start of 10.2 tests +--echo # + +--echo # +--echo # MDEV-27690 Crash on `CHARACTER SET csname COLLATE DEFAULT` in column definition +--echo # + +CREATE TABLE t1 (a CHAR(10) CHARACTER SET latin1 COLLATE DEFAULT); +DROP TABLE t1; +SELECT CAST('a' AS CHAR(10) CHARACTER SET latin1 COLLATE DEFAULT); +SELECT COLUMN_GET(COLUMN_CREATE(0, 'string'),0 AS CHAR CHARACTER SET latin1 COLLATE DEFAULT) AS c1; + +--echo # +--echo # End of 10.2 tests +--echo # + + + +--echo # +--echo # Start of 10.3 tests +--echo # + +--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; + + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/mysql-test/suite/compat/oracle/t/mysqldump_restore.test b/mysql-test/suite/compat/oracle/t/mysqldump_restore.test new file mode 100644 index 00000000..dd54c2b5 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/mysqldump_restore.test @@ -0,0 +1,30 @@ +# See comments in mysql-test/main/mysqldump_restore.test +--source include/not_embedded.inc + +SET sql_mode=ORACLE; + +let $mysqldumpfile = $MYSQLTEST_VARDIR/tmp/mysqldumpfile.sql; + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-17363 Compressed columns cannot be restored from dump +--echo # + +CREATE TABLE t1 (a VARCHAR(1000) COMPRESSED CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL); +INSERT INTO `t1` VALUES (REPEAT('a', 256)); +--exec $MYSQL_DUMP --skip-extended-insert test --skip-comments t1 > $mysqldumpfile +let $table_name = test.t1; +--source include/mysqldump.inc + +CREATE TABLE t1 (a LONGTEXT COMPRESSED CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL); +INSERT INTO `t1` VALUES (REPEAT('a', 256)); +--exec $MYSQL_DUMP --skip-extended-insert test --skip-comments t1 > $mysqldumpfile +let $table_name = test.t1; +--source include/mysqldump.inc + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/mysql-test/suite/compat/oracle/t/parser.test b/mysql-test/suite/compat/oracle/t/parser.test new file mode 100644 index 00000000..40b4e297 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/parser.test @@ -0,0 +1,727 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-15620 Crash when using "SET @@NEW.a=expr" inside a trigger +--echo # + +CREATE TABLE t1 (a INT); +--error ER_UNKNOWN_STRUCTURED_VARIABLE +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET @@NEW.a=0; +DROP TABLE t1; + +--echo # +--echo # MDEV-15615 Unexpected syntax error instead of "Unknown system variable" inside an SP +--echo # + +DELIMITER $$; +--error ER_UNKNOWN_SYSTEM_VARIABLE +DECLARE + a INT; +BEGIN + SET GLOBAL a=10; +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # MDEV-16202 Latest changes made erroneously some keywords reserved in sql_mode=ORACLE +--echo # + + +DELIMITER $$; +CREATE PROCEDURE p1(name VARCHAR(64), pattern TEXT) AS + query TEXT DEFAULT REPLACE(pattern, 'name', name); +BEGIN + SELECT query AS ''; + EXECUTE IMMEDIATE query; +EXCEPTION + WHEN OTHERS THEN + BEGIN + SHOW ERRORS; + END; +END; +$$ + +CREATE PROCEDURE p2(name VARCHAR(64)) AS +BEGIN + CALL p1(name, 'DECLARE name INT; BEGIN name:=10; SELECT name; END'); + EXECUTE IMMEDIATE REPLACE('CREATE TABLE t1 (name INT)', 'name', name); + CALL p1(name, 'SELECT name FROM t1'); + CALL p1(name, 'SELECT name ''alias'' FROM t1'); + CALL p1(name, 'SELECT name()'); + CALL p1(name, 'SELECT name.name()'); + CALL p1(name, 'SELECT name DATE FROM t1'); + CALL p1(name, 'SELECT name HISTORY FROM t1'); + CALL p1(name, 'SELECT name NEXT FROM t1'); + CALL p1(name, 'SELECT name PERIOD FROM t1'); + CALL p1(name, 'SELECT name PREVIOUS FROM t1'); + CALL p1(name, 'SELECT name SYSTEM FROM t1'); + CALL p1(name, 'SELECT name SYSTEM_TIME FROM t1'); + CALL p1(name, 'SELECT name TIME FROM t1'); + CALL p1(name, 'SELECT name TIMESTAMP FROM t1'); + CALL p1(name, 'SELECT name TRANSACTION FROM t1'); + CALL p1(name, 'SELECT name VALUE FROM t1'); + CALL p1(name, 'SELECT name VERSIONING FROM t1'); + CALL p1(name, 'SELECT name WITHOUT FROM t1'); + DROP TABLE t1; +END; +$$ +DELIMITER ;$$ + +--disable_column_names +CALL p2('date'); +CALL p2('history'); +CALL p2('next'); +CALL p2('period'); +CALL p2('previous'); +CALL p2('system'); +CALL p2('system_time'); +CALL p2('time'); +CALL p2('timestamp'); +CALL p2('transaction'); +CALL p2('value'); +CALL p2('versioning'); +CALL p2('without'); +--enable_column_names + +DROP PROCEDURE p2; +DROP PROCEDURE p1; + + +--echo # +--echo # MDEV-16244 sql_mode=ORACLE: Some keywords do not work in variable declarations +--echo # + +SET sql_mode=ORACLE; +DELIMITER /; + +DECLARE + do INT; +BEGIN + SELECT do INTO do FROM DUAL; +END; +/ + +DECLARE + handler INT; +BEGIN + SELECT handler INTO handler FROM DUAL; +END; +/ + +DECLARE + repair INT; +BEGIN + SELECT repair INTO repair FROM DUAL; +END; +/ + +DECLARE + shutdown INT; +BEGIN + SELECT shutdown INTO shutdown FROM DUAL; +END; +/ + +DECLARE + truncate INT; +BEGIN + SELECT truncate INTO truncate FROM DUAL; +END; +/ + +DECLARE + close INT; +BEGIN + SELECT close INTO close FROM DUAL; +END; +/ + +DECLARE + commit INT; +BEGIN + SELECT commit INTO commit FROM DUAL; +END; +/ + +DECLARE + open INT; +BEGIN + SELECT open INTO open FROM DUAL; +END; +/ + +DECLARE + rollback INT; +BEGIN + SELECT rollback INTO rollback FROM DUAL; +END; +/ + +DECLARE + savepoint INT; +BEGIN + SELECT savepoint INTO savepoint FROM DUAL; +END; +/ + +DECLARE + contains INT; +BEGIN + SELECT contains INTO contains FROM DUAL; +END; +/ + +DECLARE + language INT; +BEGIN + SELECT language INTO language FROM DUAL; +END; +/ + +DECLARE + no INT; +BEGIN + SELECT no INTO no FROM DUAL; +END; +/ + +DECLARE + charset INT; +BEGIN + SELECT charset INTO charset FROM DUAL; +END; +/ +DECLARE + follows INT; +BEGIN + SELECT follows INTO follows FROM DUAL; +END; +/ + +DECLARE + precedes INT; +BEGIN + SELECT precedes INTO precedes FROM DUAL; +END; +/ + +DELIMITER ;/ + + +--echo # +--echo # MDEV-16464 Oracle Comp.: Sql-Error on "SELECT name, comment FROM mysql.proc" +--echo # + +SET sql_mode=ORACLE; +SELECT name, comment FROM mysql.proc WHERE db='test'; + +CREATE TABLE comment (comment INT); +SELECT comment FROM comment; +SELECT comment comment FROM comment comment; +SELECT comment AS comment FROM comment AS comment; +DROP TABLE comment; + +DELIMITER /; +DECLARE + comment INT; +BEGIN + SELECT comment INTO comment FROM DUAL; +END; +/ +DELIMITER ;/ + +DELIMITER /; +CREATE PROCEDURE comment COMMENT 'test' AS +BEGIN + SELECT 1; +END; +/ +BEGIN + comment; +END; +/ +DELIMITER ;/ +CALL comment(); +CALL comment; +DROP PROCEDURE comment; + +enable_prepare_warnings; +DELIMITER /; +CREATE FUNCTION comment RETURN INT COMMENT 'test' AS +BEGIN + RETURN 1; +END; +/ +DELIMITER ;/ +SELECT test.comment() FROM DUAL; +disable_prepare_warnings; +DROP FUNCTION comment; + + +--echo # +--echo # MDEV-17660 sql_mode=ORACLE: Some keywords do not work as label names: history, system, versioning, without +--echo # + +DELIMITER /; +BEGIN +<<date_format>> + NULL; +END; +/ +DELIMITER ;/ + + +DELIMITER /; +BEGIN +<<decode>> + NULL; +END; +/ +DELIMITER ;/ + + +DELIMITER /; +BEGIN +<<history>> + NULL; +END; +/ +DELIMITER ;/ + + +DELIMITER /; +BEGIN +<<system>> + NULL; +END; +/ +DELIMITER ;/ + + +DELIMITER /; +BEGIN +<<versioning>> + NULL; +END; +/ +DELIMITER ;/ + + +DELIMITER /; +BEGIN +<<without>> + NULL; +END; +/ +DELIMITER ;/ + + +--echo # +--echo # MDEV-17666 sql_mode=ORACLE: Keyword ELSEIF should not be reserved +--echo # + +DELIMITER /; +DECLARE + ELSEIF INT; +BEGIN + ELSEIF:=1; +END; +/ +DELIMITER ;/ + +DELIMITER /; +BEGIN +<<ELSEIF>> + NULL; +END; +/ +DELIMITER ;/ + + +--echo # +--echo # MDEV-17693 Shift/reduce conflicts for NAMES,ROLE,PASSWORD in the option_value_no_option_type grammar +--echo # + +CREATE TABLE names (names INT); +SELECT names FROM names AS names; +DROP TABLE names; + +CREATE TABLE password (password INT); +SELECT password FROM password AS password; +DROP TABLE password; + +CREATE TABLE role (role INT); +SELECT role FROM role AS role; +DROP TABLE role; + +DELIMITER $$; +DECLARE + names VARCHAR(32) DEFAULT '[names]'; + password VARCHAR(32) DEFAULT '[password]'; + role VARCHAR(32) DEFAULT '[role]'; +BEGIN +<<names>> + SELECT names; +<<password>> + SELECT password; +<<role>> + SELECT role; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_SP_BAD_VAR_SHADOW +DECLARE + names VARCHAR(32); +BEGIN + SET names='[names]'; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_SP_BAD_VAR_SHADOW +DECLARE + password VARCHAR(32); +BEGIN + SET password='[password]'; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +DECLARE + role VARCHAR(32); +BEGIN + SET role='[role]'; +END; +$$ +DELIMITER ;$$ + +--error ER_UNKNOWN_SYSTEM_VARIABLE +SELECT @@GLOBAL.names; +--error ER_UNKNOWN_SYSTEM_VARIABLE +SELECT @@GLOBAL.password; +--error ER_UNKNOWN_SYSTEM_VARIABLE +SELECT @@GLOBAL.role; + + +--echo # +--echo # MDEV-22822 sql_mode="oracle" cannot declare without variable errors +--echo # +--echo # It's OK to have no declarations between DECLARE and BEGIN. +--echo # + +DELIMITER //; +BEGIN + DECLARE + BEGIN + NULL; + END; +EXCEPTION +WHEN OTHERS THEN + NULL; +END; +// +DELIMITER ;// + + +DELIMITER //; +DECLARE +BEGIN + NULL; +EXCEPTION +WHEN OTHERS THEN + NULL; +END; +// +DELIMITER ;// + + +DELIMITER //; +BEGIN +<<lab>> + DECLARE + BEGIN + NULL; + END; +EXCEPTION +WHEN OTHERS THEN + NULL; +END; +// +DELIMITER ;// + + +--echo # +--echo # End of 10.3 tests +--echo # + + +--echo # +--echo # MDEV-21998: Server crashes in st_select_lex::add_table_to_list +--echo # upon mix of KILL and sequences +--echo # + +--error ER_SUBQUERIES_NOT_SUPPORTED +KILL ( SELECT 1 ) + LASTVAL(s); +--error ER_SUBQUERIES_NOT_SUPPORTED +KILL LASTVAL(s); + +--echo # +--echo # MDEV-23094: Multiple calls to a Stored Procedure from another +--echo # Stored Procedure crashes server +--echo # + +create table t1 (id1 int primary key, data1 int); +create table t2 (id2 int primary key, data2 int); + +delimiter //; +create procedure p1(id int,dt int) as +begin + if (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) + then + select 1; + end if; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +case (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) +when 1 then + select 1; +else + select 0; +end case; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +declare wcont int default 1; +begin + while (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) and wcont + loop + select 1; + set wcont=0; + end loop; +end; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +declare count int default 1; +begin + repeat + select 1; + set count=count+1; + until (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) and + count < 3 + end repeat; +end; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +for i in 1..(exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) +loop + select 1; +end loop; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +set sql_mode=ORACLE; +delimiter //; +create or replace procedure p1(id int, dt int) as +begin + while (1) + loop + exit when (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)); + end loop; +end; +// +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +drop table t1,t2; + +--echo # End of 10.4 tests + +--echo # +--echo # Start of 10.5 tests +--echo # + +--echo # +--echo # MDEV-20734 Allow reserved keywords as user defined type names +--echo # + +--error ER_UNKNOWN_DATA_TYPE +CREATE TABLE t1 (a DUAL); +--error ER_UNKNOWN_DATA_TYPE +SELECT CAST(1 AS DUAL); + + +--echo # +--echo # MDEV-20735 Allow non-reserved keywords as user defined type names +--echo # + +--error ER_UNKNOWN_DATA_TYPE +CREATE TABLE t1 (a ASCII); +--error ER_UNKNOWN_DATA_TYPE +SELECT CAST(1 AS ASCII); + +--error ER_UNKNOWN_DATA_TYPE +CREATE TABLE t1 (a LANGUAGE); +--error ER_UNKNOWN_DATA_TYPE +SELECT CAST(1 AS LANGUAGE); + +--error ER_UNKNOWN_DATA_TYPE +CREATE TABLE t1 (a CLOSE); +--error ER_UNKNOWN_DATA_TYPE +SELECT CAST(1 AS CLOSE); + +--error ER_UNKNOWN_DATA_TYPE +CREATE TABLE t1 (a NAMES); +--error ER_UNKNOWN_DATA_TYPE +SELECT CAST(1 AS NAMES); + +--error ER_UNKNOWN_DATA_TYPE +CREATE TABLE t1 (a END); +--error ER_UNKNOWN_DATA_TYPE +SELECT CAST(1 AS END); + +--error ER_UNKNOWN_DATA_TYPE +CREATE TABLE t1 (a GLOBAL); +--error ER_UNKNOWN_DATA_TYPE +SELECT CAST(1 AS GLOBAL); + +--error ER_UNKNOWN_DATA_TYPE +CREATE TABLE t1 (a ACTION); +--error ER_UNKNOWN_DATA_TYPE +SELECT CAST(1 AS ACTION); + +--error ER_UNKNOWN_DATA_TYPE +CREATE TABLE t1 (a BEGIN); +--error ER_UNKNOWN_DATA_TYPE +SELECT CAST(1 AS BEGIN); + +--echo # +--echo # End of 10.5 tests +--echo # + + +--echo # +--echo # Start of 10.6 tests +--echo # + +--echo # +--echo # MDEV-19682 sql_mode="oracle" does not support sysdate +--echo # + +# SYSDATE is not deterministic. Let's use LIKE and equality. +# The main point here is only to check that SYSDATE +# gets parsed without parentheses. The actial value is not important. +SELECT sysdate LIKE '____-__-__ __:__:__'; +SELECT sysdate = sysdate(); +SELECT sysdate = sysdate(0); + +--error ER_PARSE_ERROR +CREATE DATABASE sysdate; + +--error ER_PARSE_ERROR +CREATE TABLE sysdate (a INT); + +--error ER_PARSE_ERROR +CREATE TABLE t1 (sysdate INT); + +--error ER_PARSE_ERROR +CREATE TABLE t1 (a sysdate); + +DELIMITER $$; +--error ER_PARSE_ERROR +CREATE FUNCTION sysdate RETURN INT AS +BEGIN + RETURN 1; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_PARSE_ERROR +CREATE FUNCTION sysdate() RETURN INT AS +BEGIN + RETURN 1; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_PARSE_ERROR +DECLARE + sysdate INT := 10; +BEGIN + NULL; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_PARSE_ERROR +BEGIN +<<sysdate>> + NULL; +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # End of 10.6 tests +--echo # diff --git a/mysql-test/suite/compat/oracle/t/plugin.test b/mysql-test/suite/compat/oracle/t/plugin.test new file mode 100644 index 00000000..a84c4ae7 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/plugin.test @@ -0,0 +1,3 @@ +SET sql_mode=ORACLE; + +--source include/install_plugin_if_exists.inc 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 00000000..39770b48 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/ps.test @@ -0,0 +1,290 @@ +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_SUBQUERIES_NOT_SUPPORTED +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_SUBQUERIES_NOT_SUPPORTED +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_SUBQUERIES_NOT_SUPPORTED +EXECUTE IMMEDIATE (SELECT 'SELECT 1'); +--error ER_SUBQUERIES_NOT_SUPPORTED +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 # + + +--echo # +--echo # MDEV-12846 sql_mode=ORACLE: using Oracle-style placeholders in direct query execution makes the server crash +--echo # + +# When running with --ps, the below queries return +# CR_PARAMS_NOT_BOUND instead of ER_PARSE_ERROR + +--disable_ps_protocol +--error ER_PARSE_ERROR +SELECT ? FROM DUAL; +--error ER_PARSE_ERROR +SELECT :a FROM DUAL; +--error ER_PARSE_ERROR +SELECT :1 FROM DUAL; + +--error ER_PARSE_ERROR +SELECT 1+? FROM DUAL; +--error ER_PARSE_ERROR +SELECT 1+:a FROM DUAL; +--error ER_PARSE_ERROR +SELECT 1+:1 FROM DUAL; +--enable_ps_protocol diff --git a/mysql-test/suite/compat/oracle/t/rpl_mariadb_date.test b/mysql-test/suite/compat/oracle/t/rpl_mariadb_date.test new file mode 100644 index 00000000..b2aff233 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/rpl_mariadb_date.test @@ -0,0 +1,38 @@ +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +SET SQL_MODE=DEFAULT; +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES (NULL); +INSERT INTO t1 VALUES ('2001-01-01'); + +SET SQL_MODE= ORACLE; +CREATE TABLE t2 SELECT * FROM t1; + +--let $binlog_file = LAST +source include/show_binlog_events.inc; + +SET SQL_MODE= DEFAULT; +SHOW CREATE TABLE t1; +SHOW CREATE TABLE t2; + +SET SQL_MODE= ORACLE; +SHOW CREATE TABLE t1; +SHOW CREATE TABLE t2; + +--sync_slave_with_master +SELECT * FROM t1; +SELECT * FROM t2; + +SET SQL_MODE= DEFAULT; +SHOW CREATE TABLE t1; +SHOW CREATE TABLE t2; + +SET SQL_MODE= ORACLE; +SHOW CREATE TABLE t1; +SHOW CREATE TABLE t2; + +# Cleanup +--connection master +DROP TABLE t1, t2; +--source include/rpl_end.inc diff --git a/mysql-test/suite/compat/oracle/t/rpl_sp_package.test b/mysql-test/suite/compat/oracle/t/rpl_sp_package.test new file mode 100644 index 00000000..40bb0b0d --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/rpl_sp_package.test @@ -0,0 +1,134 @@ +--source include/master-slave.inc + +connection master; + +SET sql_mode=ORACLE; +DELIMITER $$; +CREATE PACKAGE pack AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PACKAGE BODY pack AS + FUNCTION f1 RETURN INT AS + BEGIN + RETURN 10; + END; + PROCEDURE p1 AS + BEGIN + SELECT f1(); + END; +END pack; +$$ +DELIMITER ;$$ + +sync_slave_with_master; +connection slave; +--vertical_results +--replace_column 13 # 14 # +SELECT * FROM mysql.proc WHERE db='test' AND name='pack'; +--replace_column 13 # 14 # +SELECT * FROM mysql.proc WHERE db='test' AND name LIKE 'pack.%'; +--horizontal_results + +SET @@sql_mode=ORACLE; +SELECT pack.f1(); +CALL pack.p1(); +SET @@sql_mode=DEFAULT; + +connection master; +DROP PACKAGE pack; + +sync_slave_with_master; +connection slave; +SELECT COUNT(*) FROM mysql.proc WHERE db='test' AND name='pack'; + +--echo # +--echo # Creating a package with a COMMENT +--echo # + +connection master; + +DELIMITER $$; +CREATE PACKAGE p1 COMMENT 'package-p1-comment' AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY p1 COMMENT 'package-body-p1-comment' AS + PROCEDURE p1 AS + BEGIN + NULL; + END; +END; +$$ +DELIMITER ;$$ + +SELECT definer, name, security_type, type, `comment` FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type; +sync_slave_with_master; +SELECT definer, name, security_type, type, `comment` FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type; + +connection master; +DROP PACKAGE p1; +sync_slave_with_master; + + +--echo # +--echo # Creating a package with a different DEFINER +--echo # + +connection master; + +DELIMITER $$; +CREATE DEFINER=xxx@localhost PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE DEFINER=xxx@localhost PACKAGE BODY p1 AS + PROCEDURE p1 AS + BEGIN + NULL; + END; +END; +$$ +DELIMITER ;$$ + +SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type; +sync_slave_with_master; +SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type; + +connection master; +DROP PACKAGE p1; +sync_slave_with_master; + +--echo # +--echo # Creating a package with a different DEFINER + SQL SECURITY INVOKER +--echo # + +connection master; + +DELIMITER $$; +CREATE DEFINER=xxx@localhost PACKAGE p1 SQL SECURITY INVOKER AS + PROCEDURE p1; +END; +$$ +CREATE DEFINER=xxx@localhost PACKAGE BODY p1 SQL SECURITY INVOKER AS + PROCEDURE p1 AS + BEGIN + NULL; + END; +END; +$$ +DELIMITER ;$$ + +SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type; +sync_slave_with_master; +SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type; + +connection master; +DROP PACKAGE p1; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/compat/oracle/t/rpl_sp_package_variables.test b/mysql-test/suite/compat/oracle/t/rpl_sp_package_variables.test new file mode 100644 index 00000000..fca61124 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/rpl_sp_package_variables.test @@ -0,0 +1,36 @@ +--source include/master-slave.inc + +connection master; +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-13139 Package-wide variables in CREATE PACKAGE +--echo # +connection master; +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY p1 AS + va INT:=10; + PROCEDURE p1 AS + BEGIN + INSERT INTO t1 VALUES (va); + END; +BEGIN + CREATE OR REPLACE TABLE t1 (a INT); +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT * FROM t1; +sync_slave_with_master; +SELECT * FROM t1; +connection master; +DROP PACKAGE p1; +DROP TABLE t1; +sync_slave_with_master; + +--source include/rpl_end.inc 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 00000000..9bd8cec5 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sequence.test @@ -0,0 +1,48 @@ +--source include/have_binlog_format_row.inc + +SET sql_mode=ORACLE; + +--disable_ps2_protocol +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; +--enable_ps2_protocol + +CREATE SEQUENCE s1; +CREATE VIEW v1 AS SELECT s1.nextval AS a; +SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='v1'; +--disable_ps2_protocol +SELECT * FROM v1; +--enable_ps2_protocol +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 # +--disable_ps2_protocol +CREATE SEQUENCE s1; +SELECT test.s1.nextval; +SELECT test.s1.currval; +SELECT .s1.nextval; +SELECT .s1.currval; +DROP SEQUENCE s1; +--enable_ps2_protocol diff --git a/mysql-test/suite/compat/oracle/t/sp-anchor-row-type-table.test b/mysql-test/suite/compat/oracle/t/sp-anchor-row-type-table.test new file mode 100644 index 00000000..6e13a616 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-anchor-row-type-table.test @@ -0,0 +1,124 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-13581 ROW TYPE OF t1 and t1%ROWTYPE for routine parameters +--echo # + +CREATE TABLE t1 (a INT, b TEXT, c ENUM('a','b','c')); +DELIMITER $$; +CREATE PROCEDURE p1 (a t1%ROWTYPE) AS +BEGIN + CREATE TABLE t2 AS SELECT a.a AS a, a.b AS b, a.c AS c; + SHOW CREATE TABLE t2; + DROP TABLE t2; +END; +$$ +CREATE PROCEDURE p2 AS + a t1%ROWTYPE; +BEGIN + CALL p1(a); +END; +$$ +DELIMITER ;$$ +CALL p2(); +DROP PROCEDURE p2; +DROP PROCEDURE p1; +DROP TABLE t1; + + +CREATE TABLE t1 (a INT, b TEXT); +DELIMITER $$; +CREATE PROCEDURE p1 (a OUT t1%ROWTYPE) AS +BEGIN + SET a.a=10; + SET a.b='text'; +END; +$$ +CREATE PROCEDURE p2 AS + a t1%ROWTYPE; +BEGIN + CALL p1(a); + SELECT a.a, a.b; +END; +$$ +CREATE FUNCTION f1(a t1%ROWTYPE) RETURN TEXT AS +BEGIN + RETURN CONCAT(a.a, ' ', a.b); +END; +$$ +CREATE FUNCTION f2 RETURN TEXT AS + a t1%ROWTYPE; +BEGIN + CALL p1(a); + RETURN f1(a); +END; +$$ +DELIMITER ;$$ +CALL p2(); +SELECT f2(); +DROP PROCEDURE p2; +DROP PROCEDURE p1; +DROP FUNCTION f2; +DROP FUNCTION f1; +DROP TABLE t1; + + +CREATE DATABASE db1; +CREATE TABLE db1.t1 (a INT, b TEXT); +DELIMITER $$; +CREATE PROCEDURE p1 (a OUT db1.t1%ROWTYPE) AS +BEGIN + SET a.a=10; + SET a.b='text'; +END; +$$ +CREATE PROCEDURE p2 AS + a db1.t1%ROWTYPE; +BEGIN + CALL p1(a); + SELECT a.a, a.b; +END; +$$ +CREATE FUNCTION f1(a db1.t1%ROWTYPE) RETURN TEXT AS +BEGIN + RETURN CONCAT(a.a, ' ', a.b); +END; +$$ +CREATE FUNCTION f2() RETURN TEXT AS + a db1.t1%ROWTYPE; +BEGIN + CALL p1(a); + RETURN f1(a); +END; +$$ +DELIMITER ;$$ +CALL p2(); +SELECT f2(); +DROP PROCEDURE p2; +DROP PROCEDURE p1; +DROP FUNCTION f2; +DROP FUNCTION f1; +DROP DATABASE db1; + + +--echo # +--echo # MDEV-14139 Anchored data types for variables +--echo # + +CREATE TABLE t1 (int11 INT, text0 TEXT); +DELIMITER $$; +DECLARE + row1 t1%ROWTYPE; + a_row1 row1%TYPE; + aa_row1 a_row1%TYPE; +BEGIN + CREATE TABLE t2 AS SELECT a_row1.int11 AS int11, a_row1.text0 AS text0; + SHOW CREATE TABLE t2; + DROP TABLE t2; + CREATE TABLE t2 AS SELECT aa_row1.int11 AS int11, aa_row1.text0 AS text0; + SHOW CREATE TABLE t2; + DROP TABLE t2; +END; +$$ +DELIMITER ;$$ +DROP TABLE t1; 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 00000000..ac61e8ac --- /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-cache-invalidate.inc b/mysql-test/suite/compat/oracle/t/sp-cache-invalidate.inc new file mode 100644 index 00000000..945af6e7 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-cache-invalidate.inc @@ -0,0 +1,11 @@ +--echo # sp-cache-invalidate +--disable_query_log +DELIMITER $$; +CREATE FUNCTION dummy RETURN INT AS +BEGIN + RETURN 1; +END; +$$ +DELIMITER ;$$ +DROP FUNCTION dummy; +--enable_query_log 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 00000000..1ffd3b94 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-code.test @@ -0,0 +1,1088 @@ +-- 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 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; + + +--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; + +--echo # +--echo # MDEV-19640 Wrong SHOW PROCEDURE output for SET GLOBAL sysvar1=expr, sysvar2=expr +--echo # + +DELIMITER $$; +CREATE OR REPLACE PROCEDURE p1() AS +BEGIN + SET GLOBAL max_allowed_packet=16000000, max_error_count=60; + SELECT @@GLOBAL.max_allowed_packet, @@GLOBAL.max_error_count; +END; +$$ +DELIMITER ;$$ +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; + +--echo # +--echo # MDEV-19639 sql_mode=ORACLE: Wrong SHOW PROCEDURE output for sysvar:=expr +--echo # + +DELIMITER $$; +CREATE OR REPLACE PROCEDURE p1() AS +BEGIN + max_error_count:=10; +END; +$$ +DELIMITER ;$$ +SHOW PROCEDURE CODE 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 00000000..21683dd4 --- /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 00000000..78a38c5f --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-cursor-rowtype.test @@ -0,0 +1,1597 @@ +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_UNDECLARED_VAR +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; + + +--echo # +--echo # MDEV-15941 Explicit cursor FOR loop does not close the cursor +--echo # + +DELIMITER $$; +--error ER_SP_CURSOR_NOT_OPEN +DECLARE + CURSOR cur IS SELECT 1 AS a FROM DUAL; + v INT; +BEGIN + FOR rec IN cur + LOOP + NULL; + END LOOP; + FETCH cur INTO v; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_SP_CURSOR_NOT_OPEN +DECLARE + CURSOR cur IS SELECT 1 AS a FROM DUAL; + v INT; +BEGIN +<<label>> + FOR rec IN cur + LOOP + NULL; + END LOOP label; + FETCH cur INTO v; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_SP_CURSOR_ALREADY_OPEN +DECLARE + CURSOR cur IS SELECT 1 AS a FROM DUAL; +BEGIN + OPEN cur; + FOR rec IN cur + LOOP + NULL; + END LOOP; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +DECLARE + CURSOR cur IS SELECT 1 AS a FROM DUAL; +BEGIN + FOR rec IN cur + LOOP + SELECT rec.a; + END LOOP; + SELECT cur%ISOPEN; + FOR rec IN cur + LOOP + SELECT rec.a; + END LOOP; + SELECT cur%ISOPEN; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +DECLARE + CURSOR cur IS SELECT 1 AS a FROM DUAL; +BEGIN +<<label1>> + FOR rec IN cur + LOOP + SELECT rec.a; + END LOOP label1; + SELECT cur%ISOPEN; +<<label2>> + FOR rec IN cur + LOOP + SELECT rec.a; + END LOOP; + SELECT cur%ISOPEN; +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # MDEV-14139 Anchored data types for variables +--echo # + +DELIMITER $$; +DECLARE + CURSOR c1 IS SELECT 10 AS a, 'bbb' AS b, TIME'10:20:30' AS c; + row1 c1%ROWTYPE; + a_row1 row1%TYPE; + aa_row1 a_row1%TYPE; +BEGIN + CREATE TABLE t2 AS SELECT a_row1.a AS a, a_row1.b AS b, a_row1.c AS c; + SHOW CREATE TABLE t2; + DROP TABLE t2; + CREATE TABLE t2 AS SELECT aa_row1.a AS a, aa_row1.b AS b, aa_row1.c AS c; + SHOW CREATE TABLE t2; + DROP TABLE t2; +END; +$$ +DELIMITER ;$$ + +--echo # +--echo # MDEV-14388 Server crashes in handle_select / val_uint in ORACLE mode +--echo # + +CREATE TABLE t1 (id INT); +INSERT INTO t1 VALUES (0),(1),(2),(3); +DELIMITER $$; +CREATE FUNCTION f1() RETURN INT is +BEGIN + FOR v1 in (SELECT id FROM t1) + LOOP + NULL; + END LOOP; + RETURN 1; +END; +$$ +DELIMITER ;$$ +SELECT f1(); +DROP FUNCTION f1; +DROP TABLE t1; + +CREATE TABLE t1 (id INT); +INSERT INTO t1 VALUES (1),(2),(3),(4); +DELIMITER $$; +CREATE FUNCTION f1() RETURN INT IS + CURSOR cur IS SELECT id FROM t1; + rec cur%ROWTYPE; +BEGIN + RETURN 1; +END; +$$ +DELIMITER ;$$ +SELECT f1(); +DROP FUNCTION f1; +DROP TABLE t1; + + +--echo # +--echo # MDEV-17278 CURSOR FOR LOOP - ERROR: unexpected end of stream, read 0 bytes (SERVER CRASH) +--echo # + +CREATE TABLE t1 (id2 int, id int, en1 enum('aaa','a','b','c')); +INSERT INTO t1 VALUES(1,1,'aaa'),(2,2,'a'),(3,3,'b'),(4,4,'c'); + +DELIMITER $$; +CREATE PROCEDURE p1() +AS +BEGIN + FOR rec IN (SELECT en1 FROM t1) + LOOP + SELECT rec.en1; + 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 00000000..d7e2a5de --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-cursor.test @@ -0,0 +1,1044 @@ +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 + + +--echo # +--echo # MDEV-17387 MariaDB Server giving wrong error while executing select query from procedure +--echo # + +CREATE TABLE t1 +( + JOBN varchar(18) NOT NULL, + pk int(11) NOT NULL, + PRIMARY KEY (pk), + KEY (JOBN) +); + +DELIMITER $$; +CREATE PROCEDURE p1 +AS + lS NUMBER(10) :=0; + CURSOR cBPD IS SELECT * FROM t1 WHERE JOBN='x'; +BEGIN + FOR lbpd IN cBPD LOOP + lS:=lS+1; + END LOOP; +EXCEPTION + WHEN OTHERS THEN + BEGIN + SELECT SQLERRM; + END; +END; +$$ +DELIMITER ;$$ + +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +--echo # +--echo # Start of 10.8 tests +--echo # + +--echo # +--echo # MDEV-10654 IN, OUT, INOUT parameters in CREATE FUNCTION +--echo # + +DELIMITER $$; +DECLARE + va INT; + CURSOR cur (a IN INT) IS SELECT a FROM dual; +BEGIN + OPEN cur(1); + FETCH cur INTO va; + CLOSE cur; + SELECT va; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_NOT_SUPPORTED_YET +DECLARE + va INT; + CURSOR cur (a OUT INT) IS SELECT a FROM dual; +BEGIN + OPEN cur(1); + FETCH cur INTO va; + CLOSE cur; + SELECT va; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_NOT_SUPPORTED_YET +DECLARE + va INT; + CURSOR cur (a INOUT INT) IS SELECT a FROM dual; +BEGIN + OPEN cur(1); + FETCH cur INTO va; + CLOSE cur; + SELECT va; +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # End of 10.8 tests +--echo # diff --git a/mysql-test/suite/compat/oracle/t/sp-expr.test b/mysql-test/suite/compat/oracle/t/sp-expr.test new file mode 100644 index 00000000..06a5c59b --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-expr.test @@ -0,0 +1,165 @@ +# Testing expressions of different kinds in various parts of SP syntax + +SET sql_mode=ORACLE; + +--echo # +--echo # Start of 10.3 tests +--echo # + +# +# Subselects in SP control structures +# + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +DELIMITER $$; + +BEGIN + CASE ((1) IN (SELECT a FROM t1)) WHEN 1 THEN SELECT 1; + ELSE SELECT NULL; + END CASE; +END; +$$ +BEGIN + CASE (EXISTS (SELECT a FROM t1)) WHEN 1 THEN SELECT 1; + ELSE SELECT NULL; + END CASE; +END; +$$ + +BEGIN + IF ((1) IN (SELECT a FROM t1)) THEN SELECT 1; + ELSE SELECT NULL; + END IF; +END; +$$ +BEGIN + IF (EXISTS (SELECT a FROM t1)) THEN SELECT 1; + ELSE SELECT NULL; + END IF; +END; +$$ + +BEGIN + WHILE ((1234) IN (SELECT * FROM t1)) LOOP + SELECT 1; + END LOOP; +END; +$$ +BEGIN + WHILE (EXISTS (SELECT * FROM t1 WHERE a=1234)) LOOP + SELECT 1; + END LOOP; +END; +$$ + +BEGIN + REPEAT + SELECT 1; + UNTIL (1 IN (SELECT * FROM t1)) + END REPEAT; +END; +$$ +BEGIN + REPEAT + SELECT 1; + UNTIL EXISTS (SELECT * FROM t1 WHERE a=1) + END REPEAT; +END; +$$ + +BEGIN + FOR i IN 0..(1 IN (SELECT * FROM t1)) + LOOP + SELECT i; + END LOOP; +END; +$$ +BEGIN + FOR i IN 0..EXISTS (SELECT * FROM t1 WHERE a=1) + LOOP + SELECT i; + END LOOP; +END; +$$ +DELIMITER ;$$ +DROP TABLE t1; + + +# +# Subselects as SP variable default values +# + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (10); +DELIMITER $$; +DECLARE + a INT DEFAULT ((10) IN (SELECT * FROM t1)); +BEGIN + SELECT a; +END; +$$ +DECLARE + a INT DEFAULT EXISTS (SELECT * FROM t1); +BEGIN + SELECT a; +END; +$$ +DELIMITER ;$$ +DROP TABLE t1; + + +# +# Subselects SP function return values +# + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +DELIMITER $$; +CREATE FUNCTION f1() RETURN INT AS +BEGIN + RETURN ((1) IN (SELECT * FROM t1)); +END; +$$ +CREATE FUNCTION f2() RETURN INT AS +BEGIN + RETURN EXISTS (SELECT * FROM t1 WHERE a=1); +END; +$$ +DELIMITER ;$$ +SELECT f1(); +SELECT f2(); +DROP FUNCTION f1; +DROP FUNCTION f2; +DROP TABLE t1; + + +# +# Subselects in CURSOR parameters +# + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); +DELIMITER $$; +DECLARE + va INT; + CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a; +BEGIN + OPEN cur(1 IN (SELECT * FROM t1)); + FETCH cur INTO va; + SELECT va; + CLOSE cur; +END; +$$ +DECLARE + va INT; + CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a; +BEGIN + OPEN cur(EXISTS (SELECT * FROM t1)); + FETCH cur INTO va; + SELECT va; + CLOSE cur; +END; +$$ +DELIMITER ;$$ +DROP TABLE t1; diff --git a/mysql-test/suite/compat/oracle/t/sp-goto-debug.test b/mysql-test/suite/compat/oracle/t/sp-goto-debug.test new file mode 100644 index 00000000..0ded370b --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-goto-debug.test @@ -0,0 +1,178 @@ +-- source include/have_debug.inc + +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-20667 Server crash on pop_cursor +--echo # + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<< iac_err >> + RETURN; +END// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<< iac_err >> + RETURN ; +END// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + GOTO iac_err; +<< iac_err >> + RETURN ; +END// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=1 THEN + DECLARE + CURSOR cur2 IS SELECT 'cur2' FROM DUAL; + BEGIN + SELECT 'cur2'; + IF 1=1 THEN + DECLARE + CURSOR cur3 IS SELECT 'cur3' FROM DUAL; + BEGIN + SELECT 'cur3'; + IF 1=1 THEN + DECLARE + CURSOR cur4 IS SELECT 'cur4' FROM DUAL; + BEGIN + SELECT 'cur4'; + GOTO ret; + END; + END IF; + GOTO ret; + END; + END IF; + GOTO ret; + END; + END IF; +<<ret>> + RETURN; +END; +// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1(lab VARCHAR(32)) IS +BEGIN + IF 1=1 THEN + DECLARE + CURSOR cur2 IS SELECT 'cur2' FROM DUAL; + BEGIN + IF 1=1 THEN + DECLARE + CURSOR cur3 IS SELECT 'cur3' FROM DUAL; + BEGIN + IF 1=1 THEN + DECLARE + CURSOR cur4 IS SELECT 'cur4' FROM DUAL; + BEGIN + IF lab = 'cur4' THEN + SELECT 'goto from cur4' AS comment; + GOTO ret; + END IF; + END; + END IF; + IF lab = 'cur3' THEN + SELECT 'goto from cur3' AS comment; + GOTO ret; + END IF; + END; + END IF; + IF lab = 'cur2' THEN + SELECT 'goto from cur2' AS comment; + GOTO ret; + END IF; + END; + END IF; +<<ret>> + RETURN; +END; +// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +CALL p1(''); +CALL p1('cur2'); +CALL p1('cur3'); +CALL p1('cur4'); +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<<iac_err >> + RETURN; +END// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; 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 00000000..9c15d10b --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-goto.test @@ -0,0 +1,968 @@ +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; + + +--echo # +--echo # MDEV-20667 Server crash on pop_cursor +--echo # + +CREATE TABLE t1 (a VARCHAR(6)); +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<< iac_err >> + RETURN; +END// +DELIMITER ;// +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<< iac_err >> + RETURN ; +END// +DELIMITER ;// +CALL p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CURSOR cur1 IS SELECT a FROM t1 ; + BEGIN + GOTO iac_err; + END; + END; + END IF; + GOTO iac_err; +<< iac_err >> + RETURN ; +END// +DELIMITER ;// +CALL p1; +DROP PROCEDURE p1; + + +DELIMITER //; +CREATE PROCEDURE p1() IS +BEGIN + IF 1=2 THEN + BEGIN + DECLARE + CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; + BEGIN + GOTO iac_err; + END; + END; + END IF; + IF 1=1 THEN + GOTO iac_err; + END IF; +<<iac_err >> + RETURN; +END// +DELIMITER ;// +CALL p1; +DROP PROCEDURE p1; diff --git a/mysql-test/suite/compat/oracle/t/sp-inout.test b/mysql-test/suite/compat/oracle/t/sp-inout.test new file mode 100644 index 00000000..d605be64 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-inout.test @@ -0,0 +1,2501 @@ +--echo # +--echo # MDEV-10654 IN, OUT, INOUT parameters in CREATE FUNCTION +--echo # + +SET sql_mode=ORACLE; + +--echo # +--echo # CREATE PACKAGE with procedure and function with IN, OUT, INOUT qualifiers +--echo # And SHOW CREATE PACKAGE +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b IN INT, c INOUT INT, d OUT INT); + FUNCTION func_sub(d OUT INT, a IN INT, b IN INT, c INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b IN INT, c INOUT INT, d OUT INT) + AS + res INT; + BEGIN + res := func_sub(d, a, b, c); + d := d + c + res; + END; + FUNCTION func_sub(d OUT INT, a IN INT, b IN INT, c INOUT INT) RETURN INT + AS + BEGIN + c := c + 6; + d := 10; + RETURN a - b; + END; +END; +$$ +DELIMITER ;$$ + +SHOW CREATE PACKAGE pkg2; +SHOW CREATE PACKAGE BODY pkg2; +DROP PACKAGE pkg2; + +--echo # +--echo # CREATE FUNCTION with IN, OUT, INOUT qualifiers +--echo # SHOW CREATE FUNCTION +--echo # + +DELIMITER $$; +CREATE OR REPLACE FUNCTION add_func(a IN INT, b IN INT, c OUT INT, d INOUT INT) RETURN INT +AS + BEGIN + c := 100; + d := d + 1; + RETURN a + b; + END; +$$ +DELIMITER ;$$ + +SHOW CREATE FUNCTION add_func; +DROP FUNCTION add_func; + +--echo # +--echo # CREATE PROCEDURE with IN, OUT, INOUT qualifiers +--echo # SHOW CREATE PROCEDURE +--echo # + +DELIMITER $$; +CREATE OR REPLACE PROCEDURE add_proc(a IN INT, b IN INT, c INOUT INT, d OUT INT) +AS + BEGIN + d := a + b + c + d; + END; +$$ +DELIMITER ;$$ + +SHOW CREATE PROCEDURE add_proc; +DROP PROCEDURE add_proc; + +--echo # +--echo # Call function from SELECT query +--echo # SELECT > FUNCTION(IN) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION add_func2 (a IN INT, b IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION add_func2(a IN INT, b IN INT) RETURN INT + AS + BEGIN + RETURN a + b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +select pkg2.add_func2(@a, @b); +DROP PACKAGE pkg2; + +--echo # +--echo # Call function from SELECT query +--echo # SELECT > FUNCTION(OUT) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION add_func3 (a IN INT, b IN INT, c OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION add_func3(a IN INT, b IN INT, c OUT INT) RETURN INT + AS + BEGIN + c := 100; + RETURN a + b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +set @c = 0; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +select pkg2.add_func3(@a, @b, @c); +DROP PACKAGE pkg2; + +--echo # +--echo # Call function from SELECT query +--echo # SELECT > FUNCTION(INOUT) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION add_func4 (a IN INT, b IN INT, c OUT INT, d INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION add_func4(a IN INT, b IN INT, c OUT INT, d INOUT INT) RETURN INT + AS + BEGIN + c := 100; + d := d + 1; + RETURN a + b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +set @c = 0; +set @d = 9; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +select pkg2.add_func4(@a, @b, @c, @d); +DROP PACKAGE pkg2; + +--echo # +--echo # Call from procedure +--echo # PROCEDURE(OUT) > FUNCTION(IN) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE add_proc2 (a IN INT, b IN INT, c OUT INT); + FUNCTION add_func2 (a IN INT, b IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE add_proc2(a IN INT, b IN INT, c OUT INT) + AS + BEGIN + c := add_func2(a, b); + END; + + FUNCTION add_func2(a IN INT, b IN INT) RETURN INT + AS + BEGIN + RETURN a + b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +set @c = 0; +call pkg2.add_proc2(@a, @b, @c); +select @c; +DROP PACKAGE pkg2; + +--echo # +--echo # Call from procedure +--echo # PROCEDURE(OUT) > FUNCTION(OUT) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE add_proc3 (a IN INT, b IN INT, c OUT INT); + FUNCTION add_func3 (a IN INT, b IN INT, c OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE add_proc3(a IN INT, b IN INT, c OUT INT) + AS + res INT; + BEGIN + res := add_func3(a, b, c); + END; + FUNCTION add_func3(a IN INT, b IN INT, c OUT INT) RETURN INT + AS + BEGIN + c := 100; + RETURN a + b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +set @c = 0; +call pkg2.add_proc3(@a, @b, @c); +select @c; +DROP PACKAGE pkg2; + +--echo # +--echo # Call from procedure +--echo # PROCEDURE(OUT) > FUNCTION(INOUT) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE add_proc4 (a IN INT, b IN INT, c OUT INT); + FUNCTION add_func4 (a IN INT, b IN INT, c OUT INT, d INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE add_proc4(a IN INT, b IN INT, res OUT INT) + AS + c INT; + d INT; + BEGIN + d := 30; + res := add_func4(a, b, c, d); + res := c + d; + END; + FUNCTION add_func4(a IN INT, b IN INT, c OUT INT, d INOUT INT) RETURN INT + AS + BEGIN + c := 100; + d := d + 1; + RETURN a + b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +set @res = 0; +call pkg2.add_proc4(@a, @b, @res); +select @res; +DROP PACKAGE pkg2; + +--echo # +--echo # Call from procedure +--echo # PROCEDURE(OUT) > PROCEDURE(OUT) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE test_proc1 (a IN INT, b IN INT, c OUT INT); + PROCEDURE add_proc (a IN INT, b IN INT, c OUT INT); +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE test_proc1(a IN INT, b IN INT, c OUT INT) + AS + BEGIN + call pkg2.add_proc(a, b, c); + END; + PROCEDURE add_proc(a IN INT, b IN INT, c OUT INT) + AS + BEGIN + c := a + b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +set @c = 0; +call pkg2.test_proc1(@a, @b, @c); +select @c; +DROP PACKAGE pkg2; + +--echo # +--echo # Argument's order change +--echo # PROCEDURE(a IN, b IN, c OUT) > FUNCTION(b IN, a IN, c OUT) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b IN INT, c OUT INT); + FUNCTION func_sub(b IN INT, a IN INT, c OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b IN INT, c OUT INT) + AS + res INT; + BEGIN + res := func_sub(b, a, c); + END; + FUNCTION func_sub(b IN INT, a IN INT, c OUT INT) RETURN INT + AS + res INT; + BEGIN + c := a - b; + res := a; + RETURN res; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +set @c = 0; +call pkg2.proc_main(@a, @b, @c); +select @c; +DROP PACKAGE pkg2; + +--echo # +--echo # Argument's order change +--echo # PROCEDURE(a IN, b IN, c OUT) > FUNCTION(c OUT, b IN, a IN) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b IN INT, c OUT INT); + FUNCTION func_sub(c OUT INT, b IN INT, a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b IN INT, c OUT INT) + AS + res INT; + BEGIN + res := func_sub(c, b, a); + END; + FUNCTION func_sub(c OUT INT, b IN INT, a IN INT) RETURN INT + AS + res INT; + BEGIN + c := a - b; + res := a; + RETURN res; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +set @c = 0; +call pkg2.proc_main(@a, @b, @c); +select @c; +DROP PACKAGE pkg2; + +--echo # +--echo # Argument's order change +--echo # PROCEDURE(a IN, b IN, c INOUT, d OUT) > FUNCTION(d OUT, a IN, b IN, c INOUT) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b IN INT, c INOUT INT, d OUT INT); + FUNCTION func_sub(d OUT INT, a IN INT, b IN INT, c INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b IN INT, c INOUT INT, d OUT INT) + AS + res INT; + BEGIN + res := func_sub(d, a, b, c); + d := d + c + res; + END; + FUNCTION func_sub(d OUT INT, a IN INT, b IN INT, c INOUT INT) RETURN INT + AS + BEGIN + c := c + 6; + d := 10; + RETURN a - b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 15; +set @b = 5; +set @c = 4; +set @d= 0; +call pkg2.proc_main(@a, @b, @c, @d); +select @d; +DROP PACKAGE pkg2; + +--echo # +--echo # Argument's order change +--echo # PROCEDURE(a IN INT, b IN INT, c INOUT INT, d OUT INT) > FUNCTION1(c INOUT INT, b IN INT) > FUNCTION2(d OUT INT, a IN INT) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b IN INT, c INOUT INT, d OUT INT); + FUNCTION func_sub1(c INOUT INT, b IN INT) RETURN INT; + FUNCTION func_sub2(d OUT INT, a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b IN INT, c INOUT INT, d OUT INT) + AS + res1 INT; + res2 INT; + BEGIN + res1 := func_sub1(c, b); + res2 := func_sub2(d, a); + d := d + c; + END; + FUNCTION func_sub1(c INOUT INT, b IN INT) RETURN INT + AS + BEGIN + c := c + b; + RETURN 0; + END; + FUNCTION func_sub2(d OUT INT, a IN INT) RETURN INT + AS + BEGIN + d := 5 + a; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 15; +set @b = 6; +set @c = 4; +set @d= 0; +call pkg2.proc_main(@a, @b, @c, @d); +select @d; +DROP PACKAGE pkg2; + +--echo # +--echo # Argument's order change +--echo # FUNCTION1(a IN, b IN) > FUNCTION2(b IN, c OUT, a IN) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a IN INT, b IN INT) RETURN INT; + FUNCTION func_sub(b IN INT, c OUT INT, a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a IN INT, b IN INT) RETURN INT + AS + c INT; + res INT; + BEGIN + res := func_sub(b, c, a); + RETURN res + c; + END; + FUNCTION func_sub(b IN INT, c OUT INT, a IN INT) RETURN INT + AS + BEGIN + c := 100; + RETURN a + b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +select pkg2.func_main(@a, @b); +DROP PACKAGE pkg2; + +--echo # +--echo # Call procedure inside function +--echo # FUNCTION1(a IN, b IN) > PROCEDURE(a IN, b IN, c OUT) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(b IN INT, a IN INT) RETURN INT; + PROCEDURE proc_sub(a IN INT, b IN INT, c OUT INT); +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(b IN INT, a IN INT) RETURN INT + AS + c INT; + BEGIN + call proc_sub(a, b, c); + RETURN c; + END; + PROCEDURE proc_sub(a IN INT, b IN INT, c OUT INT) + AS + BEGIN + c := a + b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +select pkg2.func_main(@a, @b); +DROP PACKAGE pkg2; + +--echo # +--echo # Call procedure inside function +--echo # FUNCTION1(a IN, b IN) > PROCEDURE(a IN, b INOUT) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(b IN INT, a IN INT) RETURN INT; + PROCEDURE proc_sub(a IN INT, b INOUT INT); +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(b IN INT, a IN INT) RETURN INT + AS + BEGIN + call proc_sub(a, b); + RETURN b; + END; + PROCEDURE proc_sub(a IN INT, b INOUT INT) + AS + BEGIN + b := a + b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +select pkg2.func_main(@a, @b); +DROP PACKAGE pkg2; + +--echo # +--echo # Call procedure inside function +--echo # FUNCTION1(a IN, b IN, c OUT) > PROCEDURE(a IN, b IN, c OUT) +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(b IN INT, a IN INT, c OUT INT) RETURN INT; + PROCEDURE proc_sub(a IN INT, b IN INT, c OUT INT); +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(b IN INT, a IN INT, c OUT INT) RETURN INT + AS + res INT; + BEGIN + call proc_sub(a, b, c); + RETURN 0; + END; + PROCEDURE proc_sub(a IN INT, b IN INT, c OUT INT) + AS + BEGIN + c := a + b; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +set @b = 3; +set @c = 0; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +select pkg2.func_main(@a, @b, @c); +DROP PACKAGE pkg2; + +--echo # +--echo # Call function from UPDATE query +--echo # UPDATE <table> SET <column> = FUNCTION(a IN) +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func(a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func(a IN INT) RETURN INT + AS + BEGIN + RETURN a * 10; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 5; +UPDATE Persons SET Age = pkg2.func(@a) WHERE ID = 1; +SELECT * FROM Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # Call function from UPDATE query +--echo # UPDATE <table> SET <column> = FUNCTION(a OUT) +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func(a OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func(a OUT INT) RETURN INT + AS + BEGIN + a := 5; + RETURN 80; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 0; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +UPDATE Persons SET Age = pkg2.func(@a) WHERE ID = 1; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # Call function from INSERT query +--echo # INSERT INTO <table> SELECT <val1>, <val2>, FUNCTION(a IN) +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func(a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func(a IN INT) RETURN INT + AS + BEGIN + RETURN a * 10; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 4; +INSERT INTO Persons SELECT 4, 'DDD', PKG2.func(@a); +SELECT * FROM Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # Call function from INSERT query +--echo # INSERT INTO <table> SELECT <val1>, <val2>, FUNCTION(a OUT) +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func(a OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func(a OUT INT) RETURN INT + AS + BEGIN + a := 45; + RETURN 40; + END; +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +set @a = 0; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +INSERT INTO Persons SELECT 5, 'EEE', PKG2.func(@a); +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # Call function from DELETE query +--echo # DELETE FROM <table> WHERE <column> = FUNCTION(a IN) +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func(a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func(a IN INT) RETURN INT + AS + BEGIN + RETURN a; + END; +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +set @a = 4; +DELETE FROM Persons WHERE ID = PKG2.func(@a); +SELECT * FROM Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # Call function from DELETE query +--echo # DELETE FROM <table> WHERE <column> = FUNCTION(a OUT) +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func(a OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func(a OUT INT) RETURN INT + AS + BEGIN + a := 40; + RETURN 4; + END; +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +set @a = 0; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +DELETE FROM Persons WHERE ID = PKG2.func(@a); +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # SELECT query inside function +--echo # FUNCTION(a IN) > SELECT … FROM <table> +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT + AS + c INT; + BEGIN + SELECT AGE INTO c FROM Persons WHERE ID = a; + RETURN c; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 3; +select pkg2.func_main(@a); +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # SELECT query inside function +--echo # FUNCTION(a OUT) > SELECT … FROM <table> +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a OUT INT) RETURN INT + AS + BEGIN + SELECT AGE INTO a FROM Persons WHERE ID = 3; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 0; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +select pkg2.func_main(@a); +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # SELECT query inside function +--echo # FUNCTION(a INOUT) > SELECT … FROM <table> +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a INOUT INT) RETURN INT + AS + BEGIN + SELECT AGE INTO a FROM Persons WHERE ID = a; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 1; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +select pkg2.func_main(@a); +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # SELECT query inside function +--echo # FUNCTION(a IN) > FUNCTION(a IN, b OUT) > SELECT … FROM <table> +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT; + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT + AS + b INT; + res INT; + BEGIN + res := func_sub(a, b); + RETURN b; + END; + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT + AS + BEGIN + SELECT AGE INTO b FROM Persons WHERE ID = a; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 2; +select pkg2.func_main(@a); +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # UPDATE query inside function +--echo # FUNCTION(a IN) > UPDATE <table> SET … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'EEE', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT + AS + c INT; + BEGIN + UPDATE Persons SET AGE = 50 WHERE ID = a; + + SELECT AGE INTO c FROM Persons WHERE ID = a; + RETURN c; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 5; +select pkg2.func_main(@a); +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # UPDATE query inside function +--echo # FUNCTION(a IN, b OUT) > UPDATE <table> SET … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'EEE', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a IN INT, b OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a IN INT, b OUT INT) RETURN INT + AS + BEGIN + UPDATE Persons SET AGE = 60 WHERE ID = a; + SELECT AGE INTO b FROM Persons WHERE ID = a; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 5; +set @b = 0; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +select pkg2.func_main(@a, @b); +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # UPDATE query inside function +--echo # FUNCTION(a IN, b INOUT) > UPDATE <table> SET … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'EEE', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a IN INT, b INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a IN INT, b INOUT INT) RETURN INT + AS + BEGIN + UPDATE Persons SET AGE = 60 WHERE ID = a; + SELECT AGE INTO b FROM Persons WHERE ID = a; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +set @a = 5; +set @b = 0; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +select pkg2.func_main(@a, @b); +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # UPDATE query inside function +--echo # FUNCTION(a IN) > FUNCTION(a IN, b OUT) > UPDATE <table> SET … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 80); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'EEE', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT; + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT + AS + b INT; + res INT; + BEGIN + res := func_sub(a, b); + RETURN b; + END; + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT + AS + BEGIN + UPDATE Persons SET AGE = 10 WHERE ID = a; + SELECT AGE INTO b FROM Persons WHERE ID = a; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 1; +select pkg2.func_main(@a); +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # INSERT query inside function +--echo # FUNCTION(a IN) > INSERT INTO <table> VALUES … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'EEE', 50); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT + AS + b INT; + BEGIN + INSERT INTO Persons VALUE (a, 'FFF', 60); + SELECT AGE INTO b FROM Persons WHERE ID = a; + RETURN b; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 6; +--disable_ps2_protocol +select pkg2.func_main(@a); +--enable_ps2_protocol +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # INSERT query inside function +--echo # FUNCTION(a IN, b OUT) > INSERT INTO <table> VALUES … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'EEE', 50); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a IN INT, b OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a IN INT, b OUT INT) RETURN INT + AS + BEGIN + INSERT INTO Persons VALUE (a, 'FFF', 60); + SELECT AGE INTO b FROM Persons WHERE ID = a; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 6; +set @b = 0; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +select pkg2.func_main(@a, @b); +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # INSERT query inside function +--echo # FUNCTION(a IN, b INOUT) > INSERT INTO <table> VALUES … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'EEE', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a IN INT, b INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a IN INT, b INOUT INT) RETURN INT + AS + BEGIN + INSERT INTO Persons VALUE (a, 'FFF', 60); + SELECT AGE INTO b FROM Persons WHERE ID = a; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 6; +set @b = 0; +--error ER_SF_OUT_INOUT_ARG_NOT_ALLOWED +select pkg2.func_main(@a, @b); +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # INSERT query inside function +--echo # FUNCTION(a IN) > FUNCTION(a IN, b OUT) > INSERT INTO <table> VALUES … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'EEE', 40); + + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT; + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func_main(a IN INT) RETURN INT + AS + b INT; + res INT; + BEGIN + res := func_sub(a, b); + RETURN b; + END; + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT + AS + BEGIN + INSERT INTO Persons VALUE (a, 'FFF', 60); + SELECT AGE INTO b FROM Persons WHERE ID = a; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 6; +--disable_ps2_protocol +select pkg2.func_main(@a); +--enable_ps2_protocol +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # PROCEDURE > FUNCTION > SQL query +--echo # PROCEDURE(OUT) > FUNCTION(IN) > SELECT FROM <table> … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 50); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT); + FUNCTION func_sub(a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT) + AS + BEGIN + b := func_sub(a); + END; + FUNCTION func_sub(a IN INT) RETURN INT + AS + b INT; + BEGIN + SELECT AGE INTO b FROM Persons WHERE ID = a; + RETURN b; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 2; +set @b = 0; +call pkg2.proc_main(@a, @b); +select @b; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # PROCEDURE > FUNCTION > SQL query +--echo # PROCEDURE(OUT) > FUNCTION(OUT) > SELECT FROM <table> … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 50); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT); + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT) + AS + res INT; + BEGIN + res := func_sub(a, b); + END; + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT + AS + BEGIN + SELECT AGE INTO b FROM Persons WHERE ID = a; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 1; +set @b = 0; +call pkg2.proc_main(@a, @b); +select @b; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # PROCEDURE > FUNCTION > SQL query +--echo # PROCEDURE(OUT) > FUNCTION(INOUT) > SELECT FROM <table> … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 50); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT); + FUNCTION func_sub(a IN INT, b INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT) + AS + c INT; + res INT; + BEGIN + c := 5; + res := func_sub(a, c); + b := c; + END; + FUNCTION func_sub(a IN INT, c INOUT INT) RETURN INT + AS + res INT; + BEGIN + SELECT AGE INTO res FROM Persons WHERE ID = a; + c := c * 100; + RETURN res; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 2; +set @b = 0; +call pkg2.proc_main(@a, @b); +select @b; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # PROCEDURE > FUNCTION > SQL query +--echo # PROCEDURE(OUT) > FUNCTION(IN) > INSESRT INTO <table> … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 50); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT); + FUNCTION func_sub(a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT) + AS + BEGIN + b := func_sub(a); + END; + FUNCTION func_sub(a IN INT) RETURN INT + AS + BEGIN + INSERT INTO Persons VALUE (a, 'FFF', 50); + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 5; +set @b = 0; +call pkg2.proc_main(@a, @b); +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # PROCEDURE > FUNCTION > SQL query +--echo # PROCEDURE(OUT) > FUNCTION(OUT) > INSESRT INTO <table> … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 50); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'FFF', 50); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT); + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT) + AS + res INT; + BEGIN + res := func_sub(a, b); + END; + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT + AS + BEGIN + INSERT INTO Persons VALUE (a, 'GGG', 60); + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 6; +set @b = 0; +call pkg2.proc_main(@a, @b); +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # PROCEDURE > FUNCTION > SQL query +--echo # PROCEDURE(OUT) > FUNCTION(INOUT) > INSESRT INTO <table> … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 50); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'FFF', 50); +INSERT INTO Persons VALUES (6, 'GGG', 60); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT); + FUNCTION func_sub(a IN INT, b INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT) + AS + c INT; + res INT; + BEGIN + c := 5; + res := func_sub(a, c); + b := c; + END; + FUNCTION func_sub(a IN INT, c INOUT INT) RETURN INT + AS + res INT; + BEGIN + INSERT INTO Persons VALUE (a, 'HHH', 70); + c := c * 100; + RETURN res; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 7; +set @b = 0; +call pkg2.proc_main(@a, @b); +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # PROCEDURE > FUNCTION > SQL query +--echo # PROCEDURE(OUT) > FUNCTION(IN) > UPDATE <table> SET … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 50); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'FFF', 50); +INSERT INTO Persons VALUES (6, 'GGG', 60); +INSERT INTO Persons VALUES (7, 'HHH', 70); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT); + FUNCTION func_sub(a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT) + AS + BEGIN + b := func_sub(a); + END; + FUNCTION func_sub(a IN INT) RETURN INT + AS + BEGIN + UPDATE Persons SET AGE = 100 WHERE ID = a; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 5; +set @b = 0; +call pkg2.proc_main(@a, @b); +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # PROCEDURE > FUNCTION > SQL query +--echo # PROCEDURE(OUT) > FUNCTION(OUT) > UPDATE <table> SET … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 50); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'FFF', 100); +INSERT INTO Persons VALUES (6, 'GGG', 60); +INSERT INTO Persons VALUES (7, 'HHH', 70); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT); + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT) + AS + res INT; + BEGIN + res := func_sub(a, b); + END; + FUNCTION func_sub(a IN INT, b OUT INT) RETURN INT + AS + BEGIN + UPDATE Persons SET AGE = 100 WHERE ID = a; + b := 1; + RETURN 0; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 6; +set @b = 0; +call pkg2.proc_main(@a, @b); +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # PROCEDURE > FUNCTION > SQL query +--echo # PROCEDURE(OUT) > FUNCTION(INOUT) > UPDATE <table> SET … +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 50); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); +INSERT INTO Persons VALUES (4, 'DDD', 40); +INSERT INTO Persons VALUES (5, 'FFF', 100); +INSERT INTO Persons VALUES (6, 'GGG', 100); +INSERT INTO Persons VALUES (7, 'HHH', 70); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT); + FUNCTION func_sub(a IN INT, b INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc_main(a IN INT, b OUT INT) + AS + c INT; + res INT; + BEGIN + c := 5; + res := func_sub(a, c); + b := c; + END; + FUNCTION func_sub(a IN INT, c INOUT INT) RETURN INT + AS + res INT; + BEGIN + UPDATE Persons SET AGE = 100 WHERE ID = a; + c := c * 100; + RETURN res; + END; +END; +$$ +DELIMITER ;$$ + +select * from Persons; +set @a = 7; +set @b = 0; +call pkg2.proc_main(@a, @b); +select * from Persons; +DROP TABLE Persons; +DROP PACKAGE pkg2; + +--echo # +--echo # Trigger +--echo # TRIGGER AFTER UPDATE ON TABLE1 > UPDATE TABLE2 +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +CREATE TABLE PersonsLog ( + UpdateCount int +); +INSERT INTO PersonsLog VALUES (0); + +DELIMITER $$; +CREATE OR REPLACE TRIGGER my_trigger +AFTER UPDATE ON Persons +FOR EACH ROW + UPDATE PersonsLog SET UpdateCount = UpdateCount+1; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +UPDATE Persons SET Age = 20 WHERE ID = 1; +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +DROP TRIGGER my_trigger; +DROP TABLE Persons; +DROP TABLE PersonsLog; + +--echo # +--echo # Trigger +--echo # TRIGGER AFTER UPDATE ON TABLE1 > FUNCTION(IN) > UPDATE TABLE2 +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +CREATE TABLE PersonsLog ( + UpdateCount int +); +INSERT INTO PersonsLog VALUES (0); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func(a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func(a IN INT) RETURN INT + AS + BEGIN + UPDATE PersonsLog SET UpdateCount = UpdateCount+1; + RETURN 0; + END; +END; +$$ +CREATE OR REPLACE TRIGGER my_trigger +AFTER UPDATE ON Persons +FOR EACH ROW +DECLARE + a INT; + res INT; +BEGIN + a := 10; + res := 0; + res := pkg2.func(a); +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +UPDATE Persons SET Age = 30 WHERE ID = 1; +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +DROP TRIGGER my_trigger; +DROP PACKAGE pkg2; +DROP TABLE Persons; +DROP TABLE PersonsLog; + +--echo # +--echo # Trigger +--echo # TRIGGER AFTER UPDATE ON TABLE1 > FUNCTION(OUT) > UPDATE TABLE2 +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 40); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +CREATE TABLE PersonsLog ( + UpdateCount int +); +INSERT INTO PersonsLog VALUES (0); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func(a OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func(a OUT INT) RETURN INT + AS + BEGIN + UPDATE PersonsLog SET UpdateCount = UpdateCount+1; + a := 100; + RETURN 0; + END; +END; +$$ +CREATE OR REPLACE TRIGGER my_trigger +AFTER UPDATE ON Persons +FOR EACH ROW +DECLARE + a INT; + res INT; +BEGIN + a := 10; + res := 0; + res := pkg2.func(a); +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +UPDATE Persons SET Age = 50 WHERE ID = 1; +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +DROP TRIGGER my_trigger; +DROP PACKAGE pkg2; +DROP TABLE Persons; +DROP TABLE PersonsLog; + +--echo # +--echo # Trigger +--echo # TRIGGER AFTER UPDATE ON TABLE1 > FUNCTION(INOUT) > UPDATE TABLE2 +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 50); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +CREATE TABLE PersonsLog ( + UpdateCount int +); +INSERT INTO PersonsLog VALUES (0); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + FUNCTION func(a INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + FUNCTION func(a INOUT INT) RETURN INT + AS + BEGIN + UPDATE PersonsLog SET UpdateCount = UpdateCount+1; + a := 100; + RETURN 0; + END; +END; +$$ +CREATE OR REPLACE TRIGGER my_trigger +AFTER UPDATE ON Persons +FOR EACH ROW +DECLARE + a INT; + res INT; +BEGIN + a := 10; + res := 0; + res := pkg2.func(a); +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +UPDATE Persons SET Age = 60 WHERE ID = 1; +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +DROP TRIGGER my_trigger; +DROP PACKAGE pkg2; +DROP TABLE Persons; +DROP TABLE PersonsLog; + +--echo # +--echo # Trigger +--echo # TRIGGER AFTER UPDATE ON TABLE1 > PROCEDURE(IN) > UPDATE TABLE2 +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +CREATE TABLE PersonsLog ( + UpdateCount int +); +INSERT INTO PersonsLog VALUES (0); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc(a IN INT); +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc(a IN INT) + AS + BEGIN + UPDATE PersonsLog SET UpdateCount = UpdateCount+1; + END; +END; +$$ +CREATE OR REPLACE TRIGGER my_trigger +AFTER UPDATE ON Persons +FOR EACH ROW +BEGIN + call pkg2.proc(@a); +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +UPDATE Persons SET Age = 30 WHERE ID = 1; +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +DROP TRIGGER my_trigger; +DROP PACKAGE pkg2; +DROP TABLE Persons; +DROP TABLE PersonsLog; + +--echo # +--echo # Trigger +--echo # TRIGGER AFTER UPDATE ON TABLE1 > PROCEDURE(OUT) > UPDATE TABLE2 +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +CREATE TABLE PersonsLog ( + UpdateCount int +); +INSERT INTO PersonsLog VALUES (0); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc(a OUT INT); +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc(a OUT INT) + AS + BEGIN + UPDATE PersonsLog SET UpdateCount = UpdateCount+1; + END; +END; +$$ +CREATE OR REPLACE TRIGGER my_trigger +AFTER UPDATE ON Persons +FOR EACH ROW +BEGIN + call pkg2.proc(@a); +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +UPDATE Persons SET Age = 50 WHERE ID = 1; +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +DROP TRIGGER my_trigger; +DROP PACKAGE pkg2; +DROP TABLE Persons; +DROP TABLE PersonsLog; + +--echo # +--echo # Trigger +--echo # TRIGGER AFTER UPDATE ON TABLE1 > PROCEDURE(INOUT) > UPDATE TABLE2 +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +CREATE TABLE PersonsLog ( + UpdateCount int +); +INSERT INTO PersonsLog VALUES (0); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc(a INOUT INT); +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc(a INOUT INT) + AS + BEGIN + UPDATE PersonsLog SET UpdateCount = UpdateCount+1; + a := 100; + END; +END; +$$ +CREATE OR REPLACE TRIGGER my_trigger +AFTER UPDATE ON Persons +FOR EACH ROW +BEGIN + set @a = 2; + call pkg2.proc(@a); +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +UPDATE Persons SET Age = 50 WHERE ID = 1; +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +DROP TRIGGER my_trigger; +DROP PACKAGE pkg2; +DROP TABLE Persons; +DROP TABLE PersonsLog; + +--echo # +--echo # Trigger +--echo # TRIGGER AFTER UPDATE ON TABLE1 > PROCEDURE(OUT) > FUNCTION(IN) > UPDATE TABLE2 +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +CREATE TABLE PersonsLog ( + UpdateCount int +); +INSERT INTO PersonsLog VALUES (0); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc(a OUT INT); + FUNCTION func(a IN INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc(a OUT INT) + AS + res INT; + BEGIN + a := 100; + res := func(a); + END; + FUNCTION func(a IN INT) RETURN INT + AS + BEGIN + UPDATE PersonsLog SET UpdateCount = UpdateCount+1; + RETURN 0; + END; +END; +$$ +CREATE OR REPLACE TRIGGER my_trigger +AFTER UPDATE ON Persons +FOR EACH ROW +BEGIN + call pkg2.proc(@a); +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +UPDATE Persons SET Age = 60 WHERE ID = 1; +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +DROP TRIGGER my_trigger; +DROP PACKAGE pkg2; +DROP TABLE Persons; +DROP TABLE PersonsLog; + +--echo # +--echo # Trigger +--echo # TRIGGER AFTER UPDATE ON TABLE1 > PROCEDURE(OUT) > FUNCTION(OUT) > UPDATE TABLE2 +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +CREATE TABLE PersonsLog ( + UpdateCount int +); +INSERT INTO PersonsLog VALUES (0); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc(a OUT INT); + FUNCTION func(a OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc(a OUT INT) + AS + res INT; + BEGIN + a := 100; + res := func(a); + END; + FUNCTION func(a OUT INT) RETURN INT + AS + BEGIN + a := 200; + UPDATE PersonsLog SET UpdateCount = UpdateCount+1; + RETURN 0; + END; +END; +$$ +CREATE OR REPLACE TRIGGER my_trigger +AFTER UPDATE ON Persons +FOR EACH ROW +BEGIN + call pkg2.proc(@a); +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +UPDATE Persons SET Age = 80 WHERE ID = 1; +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +DROP TRIGGER my_trigger; +DROP PACKAGE pkg2; +DROP TABLE Persons; +DROP TABLE PersonsLog; + +--echo # +--echo # Trigger +--echo # TRIGGER AFTER UPDATE ON TABLE1 > PROCEDURE(OUT) > FUNCTION(INOUT) > UPDATE TABLE2 +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +CREATE TABLE PersonsLog ( + UpdateCount int +); +INSERT INTO PersonsLog VALUES (0); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc(a OUT INT); + FUNCTION func(a INOUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc(a OUT INT) + AS + res INT; + BEGIN + a := 100; + res := func(a); + END; + FUNCTION func(a INOUT INT) RETURN INT + AS + BEGIN + a := 200; + UPDATE PersonsLog SET UpdateCount = UpdateCount+1; + RETURN 0; + END; +END; +$$ +CREATE OR REPLACE TRIGGER my_trigger +AFTER UPDATE ON Persons +FOR EACH ROW +BEGIN + call pkg2.proc(@a); +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +UPDATE Persons SET Age = 90 WHERE ID = 1; +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +DROP TRIGGER my_trigger; +DROP PACKAGE pkg2; +DROP TABLE Persons; +DROP TABLE PersonsLog; + +--echo # +--echo # Trigger +--echo # TRIGGER AFTER UPDATE ON TABLE1 > PROCEDURE(OUT) > FUNCTION(OUT) > UPDATE TABLE2 with OUT argument (to check if OUT is returning by reference) +--echo # + +CREATE TABLE Persons ( + ID int, + Name varchar(255), + Age int +); +INSERT INTO Persons VALUES (1, 'AAA', 10); +INSERT INTO Persons VALUES (2, 'BBB', 20); +INSERT INTO Persons VALUES (3, 'CCC', 30); + +CREATE TABLE PersonsLog ( + UpdateCount int +); +INSERT INTO PersonsLog VALUES (0); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg2 +AS + PROCEDURE proc(a OUT INT); + FUNCTION func(a OUT INT) RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg2 +AS + PROCEDURE proc(a OUT INT) + AS + res INT; + BEGIN + res := func(a); + UPDATE PersonsLog SET UpdateCount = a; + END; + FUNCTION func(a OUT INT) RETURN INT + AS + BEGIN + a := 111; + UPDATE PersonsLog SET UpdateCount = UpdateCount+1; + RETURN 0; + END; +END; +$$ +CREATE OR REPLACE TRIGGER my_trigger +AFTER UPDATE ON Persons +FOR EACH ROW +BEGIN + call pkg2.proc(@a); +END; +$$ +DELIMITER ;$$ + +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +UPDATE Persons SET Age = 80 WHERE ID = 1; +SELECT * FROM Persons; +SELECT * FROM PersonsLog; +DROP TRIGGER my_trigger; +DROP PACKAGE pkg2; +DROP TABLE Persons; +DROP TABLE PersonsLog; + + +--echo # +--echo # Package BODY variables as OUT parameters +--echo # + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + FUNCTION f1(b IN OUT INT) RETURN INT; + FUNCTION show_private_variables() RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + pa INT:= 0; + pb INT:= 10; + FUNCTION f1(b IN OUT INT) RETURN INT AS + BEGIN + b:= b + 100; + RETURN 500+b-100; + END; + + FUNCTION show_private_variables() RETURN TEXT AS + BEGIN + RETURN 'Private variables: pa=' || pa || ' pb=' || pb; + END; +BEGIN + SET pa=f1(pb); +END; +$$ +DELIMITER ;$$ +SELECT pkg1.show_private_variables(); +DROP PACKAGE pkg1; diff --git a/mysql-test/suite/compat/oracle/t/sp-memory-leak.test b/mysql-test/suite/compat/oracle/t/sp-memory-leak.test new file mode 100644 index 00000000..015169c2 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-memory-leak.test @@ -0,0 +1,35 @@ +--echo # +--echo # Start of 10.5 tests +--echo # + +--echo # +--echo # MDEV-26186 280 Bytes lost in mysys/array.c, mysys/hash.c, sql/sp.cc, sql/sp.cc, sql/item_create.cc, sql/item_create.cc, sql/sql_yacc.yy:10748 when using oracle sql_mode +--echo # + +SET sql_mode= 'oracle'; +--error ER_SP_LILABEL_MISMATCH +BEGIN CONTINUE WHEN f0(); + +SET sql_mode= 'oracle'; +--error ER_SP_LILABEL_MISMATCH +BEGIN CONTINUE label WHEN f0(); + +SET sql_mode= 'oracle'; +--error ER_SP_LILABEL_MISMATCH +BEGIN EXIT WHEN f0(); + +SET sql_mode= 'oracle'; +--error ER_SP_LILABEL_MISMATCH +BEGIN EXIT label WHEN f0(); + +SET sql_mode= 'oracle'; +--error ER_PARSE_ERROR +--query WHILE f(8)<1 DO SELECT 1; + +SET sql_mode= 'oracle'; +--error ER_SP_BADRETURN +BEGIN DECLARE CONTINUE HANDLER FOR SQLEXCEPTION RETURN f0(); + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/mysql-test/suite/compat/oracle/t/sp-package-code.test b/mysql-test/suite/compat/oracle/t/sp-package-code.test new file mode 100644 index 00000000..9cca5396 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-code.test @@ -0,0 +1,182 @@ +-- source include/have_debug.inc + +SET sql_mode=ORACLE; + + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; + PROCEDURE p2show; + PROCEDURE p2public; + FUNCTION f2public RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + a INT:=10; + PROCEDURE p1 AS + b INT:=20; + BEGIN + b:=a; + b:=a+1; + a:=b; + a:=b+1; + a:=a+1; + SET @a:=@a+2; + SELECT f1() FROM DUAL; + END; + FUNCTION f1 RETURN INT AS + BEGIN + RETURN a; + END; + PROCEDURE p2private AS + BEGIN + SELECT 'This is p2private'; + END; + PROCEDURE p2public AS + BEGIN + SELECT 'This is p2public'; + END; + FUNCTION f2private RETURN TEXT AS + BEGIN + RETURN 'This is f2private'; + END; + FUNCTION f2public RETURN TEXT AS + BEGIN + RETURN 'This is f2public'; + END; + PROCEDURE p2show AS + BEGIN + SHOW FUNCTION CODE f2public; + SHOW FUNCTION CODE f2private; + SHOW PROCEDURE CODE p2public; + SHOW PROCEDURE CODE p2private; + SHOW PROCEDURE CODE p2show; + END; +BEGIN + a:=a+1; + DECLARE + b INT; + BEGIN + b:=a; + b:=a+1; + a:=b; + a:=b+1; + END; +END; +$$ +DELIMITER ;$$ + +SHOW PROCEDURE CODE pkg1.p1; +SHOW FUNCTION CODE pkg1.f1; +SHOW PACKAGE BODY CODE pkg1; +CALL pkg1.p2show; + +DROP PACKAGE pkg1; + + +CREATE TABLE t1 (a INT); +DELIMITER $$; +CREATE PACKAGE pkg1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + a t1.a%TYPE:=10; + PROCEDURE p1 AS + b t1.a%TYPE:=20; + BEGIN + b:=a; + b:=a+1; + b:=b+1; + a:=b; + a:=b+1; + a:=a+1; + END; +BEGIN + a:=a+1; + DECLARE + b t1.a%TYPE; + BEGIN + b:=a; + b:=a+1; + a:=b; + a:=b+1; + END; +END; +$$ +DELIMITER ;$$ +SHOW PROCEDURE CODE pkg1.p1; +SHOW PACKAGE BODY CODE pkg1; +DROP PACKAGE pkg1; +DROP TABLE t1; + + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + a ROW(a INT,b TEXT):=ROW(10,'x10'); + PROCEDURE p1 AS + b ROW(a INT,b TEXT):=ROW(20,'x20'); + BEGIN + b:=a; + a:=b; + b.a:=a.a+1; + a.a:=b.a+1; + a.a:=a.a+1; + END; +BEGIN + a.a:=a.a+1; + DECLARE + b ROW(a INT,b TEXT):=ROW(30,'x30'); + BEGIN + b:=a; + b.a:=a.a+1; + a:=b; + a.a:=b.a+1; + END; +END; +$$ +DELIMITER ;$$ +SHOW PROCEDURE CODE pkg1.p1; +SHOW PACKAGE BODY CODE pkg1; +DROP PACKAGE pkg1; + + +CREATE TABLE t1 (a INT, b TEXT); +DELIMITER $$; +CREATE PACKAGE pkg1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + a t1%ROWTYPE:=ROW(10,'x10'); + PROCEDURE p1 AS + b t1%ROWTYPE:=ROW(20,'x20'); + BEGIN + b:=a; + a:=b; + b.a:=a.a+1; + a.a:=b.a+1; + a.a:=a.a+1; + END; +BEGIN + a.a:=a.a+1; + DECLARE + b t1%ROWTYPE:=ROW(30,'x30'); + BEGIN + b:=a; + b.a:=a.a+1; + a:=b; + a.a:=b.a+1; + END; +END; +$$ +DELIMITER ;$$ +SHOW PROCEDURE CODE pkg1.p1; +SHOW PACKAGE BODY CODE pkg1; +DROP PACKAGE pkg1; +DROP TABLE t1; diff --git a/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-db.test b/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-db.test new file mode 100644 index 00000000..0528e6cb --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-db.test @@ -0,0 +1,6 @@ +--echo # +--echo # MDEV-15070 Crash when doing a CREATE VIEW inside a package routine +--echo # + +SET @object_type='db'; +--source sp-package-concurrent-dml.inc diff --git a/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-package.test b/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-package.test new file mode 100644 index 00000000..0f1a0ef3 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-package.test @@ -0,0 +1,10 @@ +--echo # +--echo # MDEV-15070 Crash when doing a CREATE VIEW inside a package routine +--echo # + +SET @object_type='package_replace_pkg1'; +--source sp-package-concurrent-dml.inc + +SET @object_type='package_body_replace_pkg1'; +--source sp-package-concurrent-dml.inc + diff --git a/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-trigger.test b/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-trigger.test new file mode 100644 index 00000000..09ba1d70 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-trigger.test @@ -0,0 +1,6 @@ +--echo # +--echo # MDEV-15070 Crash when doing a CREATE VIEW inside a package routine +--echo # + +SET @object_type='trigger'; +--source sp-package-concurrent-dml.inc diff --git a/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-view.test b/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-view.test new file mode 100644 index 00000000..d2c2041a --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml-view.test @@ -0,0 +1,6 @@ +--echo # +--echo # MDEV-15070 Crash when doing a CREATE VIEW inside a package routine +--echo # + +SET @object_type='view'; +--source sp-package-concurrent-dml.inc diff --git a/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml.inc b/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml.inc new file mode 100644 index 00000000..8ee96d1e --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml.inc @@ -0,0 +1,107 @@ +--echo # +--echo # Start of sp-package-concurrent-dml.inc +--echo # + +--source include/count_sessions.inc + +let $object_type= `SELECT @object_type`; + +SET sql_mode=ORACLE; +DELIMITER $$; +CREATE PACKAGE pkg1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p2 AS + BEGIN + SELECT 'This is p2' AS msg; + END; + PROCEDURE p1 AS + BEGIN + SELECT 'This is p1' AS msg; + DO GET_LOCK('mdev15070',120); + CALL p2(); + DO RELEASE_LOCK('mdev15070'); + END; +END; +$$ +DELIMITER ;$$ + +connect (con2,localhost,root); +connection con2; +DO GET_LOCK('mdev15070', 120); + +connection default; +send CALL pkg1.p1; + +connection con2; +let $wait_condition= + SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE state = "User lock" AND info LIKE "%GET_LOCK%mdev15070%"; +--source include/wait_condition.inc + + +if ($object_type==view) +{ + CREATE VIEW v1 AS SELECT 1 AS c; + DROP VIEW v1; +} + + +if ($object_type==package_replace_pkg1) +{ + SET sql_mode=ORACLE; + DELIMITER $$; + CREATE OR REPLACE PACKAGE pkg1 AS + PROCEDURE p1; + END; + $$ + DELIMITER ;$$ + DROP PACKAGE pkg1; +} + + +if ($object_type==package_body_replace_pkg1) +{ + SET sql_mode=ORACLE; + DELIMITER $$; + CREATE OR REPLACE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS + BEGIN + SELECT 'This is p1 version 2' AS msg; + END; + END; + $$ + DELIMITER ;$$ + DROP PACKAGE pkg1; +} + + +if ($object_type==trigger) +{ + CREATE TABLE t1 (a INT); + CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=1; + DROP TRIGGER tr1; + DROP TABLE t1; +} + + +if ($object_type=='db') +{ + CREATE DATABASE test1; + CREATE FUNCTION test1.f1() RETURNS INT RETURN 10; + DROP DATABASE test1; +} + + +DO RELEASE_LOCK('mdev15070'); + +disconnect con2; + +connection default; +reap; + +DROP PACKAGE IF EXISTS pkg1; + +--source include/wait_until_count_sessions.inc diff --git a/mysql-test/suite/compat/oracle/t/sp-package-i_s.test b/mysql-test/suite/compat/oracle/t/sp-package-i_s.test new file mode 100644 index 00000000..a355e484 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-i_s.test @@ -0,0 +1,69 @@ +--source include/default_charset.inc + +--echo # +--echo # Start of 10.5 tests +--echo # + + +--echo # +--echo # MDEV-30662 SQL/PL package body does not appear in I_S.ROUTINES.ROUTINE_DEFINITION +--echo # + +# Testing a package without the executable section + +SET sql_mode=ORACLE; +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg1 AS + FUNCTION f1() RETURN INT; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + FUNCTION f1() RETURN INT AS + BEGIN + RETURN 1; + END; +END; +$$ +DELIMITER ;$$ + +--vertical_results +SELECT routine_name, routine_type, routine_definition +FROM information_schema.routines +WHERE routine_type LIKE 'PACKAGE%' +ORDER BY routine_type; +--horizontal_results + +DROP PACKAGE pkg1; + +# Testing a package with the executable section + +SET sql_mode=ORACLE; +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg1 AS + FUNCTION f1() RETURN INT; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + FUNCTION f1() RETURN INT AS + BEGIN + RETURN 1; + END; +BEGIN + SET @a=10; + SET @a=f1(); +END; +$$ +DELIMITER ;$$ + +--vertical_results +SELECT routine_name, routine_type, routine_definition +FROM information_schema.routines +WHERE routine_type LIKE 'PACKAGE%' +ORDER BY routine_type; +--horizontal_results + +DROP PACKAGE pkg1; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/mysql-test/suite/compat/oracle/t/sp-package-innodb.test b/mysql-test/suite/compat/oracle/t/sp-package-innodb.test new file mode 100644 index 00000000..94c7b714 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-innodb.test @@ -0,0 +1,66 @@ +-- source include/have_innodb.inc + +SET default_storage_engine=InnoDB; + +SET sql_mode=ORACLE; + +CREATE TABLE t1 (a INT, routine TEXT); +SELECT ENGINE FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'; +INSERT INTO t1 VALUES (10,'none'); + +--enable_prepare_warnings + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + a INT; + PROCEDURE p1 AS + BEGIN + a:=a+1; + INSERT INTO t1 VALUES (a,'p1'); + END; +BEGIN + SELECT MAX(t1.a) FROM t1 INTO a; + a:=a+1; + INSERT INTO t1 VALUES (a,'pkg1 initialization'); +END; +$$ +DELIMITER ;$$ +CALL pkg1.p1; +SELECT * FROM t1 ORDER BY a; +DELETE FROM t1; + +--source sp-cache-invalidate.inc +START TRANSACTION; +CALL pkg1.p1; +SELECT * FROM t1 ORDER BY a; +ROLLBACK; +SELECT * FROM t1 ORDER BY a; +DELETE FROM t1; + +--source sp-cache-invalidate.inc +INSERT INTO t1 VALUES (20,'none'); +START TRANSACTION; +CALL pkg1.p1; +SELECT * FROM t1 ORDER BY a; +COMMIT; +SELECT * FROM t1 ORDER BY a; +DELETE FROM t1; + +--source sp-cache-invalidate.inc +INSERT INTO t1 VALUES (20,'none'); +START TRANSACTION; +CALL pkg1.p1; +SELECT * FROM t1 ORDER BY a; +ROLLBACK; +SELECT * FROM t1 ORDER BY a; +DELETE FROM t1; + +--disable_prepare_warnings + +DROP PACKAGE pkg1; +DROP TABLE t1; diff --git a/mysql-test/suite/compat/oracle/t/sp-package-mdl.test b/mysql-test/suite/compat/oracle/t/sp-package-mdl.test new file mode 100644 index 00000000..de4f7aaa --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-mdl.test @@ -0,0 +1,110 @@ +--source include/have_metadata_lock_info.inc + +# +# This test demonstrates that: +# - A call to a package routine acquires a shared MDL lock on the entire package +# - "DROP PACKAGE" waits until the currently running package routines end +# + +SET sql_mode=ORACLE; +DO GET_LOCK('lock',300); + + +# +# conn1 will execute package pkg1 routines and +# and therefore acquire a shared MDL on "package body pkg1" +# + +connect (conn1,localhost,root,,); +SET sql_mode=ORACLE; +let $conn1_id= `SELECT CONNECTION_ID()`; +DELIMITER $$; +CREATE PACKAGE pkg1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS + BEGIN + DO GET_LOCK('lock',300); + END; + FUNCTION f1 RETURN INT AS + BEGIN + CALL p1; + RETURN 1; + END; +END; +$$ +DELIMITER ;$$ +send SELECT pkg1.f1(); + +# +# wait for conn1 to actually start execution of pkg1.p1 +# + +connection default; +let $wait_timeout= 60; +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE ID=$conn1_id AND INFO LIKE '%GET_LOCK%' AND STATE='User lock'; +--source include/wait_condition.inc + + +# +# conn2 will do "DROP PACKAGE pkg1". +# It will acquire an exclusive MDL on "package body pkg1", and therefore +# it should wait until conn1 ends the package routine execution +# + +connect (conn2,localhost,root,,); +let $conn2_id= `SELECT CONNECTION_ID()`; +SET sql_mode=ORACLE; +send DROP PACKAGE pkg1; + +# +# wait for conn2 to actually enter the "DROP" statement and get locked by conn1 +# +connection default; +let $wait_timeout= 60; +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE ID=$conn2_id + AND INFO LIKE '%DROP PACKAGE%' + AND STATE='Waiting for stored package body metadata lock'; +--source include/wait_condition.inc + +# +# Now we have three threads involved. +# The following I_S query will check that the threads are in these states: +# +# default (0) - is holding a user lock 'lock' +# conn1 (1) - is executing the package procedure test.pkg1.p1, +# is holding a shared MDL on 'package body pkg1', +# is waiting for the user lock 'lock' to be released +# conn2 (2) - is waiting for 'conn1' to end execution of test.pkg1.* routines, +# to acquire an exclusive MDL on 'package body pkg1', +# to DROP the package pkg1 +# +--vertical_results +SELECT ID-CONNECTION_ID() AS CONN,INFO,STATE,LOCK_MODE,LOCK_TYPE,TABLE_NAME + FROM INFORMATION_SCHEMA.PROCESSLIST + LEFT JOIN INFORMATION_SCHEMA.METADATA_LOCK_INFO + ON (ID=THREAD_ID) + ORDER BY ID,TABLE_NAME,LOCK_MODE,LOCK_TYPE; +--horizontal_results + +# +# Now let conn1 finish the package routine execution +# +DO RELEASE_LOCK('lock'); +connection conn1; +reap; +disconnect conn1; + +# +# Now conn2 should actually DROP the package +# +connection conn2; +reap; +disconnect conn2; + +connection default; diff --git a/mysql-test/suite/compat/oracle/t/sp-package-mysqldump.test b/mysql-test/suite/compat/oracle/t/sp-package-mysqldump.test new file mode 100644 index 00000000..c4e4b2a1 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-mysqldump.test @@ -0,0 +1,94 @@ +--source include/have_utf8mb4.inc +--source include/not_embedded.inc + +SET sql_mode=ORACLE; + +# +# Create a standalone procedure test.p1 and a package pkg1. +# The standalone routine test.p1 and the package routines call each other. +# + +DELIMITER $$; +CREATE PROCEDURE p1 AS +BEGIN + SELECT pkg1.f1(); -- a standalone routine calls a package routine +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS + BEGIN + CALL test.p1; -- a package routine calls a standalone routine + END; + FUNCTION f1 RETURN INT AS + BEGIN + RETURN 10; + END; +END; +$$ +DELIMITER ;$$ + +CALL p1; +CALL pkg1.p1; +SELECT pkg1.f1(); + + +# +# Create specifications for one more package, without a BODY +# +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +DELIMITER ;$$ + + +--exec $MYSQL_DUMP --skip-comments --routines --default-character-set=utf8mb4 test +--exec $MYSQL_DUMP --skip-comments --routines --xml test + +let $dump = $MYSQLTEST_VARDIR/tmp/sp-package-mysqldump.sql; + +--exec $MYSQL_DUMP --compact --routines test > $dump + +DROP PACKAGE pkg1; +DROP PACKAGE pkg2; +DROP PROCEDURE p1; + +--exec $MYSQL test < $dump + +--vertical_results +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +SHOW PACKAGE STATUS; +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +SHOW PACKAGE BODY STATUS; +--horizontal_results + +SHOW CREATE PACKAGE pkg1; +SHOW CREATE PACKAGE pkg2; +SHOW CREATE PACKAGE BODY pkg1; + +CALL p1; +CALL pkg1.p1; +SELECT pkg1.f1(); + +DROP PACKAGE pkg1; +DROP PACKAGE pkg2; +DROP PROCEDURE p1; + +--echo # removing the dump file +--error 0,1 +--remove_file $dump diff --git a/mysql-test/suite/compat/oracle/t/sp-package-security.test b/mysql-test/suite/compat/oracle/t/sp-package-security.test new file mode 100644 index 00000000..583f70af --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-security.test @@ -0,0 +1,332 @@ +--source include/not_embedded.inc +--source include/default_charset.inc + +SET sql_mode=ORACLE; + +CREATE DATABASE db1; +CREATE USER u1@localhost IDENTIFIED BY ''; +GRANT SELECT ON db1.* TO u1@localhost; + +connect (conn1,localhost,u1,,db1); +SELECT CURRENT_USER; +SET sql_mode=ORACLE; + +--echo # +--echo # User u1 cannot drop PROCEDURE, PACKAGE, PACKAGE BODY by default +--echo # + +--error ER_PROCACCESS_DENIED_ERROR +DROP PROCEDURE p1; +--error ER_PROCACCESS_DENIED_ERROR +DROP PACKAGE pkg1; +--error ER_PROCACCESS_DENIED_ERROR +DROP PACKAGE BODY pkg1; + +--echo # +--echo # User u1 cannot create PROCEDURE, PACKAGE, PACKAGE BODY by default +--echo # + +DELIMITER $$; +--error ER_DBACCESS_DENIED_ERROR +CREATE PROCEDURE p1 AS +BEGIN + NULL; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_DBACCESS_DENIED_ERROR +CREATE PACKAGE pkg1 AS + PROCEDURE p1; +END; +$$ +DELIMITER ;$$ + +# TODO: this should probably return ER_DBACCESS_DENIED_ERROR +DELIMITER $$; +--error ER_SP_DOES_NOT_EXIST +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS BEGIN NULL; END; +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # Now create a PACKAGE by root +--echo # + +connection default; +USE db1; + +DELIMITER $$; +CREATE PROCEDURE p1root AS +BEGIN + SELECT 1; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + PROCEDURE p1; + FUNCTION f1 RETURN TEXT; +END; +$$ +DELIMITER ;$$ +SHOW CREATE PACKAGE pkg1; + +--echo # +--echo # u1 cannot SHOW yet: +--echo # - the standalone procedure earlier created by root +--echo # - the package specifications earlier create by root +--echo # + +connection conn1; +--error ER_SP_DOES_NOT_EXIST +SHOW CREATE PROCEDURE p1root; +--error ER_SP_DOES_NOT_EXIST +SHOW CREATE PACKAGE pkg1; + + +--echo # +--echo # User u1 still cannot create a PACKAGE BODY +--echo # + +connection conn1; +DELIMITER $$; +--error ER_DBACCESS_DENIED_ERROR +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS BEGIN NULL; END; + FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is f1'; END; +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # Now grant EXECUTE: +--echo # - on the standalone procedure earlier created by root +--echo # - on the package specification earlier created by root +--echo # +connection default; +GRANT EXECUTE ON PROCEDURE db1.p1root TO u1@localhost; +GRANT EXECUTE ON PACKAGE db1.pkg1 TO u1@localhost; + +--echo # +--echo # Now u1 can do SHOW for: +--echo # - the standalone procedure earlier created by root +--echo # - the package specification earlier created by root +--echo # + +disconnect conn1; +connect (conn1,localhost,u1,,db1); +SET sql_mode=ORACLE; +SHOW CREATE PROCEDURE db1.p1root; +SHOW CREATE PACKAGE db1.pkg1; + + +--echo # +--echo # Now revoke EXECUTE and grant CREATE ROUTINE instead +--echo # + +connection default; +REVOKE EXECUTE ON PROCEDURE db1.p1root FROM u1@localhost; +REVOKE EXECUTE ON PACKAGE db1.pkg1 FROM u1@localhost; +GRANT CREATE ROUTINE ON db1.* TO u1@localhost; + +--echo # +--echo # Reconnect u1 to make new grants have effect +--echo # + +disconnect conn1; +connect (conn1,localhost,u1,,db1); +SET sql_mode=ORACLE; + +--echo # +--echo # Now u1 can SHOW: +--echo # - standalone routines earlier created by root +--echo # - package specifications earlier created by root +--echo # +SHOW CREATE PROCEDURE p1root; +SHOW CREATE PACKAGE pkg1; + +--echo # +--echo # Now u1 can CREATE, DROP and EXECUTE its own standalone procedures +--echo # + +DELIMITER $$; +CREATE PROCEDURE p1 AS +BEGIN + NULL; +END; +$$ +DELIMITER ;$$ +SHOW GRANTS; +CALL p1; +DROP PROCEDURE p1; +SHOW GRANTS; + +--echo # +--echo # Now u1 can also CREATE, DROP its own package specifications +--echo # + +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; + FUNCTION f1 RETURN TEXT; +END; +$$ +DELIMITER ;$$ +SHOW CREATE PACKAGE pkg2; +SHOW GRANTS; +DROP PACKAGE pkg2; +SHOW GRANTS; + + +--echo # +--echo # Now u1 can also CREATE, DROP package bodies and EXECUTE package body routines +--echo # + +DELIMITER $$; +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS BEGIN SELECT 'This is pkg1.p1' AS `comment`; END; + FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is pkg1.f1'; END; +END; +$$ +DELIMITER ;$$ +SHOW CREATE PACKAGE pkg1; +SHOW CREATE PACKAGE BODY pkg1; +SHOW GRANTS; +CALL pkg1.p1; +SELECT pkg1.f1(); +DROP PACKAGE BODY pkg1; +SHOW GRANTS; + +--echo # +--echo # Now create a PACKAGE BODY by root. +--echo # u1 does not have EXECUTE access by default. +--echo # + +connection default; +DELIMITER $$; +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS BEGIN SELECT 'This is pkg1.p1' AS `comment`; END; + FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is pkg1.f1'; END; +END; +$$ +DELIMITER ;$$ + +connection conn1; +SHOW CREATE PACKAGE pkg1; +SHOW CREATE PACKAGE BODY pkg1; +--error ER_PROCACCESS_DENIED_ERROR +CALL pkg1.p1; +--error ER_PROCACCESS_DENIED_ERROR +SELECT pkg1.f1(); + +--echo # +--echo # Now grant EXECUTE to u1 on the PACKAGE BODY created by root +--echo # + +connection default; +GRANT EXECUTE ON PACKAGE BODY db1.pkg1 TO u1@localhost; +disconnect conn1; +connect (conn1,localhost,u1,,db1); +SELECT CURRENT_USER; +SET sql_mode=ORACLE; +SHOW GRANTS; +CALL pkg1.p1; +SELECT pkg1.f1(); + +connection default; +DROP PACKAGE BODY pkg1; + + +--echo # +--echo # u1 still cannot DROP the package specification earlier created by root. +--echo # + +connection conn1; +--error ER_PROCACCESS_DENIED_ERROR +DROP PACKAGE pkg1; + +--echo # +--echo # Grant ALTER ROUTINE to u1 +--echo # + +connection default; +GRANT ALTER ROUTINE ON db1.* TO u1@localhost; + +--echo # +--echo # Now u1 can DROP: +--echo # - the standalone procedure earlier created by root +--echo # - the package specification earlier created by root +--echo # + +disconnect conn1; +connect (conn1,localhost,u1,,db1); +SET sql_mode=ORACLE; +DROP PACKAGE pkg1; +DROP PROCEDURE p1root; + +disconnect conn1; +connection default; + +DROP USER u1@localhost; +DROP DATABASE db1; +USE test; + + +--echo # +--echo # Creator=root, definer=xxx +--echo # + +CREATE USER xxx@localhost; +DELIMITER $$; +CREATE DEFINER=xxx@localhost PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE DEFINER=xxx@localhost PACKAGE BODY p1 AS + PROCEDURE p1 AS + BEGIN + SELECT SESSION_USER(), CURRENT_USER(), 'p1.p1' AS msg; + END; +BEGIN + SELECT SESSION_USER(), CURRENT_USER(), 'package body p1' AS msg; +END; +$$ +DELIMITER ;$$ +--error ER_PROCACCESS_DENIED_ERROR +CALL p1.p1; +GRANT EXECUTE ON PACKAGE BODY test.p1 TO xxx@localhost; +CALL p1.p1; +DROP PACKAGE p1; +DROP USER xxx@localhost; + + +--echo # +--echo # Creator=root, definer=xxx, SQL SECURITY INVOKER +--echo # + +CREATE USER xxx@localhost; +DELIMITER $$; +CREATE DEFINER=xxx@localhost PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE DEFINER=xxx@localhost PACKAGE BODY p1 SQL SECURITY INVOKER AS + PROCEDURE p1 AS + BEGIN + SELECT SESSION_USER(), CURRENT_USER(), 'p1.p1' AS msg; + END; +BEGIN + SELECT SESSION_USER(), CURRENT_USER(), 'package body p1' AS msg; +END; +$$ +DELIMITER ;$$ +CALL p1.p1; +DROP PACKAGE p1; +DROP USER xxx@localhost; diff --git a/mysql-test/suite/compat/oracle/t/sp-package.test b/mysql-test/suite/compat/oracle/t/sp-package.test new file mode 100644 index 00000000..b6310eed --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package.test @@ -0,0 +1,3092 @@ +--source include/default_charset.inc + +SET sql_mode=ORACLE; + +--enable_prepare_warnings +--disable_ps2_protocol + +--echo # +--echo # Creating a body of a non-existing package +--echo # +DELIMITER $$; +--error ER_SP_DOES_NOT_EXIST +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END; +END; +$$ +DELIMITER ;$$ + +--echo # +--echo # Dropping a non-existing package +--echo # +--error ER_SP_DOES_NOT_EXIST +DROP PACKAGE test2; +DROP PACKAGE IF EXISTS test2; +--error ER_SP_DOES_NOT_EXIST +DROP PACKAGE BODY test2; + + +--echo # +--echo # Bad combinations of OR REPLACE and IF EXISTS +--echo # + +DELIMITER $$; +--error ER_WRONG_USAGE +CREATE OR REPLACE PACKAGE IF NOT EXISTS pkg AS + PROCEDURE p1; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_WRONG_USAGE +CREATE OR REPLACE PACKAGE BODY IF NOT EXISTS pkg AS + PROCEDURE p1 AS BEGIN NULL; END; +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # PACKAGE and PS +--echo # + +PREPARE stmt FROM 'CREATE PACKAGE test2 AS FUNCTION f1 RETURN INT; END test2'; + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; +END; +$$ +DELIMITER ;$$ +PREPARE stmt FROM 'CREATE PACKAGE BODY test2 AS' + ' FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END;' + 'END test2'; +DROP PACKAGE test2; + + +--echo # +--echo # Package and READ ONLY transactions +--echo # + +SET SESSION TRANSACTION READ ONLY; + +DELIMITER $$; +--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END +$$ +DELIMITER ;$$ + +SET SESSION TRANSACTION READ WRITE; + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + FUNCTION f2 RETURN INT; +END; +$$ +SET SESSION TRANSACTION READ ONLY +$$ +--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END; + FUNCTION f2 RETURN INT AS BEGIN RETURN f1(); END; + PROCEDURE p1 AS + BEGIN + SELECT f2(); + END; +END; +$$ +DELIMITER ;$$ +SET SESSION TRANSACTION READ WRITE; +DROP PACKAGE test2; + +SET SESSION TRANSACTION READ ONLY; +--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION +DROP PACKAGE test2; +--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION +DROP PACKAGE BODY test2; + +SET SESSION TRANSACTION READ WRITE; + + +--echo # +--echo # Syntax error inside a CREATE PACKAGE, inside a routine definition +--echo # + +DELIMITER $$; +--error ER_PARSE_ERROR +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + FUNCTION f2 RETURN INT; + FUNCTION f3; + FUNCTION f4 RETURN INT; +END +$$ +DELIMITER ;$$ + + +--echo # +--echo # Syntax error inside a CREATE PACKAGE, outside of a routine definition +--echo # + +# The definition "FUNCTION f3 RETURN INT AS BEGIN RETURN 10; END;" +# is valid in CREATE PACKAGE BODY, but not in CREATE PACKAGE. +# Syntax error happens after parsing "FUNCTION f3 RETURN INT". + +DELIMITER $$; +--error ER_PARSE_ERROR +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + FUNCTION f2 RETURN INT; + FUNCTION f3 RETURN INT AS BEGIN RETURN 10; END; + FUNCTION f4 RETURN INT; +END +$$ +DELIMITER ;$$ + + +--echo # +--echo # Syntax error inside a CREATE PACKAGE BODY, inside a routine definition +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + FUNCTION f2 RETURN INT; +END; +$$ +--error ER_PARSE_ERROR +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END; + FUNCTION f2 RETURN INT SA BEGIN RETURN 10; END; -- Notice "SA" vs "AS" +END +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + +--echo # +--echo # Syntax error inside a CREATE PACKAGE BODY, outside a routine definition +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + FUNCTION f2 RETURN INT; +END; +$$ +--error ER_PARSE_ERROR +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END; + SOME SYNTAX ERROR; + FUNCTION f2 RETURN INT AS BEGIN RETURN 10; END; +END +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + + +--echo # +--echo # Syntax error inside a CREATE PACKAGE BODY executable section +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; +END; +$$ +--error ER_PARSE_ERROR +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END; +BEGIN + SOME SYNTAX ERROR; +END +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + + +--echo # +--echo # CREATE PROCEDURE inside a package PROCEDURE is not allowed +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +--error ER_SP_NO_RECURSIVE_CREATE +CREATE PACKAGE BODY test2 AS + PROCEDURE p1 AS + BEGIN + CREATE PROCEDURE p1 AS BEGIN NULL; END; + END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + + +--echo # +--echo # CREATE PACKAGE inside a package PROCEDURE is not allowed +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +--error ER_SP_NO_RECURSIVE_CREATE +CREATE PACKAGE BODY test2 AS + PROCEDURE p1 AS + BEGIN + CREATE PACKAGE p1 AS PROCEDURE p1; END; + END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + + +--echo # +--echo # CREATE PROCEDURE inside a package executable section is not allowed +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +--error ER_SP_NO_RECURSIVE_CREATE +CREATE PACKAGE BODY test2 AS + PROCEDURE p1 AS BEGIN NULL; END; +BEGIN + CREATE PROCEDURE p1 AS BEGIN NULL; END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + + +--echo # +--echo # CREATE FUNCTION inside a package executable section is not allowed +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +--error ER_SP_NO_RECURSIVE_CREATE +CREATE PACKAGE BODY test2 AS + PROCEDURE p1 AS BEGIN NULL; END; +BEGIN + CREATE FUNCTION f1 RETURN INT AS BEGIN RETURN 0; END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + + +--echo # +--echo # CREATE PACKAGE inside a package executable section is not allowed +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +--error ER_SP_NO_RECURSIVE_CREATE +CREATE PACKAGE BODY test2 AS + PROCEDURE p1 AS BEGIN NULL; END; +BEGIN + CREATE PACKAGE p1 AS PROCEDURE p1; END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + + +--echo # +--echo # Broken CREATE PACKAGE at CREATE PACKAGE BODY time +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; +END; +$$ +DELIMITER ;$$ + +UPDATE mysql.proc SET `body`='garbage' + WHERE db='test' AND name='test2' AND type='PACKAGE'; + +DELIMITER $$; +--error ER_SP_PROC_TABLE_CORRUPT +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT + AS BEGIN + RETURN f2(); + END; +END; +$$ +DELIMITER ;$$ +show warnings; + +DROP PACKAGE test2; + + +--echo # +--echo # Broken CREATE PACKAGE at a package function call time +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT + AS BEGIN + RETURN f2(); + END; +END; +$$ +DELIMITER ;$$ + +--error ER_SP_DOES_NOT_EXIST +SELECT test2.f1(); +UPDATE mysql.proc SET `body`='garbage' + WHERE db='test' AND name='test2' AND type='PACKAGE'; +--source sp-cache-invalidate.inc +--error ER_SP_PROC_TABLE_CORRUPT +SELECT test2.f1(); +show warnings; +--error ER_SP_PROC_TABLE_CORRUPT +SELECT test2.f1(); +show warnings; +--error ER_SP_PROC_TABLE_CORRUPT +SELECT test2.f1(); +show warnings; + +DROP PACKAGE test2; + + +--echo # +--echo # Broken CREATE PACKAGE at a package procedure call time +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PACKAGE BODY test2 AS + PROCEDURE p1 + AS BEGIN + CALL p2; + END; +END; +$$ +DELIMITER ;$$ + +--error ER_SP_DOES_NOT_EXIST +CALL test2.f1(); +UPDATE mysql.proc SET `body`='garbage' + WHERE db='test' AND name='test2' AND type='PACKAGE'; +--source sp-cache-invalidate.inc +--error ER_SP_PROC_TABLE_CORRUPT +CALL test2.p1(); +show warnings; +--error ER_SP_PROC_TABLE_CORRUPT +CALL test2.p1(); +show warnings; +--error ER_SP_PROC_TABLE_CORRUPT +CALL test2.p1(); +show warnings; + +DROP PACKAGE test2; + + +--echo # +--echo # Bad routine names +--echo # + +DELIMITER $$; +--error ER_TOO_LONG_IDENT +CREATE PACKAGE p1 AS + PROCEDURE pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp1; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_TOO_LONG_IDENT +CREATE PACKAGE p1 AS + FUNCTION fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1 + RETURN INT; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_SP_WRONG_NAME +CREATE PACKAGE p1 AS + PROCEDURE "p1 "; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_SP_WRONG_NAME +CREATE PACKAGE p1 AS + FUNCTION "f1 " RETURN INT; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_SP_WRONG_NAME +CREATE PACKAGE p1 AS + PROCEDURE "p1.p1"; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_SP_WRONG_NAME +CREATE PACKAGE p1 AS + FUNCTION "f1.f1" RETURN INT; +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # Duplicate PROCEDURE in CREATE PACKAGE +--echo # + +DELIMITER $$; +--error ER_SP_ALREADY_EXISTS, +CREATE PACKAGE test2 AS + PROCEDURE p1; + PROCEDURE p1; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_SP_ALREADY_EXISTS, +CREATE PACKAGE test2 AS + PROCEDURE p1; + PROCEDURE P1; +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # Duplicate FUNCTION in CREATE PACKAGE +--echo # + +DELIMITER $$; +--error ER_SP_ALREADY_EXISTS, +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + FUNCTION f1 RETURN INT; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_SP_ALREADY_EXISTS, +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + FUNCTION F1 RETURN INT; +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # Duplicate PROCEDURE in CREATE PACKAGE BODY +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +--error ER_SP_ALREADY_EXISTS +CREATE PACKAGE BODY test2 AS + PROCEDURE p1 AS BEGIN NULL; END; + PROCEDURE p1 AS BEGIN NULL; END; +END; +$$ +--error ER_SP_ALREADY_EXISTS +CREATE PACKAGE BODY test2 AS + PROCEDURE p1 AS BEGIN NULL; END; + PROCEDURE P1 AS BEGIN NULL; END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + + +--echo # +--echo # Duplicate FUNCTION in CREATE PACKAGE BODY +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; +END; +$$ +--error ER_SP_ALREADY_EXISTS +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 0; END; + FUNCTION f1 RETURN INT AS BEGIN RETURN 0; END; +END; +$$ +--error ER_SP_ALREADY_EXISTS +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 0; END; + FUNCTION F1 RETURN INT AS BEGIN RETURN 0; END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + + +--echo # +--echo # Routines declared in CREATE PACKAGE missing in CREATE PACKAGE BODY +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +--error ER_PACKAGE_ROUTINE_IN_SPEC_NOT_DEFINED_IN_BODY +CREATE PACKAGE BODY test2 AS + PROCEDURE p2 AS BEGIN NULL; END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; +END; +$$ +--error ER_PACKAGE_ROUTINE_IN_SPEC_NOT_DEFINED_IN_BODY +CREATE PACKAGE BODY test2 AS + FUNCTION f2 RETURN INT AS BEGIN RETURN 10; END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +--error ER_PACKAGE_ROUTINE_IN_SPEC_NOT_DEFINED_IN_BODY +CREATE PACKAGE BODY test2 AS + FUNCTION p1 RETURN INT AS BEGIN RETURN 10; END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +--error ER_PACKAGE_ROUTINE_IN_SPEC_NOT_DEFINED_IN_BODY +CREATE PACKAGE BODY test2 AS + PROCEDURE p1(a INT) AS BEGIN NULL; END; -- Notice different prototype +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + +--echo # +--echo # Forward declarations in CREATE PACKAGE BODY with missing implementations +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +--error ER_PACKAGE_ROUTINE_FORWARD_DECLARATION_NOT_DEFINED +CREATE PACKAGE BODY test2 AS + PROCEDURE p1 AS BEGIN NULL; END; + PROCEDURE p2; +END; +$$ +--error ER_PACKAGE_ROUTINE_FORWARD_DECLARATION_NOT_DEFINED +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT; + PROCEDURE p1 AS BEGIN NULL; END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + + +--echo # +--echo # Creating a new package +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 COMMENT 'package-test2-comment' AS + FUNCTION f1 RETURN INT DETERMINISTIC; + FUNCTION f2(a INT) RETURN INT; + FUNCTION concat RETURN INT; + PROCEDURE p1; + PROCEDURE p2(a INT); +END +$$ +DELIMITER ;$$ + +--vertical_results +--replace_column 13 # 14 # +SELECT * FROM mysql.proc WHERE db='test' AND name='test2'; +--replace_column 24 # 25 # +SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA='test' AND ROUTINE_NAME='test2'; +--horizontal_results + +DELIMITER $$; +CREATE PACKAGE IF NOT EXISTS test2 AS + FUNCTION f1 RETURN INT; +END test2 +$$ +DELIMITER ;$$ + + +DELIMITER $$; +CREATE PACKAGE BODY test2 COMMENT 'package-body-test2-comment' AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END; + FUNCTION f2(a INT) RETURN INT AS BEGIN RETURN f1()+a; END; + FUNCTION concat RETURN INT AS BEGIN RETURN 1; END; + PROCEDURE p1 AS + BEGIN + SELECT f2(0); + END; + PROCEDURE p2(a INT) AS + BEGIN + SELECT f2(a); + END; +END; +$$ +DELIMITER ;$$ + +# This should do nothing and return a warning +DELIMITER $$; +CREATE PACKAGE BODY IF NOT EXISTS test2 AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 20; END; + FUNCTION f2(a INT) RETURN INT AS BEGIN RETURN f1()+a; END; + FUNCTION concat RETURN INT AS BEGIN RETURN 1; END; + PROCEDURE p1 AS + BEGIN + SELECT f2(0); + END; + PROCEDURE p2(a INT) AS + BEGIN + SELECT f2(a); + END; +END; +$$ +DELIMITER ;$$ + +# +# The next query issues a warning about "concat" name collision, +# raised during compilation of the package body. +# However, "mtr --ps" does not produce the warning. +# It's not a package specific issue. The same difference exists for +# standalone functions. So just suppress warning for now. +# +--disable_warnings +SELECT test2.f1(); +--enable_warnings +SELECT test2.f2(1); +CALL test2.p1(); +CALL test2.p2(1); + +--vertical_results +--replace_column 13 # 14 # +SELECT * FROM mysql.proc WHERE db='test' AND name LIKE 'test2.%'; +--replace_column 24 # 25 # +SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA='test' AND ROUTINE_NAME='test2'; +--replace_column 24 # 25 # +SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA='test' AND ROUTINE_NAME LIKE 'test2.%'; +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +SHOW PACKAGE STATUS; +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +SHOW PACKAGE BODY STATUS; +SHOW CREATE PACKAGE test2; +SHOW CREATE PACKAGE BODY test2; +--horizontal_results + + + +DROP PACKAGE BODY test2; +--error ER_SP_DOES_NOT_EXIST +SELECT test2.f1(); +--error ER_SP_DOES_NOT_EXIST +SELECT test2.f2(); +--error ER_SP_DOES_NOT_EXIST +CALL test2.p1(); + +DROP PACKAGE BODY IF EXISTS test2; + +--error ER_SP_DOES_NOT_EXIST +DROP PACKAGE BODY test2; + + +DROP PACKAGE test2; + + +--echo # +--echo # Creating a new package in a remote database +--echo # + +CREATE DATABASE test2; + +DELIMITER $$; +CREATE PACKAGE test2.test2 COMMENT 'package-test2-comment' AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PACKAGE BODY test2.test2 COMMENT 'package-body-test2-comment' AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END; + PROCEDURE p1 AS BEGIN SELECT f1(); END; +END; +$$ +DELIMITER ;$$ + +--vertical_results +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +SHOW PACKAGE STATUS; +--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +SHOW PACKAGE BODY STATUS; +--horizontal_results + +USE test2; +SELECT test2.f1(); +CALL test2.p1(); +USE test; +DROP PACKAGE BODY test2.test2; +DROP PACKAGE test2.test2; +DROP DATABASE test2; + + +--echo # +--echo # Only public routines are available outside +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY test2 AS + -- Public routines + FUNCTION f1 RETURN TEXT AS + BEGIN + RETURN 'This is test2.f1'; + END; + PROCEDURE p1 AS + BEGIN + SELECT 'This is test2.p1'; + END; + -- Private routines + FUNCTION f2 RETURN TEXT AS + BEGIN + RETURN 'This is test2.f2'; + END; + PROCEDURE p2 AS + BEGIN + SELECT 'This is test2.p2'; + END; +END; +$$ +DELIMITER ;$$ +SELECT test2.f1(); +CALL test2.p1(); +--error ER_SP_DOES_NOT_EXIST +SELECT test2.f2(); +--error ER_SP_DOES_NOT_EXIST +CALL test2.p2(); +DROP PACKAGE test2; + + +--echo # +--echo # PACKAGE BODY with forward declarations +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY test2 AS + -- Forward declarations + FUNCTION f2private RETURN TEXT; + PROCEDURE p2private; + -- Public routines + FUNCTION f1 RETURN TEXT AS + BEGIN + RETURN f2private(); + END; + PROCEDURE p1 AS + BEGIN + CALL p2private; + END; + -- Definitions for the forward declarations + FUNCTION f2private RETURN TEXT AS + BEGIN + RETURN 'This is f2private'; + END; + PROCEDURE p2private AS + BEGIN + SELECT 'This is p2private'; + END; +END; +$$ +DELIMITER ;$$ +SELECT test2.f1(); +CALL test2.p1(); +DROP PACKAGE test2; + + +--echo # +--echo # Calling private routines with forward declarations, +--echo # using qualified notation, e.g. "CALL pkg.proc" +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY test2 AS + -- Forward declarations + FUNCTION f2private RETURN TEXT; + PROCEDURE p2private; + -- Public routines + FUNCTION f1 RETURN TEXT AS + BEGIN + RETURN test2.f2private(); + END; + PROCEDURE p1 AS + BEGIN + CALL test2.p2private; + END; + -- Definitions for the forward declarations + FUNCTION f2private RETURN TEXT AS + BEGIN + RETURN 'This is f2private'; + END; + PROCEDURE p2private AS + BEGIN + SELECT 'This is p2private' AS msg; + END; +END; +$$ +DELIMITER ;$$ +SELECT test2.f1(); +CALL test2.p1(); +DROP PACKAGE test2; + + +--echo # +--echo # Calling private routines, using qualified notation, e.g. "pkg.proc" +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY test2 AS + -- Private routines + FUNCTION f2private RETURN TEXT AS + BEGIN + RETURN 'This is f2private'; + END; + PROCEDURE p2private AS + BEGIN + SELECT 'This is p2private' AS msg; + END; + -- Public routines + FUNCTION f1 RETURN TEXT AS + BEGIN + RETURN test2.f2private(); + END; + PROCEDURE p1 AS + BEGIN + CALL test2.p2private; + END; +END; +$$ +DELIMITER ;$$ +SELECT test2.f1(); +CALL test2.p1(); +DROP PACKAGE test2; + + +--echo # +--echo # Calling private routines from the package initialization section, +--echo # using qualified notation, e.g. "pkg.proc" +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY test2 AS + -- Private routines + FUNCTION f2private RETURN TEXT AS + BEGIN + RETURN 'This is f2private'; + END; + PROCEDURE p2private AS + BEGIN + SELECT 'This is p2private' AS msg; + END; + -- Public routines + PROCEDURE p1 AS + BEGIN + SELECT 'This is p1' AS msg; + END; +BEGIN + SELECT test2.f2private(); + CALL test2.p2private(); +END; +$$ +DELIMITER ;$$ +CALL test2.p1(); +DROP PACKAGE test2; + + +--echo # +--echo # Testing OR REPLACE +--echo # + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg AS + FUNCTION f0 RETURN INT; +END; +$$ +CREATE OR REPLACE PACKAGE pkg AS + FUNCTION f1 RETURN INT; +END; +$$ +DELIMITER ;$$ +SELECT name, type, `body` FROM mysql.proc WHERE name LIKE 'pkg%' ORDER BY type; + +DELIMITER $$; +CREATE OR REPLACE PACKAGE BODY pkg AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END; +END; +$$ +DELIMITER ;$$ +SELECT name, type, `body` FROM mysql.proc WHERE name LIKE 'pkg%' ORDER BY type; +SELECT pkg.f1(); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE BODY pkg AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 20; END; +END; +$$ +DELIMITER ;$$ +SELECT name, type, `body` FROM mysql.proc WHERE name LIKE 'pkg%' ORDER BY type; +SELECT pkg.f1(); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg AS + FUNCTION f1 RETURN BIGINT; +END; +$$ +DELIMITER ;$$ +SELECT name, type, `body` FROM mysql.proc WHERE name LIKE 'pkg%' ORDER BY type; +--error ER_SP_DOES_NOT_EXIST +SELECT pkg.f1(); + +DELIMITER $$; +CREATE OR REPLACE PACKAGE BODY pkg AS + FUNCTION f1 RETURN INT AS BEGIN RETURN 30; END; +END; +$$ +DELIMITER ;$$ +SELECT name, type, `body` FROM mysql.proc WHERE name LIKE 'pkg%' ORDER BY type; +SELECT pkg.f1(); + +DROP PACKAGE pkg; + + +--echo # +--echo # Package routines accessing tables +--echo # +CREATE TABLE t1 (a INT); +DELIMITER $$; +CREATE PACKAGE test2 AS + PROCEDURE p1(a INT); +END; +$$ +CREATE PACKAGE BODY test2 AS + PROCEDURE p1(a INT) AS + BEGIN + INSERT INTO t1 VALUES (10); + END; +END; +$$ +DELIMITER ;$$ +CALL test2.p1(10); +SELECT * FROM t1; +DROP PACKAGE test2; +DROP TABLE t1; + + +--echo # +--echo # CREATE PACKAGE: Optional package name after the "END" keyword +--echo # + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END test2.test2 +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END test3 +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END test2 +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + + +--echo # +--echo # MDEV-12089 sql_mode=ORACLE: Understand optional routine name after the END keyword +--echo # + + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN INT; + PROCEDURE p1; +END test2; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_PARSE_ERROR +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT AS + BEGIN + RETURN 10; + END f1.f1; +END test2; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT AS + BEGIN + RETURN 10; + END f2; +END test2; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_PARSE_ERROR +CREATE PACKAGE BODY test2 AS + PROCEDURE p1 AS + BEGIN + NULL; + END p1.p1; +END test2; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_END_IDENTIFIER_DOES_NOT_MATCH +CREATE PACKAGE BODY test2 AS + PROCEDURE p1 AS + BEGIN + NULL; + END p2; +END test2; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN INT AS + BEGIN + RETURN 10; + END f1; + PROCEDURE p1 AS + BEGIN + NULL; + END p1; +END test2; +$$ +DELIMITER ;$$ +DROP PACKAGE test2; + +--echo # +--echo # Package and package routine name and end name are case insensitive +--echo # + +DELIMITER $$; +CREATE PACKAGE test2 AS + FUNCTION f1 RETURN TEXT; + PROCEDURE p1; +END TEST2; +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PACKAGE BODY test2 AS + FUNCTION f1 RETURN TEXT AS + BEGIN + RETURN 'This is f1'; + END F1; + PROCEDURE P1 AS + BEGIN + SELECT 'This is p1' AS msg; + END p1; +END TEST2; +$$ +DELIMITER ;$$ +SELECT TEST2.F1(); +SELECT test2.f1(); +CALL TEST2.p1(); +CALL test2.P1(); +DROP PACKAGE BODY TEST2; +DROP PACKAGE TEST2; + + +--echo # +--echo # Testing various qualified/non-qualified db/package SP call chains +--echo # + +DELIMITER $$; +CREATE FUNCTION f3() RETURN TEXT AS +BEGIN + SET @track= @track || ' ' || 'test.f3()'; + RETURN ''; +END; +$$ +CREATE PROCEDURE p3() AS +BEGIN + SET @track= @track || ' ' || 'test.p3()'; +END; +$$ +CREATE FUNCTION ff2(task TEXT) RETURN TEXT AS + step TEXT := REGEXP_SUBSTR(task,'^[^ ]*'); + tail TEXT := REGEXP_REPLACE(task,'^[^ ]*[ ]*(.*)','\\1'); + rc TEXT; +BEGIN + SET @track= @track || ' ' || 'test.ff2()'; + CASE step + WHEN '' THEN NULL; + WHEN 'p3' THEN CALL p3(); + WHEN 'f3' THEN rc:= f3(); + WHEN 'pack.p2' THEN CALL pack.p2(tail); + WHEN 'pack.f2' THEN rc:= pack.f2(tail); + WHEN 'pack.p3' THEN CALL pack.p3(); + WHEN 'pack.f3' THEN rc:= pack.f3(); + WHEN 'test.p3' THEN CALL test.p3(); + WHEN 'test.f3' THEN rc:= test.f3(); + WHEN 'test.pp2' THEN CALL test.pp2(tail); + WHEN 'test.ff2' THEN rc:= test.ff2(tail); + ELSE SET @track= @track || ' ' || step || ' [unknown step]'; + END CASE; + RETURN ''; +END; +$$ +CREATE PROCEDURE pp2(task TEXT) AS + step TEXT := REGEXP_SUBSTR(task,'^[^ ]*'); + tail TEXT := REGEXP_REPLACE(task,'^[^ ]*[ ]*(.*)','\\1'); + rc TEXT; +BEGIN + SET @track= @track || ' ' || 'test.pp2()'; + CASE step + WHEN '' THEN NULL; + WHEN 'p3' THEN CALL p3(); + WHEN 'f3' THEN rc:= f3(); + WHEN 'pack.p2' THEN CALL pack.p2(tail); + WHEN 'pack.f2' THEN rc:= pack.f2(tail); + WHEN 'pack.p3' THEN CALL pack.p3(); + WHEN 'pack.f3' THEN rc:= pack.f3(); + WHEN 'test.p3' THEN CALL test.p3(); + WHEN 'test.f3' THEN rc:= test.f3(); + WHEN 'test.pp2' THEN CALL test.pp2(tail); + WHEN 'test.ff2' THEN rc:= test.ff2(tail); + ELSE SET @track= @track || ' ' || step || ' [unknown step]'; + END CASE; +END; +$$ +CREATE PACKAGE pack AS + PROCEDURE p1(task TEXT); + PROCEDURE p2(task TEXT); + FUNCTION f1(task TEXT) RETURN TEXT; + FUNCTION f2(step2 TEXT) RETURN TEXT; + FUNCTION f3 RETURN TEXT; + PROCEDURE p3; +END; +$$ +CREATE PACKAGE BODY pack AS + PROCEDURE p1(task TEXT) AS + step TEXT := REGEXP_SUBSTR(task,'^[^ ]*'); + tail TEXT := REGEXP_REPLACE(task,'^[^ ]*[ ]*(.*)','\\1'); + rc TEXT; + BEGIN + SET @track= 'test.pack.p1()'; + CASE step + WHEN '' THEN NULL; + WHEN 'p2' THEN CALL p2(tail); + WHEN 'f2' THEN rc:= f2(tail); + WHEN 'p3' THEN CALL p3(); + WHEN 'f3' THEN rc:= f3(); + WHEN 'px' THEN CALL px(); + WHEN 'fx' THEN rc:= fx(); + WHEN 'pp2' THEN CALL pp2(tail); + WHEN 'ff2' THEN rc:= ff2(tail); + WHEN 'pack.p2' THEN CALL pack.p2(tail); + WHEN 'pack.f2' THEN rc:= pack.f2(tail); + WHEN 'pack.p3' THEN CALL pack.p3(); + WHEN 'pack.f3' THEN rc:= pack.f3(); + WHEN 'pack.px' THEN CALL pack.px(); + WHEN 'pack.fx' THEN rc:= pack.fx(); + WHEN 'test.p3' THEN CALL test.p3(); + WHEN 'test.f3' THEN rc:= test.f3(); + WHEN 'test.pp2' THEN CALL test.pp2(tail); + WHEN 'test.ff2' THEN rc:= test.ff2(tail); + ELSE SET @track= @track || ' ' || step || ' [unknown step]'; + END CASE; + SELECT @track; + END; + + FUNCTION f1(task TEXT) RETURN TEXT AS + step TEXT := REGEXP_SUBSTR(task,'^[^ ]*'); + tail TEXT := REGEXP_REPLACE(task,'^[^ ]*[ ]*(.*)','\\1'); + rc TEXT; + BEGIN + SET @track= 'test.pack.f1()'; + CASE step + WHEN '' THEN NULL; + WHEN 'p2' THEN CALL p2(tail); + WHEN 'f2' THEN rc:= f2(tail); + WHEN 'p3' THEN CALL p3(); + WHEN 'f3' THEN rc:= f3(); + WHEN 'px' THEN CALL px(); + WHEN 'fx' THEN rc:= fx(); + WHEN 'pp2' THEN CALL pp2(tail); + WHEN 'ff2' THEN rc:= ff2(tail); + WHEN 'pack.p2' THEN CALL pack.p2(tail); + WHEN 'pack.f2' THEN rc:= pack.f2(tail); + WHEN 'pack.p3' THEN CALL pack.p3(); + WHEN 'pack.f3' THEN rc:= pack.f3(); + WHEN 'pack.px' THEN CALL pack.px(); + WHEN 'pack.fx' THEN rc:= pack.fx(); + WHEN 'test.p3' THEN CALL test.p3(); + WHEN 'test.f3' THEN rc:= test.f3(); + WHEN 'test.pp2' THEN CALL test.pp2(tail); + WHEN 'test.ff2' THEN rc:= test.ff2(tail); + ELSE SET @track= @track || ' ' || step || ' [unknown step]'; + END CASE; + SIGNAL SQLSTATE '01000' SET MESSAGE_TEXT=@track; + RETURN ''; + END; + + PROCEDURE p2(task TEXT) AS + step TEXT := REGEXP_SUBSTR(task,'^[^ ]*'); + tail TEXT := REGEXP_REPLACE(task,'^[^ ]*[ ]*(.*)','\\1'); + rc TEXT; + BEGIN + SET @track= @track || ' ' || 'test.pack.p2()'; + CASE step + WHEN '' THEN NULL; + WHEN 'p2' THEN CALL p2(tail); + WHEN 'f2' THEN rc:= f2(tail); + WHEN 'p3' THEN CALL p3(); + WHEN 'f3' THEN rc:= f3(); + WHEN 'px' THEN CALL px(); + WHEN 'fx' THEN rc:= fx(); + WHEN 'pp2' THEN CALL pp2(tail); + WHEN 'ff2' THEN rc:= ff2(tail); + WHEN 'pack.p2' THEN CALL pack.p2(tail); + WHEN 'pack.f2' THEN rc:= pack.f2(tail); + WHEN 'pack.p3' THEN CALL pack.p3(); + WHEN 'pack.f3' THEN rc:= pack.f3(); + WHEN 'pack.px' THEN CALL pack.px(); + WHEN 'pack.fx' THEN rc:= pack.fx(); + WHEN 'test.p3' THEN CALL test.p3(); + WHEN 'test.f3' THEN rc:= test.f3(); + WHEN 'test.pp2' THEN CALL test.pp2(tail); + WHEN 'test.ff2' THEN rc:= test.ff2(tail); + ELSE SET @track= @track || ' ' || step || ' [unknown step]'; + END CASE; + END; + + FUNCTION f2(task TEXT) RETURN TEXT AS + step TEXT := REGEXP_SUBSTR(task,'^[^ ]*'); + tail TEXT := REGEXP_REPLACE(task,'^[^ ]*[ ]*(.*)','\\1'); + rc TEXT; + BEGIN + SET @track= @track || ' ' || 'test.pack.f2()'; + CASE step + WHEN '' THEN NULL; + WHEN 'p2' THEN CALL p2(tail); + WHEN 'f2' THEN rc:= f2(tail); + WHEN 'p3' THEN CALL p3(); + WHEN 'f3' THEN rc:= f3(); + WHEN 'px' THEN CALL px(); + WHEN 'fx' THEN rc:= fx(); + WHEN 'pp2' THEN CALL pp2(tail); + WHEN 'ff2' THEN rc:= ff2(tail); + WHEN 'pack.p2' THEN CALL pack.p2(tail); + WHEN 'pack.f2' THEN rc:= pack.f2(tail); + WHEN 'pack.p3' THEN CALL pack.p3(); + WHEN 'pack.f3' THEN rc:= pack.f3(); + WHEN 'pack.px' THEN CALL pack.px(); + WHEN 'pack.fx' THEN rc:= pack.fx(); + WHEN 'test.p3' THEN CALL test.p3(); + WHEN 'test.f3' THEN rc:= test.f3(); + WHEN 'test.pp2' THEN CALL test.pp2(tail); + WHEN 'test.ff2' THEN rc:= test.ff2(tail); + ELSE SET @track= @track || ' ' || step || ' [unknown step]'; + END CASE; + RETURN ''; + END; + PROCEDURE p3 AS + BEGIN + SET @track= @track || ' ' || 'test.pack.p3()'; + END; + FUNCTION f3 RETURN TEXT AS + BEGIN + SET @track= @track || ' ' || 'test.pack.f3()'; + RETURN ''; + END; + +END pack; +$$ +DELIMITER ;$$ + +SET max_sp_recursion_depth=10; + +--echo # pack.routine -> * + +CALL pack.p1('p2'); +CALL pack.p1('f2'); +--error ER_SP_DOES_NOT_EXIST +CALL pack.p1('px'); +--error ER_SP_DOES_NOT_EXIST +CALL pack.p1('fx'); + +CALL pack.p1('pp2'); +CALL pack.p1('ff2'); + +CALL pack.p1('pack.p2'); +CALL pack.p1('pack.f2'); +--error ER_SP_DOES_NOT_EXIST +CALL pack.p1('pack.px'); +--error ER_SP_DOES_NOT_EXIST +CALL pack.p1('pack.fx'); + +CALL pack.p1('test.pp2'); +CALL pack.p1('test.ff2'); + +DO pack.f1('p2'); +DO pack.f1('f2'); +--error ER_SP_DOES_NOT_EXIST +DO pack.p1('px'); +--error ER_SP_DOES_NOT_EXIST +DO pack.p1('fx'); + +DO pack.f1('pp2'); +DO pack.f1('ff2'); + +DO pack.f1('pack.p2'); +DO pack.f1('pack.f2'); +--error ER_SP_DOES_NOT_EXIST +SELECT pack.f1('pack.px'); +--error ER_SP_DOES_NOT_EXIST +SELECT pack.f1('pack.fx'); + +DO pack.f1('test.pp2'); +DO pack.f1('test.ff2'); + +--echo # +--echo # Qualified_package_routine -> Non_qualified_package_routine +--echo # + +--echo # pack.routine -> [pack.]routine -> pack.routine + +CALL pack.p1('p2 pack.p3'); +CALL pack.p1('p2 pack.f3'); +CALL pack.p1('f2 pack.p3'); +CALL pack.p1('f2 pack.f3'); + +DO pack.f1('p2 pack.p3'); +DO pack.f1('p2 pack.f3'); +DO pack.f1('f2 pack.p3'); +DO pack.f1('f2 pack.f3'); + +--echo # pack.routine -> [pack.]routine -> [pack]routine + +CALL pack.p1('p2 p3'); +CALL pack.p1('p2 f3'); +CALL pack.p1('f2 p3'); +CALL pack.p1('f2 f3'); + +DO pack.f1('p2 p3'); +DO pack.f1('p2 f3'); +DO pack.f1('f2 p3'); +DO pack.f1('f2 f3'); + +--echo # pack.routine -> [pack.]routine -> test.routine + +CALL pack.p1('p2 test.p3'); +CALL pack.p1('p2 test.f3'); +CALL pack.p1('f2 test.p3'); +CALL pack.p1('f2 test.f3'); + +DO pack.f1('p2 test.p3'); +DO pack.f1('p2 test.f3'); +DO pack.f1('f2 test.p3'); +DO pack.f1('f2 test.f3'); + +--echo # pack.routine -> [pack.]routine -> [test.]routine + +CALL pack.p1('p2 pp2'); +CALL pack.p1('p2 ff2'); +CALL pack.p1('f2 pp2'); +CALL pack.p1('f2 ff2'); + +DO pack.f1('p2 pp2'); +DO pack.f1('p2 ff2'); +DO pack.f1('f2 pp2'); +DO pack.f1('f2 ff2'); + + +--echo # +--echo # Qualified_package_routine -> Non_qualified_database_routine +--echo # + +--echo # pack.routine -> [test.]routine -> pack.routine + +CALL pack.p1('pp2 pack.p3'); +CALL pack.p1('pp2 pack.f3'); +CALL pack.p1('ff2 pack.p3'); +CALL pack.p1('ff2 pack.f3'); + +DO pack.f1('pp2 pack.p3'); +DO pack.f1('pp2 pack.f3'); +DO pack.f1('ff2 pack.p3'); +DO pack.f1('ff2 pack.f3'); + +--echo # pack.routine -> [test.]routine -> test.routine + +CALL pack.p1('pp2 test.p3'); +CALL pack.p1('pp2 test.f3'); +CALL pack.p1('ff2 test.p3'); +CALL pack.p1('ff2 test.f3'); + +DO pack.f1('pp2 test.p3'); +DO pack.f1('pp2 test.f3'); +DO pack.f1('ff2 test.p3'); +DO pack.f1('ff2 test.f3'); + +--echo # pack.routine -> [test.]routine -> [test.]routine + +CALL pack.p1('pp2 p3'); +CALL pack.p1('pp2 f3'); +CALL pack.p1('ff2 p3'); +CALL pack.p1('ff2 f3'); + +DO pack.f1('pp2 p3'); +DO pack.f1('pp2 f3'); +DO pack.f1('ff2 p3'); +DO pack.f1('ff2 f3'); + + +--echo # +--echo # Qualified_package_routine -> Qualified_package_routine +--echo # + +--echo # pack.routine -> pack.routine -> pack.routine + +CALL pack.p1('pack.p2 pack.p3'); +CALL pack.p1('pack.p2 pack.f3'); +CALL pack.p1('pack.f2 pack.p3'); +CALL pack.p1('pack.f2 pack.f3'); + +DO pack.f1('pack.p2 pack.p3'); +DO pack.f1('pack.p2 pack.f3'); +DO pack.f1('pack.f2 pack.p3'); +DO pack.f1('pack.f2 pack.f3'); + +--echo # pack.routine -> pack.routine -> [pack.]routine + +CALL pack.p1('pack.p2 p3'); +CALL pack.p1('pack.p2 f3'); +CALL pack.p1('pack.f2 p3'); +CALL pack.p1('pack.f2 f3'); + +DO pack.f1('pack.p2 p3'); +DO pack.f1('pack.p2 f3'); +DO pack.f1('pack.f2 p3'); +DO pack.f1('pack.f2 f3'); + +--echo # pack.routine -> pack.routine -> test.routine + +CALL pack.p1('pack.p2 test.p3'); +CALL pack.p1('pack.p2 test.f3'); +CALL pack.p1('pack.f2 test.p3'); +CALL pack.p1('pack.f2 test.f3'); + +DO pack.f1('pack.p2 test.p3'); +DO pack.f1('pack.p2 test.f3'); +DO pack.f1('pack.f2 test.p3'); +DO pack.f1('pack.f2 test.f3'); + +--echo # pack.routine -> pack.routine -> [test.]routine + +CALL pack.p1('pack.p2 pp2'); +CALL pack.p1('pack.p2 ff2'); +CALL pack.p1('pack.f2 pp2'); +CALL pack.p1('pack.f2 ff2'); + +DO pack.f1('pack.p2 pp2'); +DO pack.f1('pack.p2 ff2'); +DO pack.f1('pack.f2 pp2'); +DO pack.f1('pack.f2 ff2'); + + +--echo # +--echo # Qualified_package_routine -> Qualified_database_routine +--echo # + +--echo pack.routine -> test.routine -> pack.routine + +CALL pack.p1('test.pp2 pack.p3'); +CALL pack.p1('test.pp2 pack.f3'); +CALL pack.p1('test.ff2 pack.p3'); +CALL pack.p1('test.ff2 pack.f3'); + +DO pack.f1('test.pp2 pack.p3'); +DO pack.f1('test.pp2 pack.f3'); +DO pack.f1('test.ff2 pack.p3'); +DO pack.f1('test.ff2 pack.f3'); + +--echo pack.routine -> test.routine -> test.routine + +CALL pack.p1('test.pp2 test.p3'); +CALL pack.p1('test.pp2 test.f3'); +CALL pack.p1('test.ff2 test.p3'); +CALL pack.p1('test.ff2 test.f3'); + +DO pack.f1('test.pp2 test.p3'); +DO pack.f1('test.pp2 test.f3'); +DO pack.f1('test.ff2 test.p3'); +DO pack.f1('test.ff2 test.f3'); + +--echo pack.routine -> test.routine -> [test.]routine + +CALL pack.p1('test.pp2 p3'); +CALL pack.p1('test.pp2 f3'); +CALL pack.p1('test.ff2 p3'); +CALL pack.p1('test.ff2 f3'); + +DO pack.f1('test.pp2 p3'); +DO pack.f1('test.pp2 f3'); +DO pack.f1('test.ff2 p3'); +DO pack.f1('test.ff2 f3'); + + +--echo # Longer chains + +CALL pack.p1('p2 f2 p2 test.pp2 test.ff2 pack.p3'); +CALL pack.p1('p2 test.pp2 pack.p2 pack.f2 test.ff2 pack.p3'); + + +DROP PACKAGE pack; +DROP FUNCTION f3; +DROP PROCEDURE p3; +DROP FUNCTION ff2; +DROP PROCEDURE pp2; + + +--echo # +--echo # Calling a standalone function from a non-current database, +--echo # which calls a package routine from the same non-current database. +--echo # + +DELIMITER $$; +CREATE PROCEDURE p1 AS +BEGIN + CALL pkg1.p1; +END; +$$ +CREATE PACKAGE pkg1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS + BEGIN + SELECT database(); + END; +END; +$$ +DELIMITER ;$$ +# Current database +CALL p1; +CREATE DATABASE test2; +USE test2; +# Non-current database +CALL test.p1; +DROP DATABASE test2; +# No current database at all +CALL test.p1; +USE test; +DROP PACKAGE pkg1; +DROP PROCEDURE p1; + + +--echo # +--echo # Creating a package with a different DEFINER +--echo # + +CREATE USER xxx@localhost; +DELIMITER $$; +CREATE DEFINER=xxx@localhost PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE DEFINER=xxx@localhost PACKAGE BODY p1 AS + PROCEDURE p1 AS + BEGIN + NULL; + END; +END; +$$ +DELIMITER ;$$ +SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type; +DROP PACKAGE p1; +DROP USER xxx@localhost; + +--echo # +--echo # Creating a package with a different DEFINER, with SQL SECURITY INVOKER +--echo # + +CREATE USER xxx@localhost; +DELIMITER $$; +CREATE DEFINER=xxx@localhost PACKAGE p1 SQL SECURITY INVOKER AS + PROCEDURE p1; +END; +$$ +CREATE DEFINER=xxx@localhost PACKAGE BODY p1 SQL SECURITY INVOKER AS + PROCEDURE p1 AS + BEGIN + NULL; + END; +END; +$$ +DELIMITER ;$$ +SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type; +DROP PACKAGE p1; +DROP USER xxx@localhost; + +--echo # +--echo # A package with an initialization section +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY p1 AS + PROCEDURE p1 AS BEGIN SET @a=@a+1; SELECT @a; END; + FUNCTION f1 RETURN INT AS BEGIN SET @a=@a+1; RETURN @a; END; +BEGIN + SET @a:=10; +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT p1.f1(); +SELECT p1.f1(); +--source sp-cache-invalidate.inc +SELECT p1.f1(); +CALL p1.p1(); +SELECT p1.f1(); +CALL p1.p1(); +DROP PACKAGE p1; + + +--echo # +--echo # A package with an initialization section calling +--echo # routines from the same package, and standalone routines. +--echo # + +DELIMITER $$; +CREATE PROCEDURE init20 AS +BEGIN + SET @msg= @msg || '[init20]'; +END; +$$ +CREATE PACKAGE p1 AS + PROCEDURE init1; + PROCEDURE init2; + FUNCTION init3 RETURN INT; + PROCEDURE p1; + FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY p1 AS + PROCEDURE init1 AS + BEGIN + SET @msg= @msg || '[p1.init1]'; + END; + PROCEDURE init2 AS + BEGIN + SET @msg= @msg || '[p1.init2]'; + END; + FUNCTION init3 RETURN INT AS + BEGIN + SET @msg= @msg || '[p1.init3]'; + RETURN 0; + END; + PROCEDURE p1 AS + BEGIN + SET @msg= @msg || '[p1.p1]'; + SELECT @msg; + END; + FUNCTION f1 RETURN TEXT AS + BEGIN + SET @msg= @msg || '[p1.f1]'; + RETURN @msg; + END; +BEGIN + SET @msg= ''; + init1(); + init2(); + DO init3(); + init20(); +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT p1.f1(); +SELECT p1.f1(); +--source sp-cache-invalidate.inc +SELECT p1.f1(); +CALL p1.p1(); +SELECT p1.f1(); +CALL p1.p1(); +DROP PACKAGE p1; +DROP PROCEDURE init20; + + +--echo # +--echo # EXECUTE IMMEDIATE in the package initialization section +--echo # + +SET @a=1000; +CREATE TABLE t1 AS SELECT 10 AS a; +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY p1 AS + PROCEDURE p1 AS BEGIN SET @a=@a+1; SELECT @a; END; + FUNCTION f1 RETURN INT AS BEGIN SET @a=@a+1; RETURN @a; END; +BEGIN + EXECUTE IMMEDIATE 'SELECT MAX(a) FROM t1 INTO @a'; +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT p1.f1(); +SELECT p1.f1(); +--source sp-cache-invalidate.inc +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG +SELECT p1.f1(); +DROP PACKAGE p1; +DROP TABLE t1; + + +--echo # +--echo # A package with an initialization section, loading table data into a user variable +--echo # + +SET @a=1000; +CREATE TABLE t1 AS SELECT 10 AS a; +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY p1 AS + PROCEDURE p1 AS BEGIN SET @a=@a+1; SELECT @a; END; + FUNCTION f1 RETURN INT AS BEGIN SET @a=@a+1; RETURN @a; END; +BEGIN + SELECT MAX(a) FROM t1 INTO @a; +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT p1.f1(); +SELECT p1.f1(); +--source sp-cache-invalidate.inc +SELECT p1.f1(); +DROP PACKAGE p1; +DROP TABLE t1; + +--echo # +--echo # A package with an initialization section producing an error +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY p1 AS + PROCEDURE p1 AS BEGIN SELECT 'This is p1' AS msg; END; + FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is f1'; END; +BEGIN + SELECT 1 FROM t1 INTO @a; +END; +$$ +DELIMITER ;$$ +--error ER_NO_SUCH_TABLE +CALL p1.p1(); +--error ER_NO_SUCH_TABLE +SELECT p1.f1(); +--source sp-cache-invalidate.inc +--error ER_NO_SUCH_TABLE +SELECT p1.f1(); +--error ER_NO_SUCH_TABLE +CALL p1.p1(); +--error ER_NO_SUCH_TABLE +SELECT p1.f1(); +CREATE TABLE t1 (a INT) AS SELECT 1; +CALL p1.p1(); +--source sp-cache-invalidate.inc +SELECT p1.f1(); +--source sp-cache-invalidate.inc +CALL p1.p1(); +DROP TABLE t1; +DROP PACKAGE p1; + + +--echo # +--echo # A package with SF-unsafe statements in the initialization section +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY p1 AS + PROCEDURE p1 AS BEGIN SELECT 'This is p1' AS msg; END; + FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is f1'; END; +BEGIN + CREATE TABLE IF NOT EXISTS t1 (a INT); + DROP TABLE IF EXISTS t1; +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +SELECT p1.f1(); +--source sp-cache-invalidate.inc +--error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +SELECT p1.f1(); +CALL p1.p1(); +SELECT p1.f1(); +DROP PACKAGE p1; + + +--echo # +--echo # MDEV-13139 Package-wide variables in CREATE PACKAGE +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +--error ER_SP_DUP_VAR +CREATE PACKAGE BODY p1 AS + a INT; + a INT; + PROCEDURE p1 AS + BEGIN + CREATE VIEW v1 AS SELECT a; + END; +END; +$$ +--error ER_PARSE_ERROR +CREATE PACKAGE BODY p1 AS + a INT; + PROCEDURE p1 AS + BEGIN + NULL; + END; + b INT; -- Variables cannot go after routine definitions +END; +$$ +--error ER_VIEW_SELECT_VARIABLE +CREATE PACKAGE BODY p1 AS + a INT; + PROCEDURE p1 AS + BEGIN + CREATE VIEW v1 AS SELECT a; + END; +END; +$$ +CREATE PACKAGE BODY p1 AS + a INT:=NULL; + PROCEDURE p1 AS + BEGIN + SELECT a; + a:=COALESCE(a,0)+100; + SET a=a+1; + END; + FUNCTION f1 RETURN INT AS + BEGIN + RETURN a; + END; +END; +$$ +DELIMITER ;$$ +CALL p1.p1; +CALL p1.p1; +CALL p1.p1; +SELECT p1.f1(); +DROP PACKAGE p1; + + +--echo # +--echo # One package variable with a default value +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY p1 AS + a INT:=10; + PROCEDURE p1 AS BEGIN a:=a+1; SELECT a; END; + FUNCTION f1 RETURN INT AS BEGIN a:=a+1; RETURN a; END; +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT p1.f1(); +SELECT p1.f1(); +--source sp-cache-invalidate.inc +SELECT p1.f1(); +CALL p1.p1(); +SELECT p1.f1(); +CALL p1.p1(); +DROP PACKAGE p1; + + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY p1 AS + a ROW (a INT, b TEXT):=ROW(10,'bbb'); + PROCEDURE p1 AS + BEGIN + a.a:= a.a+1; + a.b:= a.b || 'B'; + SELECT a.a, a.b; + END; + FUNCTION f1 RETURN INT AS BEGIN a.a:= a.a+1; RETURN a.a; END; +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT p1.f1(); +SELECT p1.f1(); +--source sp-cache-invalidate.inc +SELECT p1.f1(); +CALL p1.p1(); +SELECT p1.f1(); +CALL p1.p1(); +DROP PACKAGE p1; + + +CREATE TABLE t1 (a INT); +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY p1 AS + a t1.a%TYPE:=10; + PROCEDURE p1 AS BEGIN a:=a+1; SELECT a; END; + FUNCTION f1 RETURN INT AS BEGIN a:=a+1; RETURN a; END; +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT p1.f1(); +SELECT p1.f1(); +--source sp-cache-invalidate.inc +SELECT p1.f1(); +CALL p1.p1(); +SELECT p1.f1(); +CALL p1.p1(); +DROP PACKAGE p1; +DROP TABLE t1; + + +CREATE TABLE t1 (a INT, b TEXT); +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY p1 AS + a t1%ROWTYPE:=ROW(10,'bbb'); + PROCEDURE p1 AS + BEGIN + a.a:= a.a+1; + a.b:= a.b || 'B'; + SELECT a.a, a.b; + END; + FUNCTION f1 RETURN INT AS BEGIN a.a:= a.a+1; RETURN a.a; END; +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT p1.f1(); +SELECT p1.f1(); +--source sp-cache-invalidate.inc +SELECT p1.f1(); +CALL p1.p1(); +SELECT p1.f1(); +CALL p1.p1(); +DROP PACKAGE p1; +DROP TABLE t1; + + +--echo # +--echo # One package variable, set in the package initialization section +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY p1 AS + a INT; + PROCEDURE p1 AS BEGIN a:=a+1; SELECT a; END; + FUNCTION f1 RETURN INT AS BEGIN a:=a+1; RETURN a; END; +BEGIN + a:=10; +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT p1.f1(); +SELECT p1.f1(); +--source sp-cache-invalidate.inc +SELECT p1.f1(); +CALL p1.p1(); +SELECT p1.f1(); +CALL p1.p1(); +DROP PACKAGE p1; + + +--echo # +--echo # A package with an initialization section, +--echo # loading table data into a package variable +--echo # + +CREATE TABLE t1 AS SELECT 10 AS a; +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY p1 AS + a INT; + PROCEDURE p1 AS BEGIN SET a=a+1; SELECT a; END; + FUNCTION f1 RETURN INT AS BEGIN SET a=a+1; RETURN a; END; +BEGIN + a:=(SELECT MAX(t1.a) FROM t1); +END; +$$ +DELIMITER ;$$ +CALL p1.p1(); +CALL p1.p1(); +SELECT p1.f1(); +SELECT p1.f1(); +--source sp-cache-invalidate.inc +SELECT p1.f1(); +DROP PACKAGE p1; +DROP TABLE t1; + +--echo # +--echo # Package variables and XPath +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY p1 AS + i INT:=0; + xml TEXT:= '<a><b>b1</b><b>b2</b><b>b3</b></a>'; + FUNCTION f1 RETURN TEXT AS + BEGIN + SET i=i+1; + RETURN ExtractValue(xml, '/a/b[$i]'); + END; +END; +$$ +DELIMITER ;$$ +SELECT p1.f1(); +SELECT p1.f1(); +SELECT p1.f1(); +DROP PACKAGE p1; + +--echo # +--echo # Package variables as OUT routine parameter +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY p1 AS + a INT; + b INT; + c INT:=10; + PROCEDURE p2(a OUT INT) AS + BEGIN + a:=c; + c:=c+1; + END; + PROCEDURE p1 AS + BEGIN + CALL p2(b); + SELECT a,b; + END; +BEGIN + CALL p2(a); +END; +$$ +DELIMITER ;$$ +CALL p1.p1; +DROP PACKAGE p1; + + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY p1 AS + a ROW(a INT, b TEXT); + b ROW(a INT, b TEXT); + c ROW(a INT, b TEXT):=ROW(1,'b'); + PROCEDURE p2(x OUT ROW(a INT,b TEXT)) AS + BEGIN + x:=c; + x.a:=c.a+100; + x.b:=c.b||'X'; + c.a:=c.a+1; + c.b:=c.b||'B'; + END; + PROCEDURE p1 AS + BEGIN + CALL p2(b); + SELECT a.a,a.b,b.a,b.b; + END; +BEGIN + CALL p2(a); +END; +$$ +DELIMITER ;$$ +CALL p1.p1; +DROP PACKAGE p1; + + +CREATE TABLE t1 (a INT,b TEXT); +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY p1 AS + a t1%ROWTYPE; + b t1%ROWTYPE; + c t1%ROWTYPE:=ROW(1,'b'); + PROCEDURE p2(x OUT t1%ROWTYPE) AS + BEGIN + x:=c; + x.a:=c.a+100; + x.b:=c.b||'X'; + c.a:=c.a+1; + c.b:=c.b||'B'; + END; + PROCEDURE p1 AS + BEGIN + CALL p2(b); + SELECT a.a,a.b,b.a,b.b; + END; +BEGIN + CALL p2(a); +END; +$$ +DELIMITER ;$$ +CALL p1.p1; +DROP PACKAGE p1; +DROP TABLE t1; + + +--echo # +--echo # Package variable fields as OUT routine parameters +--echo # + +CREATE TABLE t1 (a INT,b TEXT); +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY p1 AS + a t1%ROWTYPE; + x t1%ROWTYPE:=ROW(10,'b'); + PROCEDURE p2(a OUT INT,b OUT TEXT) AS + BEGIN + a:=x.a; + b:=x.b; + x.a:=x.a+1; + x.b:=x.b||'B'; + END; + PROCEDURE p1 AS + BEGIN + CALL p2(a.a, a.b); + SELECT a.a,a.b; + END; +BEGIN + CALL p2(a.a, a.b); + SELECT a.a, a.b; +END; +$$ +DELIMITER ;$$ +CALL p1.p1; +DROP PACKAGE p1; +DROP TABLE t1; + + +--echo # +--echo # Package variables as SELECT INTO targets +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY p1 AS + a INT; + b INT; + PROCEDURE p1 AS + BEGIN + SELECT 2 INTO b; + SELECT a,b; + END; +BEGIN + SELECT 1 INTO a; +END; +$$ +DELIMITER ;$$ +CALL p1.p1; +DROP PACKAGE p1; + + +CREATE TABLE t1 (a INT, b TEXT); +INSERT INTO t1 VALUES (10,'b'); +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY p1 AS + a t1%ROWTYPE; + b t1%ROWTYPE; + PROCEDURE p1 AS + BEGIN + SELECT * FROM t1 INTO a; + SELECT a.a,a.b; + END; +BEGIN + SELECT * FROM t1 INTO b; + SELECT b.a, b.b; +END; +$$ +DELIMITER ;$$ +CALL p1.p1; +DROP PACKAGE p1; +DROP TABLE t1; + + +--echo # +--echo # Package variable fields as SELECT INTO targets +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY p1 AS + a ROW(a INT, b TEXT); + b ROW(a INT, b TEXT); + PROCEDURE p1 AS + BEGIN + SELECT 20,'x2' INTO b.a,b.b; + SELECT a.a,a.b,b.a,b.b; + END; +BEGIN + SELECT 10,'x1' INTO a.a,a.b; +END; +$$ +DELIMITER ;$$ +CALL p1.p1; +DROP PACKAGE p1; + + +--echo # +--echo # Recursive package procedure calls +--echo # Makes sure that the non-top sp_head instances created by +--echo # sp_clone_and_link_routine() correctly reproduce the package context: +--echo # package variables, package routines. +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1(c INT); +END p1; +$$ +CREATE PACKAGE BODY p1 AS + pv1 INT:=10; + FUNCTION f1 RETURN INT AS BEGIN RETURN pv1+100; END; + PROCEDURE p1(c INT) AS + BEGIN + SELECT c, pv1, f1(); + IF c>0 THEN + pv1:=pv1+1; + CALL p1(c-1); + END IF; + END; +END; +$$ +DELIMITER ;$$ +SET max_sp_recursion_depth=5; +CALL p1.p1(5); +SET max_sp_recursion_depth=0; +CALL p1.p1(0); +--error ER_SP_RECURSION_LIMIT +CALL p1.p1(1); +DROP PACKAGE p1; + + +--echo # +--echo # Non-reserved keywords as package body variable names +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; +END p1; +$$ +CREATE PACKAGE BODY p1 AS + ascii INT:=10; + action INT:=20; + PROCEDURE p1 AS + BEGIN + SELECT ascii, action; + END; +BEGIN + ascii := ascii + 1; + action := action + 1; +END; +$$ +DELIMITER ;$$ +CALL p1.p1; +DROP PACKAGE p1; + + +--echo # +--echo # Package routines calling routines of another package +--echo # + +DELIMITER $$; +CREATE PACKAGE p1 AS + PROCEDURE p1; + FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE p2 AS + PROCEDURE p1; + FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY p1 AS + PROCEDURE p1 AS + BEGIN + SELECT 'This is p1.p1' AS msg; + END; + FUNCTION f1 RETURN TEXT AS + BEGIN + RETURN 'This is p1.f1'; + END; +END; +$$ +CREATE PACKAGE BODY p2 AS + PROCEDURE p1 AS + BEGIN + CALL p1.p1; + END; + FUNCTION f1 RETURN TEXT AS + BEGIN + RETURN p1.f1(); + END; +END; +$$ +DELIMITER ;$$ +CALL p1.p1; +CALL p2.p1; +SELECT p1.f1(), p2.f1(); +DROP PACKAGE p2; +DROP PACKAGE p1; + +--echo # +--echo # Package names with dot characters +--echo # + +DELIMITER $$; +CREATE PACKAGE "p1.p1" AS + PROCEDURE p1; + FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY "p1.p1" AS + PROCEDURE p1 AS + BEGIN + SELECT 'This is p1' AS msg; + END; + FUNCTION f1 RETURN TEXT AS + BEGIN + RETURN 'This is f1'; + END; +END; +$$ +DELIMITER ;$$ +CALL "p1.p1"."p1"; +SELECT "p1.p1"."f1"(); +DROP PACKAGE "p1.p1"; + + +--echo # +--echo # MDEV-15070 Crash when doing a CREATE VIEW inside a package routine +--echo # + +SET sql_mode=ORACLE; +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg1 AS + PROCEDURE p00(); +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg1 AS + PROCEDURE p01() AS + BEGIN + SELECT 'This is p01' AS msg; + END; + PROCEDURE p00() AS + BEGIN + CREATE OR REPLACE VIEW v1 AS SELECT 1; + DROP VIEW v1; + CALL p01(); + END; +END; +$$ +DELIMITER ;$$ +CALL pkg1.p00; +DROP PACKAGE pkg1; + + +CREATE OR REPLACE TABLE t1 (a INT); +CREATE OR REPLACE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=1; +DELIMITER $$; +CREATE OR REPLACE PACKAGE pkg1 AS + PROCEDURE p00(); +END; +$$ +CREATE OR REPLACE PACKAGE BODY pkg1 AS + PROCEDURE p01() AS + BEGIN + SELECT 'This is p01' AS msg; + END; + PROCEDURE p00() AS + BEGIN + DROP TRIGGER tr1; + CALL p01(); + END; +END; +$$ +DELIMITER ;$$ +CALL pkg1.p00; +DROP PACKAGE pkg1; +DROP TABLE t1; + + +--echo # +--echo # MDEV-17387 MariaDB Server giving wrong error while executing select query from procedure +--echo # + +CREATE TABLE t1 ( + CTR varchar(2) NOT NULL, + COR varchar(3) NOT NULL, + DATE datetime NOT NULL, + CHAN varchar(4) NOT NULL, + CNO varchar(20) NOT NULL, + JOBN varchar(18) NOT NULL, + C1 varchar(30) DEFAULT NULL, + C2 varchar(30) DEFAULT NULL, + TIME datetime DEFAULT NULL, + AMT decimal(12,2) DEFAULT NULL, + DT datetime NOT NULL, + pk int(11) NOT NULL, + PRIMARY KEY (pk), + KEY Indx1 (JOBN) +); + +DELIMITER $$; + +CREATE PACKAGE xyz IS + PROCEDURE xyz123(ctr IN VARCHAR2,Jn IN VARCHAR2,R OUT VARCHAR2); +END; +$$ + +CREATE OR REPLACE PACKAGE BODY xyz IS + PROCEDURE xyz123( + ctr IN VARCHAR2, + Jn IN VARCHAR2, + R OUT VARCHAR2) + AS + lS NUMBER(10) :=0; + CURSOR cBPD IS + SELECT CTR, COR, DATE, CHAN, CNO, C1, C2, TIME, AMT + FROM t1 WHERE JOBN=Jn; + BEGIN + FOR lbpd IN cBPD + LOOP + lS:=lS+1; + END LOOP; + EXCEPTION + WHEN OTHERS THEN + BEGIN + SELECT SQLERRM; + END; + END; +END $$ +DELIMITER ;$$ + +CALL xyz.xyz123(17,18,@R); +DROP PACKAGE xyz; +DROP TABLE t1; +--disable_prepare_warnings + + +--echo # +--echo # MDEV-28166 sql_mode=ORACLE: fully qualified package function calls do not work: db.pkg.func() +--echo # + +--error ER_WRONG_DB_NAME +SELECT `db `.pkg.func(); +--error ER_SP_WRONG_NAME +SELECT db.`pkg `.func(); +--error ER_SP_WRONG_NAME +SELECT db.pkg.`func `(); + + +CREATE DATABASE db1; +USE db1; + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + FUNCTION f1 RETURN TEXT; + FUNCTION f2_db1_pkg1_f1 RETURN TEXT; + FUNCTION f2_pkg1_f1 RETURN TEXT; + FUNCTION f2_f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY pkg1 +AS + FUNCTION f1 RETURN TEXT IS + BEGIN + RETURN 'This is db1.pkg1.f1'; + END; + FUNCTION f2_db1_pkg1_f1 RETURN TEXT IS + BEGIN + RETURN db1.pkg1.f1(); + END; + FUNCTION f2_pkg1_f1 RETURN TEXT IS + BEGIN + RETURN pkg1.f1(); + END; + FUNCTION f2_f1 RETURN TEXT IS + BEGIN + RETURN f1(); + END; +END; +$$ +DELIMITER ;$$ + +USE db1; +SELECT pkg1.f2_db1_pkg1_f1(); +SELECT pkg1.f2_pkg1_f1(); +SELECT pkg1.f2_f1(); + +SELECT db1.pkg1.f2_db1_pkg1_f1(); +SELECT db1.pkg1.f2_pkg1_f1(); +SELECT db1.pkg1.f2_f1(); + +USE test; +SELECT db1.pkg1.f2_db1_pkg1_f1(); +SELECT db1.pkg1.f2_pkg1_f1(); +SELECT db1.pkg1.f2_f1(); + +DROP DATABASE db1; + + +# +# Testing db.pkg.func() in the package initialization section +# + +CREATE DATABASE db1; +CREATE DATABASE db2; + +DELIMITER $$; +CREATE PACKAGE db1.pkg1 AS + FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY db1.pkg1 AS + FUNCTION f1 RETURN TEXT AS + BEGIN + RETURN 'This is db1.pkg1.f1'; + END; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +CREATE PACKAGE db2.pkg1 AS + FUNCTION f1 RETURN TEXT; + FUNCTION var1 RETURN TEXT; + FUNCTION var2 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY db2.pkg1 AS + m_var1 TEXT; + m_var2 TEXT; + FUNCTION f1 RETURN TEXT AS + BEGIN + RETURN 'This is db2.pkg1.f1'; + END; + FUNCTION var1 RETURN TEXT AS + BEGIN + RETURN m_var1; + END; + FUNCTION var2 RETURN TEXT AS + BEGIN + RETURN m_var2; + END; +BEGIN + m_var1:= db1.pkg1.f1(); + m_var2:= db2.pkg1.f1(); +END; +$$ +DELIMITER ;$$ + +SELECT db2.pkg1.var1(), db2.pkg1.var2(); + +DROP DATABASE db1; +DROP DATABASE db2; + +# +# Make sure fully qualified package function call does not support AS syntax: +# SELECT db.pkg.func(10 AS a); +# + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + FUNCTION f1(a TEXT) RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY pkg1 AS + FUNCTION f1(a TEXT) RETURN TEXT AS + BEGIN + RETURN a; + END; +END; +$$ +DELIMITER ;$$ +SELECT test.pkg1.f1('xxx'); +--error ER_PARSE_ERROR +SELECT test.pkg1.f1('xxx' AS a); +DROP PACKAGE pkg1; + + +--echo # +--echo # MDEV-19328 sql_mode=ORACLE: Package function in VIEW +--echo # + +SET sql_mode=ORACLE; +DELIMITER $$; +CREATE PACKAGE test1 AS + FUNCTION f_test RETURN number; +END test1; +$$ +CREATE PACKAGE BODY test1 +AS + FUNCTION f_test RETURN NUMBER IS + BEGIN + RETURN 1; + END; +END test1; +$$ +DELIMITER ;$$ + + +SET sql_mode=ORACLE; +CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test1.f_test(); +SELECT * FROM v_test; +--vertical_results +SHOW CREATE VIEW v_test; +--horizontal_results +SET sql_mode=DEFAULT; +SELECT * FROM v_test; +--vertical_results +SHOW CREATE VIEW v_test; +--horizontal_results +DROP VIEW v_test; + + +SET sql_mode=DEFAULT; +--error ER_SP_DOES_NOT_EXIST +CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test1.f_test(); + + +SET sql_mode=ORACLE; +CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test.test1.f_test(); +SELECT * FROM v_test; +--vertical_results +SHOW CREATE VIEW v_test; +--horizontal_results +SET sql_mode=DEFAULT; +SELECT * FROM v_test; +--vertical_results +SHOW CREATE VIEW v_test; +--horizontal_results +DROP VIEW v_test; + + +SET sql_mode=DEFAULT; +CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test.test1.f_test(); +SELECT * FROM v_test; +--vertical_results +SHOW CREATE VIEW v_test; +--horizontal_results +SET sql_mode=ORACLE; +SELECT * FROM v_test; +--vertical_results +SHOW CREATE VIEW v_test; +--horizontal_results +DROP VIEW v_test; + +SET sql_mode=ORACLE; +DROP PACKAGE test1; + + +--echo # +--echo # MDEV-19804 sql_mode=ORACLE: call procedure in packages +--echo # + +--error ER_WRONG_DB_NAME +CALL `db1 `.pkg.p; +--error ER_SP_WRONG_NAME +CALL db1.`pkg `.p; +--error ER_SP_WRONG_NAME +CALL db1.pkg.`p `; + + +SET sql_mode=ORACLE; +DELIMITER $$; +CREATE PACKAGE pkg1 as + PROCEDURE p1(); +END; +$$ +CREATE PACKAGE BODY pkg1 as + PROCEDURE p1() as + BEGIN + SELECT 'test-function' AS c1; + END; +END; +$$ +DELIMITER ;$$ + +CALL pkg1.p1; +CALL test.pkg1.p1; + +# In sql_mode=DEFAULT we support fully qualified package function names +# (this is needed for VIEWs). Let's make sure we also support fully +# qualified package procedure names, for symmetry + +SET sql_mode=DEFAULT; +CALL test.pkg1.p1; +SET sql_mode=ORACLE; + +DELIMITER $$; +BEGIN + CALL pkg1.p1; + CALL test.pkg1.p1; +END +$$ +DELIMITER ;$$ + +DELIMITER $$; +BEGIN + pkg1.p1; + test.pkg1.p1; +END +$$ +DELIMITER ;$$ + +DROP PACKAGE pkg1; + + +# +# Testing packages in different databases calling each other +# in routines and in the initialization section. +# + +CREATE DATABASE db1; +DELIMITER $$; +CREATE PACKAGE db1.pkg1 AS + PROCEDURE p1(a OUT TEXT); +END; +$$ +CREATE PACKAGE BODY db1.pkg1 AS + PROCEDURE p1(a OUT TEXT) AS + BEGIN + a:= 'This is db1.pkg1.p1'; + END; +END; +$$ +DELIMITER ;$$ + +CREATE DATABASE db2; +DELIMITER $$; +CREATE PACKAGE db2.pkg1 AS + FUNCTION var1 RETURN TEXT; + PROCEDURE p1(a OUT TEXT); + PROCEDURE p2_db1_pkg1_p1; +END; +$$ +CREATE PACKAGE BODY db2.pkg1 AS + m_var1 TEXT; + FUNCTION var1 RETURN TEXT AS + BEGIN + RETURN m_var1; + END; + PROCEDURE p1(a OUT TEXT) AS + BEGIN + a:= 'This is db2.pkg1.p1'; + END; + PROCEDURE p2_db1_pkg1_p1 AS + a TEXT; + BEGIN + db1.pkg1.p1(a); + SELECT a; + END; +BEGIN + db1.pkg1.p1(m_var1); +END; +$$ +DELIMITER ;$$ + +SELECT db2.pkg1.var1(); +CALL db2.pkg1.p2_db1_pkg1_p1; +--enable_ps2_protocol + +DROP DATABASE db1; +DROP DATABASE db2; + + +--echo # +--echo # MDEV-29370 Functions in packages are slow and seems to ignore deterministic +--echo # + +SET SQL_MODE=ORACLE; + +CREATE TABLE t1 (c1 CHAR(1)); + +DELIMITER //; +CREATE FUNCTION f1_deterministic() +RETURN CHAR(1) +DETERMINISTIC +IS +BEGIN + RETURN 'X'; +END; +// + +CREATE FUNCTION f2_not_deterministic() +RETURN CHAR(1) +IS +BEGIN + RETURN 'X'; +END; +// + +CREATE PACKAGE pkg1 +IS + PROCEDURE t1_populate(numrows INTEGER); + FUNCTION f3_deterministic() RETURN CHAR(1) DETERMINISTIC; + FUNCTION f4_not_deterministic() RETURN CHAR(1); +END; +// + +CREATE PACKAGE BODY pkg1 +IS + PROCEDURE t1_populate(numrounds INTEGER) + IS + i INTEGER; + BEGIN + INSERT INTO t1 VALUES('Y'); + FOR i IN 1..numrounds LOOP + INSERT INTO t1 SELECT * FROM t1; + END LOOP; + END; + FUNCTION f3_deterministic() RETURN CHAR(1) DETERMINISTIC COMMENT 'xxx' + IS + BEGIN + RETURN 'X'; + END; + FUNCTION f4_not_deterministic() RETURN CHAR(1) + IS + BEGIN + RETURN 'X'; + END; +END; +// +DELIMITER ;// + +CALL pkg1.t1_populate(3); + +EXPLAIN EXTENDED SELECT 'Deterministic function', COUNT(*) FROM t1 WHERE c1 = f1_deterministic(); +EXPLAIN EXTENDED SELECT 'Non-deterministic function', COUNT(*) FROM t1 WHERE c1 = f2_not_deterministic(); +EXPLAIN EXTENDED SELECT 'Deterministic package function', COUNT(*) FROM t1 WHERE c1 = pkg1.f3_deterministic(); +EXPLAIN EXTENDED SELECT 'Non-deterministic package function', COUNT(*) FROM t1 WHERE c1 = pkg1.f4_not_deterministic(); + +DROP TABLE t1; +DROP FUNCTION f1_deterministic; +DROP FUNCTION f2_not_deterministic; +DROP PACKAGE pkg1; 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 00000000..35bce8ac --- /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 00000000..b887858d --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-param.test @@ -0,0 +1,363 @@ +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 + +--echo +--echo MDEV-13919 sql_mode=ORACLE: Derive length of VARCHAR SP parameters with no length from actual parameters +--echo +set sql_mode= 'oracle,strict_trans_tables'; +delimiter /; +CREATE OR REPLACE PROCEDURE p1(pinout INOUT varchar, pin IN varchar) +AS +BEGIN + pinout:=pin; +END; +/ +call p1(@w,'0123456789') +/ +declare w varchar(10); +begin + call p1(w,'0123456789'); +end; +/ +--error ER_DATA_TOO_LONG +declare w varchar(5); +begin + call p1(w,'0123456789'); +end; +/ +declare w varchar(20); +begin + w:='aaa'; + call p1(w,'0123456789'); +end; +/ +--error ER_DATA_TOO_LONG +declare w varchar(8); +begin + w:='aaa'; + call p1(w,'0123456789'); +end; +/ +declare str varchar(6000); + pout varchar(6000); +begin + str:=lpad('x',6000,'y'); + call p1(pout,str); + select length(pout); +end; +/ +--error ER_DATA_TOO_LONG +declare str varchar(6000); + pout varchar(4000); +begin + str:=lpad('x',6000,'y'); + call p1(pout,str); + select length(pout); +end; +/ +declare str varchar(40000); + pout varchar(60000); +begin + str:=lpad('x',40000,'y'); + call p1(pout,str); + select length(pout); +end; +/ +--error ER_DATA_TOO_LONG +declare str text(80000); + pout text(80000); +begin + str:=lpad('x',80000,'y'); + call p1(pout,str); + select length(pout); +end; +/ +declare str text(80000); + pout text(80000); +begin + str:=lpad('x',60000,'y'); + call p1(pout,str); + select length(pout); +end; +/ +drop procedure p1 +/ +DELIMITER ;/ + + +# +# Procedure, non-strict mode +# + +SET sql_mode=ORACLE; +DELIMITER /; +CREATE PROCEDURE p1(pinout INOUT varchar, pin IN varchar) +AS +BEGIN + pinout:=pin; +END; +/ +CREATE PROCEDURE p2(len INT) +AS + pinout VARCHAR(10); + pin VARCHAR(30); +BEGIN + pin:= REPEAT('x', len); + p1(pinout, pin); + SELECT LENGTH(pinout); +END; +/ +DELIMITER ;/ +CALL p2(10); +CALL p2(11); +DROP PROCEDURE p1; +DROP PROCEDURE p2; + + +# +# Function, not-strict mode +# + +SET sql_mode=ORACLE; +DELIMITER /; +CREATE FUNCTION f1(pin VARCHAR, padlen INT) RETURN TEXT +AS +BEGIN + pin:=LPAD(pin, padlen); + RETURN pin; +END; +/ +CREATE PROCEDURE p2(padlen INT) AS + str TEXT :='x'; +BEGIN + SELECT LENGTH(f1(str,padlen)); +END; +/ +DELIMITER ;/ +CALL p2(65535); +CALL p2(65536); +DROP PROCEDURE p2; +DROP FUNCTION f1; + + +# +# Procedure, utf8 formal parameter, latin actual parameter +# + +SET sql_mode='ORACLE,STRICT_TRANS_TABLES'; +DELIMITER /; +CREATE PROCEDURE p1(pinout INOUT VARCHAR CHARACTER SET utf8, + pin IN VARCHAR CHARACTER SET utf8) +AS +BEGIN + pinout:=pin; +END; +/ +CREATE PROCEDURE p2(padlen INT) AS + str VARCHAR(40000) CHARACTER SET latin1; + pout VARCHAR(60000) CHARACTER SET latin1; +BEGIN + str:=lpad('x',padlen,'y'); + p1(pout,str); + SELECT length(pout); +END; +/ +DELIMITER ;/ +CALL p2(21844); +--error ER_DATA_TOO_LONG +CALL p2(21845); +--error ER_DATA_TOO_LONG +CALL p2(21846); +DROP PROCEDURE p2; +DROP PROCEDURE p1; + + +# +# Procedure, utf8 formal parameter, utf8 actual parameter +# + +SET sql_mode='ORACLE,STRICT_TRANS_TABLES'; +DELIMITER /; +CREATE PROCEDURE p1(pinout INOUT VARCHAR CHARACTER SET utf8, + pin IN VARCHAR CHARACTER SET utf8) +AS +BEGIN + pinout:=pin; +END; +/ +CREATE PROCEDURE p2(padlen INT) AS + str TEXT CHARACTER SET utf8; + pout TEXT CHARACTER SET utf8; +BEGIN + str:=lpad('x',padlen,'y'); + p1(pout,str); + SELECT length(pout); +END; +/ +DELIMITER ;/ +CALL p2(21844); +--error ER_DATA_TOO_LONG +CALL p2(21845); +--error ER_DATA_TOO_LONG +CALL p2(21846); +DROP PROCEDURE p2; +DROP PROCEDURE p1; + + +# +# Function, latin1 formal parameter, latin1 actual parameter +# + +SET sql_mode='ORACLE,STRICT_TRANS_TABLES'; +DELIMITER /; +CREATE FUNCTION f1(pin VARCHAR CHARACTER SET latin1, padlen INT) RETURN TEXT +AS +BEGIN + pin:=LPAD(pin, padlen); + RETURN pin; +END; +/ +CREATE PROCEDURE p2(padlen INT) AS + str TEXT CHARACTER SET latin1 :='x'; +BEGIN + SELECT LENGTH(f1(str,padlen)); +END; +/ +DELIMITER ;/ +CALL p2(65532); +--error ER_DATA_TOO_LONG +CALL p2(65533); +--error ER_DATA_TOO_LONG +CALL p2(65534); +--error ER_DATA_TOO_LONG +CALL p2(65535); +--error ER_DATA_TOO_LONG +CALL p2(65536); +DROP PROCEDURE p2; +DROP FUNCTION f1; + + +# +# Function, utf8 formal parameter, utf8 actual parameter +# + +SET sql_mode='ORACLE,STRICT_TRANS_TABLES'; +DELIMITER /; +CREATE FUNCTION f1(pin VARCHAR CHARACTER SET utf8, padlen INT) RETURN TEXT +AS +BEGIN + pin:=LPAD(pin, padlen); + RETURN pin; +END; +/ +CREATE PROCEDURE p2(padlen INT) AS + str TEXT CHARACTER SET utf8 := 'x'; +BEGIN + SELECT LENGTH(f1(str,padlen)); +END; +/ +DELIMITER ;/ +CALL p2(21844); +--error ER_DATA_TOO_LONG +CALL p2(21845); +--error ER_DATA_TOO_LONG +CALL p2(21846); +DROP PROCEDURE p2; +DROP FUNCTION f1; + + +# +# Function, utf8 formal parameter, latin1 actual parameter +# + +SET sql_mode='ORACLE,STRICT_TRANS_TABLES'; +DELIMITER /; +CREATE FUNCTION f1(pin VARCHAR CHARACTER SET utf8, padlen INT) RETURN TEXT +AS +BEGIN + pin:=LPAD(pin, padlen); + RETURN pin; +END; +/ +CREATE PROCEDURE p2(padlen INT) AS + str TEXT CHARACTER SET latin1 := 'x'; +BEGIN + SELECT LENGTH(f1(str,padlen)); +END; +/ +DELIMITER ;/ +CALL p2(21844); +--error ER_DATA_TOO_LONG +CALL p2(21845); +--error ER_DATA_TOO_LONG +CALL p2(21846); +DROP PROCEDURE p2; +DROP FUNCTION f1; + + +# +# Function, latin1 formal parameter, utf8 actual parameter +# + +SET sql_mode='ORACLE,STRICT_TRANS_TABLES'; +DELIMITER /; +CREATE FUNCTION f1(pin VARCHAR CHARACTER SET latin1, padlen INT) RETURN TEXT +AS +BEGIN + pin:=LPAD(pin, padlen); + RETURN pin; +END; +/ +CREATE PROCEDURE p2(padlen INT) AS + str TEXT CHARACTER SET utf8 := 'x'; +BEGIN + SELECT LENGTH(f1(str,padlen)); +END; +/ +DELIMITER ;/ +CALL p2(65532); +--error ER_DATA_TOO_LONG +CALL p2(65533); +--error ER_DATA_TOO_LONG +CALL p2(65534); +--error ER_DATA_TOO_LONG +CALL p2(65535); +--error ER_DATA_TOO_LONG +CALL p2(65536); +DROP PROCEDURE p2; +DROP FUNCTION f1; 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 00000000..14f6f7df --- /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 00000000..c7658c76 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-row.test @@ -0,0 +1,2418 @@ + +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_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +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_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +CALL p1(); +DROP PROCEDURE p1; + + +DELIMITER $$; +CREATE PROCEDURE p1() +AS + a ROW (a INT,b INT); +BEGIN + SELECT a+1; +END; +$$ +DELIMITER ;$$ +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +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_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +CALL p1(); +DROP PROCEDURE p1; + + +DELIMITER $$; +CREATE PROCEDURE p1() +AS + a ROW (a INT,b INT); +BEGIN + SELECT 1=a; +END; +$$ +DELIMITER ;$$ +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +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_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +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_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +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_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +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 # + +--enable_prepare_warnings + +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; + +--disable_prepare_warnings + +--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 # + + +--enable_prepare_warnings +--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; +--disable_prepare_warnings + +--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; + +--echo # +--echo # MDEV-13527 Crash when EXPLAIN SELECT .. INTO row_sp_variable.field +--echo # + +DELIMITER $$; +DECLARE + a ROW(a INT); +BEGIN + EXPLAIN SELECT 1 INTO a.a; +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # MDEV-14139 Anchored data types for variables +--echo # + +DELIMITER $$; +DECLARE + row1 ROW(int11 INT,text1 TEXT); + a_row1 row1%TYPE; + aa_row1 a_row1%TYPE; +BEGIN + CREATE TABLE t1 AS SELECT a_row1.int11 AS int11, a_row1.text1 AS text1; + SHOW CREATE TABLE t1; + DROP TABLE t1; + CREATE TABLE t1 AS SELECT aa_row1.int11 AS int11, aa_row1.text1 AS text1; + SHOW CREATE TABLE t1; + DROP TABLE t1; +END; +$$ +DELIMITER ;$$ 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 00000000..1732c0b8 --- /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 00000000..69b8608b --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp.test @@ -0,0 +1,2430 @@ +--source include/default_charset.inc + +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 # Keywords that are OK for table names, but not for SP variables +CREATE TABLE function (function int); +INSERT INTO function SET function=10; +SELECT function.function FROM function; +DROP TABLE function; + +--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;/ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 (exception OUT INT) AS BEGIN exception:=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/ +CREATE PROCEDURE p1 (exception OUT INT) AS BEGIN SET exception=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; +CREATE TABLE exception (exception INT); +DROP TABLE exception; + +--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 1..a + 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 $$; +--error ER_SP_UNDECLARED_VAR +CREATE PROCEDURE p1 +AS +BEGIN + LOOP + EXIT WHEN unknown_ident IS NULL; + END LOOP; +END$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_SP_UNDECLARED_VAR +CREATE PROCEDURE p1 +AS +BEGIN + <<label>> + LOOP + EXIT label WHEN unknown_ident IS NULL; + END LOOP; +END$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_SP_UNDECLARED_VAR +CREATE PROCEDURE p1 +AS +BEGIN + LOOP + CONTINUE WHEN unknown_ident IS NULL; + END LOOP; +END$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_SP_UNDECLARED_VAR +CREATE PROCEDURE p1 +AS +BEGIN + <<label>> + LOOP + CONTINUE label WHEN unknown_ident IS NULL; + END LOOP; +END$$ +DELIMITER ;$$ + +--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_UNKNOWN_DATA_TYPE +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 + +--echo # +--echo # MDEV-13686 EXCEPTION reserved keyword in SQL_MODE=oracle but not in Oracle itself +--echo # +CREATE TABLE t1 (c1 int); +CREATE VIEW v1 AS SELECT c1 exception FROM t1; +SELECT exception FROM v1; +DROP VIEW v1; +DROP TABLE t1; + + + +--echo # +--echo # MDEV-14139 Anchored data types for variables +--echo # + +DELIMITER $$; +--error ER_SP_UNDECLARED_VAR +BEGIN NOT ATOMIC + DECLARE a a%TYPE; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +DECLARE + int11 INT; + dec103 DECIMAL(10,3); + flt0 FLOAT; + dbl0 DOUBLE; + enum0 ENUM('a','b'); + bit3 BIT(3); + + varchar10 VARCHAR(10); + text1 TEXT; + tinytext1 TINYTEXT; + mediumtext1 MEDIUMTEXT; + longtext1 LONGTEXT; + + time3 TIME(3); + datetime4 DATETIME(4); + timestamp5 TIMESTAMP(5); + date0 DATE; + + a_int11 int11%TYPE; + a_dec103 dec103%TYPE; + a_flt0 flt0%TYPE; + a_dbl0 dbl0%TYPE; + a_bit3 bit3%TYPE; + a_enum0 enum0%TYPE; + a_varchar10 varchar10%TYPE; + a_text1 text1%TYPE; + a_tinytext1 tinytext1%TYPE; + a_mediumtext1 mediumtext1%TYPE; + a_longtext1 longtext1%TYPE; + a_time3 time3%TYPE; + a_datetime4 datetime4%TYPE; + a_timestamp5 timestamp5%TYPE; + a_date0 date0%TYPE; + + aa_int11 a_int11%TYPE; + aa_dec103 a_dec103%TYPE; + aa_flt0 a_flt0%TYPE; + aa_dbl0 a_dbl0%TYPE; + aa_bit3 a_bit3%TYPE; + aa_enum0 a_enum0%TYPE; + aa_varchar10 a_varchar10%TYPE; + aa_text1 a_text1%TYPE; + aa_tinytext1 a_tinytext1%TYPE; + aa_mediumtext1 a_mediumtext1%TYPE; + aa_longtext1 a_longtext1%TYPE; + aa_time3 a_time3%TYPE; + aa_datetime4 a_datetime4%TYPE; + aa_timestamp5 a_timestamp5%TYPE; + aa_date0 a_date0%TYPE; +BEGIN + CREATE TABLE t1 AS + SELECT a_int11,a_dec103,a_flt0,a_dbl0,a_bit3, + a_enum0,a_varchar10, + a_text1,a_tinytext1,a_mediumtext1,a_longtext1, + a_time3,a_datetime4,a_timestamp5,a_date0; + SHOW CREATE TABLE t1; + DROP TABLE t1; + + CREATE TABLE t1 AS + SELECT aa_int11,aa_dec103,aa_flt0,aa_dbl0,aa_bit3, + aa_enum0,aa_varchar10, + aa_text1,aa_tinytext1,aa_mediumtext1,aa_longtext1, + aa_time3,aa_datetime4,aa_timestamp5,aa_date0; + SHOW CREATE TABLE t1; + DROP TABLE t1; + +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # MDEV-11160 "Incorrect column name" when "CREATE TABLE t1 AS SELECT spvar" +--echo # + + +CREATE TABLE t1 (x INT); +INSERT INTO t1 VALUES (10); +CREATE VIEW v1 AS SELECT x+1 AS a,x+1 AS b FROM t1; +DELIMITER $$; +CREATE PROCEDURE p1 +AS + a INT := 1; + b INT := 2; +BEGIN + CREATE TABLE t2 AS SELECT a,b FROM v1; + SHOW CREATE TABLE t2; + SELECT * FROM t2; + DROP TABLE t2; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP VIEW v1; +DROP TABLE t1; + + +--echo # +--echo # MDEV-14228 MariaDB crashes with function +--echo # + +CREATE TABLE t1 (c VARCHAR(16), KEY(c)); +INSERT INTO t1 VALUES ('foo'); + +DELIMITER $$; +CREATE FUNCTION f1() RETURN VARCHAR(16) +IS + v VARCHAR2(16); +BEGIN + FOR v IN (SELECT DISTINCT c FROM t1) + LOOP + IF (v = 'bar') THEN + SELECT 1 INTO @a; + END IF; + END LOOP; + RETURN 'qux'; +END $$ +DELIMITER ;$$ +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT f1(); +DROP FUNCTION f1; + +DELIMITER $$; +CREATE FUNCTION f1() RETURN VARCHAR(16) +IS + v t1%ROWTYPE; +BEGIN + IF v = 'bar' THEN + NULL; + END IF; + RETURN 'qux'; +END $$ +DELIMITER ;$$ +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT f1(); +DROP FUNCTION f1; + +DELIMITER $$; +CREATE FUNCTION f1() RETURN VARCHAR(16) +IS + v ROW(a INT); +BEGIN + IF v = 'bar' THEN + NULL; + END IF; + RETURN 'qux'; +END $$ +DELIMITER ;$$ +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +SELECT f1(); +DROP FUNCTION f1; + +DROP TABLE t1; + + +DELIMITER $$; +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +DECLARE + v ROW(a INT); +BEGIN + SELECT v IN ('a','b'); +END $$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +DECLARE + v ROW(a INT); +BEGIN + SELECT 'a' IN (v,'b'); +END $$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +DECLARE + v ROW(a INT); +BEGIN + SELECT 'a' IN ('b',v); +END $$ +DELIMITER ;$$ + +--echo # +--echo # MDEV-17253 Oracle compatibility: The REVERSE key word for FOR loop behaves incorrectly +--echo # + +DELIMITER $$; +DECLARE + totalprice DECIMAL(12,2):=NULL; + loop_start INTEGER := 1; +BEGIN + FOR idx IN REVERSE loop_start..10 LOOP + SELECT idx; + END LOOP; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +CREATE PROCEDURE p1 AS + loop_start INTEGER := 1; +BEGIN + FOR idx IN REVERSE 3..loop_start LOOP + SELECT idx; + END LOOP; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; + + +DELIMITER $$; +CREATE PROCEDURE p1 AS + loop_start INTEGER := 1; +BEGIN + FOR idx IN REVERSE loop_start..3 LOOP + SELECT idx; + END LOOP; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; + + +--echo # +--echo # MDEV-28588 SIGSEGV in __memmove_avx_unaligned_erms, strmake_root +--echo # + +SET sql_mode=ORACLE; +BEGIN END; + +CREATE TABLE t1 (a INT); +CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW BEGIN END; +--vertical_results +SELECT ACTION_STATEMENT FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA='test' AND TRIGGER_NAME='tr'; +--horizontal_results +DROP TRIGGER tr; +DROP TABLE t1; + +--echo # +--echo # End of 10.3 tests +--echo # + +--echo # +--echo # MDEV-19637 Crash on an SP variable assignment to a wrong subselect +--echo # + +DELIMITER $$; +--error ER_CANT_USE_OPTION_HERE +DECLARE + a INT; +BEGIN + SET a=(SELECT 1 FROM DUAL UNION SELECT HIGH_PRIORITY 2 FROM DUAL); +END; +$$ +DELIMITER ;$$ + + +--echo # +--echo # End of 10.4 tests +--echo # diff --git a/mysql-test/suite/compat/oracle/t/statement-expr.test b/mysql-test/suite/compat/oracle/t/statement-expr.test new file mode 100644 index 00000000..1caab623 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/statement-expr.test @@ -0,0 +1,86 @@ +# Testing expressions of different kinds in various non-SELECT statements + +SET sql_mode=ORACLE; + +--echo # +--echo # Start of 10.3 tests +--echo # + +# +# Subselects in non-SELECT statements +# + +CREATE TABLE t1 (id INT, id1 INT); +INSERT INTO t1 VALUES (1,7); +INSERT INTO t1 VALUES (1,8); +SELECT ROW(1,7) IN (SELECT id, id1 FROM t1 WHERE id1= 8); +EXECUTE IMMEDIATE 'SELECT ROW(1, 7) IN (SELECT id, id1 FROM t1 WHERE id1= 8)'; +DROP TABLE t1; + +--error ER_SUBQUERIES_NOT_SUPPORTED +EXECUTE IMMEDIATE 'SELECT ?' USING (1 IN (SELECT * FROM t1)); +--error ER_SUBQUERIES_NOT_SUPPORTED +EXECUTE IMMEDIATE 'SELECT ?' USING (SELECT * FROM t1); + + +CREATE TABLE t1 (id INT); +INSERT INTO t1 VALUES (10); +DELIMITER $$; +CREATE PROCEDURE p1(a INT) AS BEGIN NULL; END; +$$ +DELIMITER ;$$ +CALL p1((1) IN (SELECT * FROM t1)); +CALL p1(EXISTS (SELECT * FROM t1)); +DROP PROCEDURE p1; +DROP TABLE t1; + +--error ER_PARSE_ERROR +SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=(1 IN (SELECT * FROM t1)); +--error ER_PARSE_ERROR +SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=EXISTS (SELECT * FROM t1); + +DELIMITER $$; +--error ER_PARSE_ERROR +BEGIN NOT ATOMIC + DECLARE CONTINUE HANDLER FOR SQLWARNING + RESIGNAL SET MYSQL_ERRNO=(1 IN (SELECT * FROM t1)); + SIGNAL SQLSTATE '01000'; +END; +$$ +--error ER_PARSE_ERROR +BEGIN NOT ATOMIC + DECLARE CONTINUE HANDLER FOR SQLWARNING + RESIGNAL SET MYSQL_ERRNO=EXISTS (SELECT * FROM t1); + SIGNAL SQLSTATE '01000'; +END; +$$ +DELIMITER ;$$ + + +--error ER_SUBQUERIES_NOT_SUPPORTED +PREPARE stmt FROM (1 IN (SELECT * FROM t1)); +--error ER_SUBQUERIES_NOT_SUPPORTED +PREPARE stmt FROM EXISTS (SELECT * FROM t1); + +--error ER_SUBQUERIES_NOT_SUPPORTED +EXECUTE IMMEDIATE (1 IN (SELECT * FROM t1)); +--error ER_SUBQUERIES_NOT_SUPPORTED +EXECUTE IMMEDIATE EXISTS (SELECT * FROM t1); + +--error ER_PARSE_ERROR +GET DIAGNOSTICS CONDITION (1 IN (SELECT * FROM t1)) @errno=MYSQL_ERRNO; +--error ER_PARSE_ERROR +GET DIAGNOSTICS CONDITION EXISTS (SELECT * FROM t1) @errno=MYSQL_ERRNO; + +--error ER_SUBQUERIES_NOT_SUPPORTED +PURGE BINARY LOGS BEFORE (1 IN (SELECT * FROM t1)); +--error ER_SUBQUERIES_NOT_SUPPORTED +PURGE BINARY LOGS BEFORE EXISTS (SELECT * FROM t1); + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); +DO 1 IN (SELECT * FROM t1); +DO EXISTS (SELECT * FROM t1); +DROP TABLE t1; + + diff --git a/mysql-test/suite/compat/oracle/t/table_value_constr.test b/mysql-test/suite/compat/oracle/t/table_value_constr.test new file mode 100644 index 00000000..ca3c40bb --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/table_value_constr.test @@ -0,0 +1,1287 @@ +SET sql_mode=ORACLE; + +create table t1 (a int, b int); + +insert into t1 values (1,2),(4,6),(9,7), + (1,1),(2,5),(7,8); + +--echo # just VALUES + +values (1,2); + +values (1,2), (3,4), (5.6,0); + +values ('abc', 'def'); + +--echo # UNION that uses VALUES structure(s) + +select 1,2 +union +values (1,2); + +values (1,2) +union +select 1,2; + +select 1,2 +union +values (1,2),(3,4),(5,6),(7,8); + +select 3,7 +union +values (1,2),(3,4),(5,6); + +select 3,7,4 +union +values (1,2,5),(4,5,6); + +select 1,2 +union +values (1,7),(3,6.5); + +select 1,2 +union +values (1,2.0),(3,6); + +select 1.8,2 +union +values (1,2),(3,6); + +values (1,2.4),(3,6) +union +select 2.8,9; + +values (1,2),(3,4),(5,6),(7,8) +union +select 5,6; + +select 'ab','cdf' +union +values ('al','zl'),('we','q'); + +values ('ab', 'cdf') +union +select 'ab','cdf'; + +values (1,2) +union +values (1,2),(5,6); + +values (1,2) +union +values (3,4),(5,6); + +values (1,2) +union +values (1,2) +union values (4,5); + +--echo # UNION ALL that uses VALUES structure + +values (1,2),(3,4) +union all +select 5,6; + +values (1,2),(3,4) +union all +select 1,2; + +select 5,6 +union all +values (1,2),(3,4); + +select 1,2 +union all +values (1,2),(3,4); + +values (1,2) +union all +values (1,2),(5,6); + +values (1,2) +union all +values (3,4),(5,6); + +values (1,2) +union all +values (1,2) +union all +values (4,5); + +values (1,2) +union all +values (1,2) +union values (1,2); + +values (1,2) +union +values (1,2) +union all +values (1,2); + +--echo # EXCEPT that uses VALUES structure(s) + +select 1,2 +except +values (3,4),(5,6); + +select 1,2 +except +values (1,2),(3,4); + +values (1,2),(3,4) +except +select 5,6; + +values (1,2),(3,4) +except +select 1,2; + +values (1,2),(3,4) +except +values (5,6); + +values (1,2),(3,4) +except +values (1,2); + +--echo # INTERSECT that uses VALUES structure(s) + +select 1,2 +intersect +values (3,4),(5,6); + +select 1,2 +intersect +values (1,2),(3,4); + +values (1,2),(3,4) +intersect +select 5,6; + +values (1,2),(3,4) +intersect +select 1,2; + +values (1,2),(3,4) +intersect +values (5,6); + +values (1,2),(3,4) +intersect +values (1,2); + +--echo # combination of different structures that uses VALUES structures : UNION + EXCEPT + +values (1,2),(3,4) +except +select 1,2 +union values (1,2); + +values (1,2),(3,4) +except +values (1,2) +union +values (1,2); + +values (1,2),(3,4) +except +values (1,2) +union +values (3,4); + +values (1,2),(3,4) +union +values (1,2) +except +values (1,2); + +--echo # combination of different structures that uses VALUES structures : UNION ALL + EXCEPT + +values (1,2),(3,4) +except +select 1,2 +union all +values (1,2); + +values (1,2),(3,4) +except +values (1,2) +union all +values (1,2); + +values (1,2),(3,4) +except +values (1,2) +union all +values (3,4); + +values (1,2),(3,4) +union all +values (1,2) +except +values (1,2); + +--echo # combination of different structures that uses VALUES structures : UNION + INTERSECT + +values (1,2),(3,4) +intersect +select 1,2 +union +values (1,2); + +values (1,2),(3,4) +intersect +values (1,2) +union +values (1,2); + +values (1,2),(3,4) +intersect +values (1,2) +union +values (3,4); + +values (1,2),(3,4) +union +values (1,2) +intersect +values (1,2); + +--echo # combination of different structures that uses VALUES structures : UNION ALL + INTERSECT + +values (1,2),(3,4) +intersect +select 1,2 +union all +values (1,2); + +values (1,2),(3,4) +intersect +values (1,2) +union all +values (1,2); + +values (1,2),(3,4) +intersect +values (1,2) +union all +values (3,4); + +values (1,2),(3,4) +union all +values (1,2) +intersect +values (1,2); + +--echo # combination of different structures that uses VALUES structures : UNION + UNION ALL + +values (1,2),(3,4) +union all +select 1,2 +union +values (1,2); + +values (1,2),(3,4) +union all +values (1,2) +union +values (1,2); + +values (1,2),(3,4) +union all +values (1,2) +union +values (3,4); + +values (1,2),(3,4) +union +values (1,2) +union all +values (1,2); + +values (1,2) +union +values (1,2) +union all +values (1,2); + +--echo # CTE that uses VALUES structure(s) : non-recursive CTE + +with t2 as +( + values (1,2),(3,4) +) +select * from t2; + +with t2 as +( + select 1,2 + union + values (1,2) +) +select * from t2; + +with t2 as +( + select 1,2 + union + values (1,2),(3,4) +) +select * from t2; + +with t2 as +( + values (1,2) + union + select 1,2 +) +select * from t2; + +with t2 as +( + values (1,2),(3,4) + union + select 1,2 +) +select * from t2; + +with t2 as +( + values (5,6) + union + values (1,2),(3,4) +) +select * from t2; + +with t2 as +( + values (1,2) + union + values (1,2),(3,4) +) +select * from t2; + +with t2 as +( + select 1,2 + union all + values (1,2),(3,4) +) +select * from t2; + +with t2 as +( + values (1,2),(3,4) + union all + select 1,2 +) +select * from t2; + +with t2 as +( + values (1,2) + union all + values (1,2),(3,4) +) +select * from t2; + +--echo # recursive CTE that uses VALUES structure(s) : singe VALUES structure as anchor + +with recursive t2(a,b) as +( + values(1,1) + union + select t1.a, t1.b + from t1,t2 + where t1.a=t2.a +) +select * from t2; + +with recursive t2(a,b) as +( + values(1,1) + union + select t1.a+1, t1.b + from t1,t2 + where t1.a=t2.a +) +select * from t2; + +--echo # recursive CTE that uses VALUES structure(s) : several VALUES structures as anchors + +with recursive t2(a,b) as +( + values(1,1) + union + values (3,4) + union + select t2.a+1, t1.b + from t1,t2 + where t1.a=t2.a +) +select * from t2; + +--echo # recursive CTE that uses VALUES structure(s) : that uses UNION ALL + +with recursive t2(a,b,st) as +( + values(1,1,1) + union all + select t2.a, t1.b, t2.st+1 + from t1,t2 + where t1.a=t2.a and st<3 +) +select * from t2; + +--echo # recursive CTE that uses VALUES structure(s) : computation of factorial (first 10 elements) + +with recursive fact(n,f) as +( + values(1,1) + union + select n+1,f*n from fact where n < 10 +) +select * from fact; + +--echo # Derived table that uses VALUES structure(s) : singe VALUES structure + +select * from (values (1,2),(3,4)) as t2; + +--echo # Derived table that uses VALUES structure(s) : UNION with VALUES structure(s) + +select * from (select 1,2 union values (1,2)) as t2; + +select * from (select 1,2 union values (1,2),(3,4)) as t2; + +select * from (values (1,2) union select 1,2) as t2; + +select * from (values (1,2),(3,4) union select 1,2) as t2; + +select * from (values (5,6) union values (1,2),(3,4)) as t2; + +select * from (values (1,2) union values (1,2),(3,4)) as t2; + +--echo # Derived table that uses VALUES structure(s) : UNION ALL with VALUES structure(s) + +select * from (select 1,2 union all values (1,2),(3,4)) as t2; + +select * from (values (1,2),(3,4) union all select 1,2) as t2; + +select * from (values (1,2) union all values (1,2),(3,4)) as t2; + +--echo # CREATE VIEW that uses VALUES structure(s) : singe VALUES structure + +let $drop_view= drop view v1; +let $select_view= select * from v1; + +create view v1 as values (1,2),(3,4); + +eval $select_view; +eval $drop_view; + +--echo # CREATE VIEW that uses VALUES structure(s) : UNION with VALUES structure(s) + +create view v1 as + select 1,2 + union + values (1,2); + +eval $select_view; +eval $drop_view; + +create view v1 as + select 1,2 + union + values (1,2),(3,4); + +eval $select_view; +eval $drop_view; + +create view v1 as + values (1,2) + union + select 1,2; + +eval $select_view; +eval $drop_view; + +create view v1 as + values (1,2),(3,4) + union + select 1,2; + +eval $select_view; +eval $drop_view; + +create view v1 as + values (5,6) + union + values (1,2),(3,4); + +eval $select_view; +eval $drop_view; + +--echo # CREATE VIEW that uses VALUES structure(s) : UNION ALL with VALUES structure(s) + +create view v1 as + values (1,2) + union + values (1,2),(3,4); + +eval $select_view; +eval $drop_view; + +create view v1 as + select 1,2 + union all + values (1,2),(3,4); + +eval $select_view; +eval $drop_view; + +create view v1 as + values (1,2),(3,4) + union all + select 1,2; + +eval $select_view; +eval $drop_view; + +create view v1 as + values (1,2) + union all + values (1,2),(3,4); + +eval $select_view; +eval $drop_view; + +--echo # IN-subquery with VALUES structure(s) : simple case +let $query= +select * from t1 +where a in (values (1)); +let $subst_query= +select * from t1 +where a in (select * from (values (1)) as tvc_0); +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # IN-subquery with VALUES structure(s) : UNION with VALUES on the first place +let $query= +select * from t1 +where a in (values (1) union select 2); +let $subst_query= +select * from t1 +where a in (select * from (values (1)) as tvc_0 union + select 2); +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # IN-subquery with VALUES structure(s) : UNION with VALUES on the second place +let $query= +select * from t1 +where a in (select 2 union values (1)); +let $subst_query= +select * from t1 +where a in (select 2 union + select * from (values (1)) tvc_0); +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # IN-subquery with VALUES structure(s) : UNION ALL +let $query= +select * from t1 +where a in (values (1) union all select b from t1); +let $subst_query= +select * from t1 +where a in (select * from (values (1)) as tvc_0 union all + select b from t1); + +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # NOT IN subquery with VALUES structure(s) : simple case +let $query= +select * from t1 +where a not in (values (1),(2)); +let $subst_query= +select * from t1 +where a not in (select * from (values (1),(2)) as tvc_0); + +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # NOT IN subquery with VALUES structure(s) : UNION with VALUES on the first place +let $query= +select * from t1 +where a not in (values (1) union select 2); +let $subst_query= +select * from t1 +where a not in (select * from (values (1)) as tvc_0 union + select 2); + +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # NOT IN subquery with VALUES structure(s) : UNION with VALUES on the second place +let $query= +select * from t1 +where a not in (select 2 union values (1)); +let $subst_query= +select * from t1 +where a not in (select 2 union + select * from (values (1)) as tvc_0); + +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # ANY-subquery with VALUES structure(s) : simple case +let $query= +select * from t1 +where a = any (values (1),(2)); +let $subst_query= +select * from t1 +where a = any (select * from (values (1),(2)) as tvc_0); + +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # ANY-subquery with VALUES structure(s) : UNION with VALUES on the first place +let $query= +select * from t1 +where a = any (values (1) union select 2); +let $subst_query= +select * from t1 +where a = any (select * from (values (1)) as tvc_0 union + select 2); + +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # ANY-subquery with VALUES structure(s) : UNION with VALUES on the second place +let $query= +select * from t1 +where a = any (select 2 union values (1)); +let $subst_query= +select * from t1 +where a = any (select 2 union + select * from (values (1)) as tvc_0); + +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # ALL-subquery with VALUES structure(s) : simple case +let $query= +select * from t1 +where a = all (values (1)); +let $subst_query= +select * from t1 +where a = all (select * from (values (1)) as tvc_0); + +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # ALL-subquery with VALUES structure(s) : UNION with VALUES on the first place +let $query= +select * from t1 +where a = all (values (1) union select 1); +let $subst_query= +select * from t1 +where a = all (select * from (values (1)) as tvc_0 union + select 1); + +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # ALL-subquery with VALUES structure(s) : UNION with VALUES on the second place +let $query= +select * from t1 +where a = any (select 1 union values (1)); +let $subst_query= +select * from t1 +where a = any (select 1 union + select * from (values (1)) as tvc_0); + +eval $query; +eval $subst_query; +eval explain extended $query; +eval explain extended $subst_query; + +--echo # prepare statement that uses VALUES structure(s): single VALUES structure + +prepare stmt1 from ' +values (1,2); +'; + +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +--echo # prepare statement that uses VALUES structure(s): UNION with VALUES structure(s) + +prepare stmt1 from ' + select 1,2 + union + values (1,2),(3,4); +'; + +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +prepare stmt1 from ' + values (1,2),(3,4) + union + select 1,2; +'; + +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +prepare stmt1 from ' + select 1,2 + union + values (3,4) + union + values (1,2); +'; + +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +prepare stmt1 from ' + values (5,6) + union + values (1,2),(3,4); +'; + +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +--echo # prepare statement that uses VALUES structure(s): UNION ALL with VALUES structure(s) + +prepare stmt1 from ' + select 1,2 + union + values (1,2),(3,4); +'; + +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +prepare stmt1 from ' + values (1,2),(3,4) + union all + select 1,2; +'; + +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +prepare stmt1 from ' + select 1,2 + union all + values (3,4) + union all + values (1,2); +'; + +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +prepare stmt1 from ' + values (1,2) + union all + values (1,2),(3,4); +'; + +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +--echo # explain query that uses VALUES structure(s): single VALUES structure + +explain +values (1,2); + +explain format=json +values (1,2); + +--echo # explain query that uses VALUES structure(s): UNION with VALUES structure(s) + +explain +select 1,2 +union +values (1,2),(3,4); + +explain +values (1,2),(3,4) +union +select 1,2; + +explain +values (5,6) +union +values (1,2),(3,4); + +explain format=json +select 1,2 +union +values (1,2),(3,4); + +explain format=json +values (1,2),(3,4) +union +select 1,2; + +explain format=json +values (5,6) +union +values (1,2),(3,4); + +explain +select 1,2 +union +values (3,4) +union +values (1,2); + +explain format=json +select 1,2 +union +values (3,4) +union +values (1,2); + +--echo # explain query that uses VALUES structure(s): UNION ALL with VALUES structure(s) + +explain +select 1,2 +union +values (1,2),(3,4); + +explain +values (1,2),(3,4) +union all +select 1,2; + +explain +values (1,2) +union all +values (1,2),(3,4); + +explain format=json +values (1,2),(3,4) +union all +select 1,2; + +explain format=json +select 1,2 +union +values (1,2),(3,4); + +explain format=json +values (1,2) +union all +values (1,2),(3,4); + +explain +select 1,2 +union all +values (3,4) +union all +values (1,2); + +explain format=json +select 1,2 +union all +values (3,4) +union all +values (1,2); + +--echo # analyze query that uses VALUES structure(s): single VALUES structure + +analyze +values (1,2); + +--source include/analyze-format.inc +analyze format=json +values (1,2); + +--echo # analyze query that uses VALUES structure(s): UNION with VALUES structure(s) + +analyze +select 1,2 +union +values (1,2),(3,4); + +analyze +values (1,2),(3,4) +union +select 1,2; + +analyze +values (5,6) +union +values (1,2),(3,4); + +--source include/analyze-format.inc +analyze format=json +select 1,2 +union +values (1,2),(3,4); + +--source include/analyze-format.inc +analyze format=json +values (1,2),(3,4) +union +select 1,2; + +--source include/analyze-format.inc +analyze format=json +values (5,6) +union +values (1,2),(3,4); + +analyze +select 1,2 +union +values (3,4) +union +values (1,2); + +--source include/analyze-format.inc +analyze format=json +select 1,2 +union +values (3,4) +union +values (1,2); + +--echo # analyze query that uses VALUES structure(s): UNION ALL with VALUES structure(s) + +analyze +select 1,2 +union +values (1,2),(3,4); + +analyze +values (1,2),(3,4) +union all +select 1,2; + +analyze +values (1,2) +union all +values (1,2),(3,4); + +--source include/analyze-format.inc +analyze format=json +values (1,2),(3,4) +union all +select 1,2; + +--source include/analyze-format.inc +analyze format=json +select 1,2 +union +values (1,2),(3,4); + +--source include/analyze-format.inc +analyze format=json +values (1,2) +union all +values (1,2),(3,4); + +analyze +select 1,2 +union all +values (3,4) +union all +values (1,2); + +--source include/analyze-format.inc +analyze format=json +select 1,2 +union all +values (3,4) +union all +values (1,2); + +--echo # different number of values in TVC +--error ER_WRONG_NUMBER_OF_VALUES_IN_TVC +values (1,2),(3,4,5); + +--echo # illegal parameter data types in TVC +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +values (1,point(1,1)),(1,1); +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +values (1,point(1,1)+1); + +--echo # field reference in TVC +--error ER_FIELD_REFERENCE_IN_TVC +select * from (values (1), (b), (2)) as new_tvc; +--error ER_FIELD_REFERENCE_IN_TVC +select * from (values (1), (t1.b), (2)) as new_tvc; + +drop table t1; + +--echo # +--echo # MDEV-15940: cursor over TVC +--echo # + +DELIMITER |; + +DECLARE + v INT; + CURSOR cur IS VALUES(7); +BEGIN + OPEN cur; + FETCH cur INTO v; + SELECT v; +END; +| + +DECLARE + v INT DEFAULT 0; +BEGIN + FOR a IN (VALUES (7)) LOOP + SET v = v + 1; + END LOOP; + SELECT v; +END; +| + +DELIMITER ;| + +--echo # +--echo # MDEV-16038: empty row in TVC +--echo # + +--error ER_EMPTY_ROW_IN_TVC +with t as (values (),()) select 1 from t; + +--echo # +--echo # MDEV-17017: TVC in derived table +--echo # + +create table t1 (a int); +insert into t1 values (9), (3), (2); + +let $q1= +select * from (values (7), (5), (8), (1), (3), (8), (1)) t; +eval $q1; +eval explain $q1; + +let $q2= +select * from (values (1,11), (7,77), (3,31), (4,42)) t; +eval $q2; +eval explain $q2; + +let $q3= +select * from (values (7), (5), (8), (1) union values (3), (8), (1)) t; +eval $q3; +eval explain $q3; + +let $q4= +select * from (values (7), (5), (8), (1) union select * from t1) t; +eval $q4; +eval explain $q4; + +drop table t1; + +--echo # +--echo # MDEV-16930: expression in the first row of TVC specifying derived table +--echo # + +SELECT 1 + 1, 2, 'abc'; +SELECT * FROM (SELECT 1 + 1, 2, 'abc') t; +WITH cte AS (SELECT 1 + 1, 2, 'abc') SELECT * FROM cte; +SELECT 1 + 1, 2, 'abc' UNION SELECT 3+4, 3, 'abc'; +CREATE VIEW v1 AS SELECT 1 + 1, 2, 'abc'; +SELECT * FROM v1; +DROP VIEW v1; + +VALUES(1 + 1,2,'abc'); +SELECT * FROM (VALUES(1 + 1,2,'abc')) t; + +--echo # +--echo # MDEV-17894: tvc with ORDER BY ... LIMIT +--echo # + +let $q= +values (5), (7), (1), (3), (4) limit 2; +eval $q; +eval explain extended $q; + +let $q= +values (5), (7), (1), (3), (4) limit 2 offset 1; +eval $q; +eval explain extended $q; + +let $q= +values (5), (7), (1), (3), (4) order by 1 limit 2; +eval $q; +eval explain extended $q; + +let $q= +values (5), (7), (1), (3), (4) order by 1 limit 2 offset 1; +eval $q; +eval explain extended $q; + +let $q= +values (5), (7), (1), (3), (4) order by 1; +eval $q; +eval explain extended $q; + +let $q= +values (5,90), (7,20), (1,70), (3,50), (4,10) order by 2; +eval $q; +eval explain extended $q; + +let $q= +select 2 union (values (5), (7), (1), (3), (4) limit 2); +eval $q; +eval explain extended $q; + +let $q= +select 2 union (values (5), (7), (1), (3), (4) limit 2 offset 1); +eval $q; +eval explain extended $q; + +let $q= +select 2 union (values (5), (7), (1), (3), (4) order by 1 limit 2); +eval $q; +eval explain extended $q; + +let $q= +select 2 union (values (5), (7), (1), (3), (4) order by 1 limit 2 offset 1); +eval $q; +eval explain extended $q; + + +let $q= +(values (5), (7), (1), (3), (4) limit 2) union select 2; +eval $q; +eval explain extended $q; + +let $q= +(values (5), (7), (1), (3), (4) limit 2 offset 1) union select 2; +eval $q; +eval explain extended $q; + +let $q= +(values (5), (7), (1), (3), (4) order by 1 limit 2) union select 2; +eval $q; +eval explain extended $q; + +let $q= +(values (5), (7), (1), (3), (4) order by 1 limit 2 offset 1) union select 2; +eval $q; +eval explain extended $q; + + +let $q= +select 3 union all (values (5), (7), (1), (3), (4) limit 2 offset 3); +eval $q; +eval explain extended $q; + +let $q= +(values (5), (7), (1), (3), (4) limit 2 offset 3) union all select 3; +eval $q; +eval explain extended $q; + +let $q= +select 3 union all (values (5), (7), (1), (3), (4) order by 1 limit 2); +eval $q; +eval explain extended $q; + +let $q= +(values (5), (7), (1), (3), (4) order by 1 limit 2) union all select 3; +eval $q; +eval explain extended $q; + +let $q= +( values (5), (7), (1), (3), (4) limit 2 offset 1 ) + union +( values (5), (7), (1), (3), (4) order by 1 limit 2 ); +eval $q; +eval explain extended $q; + +let $q= +( values (5), (7), (1), (3), (4) limit 2 offset 1 ) + union all +( values (5), (7), (1), (3), (4) order by 1 limit 2 ); +eval $q; +eval explain extended $q; + +let $q= +(values (5), (7), (1), (3), (4) limit 2 offset 3) union all select 3 order by 1; +eval $q; +eval explain extended $q; + +let $q= +(values (5), (7), (1), (3), (4) order by 1 limit 3 offset 1) union all select 3 order by 1; +eval $q; +eval explain extended $q; + +let $q= +(values (5), (7), (1), (3), (4) order by 1 limit 3 offset 1) union all select 3 + order by 1 limit 2 offset 1; +eval $q; +eval explain extended $q; + +--error ER_BAD_FIELD_ERROR +values (5,90), (7,20), (1,70), (3,50), (4,10) order by 3; + +create view v1 as values (5), (7), (1), (3), (4) order by 1 limit 2; +show create view v1; +select * from v1; +drop view v1; + +create view v1 as +( values (5), (7), (1), (3), (4) limit 2 offset 1 ) + union +( values (5), (7), (1), (3), (4) order by 1 limit 2 ); +show create view v1; +select * from v1; +drop view v1; + +--error ER_BAD_FIELD_ERROR +create view v1 as values (5,90), (7,20), (1,70), (3,50), (4,10) order by 3; + +--error ER_BAD_FIELD_ERROR +create view v1 as +( values (5), (7), (1), (3), (4) limit 2 offset 1 ) + union +( values (5), (7), (1), (3), (4) order by 2 limit 2 ); 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 00000000..45affb2d --- /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 00000000..ac540047 --- /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 00000000..989581ee --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/type_blob.test @@ -0,0 +1,17 @@ +SET sql_mode=ORACLE; +CREATE TABLE t1 (a BLOB); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo # +--echo # MDEV-20263 sql_mode=ORACLE: BLOB(65535) should not translate to LONGBLOB +--echo # + +CREATE TABLE t1 ( + c1 BLOB(100), + c2 BLOB(65535), + c3 BLOB(16777215), + c4 BLOB(16777216) +); +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 00000000..275e368b --- /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 00000000..f6886d15 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/type_date.test @@ -0,0 +1,101 @@ +SET sql_mode=ORACLE; +CREATE TABLE t1 (a DATE); +SHOW CREATE TABLE t1; +DROP TABLE t1; + + +--echo # +--echo # MDEV-19632 Replication aborts with ER_SLAVE_CONVERSION_FAILED upon CREATE ... SELECT in ORACLE mode +--echo # + +SET sql_mode=DEFAULT; +--error ER_UNKNOWN_DATA_TYPE +CREATE TABLE t1 (a unknown.DATE); + + +SET sql_mode=DEFAULT; +CREATE TABLE t1 ( + def_date DATE, + mdb_date mariadb_schema.DATE, + ora_date oracle_schema.DATE, + max_date maxdb_schema.DATE +); +SHOW CREATE TABLE t1; +SET sql_mode=ORACLE; +SHOW CREATE TABLE t1; +DROP TABLE t1; + + +SET sql_mode=ORACLE; +CREATE TABLE t1 ( + def_date DATE, + mdb_date mariadb_schema.DATE, + ora_date oracle_schema.DATE, + max_date maxdb_schema.DATE +); +SHOW CREATE TABLE t1; +SET sql_mode=DEFAULT; +SHOW CREATE TABLE t1; +DROP TABLE t1; + + +--echo # +--echo # ALTER..MODIFY and ALTER..CHANGE understand qualifiers +--echo # + +SET sql_mode=DEFAULT; +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES ('2001-01-01'); +SET sql_mode=ORACLE; +SHOW CREATE TABLE t1; +SELECT * FROM t1; + +ALTER TABLE t1 MODIFY a DATE; +SHOW CREATE TABLE t1; +SELECT * FROM t1; + +ALTER TABLE t1 MODIFY a mariadb_schema.DATE; +SHOW CREATE TABLE t1; +SELECT * FROM t1; + +ALTER TABLE t1 MODIFY a oracle_schema.DATE; +SHOW CREATE TABLE t1; +SELECT * FROM t1; + +ALTER TABLE t1 CHANGE a b mariadb_schema.DATE; +SHOW CREATE TABLE t1; +SELECT * FROM t1; + +ALTER TABLE t1 CHANGE b a oracle_schema.DATE; +SHOW CREATE TABLE t1; +SELECT * FROM t1; + +DROP TABLE t1; + +--echo # +--echo # Qualified syntax is not supported yet in SP +--echo # See MDEV-23353 Qualified data types in SP +--echo # + +SET sql_mode=ORACLE; +DELIMITER $$; +--error ER_UNKNOWN_DATA_TYPE +CREATE FUNCTION f1() RETURN mariadb_schema.DATE AS +BEGIN + RETURN CURRENT_DATE; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1(a mariadb_schema.DATE) AS +BEGIN + NULL; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1() AS + a mariadb_schema.DATE; +BEGIN + NULL; +END; +$$ +DELIMITER ;$$ 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 00000000..d8ea04ab --- /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 00000000..3b54f5a3 --- /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 00000000..05691bfb --- /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 00000000..bd024371 --- /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/update_innodb.test b/mysql-test/suite/compat/oracle/t/update_innodb.test new file mode 100644 index 00000000..79660920 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/update_innodb.test @@ -0,0 +1,31 @@ +--source include/have_innodb.inc + +--echo # +--echo # MDEV-19535 sql_mode=ORACLE: 'SELECT INTO @var FOR UPDATE' does not lock the table +--echo # + +SET sql_mode='ORACLE'; +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY) engine=innodb; +INSERT INTO t1 VALUES (1); +START TRANSACTION; +--enable_prepare_warnings +SELECT a AS a_con1 FROM t1 INTO @a FOR UPDATE; + +--connect(con2,localhost,root,,) +SET sql_mode='ORACLE'; +START TRANSACTION; +--send SELECT a AS a_con2 FROM t1 INTO @a FOR UPDATE; + +--connection default +UPDATE t1 SET a=a+100; +COMMIT; + +--connection con2 +--reap +SELECT a AS con2 FROM t1; +COMMIT; + +--disable_prepare_warnings + +--connection default +DROP TABLE t1; 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 00000000..4705cac1 --- /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 # diff --git a/mysql-test/suite/compat/oracle/t/vcol.test b/mysql-test/suite/compat/oracle/t/vcol.test new file mode 100644 index 00000000..1317006f --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/vcol.test @@ -0,0 +1,16 @@ +--echo # +--echo # MDEV-13500 sql_mode=ORACLE: can't create a virtual column with function MOD +--echo # + +SET sql_mode=ORACLE; +CREATE TABLE t1 (c1 INTEGER, c2 INTEGER AS (c1 MOD 10) VIRTUAL); +SHOW CREATE TABLE t1; +INSERT INTO t1 (c1) VALUES (999); +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INT); +CREATE VIEW v1 AS SELECT a MOD 10 FROM t1; +SHOW CREATE VIEW v1; +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/suite/compat/oracle/t/versioning.test b/mysql-test/suite/compat/oracle/t/versioning.test new file mode 100644 index 00000000..abcca8c5 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/versioning.test @@ -0,0 +1,23 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-15975 PL/SQL parser does not understand historical queries +--echo # + +CREATE TABLE t1 (a INT) WITH SYSTEM VERSIONING; +INSERT INTO t1 VALUES (10); +DELETE FROM t1; +INSERT INTO t1 VALUES (20); +SELECT * FROM t1 FOR SYSTEM_TIME ALL; +SELECT * FROM t1 FOR SYSTEM_TIME AS OF (NOW()+INTERVAL 10 YEAR); +DROP TABLE t1; + +--echo # +--echo # MDEV-17959 Assertion `opt_bootstrap || mysql_parse_status || thd->lex->select_stack_top == 0' failed in parse_sql upon DELETE HISTORY under ORACLE mode +--echo # + +SET SQL_MODE= ORACLE; +CREATE TABLE t1 (a INT); +--error ER_VERS_NOT_VERSIONED +DELETE HISTORY FROM t1; +DROP TABLE t1; diff --git a/mysql-test/suite/compat/oracle/t/win.test b/mysql-test/suite/compat/oracle/t/win.test new file mode 100644 index 00000000..c6f0b647 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/win.test @@ -0,0 +1,22 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-13384: "window" seems like a reserved column name but it's not listed as one +--echo # +--echo # Currently we allow window as an identifier, except for table aliases. +--echo # + +CREATE TABLE door (id INT, window VARCHAR(10)); + +--error ER_PARSE_ERROR +SELECT id +FROM door as window; + +SELECT id, window +FROM door; + +--error ER_PARSE_ERROR +SELECT id, window +FROM door as window; + +DROP TABLE door; |