diff --git a/mysql-test/main/parser.result b/mysql-test/main/parser.result index ecb7d4f7c1396..edad2c9aa180a 100644 --- a/mysql-test/main/parser.result +++ b/mysql-test/main/parser.result @@ -1300,7 +1300,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp create table t1 (i int, vc serial as (i)); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'as (i))' at line 1 create function fs() returns serial return 1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'serial return 1' at line 1 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'return 1' at line 1 create table t1 ( id serial ); show create table t1; Table Create Table diff --git a/mysql-test/suite/compat/oracle/r/sp-package-spec-type-assoc.result b/mysql-test/suite/compat/oracle/r/sp-package-spec-type-assoc.result new file mode 100644 index 0000000000000..00fe94eab9804 --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/sp-package-spec-type-assoc.result @@ -0,0 +1,522 @@ +SET sql_mode=ORACLE; +# +# MDEV-39587 Package-wide TYPE for variable declarations +# +# A too long identifier chain in the TABLE OF type +CREATE PACKAGE pkg1 AS +TYPE assoc0_t IS TABLE OF cat1.db1.pkg1.rec1_t INDEX BY INTEGER; +END; +$$ +ERROR HY000: Unknown data type: '`cat1`.`db1`.`pkg1`' +# Assoc array cannot have attributes +# Currently this is not allowed by the parser in qualified types +# If we ever allow, make sure to call check_data_type_attributes() +# which will raise ER_UNSUPPORTED_DATA_TYPE_ATTRIBUTE +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); +TYPE assoc0_t IS TABLE OF rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PROCEDURE p1 AS +r0 pkg1.assoc0_t (0); -- Length attribute +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(0); -- Length attribute +BEGIN +NULL; +END' at line 2 +CREATE PROCEDURE p1 AS +r0 pkg1.assoc0_t (0,0); -- Length and dec attributes +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(0,0); -- Length and dec attributes +BEGIN +NULL; +END' at line 2 +CREATE PROCEDURE p1 AS +r0 pkg1.assoc0_t CHARACTER SET latin1; +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CHARACTER SET latin1; +BEGIN +NULL; +END' at line 2 +CREATE PROCEDURE p1 AS +r0 pkg1.assoc0_t COLLATE latin1_bin; +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'COLLATE latin1_bin; +BEGIN +NULL; +END' at line 2 +DROP PACKAGE pkg1; +# PACKAGE spec types cannot be used in schema routine parameters +# and schema function RETURN +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +TYPE assoc0_t IS TABLE OF rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PROCEDURE p1(a pkg1.assoc0_t) AS +BEGIN +NULL; +END; +$$ +ERROR HY000: Incorrect usage of parameter_declaration and package_name.type_name +CREATE FUNCTION f1 RETURN pkg1.assoc0_t AS +BEGIN +RETURN NULL; +END; +$$ +ERROR HY000: Incorrect usage of RETURN and package_name.type_name +DROP PACKAGE pkg1; +# A package routine parameter and a package function RETURN +# 2-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +TYPE assoc0_t IS TABLE OF rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p2(a pkg1.assoc0_t) AS +BEGIN +SELECT a(0).a, a(0).b; +END; +FUNCTION f1 RETURN pkg1.assoc0_t AS +res pkg1.assoc0_t; +BEGIN +res(0).a:= 10; +res(0).b:= 'b'; +RETURN res; +END; +PROCEDURE p1 AS +BEGIN +CALL p2(f1()); +END; +END; +$$ +ERROR HY000: Illegal parameter data type associative_array for operation '' +DROP PACKAGE pkg2; +DROP PACKAGE pkg1; +# RECORD as a package routine parameter and a package function RETURN +# 3-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +TYPE assoc0_t IS TABLE OF rec0_t INDEX BY INTEGER; +END; +$$ +CREATE DATABASE test1; +USE test1; +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p2(a test.pkg1.assoc0_t) AS +BEGIN +SELECT a(0).a, a(0).b; +END; +FUNCTION f1 RETURN test.pkg1.assoc0_t AS +res test.pkg1.assoc0_t; +BEGIN +res(0).a:= 10; +res(0).b:= 'b'; +RETURN res; +END; +PROCEDURE p1 AS +BEGIN +CALL p2(f1()); +END; +END; +$$ +ERROR HY000: Illegal parameter data type associative_array for operation '' +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg1; +# A self-reference to the current spec with error: 2-step +CREATE PACKAGE pkg1 AS +TYPE assoc0_t IS TABLE OF pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +ERROR HY000: Unknown data type: '`pkg1`.`rec0_t`' +CREATE DATABASE test1; +CREATE PACKAGE test1.pkg1 AS +TYPE assoc0_t IS TABLE OF pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +ERROR HY000: Unknown data type: '`pkg1`.`rec0_t`' +DROP DATABASE test1; +# A self-reference to the current spec with success: 2-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); +TYPE assoc0_t IS TABLE OF pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PROCEDURE p1 AS +r0 pkg1.rec0_t; +a0 pkg1.assoc0_t; +BEGIN +r0.a:= 10; +r0.b:= 'b'; +SELECT r0.a, r0.b; +END; +$$ +CALL p1; +r0.a r0.b +10 b +DROP PROCEDURE p1; +DROP PACKAGE pkg1; +CREATE DATABASE test1; +CREATE PACKAGE test1.pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); +TYPE assoc0_t IS TABLE OF pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PROCEDURE test1.p1 AS +r0 pkg1.rec0_t; -- This refers to test1.pkg1.rec0_t +a0 pkg1.assoc0_t; -- This refers to test1.pkg1.assoc0_t +BEGIN +r0.a:= 10; +r0.b:= 'b'; +SELECT r0.a, r0.b; +END; +$$ +CALL test1.p1; +r0.a r0.b +10 b +DROP PROCEDURE test1.p1; +DROP PACKAGE test1.pkg1; +DROP DATABASE test1; +USE test; +# A self-reference to the current spec with error: 3-step +CREATE PACKAGE pkg1 AS +TYPE assoc0_t IS TABLE OF test.pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +ERROR HY000: Unknown data type: '`test`.`pkg1`.`rec0_t`' +CREATE DATABASE test1; +CREATE PACKAGE test1.pkg1 AS +TYPE assoc0_t IS TABLE OF test1.pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +ERROR HY000: Unknown data type: '`test1`.`pkg1`.`rec0_t`' +DROP DATABASE test1; +# A self-reference to the current spec with success: 3-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); +TYPE assoc0_t IS TABLE OF test.pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PROCEDURE p1 AS +r0 pkg1.rec0_t; +a0 pkg1.assoc0_t; +BEGIN +r0.a:= 10; +r0.b:= 'b'; +SELECT r0.a, r0.b; +END; +$$ +CALL p1; +r0.a r0.b +10 b +DROP PROCEDURE p1; +DROP PACKAGE pkg1; +CREATE DATABASE test1; +CREATE PACKAGE test1.pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); +TYPE assoc0_t IS TABLE OF test1.pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PROCEDURE test1.p1 AS +r0 pkg1.rec0_t; -- This refers to test1.pkg1.rec0_t +a0 pkg1.assoc0_t; -- This refers to test1.pkg1.assoc0_t +BEGIN +r0.a:= 10; +r0.b:= 'b'; +SELECT r0.a, r0.b; +END; +$$ +CALL test1.p1; +r0.a r0.b +10 b +DROP PROCEDURE test1.p1; +DROP PACKAGE test1.pkg1; +DROP DATABASE test1; +# Various working examples +CREATE TABLE t1 (a INT, b VARCHAR(30)); +CREATE PACKAGE pkg1 AS +TYPE varchar_array IS TABLE OF VARCHAR(2000) INDEX BY INTEGER; +TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +TYPE array0_t IS TABLE OF rec0_t INDEX BY INTEGER; +TYPE array1_t IS TABLE OF test.t1.a%TYPE INDEX BY INTEGER; +TYPE array2_t IS TABLE OF test.t1%ROWTYPE INDEX BY INTEGER; +END; +$$ +# 2-Step + PROCEDURE +CREATE PROCEDURE p1 AS +v0 pkg1.varchar_array; +v1 pkg1.rec0_t; +v2 pkg1.array0_t; +v3 pkg1.array1_t; +v4 pkg1.array2_t; +BEGIN +v0(0):='test'; +SELECT v0(0); +v1.a:= 1; +v1.b:= 'b'; +SELECT v1.a, v1.b; +v2(0):= v1; +SELECT v2(0).a, v2(0).b; +v3(0):= 10; +SELECT v3(0); +v4(0):= v1; +SELECT v4(0).a, v4(0).b; +END; +$$ +CALL p1; +v0(0) +test +v1.a v1.b +1 b +v2(0).a v2(0).b +1 b +v3(0) +10 +v4(0).a v4(0).b +1 b +DROP PROCEDURE p1; +# 3-Step + PROCEDURE +CREATE DATABASE test1; +USE test1; +CREATE PROCEDURE p1 AS +v0 test.pkg1.varchar_array; +v1 test.pkg1.rec0_t; +v2 test.pkg1.array0_t; +v3 test.pkg1.array1_t; +v4 test.pkg1.array2_t; +BEGIN +v0(0):='test'; +SELECT v0(0); +v1.a:= 1; +v1.b:= 'b'; +SELECT v1.a, v1.b; +v2(0):= v1; +SELECT v2(0).a, v2(0).b; +v3(0):= 10; +SELECT v3(0); +v4(0):= v1; +SELECT v4(0).a, v4(0).b; +END; +$$ +CALL p1; +v0(0) +test +v1.a v1.b +1 b +v2(0).a v2(0).b +1 b +v3(0) +10 +v4(0).a v4(0).b +1 b +DROP PROCEDURE p1; +DROP DATABASE test1; +USE test; +# 2-Step + PACKAGE + Declarations in package PROCEDURE +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p1 AS +v0 pkg1.varchar_array; +v1 pkg1.rec0_t; +v2 pkg1.array0_t; +v3 pkg1.array1_t; +v4 pkg1.array2_t; +BEGIN +v0(0):='test'; +SELECT v0(0); +v1.a:= 1; +v1.b:= 'b'; +SELECT v1.a, v1.b; +v2(0):= v1; +SELECT v2(0).a, v2(0).b; +v3(0):= 10; +SELECT v3(0); +v4(0):= v1; +SELECT v4(0).a, v4(0).b; +END; +END; +$$ +CALL pkg2.p1; +v0(0) +test +v1.a v1.b +1 b +v2(0).a v2(0).b +1 b +v3(0) +10 +v4(0).a v4(0).b +1 b +DROP PACKAGE pkg2; +# 3-Step + PACKAGE + Declarations in package PROCEDURE +CREATE DATABASE test1; +USE test1; +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p1 AS +v0 test.pkg1.varchar_array; +v1 test.pkg1.rec0_t; +v2 test.pkg1.array0_t; +v3 test.pkg1.array1_t; +v4 test.pkg1.array2_t; +BEGIN +v0(0):='test'; +SELECT v0(0); +v1.a:= 1; +v1.b:= 'b'; +SELECT v1.a, v1.b; +v2(0):= v1; +SELECT v2(0).a, v2(0).b; +v3(0):= 10; +SELECT v3(0); +v4(0):= v1; +SELECT v4(0).a, v4(0).b; +END; +END; +$$ +CALL pkg2.p1; +v0(0) +test +v1.a v1.b +1 b +v2(0).a v2(0).b +1 b +v3(0) +10 +v4(0).a v4(0).b +1 b +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +# 3-Step + PACKAGE + Declarations in PACKAGE BODY +CREATE DATABASE test1; +USE test1; +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +v0 test.pkg1.varchar_array; +v1 test.pkg1.rec0_t; +v2 test.pkg1.array0_t; +v3 test.pkg1.array1_t; +v4 test.pkg1.array2_t; +PROCEDURE p1 AS +BEGIN +v0(0):='test'; +SELECT v0(0); +v1.a:= 1; +v1.b:= 'b'; +SELECT v1.a, v1.b; +v2(0):= v1; +SELECT v2(0).a, v2(0).b; +v3(0):= 10; +SELECT v3(0); +v4(0):= v1; +SELECT v4(0).a, v4(0).b; +END; +END; +$$ +CALL pkg2.p1; +v0(0) +test +v1.a v1.b +1 b +v2(0).a v2(0).b +1 b +v3(0) +10 +v4(0).a v4(0).b +1 b +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg1; +DROP TABLE t1; +# RECORD + Assoc array in different packages: 2-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +END; +$$ +CREATE PACKAGE pkg2 AS +TYPE array0_t IS TABLE OF pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PROCEDURE p1 AS +r0 pkg1.rec0_t; +a0 pkg2.array0_t; +BEGIN +r0.a:= 10; +r0.b:= 'b'; +a0(0):= r0; +SELECT a0(0).a, a0(0).b; +END; +$$ +CALL p1; +a0(0).a a0(0).b +10 b +DROP PROCEDURE p1; +DROP PACKAGE pkg2; +DROP PACKAGE pkg1; +# RECORD + Assoc array in different packages: 3-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +END; +$$ +CREATE DATABASE test1; +USE test1; +CREATE PACKAGE pkg2 AS +TYPE array0_t IS TABLE OF test.pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +CREATE DATABASE test2; +USE test2; +CREATE PROCEDURE p1 AS +r0 test.pkg1.rec0_t; +a0 test1.pkg2.array0_t; +BEGIN +r0.a:= 10; +r0.b:= 'b'; +a0(0):= r0; +SELECT a0(0).a, a0(0).b; +END; +$$ +CALL p1; +a0(0).a a0(0).b +10 b +DROP PROCEDURE p1; +DROP DATABASE test2; +USE test1; +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg1; diff --git a/mysql-test/suite/compat/oracle/r/sp-package-spec-type-inet6.result b/mysql-test/suite/compat/oracle/r/sp-package-spec-type-inet6.result new file mode 100644 index 0000000000000..3b918e2393aa8 --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/sp-package-spec-type-inet6.result @@ -0,0 +1,117 @@ +SET sql_mode=ORACLE; +# +# MDEV-39587 Package-wide TYPE for variable declarations +# +CREATE PACKAGE pkg1 AS +TYPE inet6_array IS TABLE OF INET6 INDEX BY INTEGER; +END; +$$ +# 2-Step + PROCEDURE +CREATE PROCEDURE p1 AS +v0 pkg1.inet6_array; +BEGIN +v0(0):='AA::BB'; +SELECT v0(0); +END; +$$ +CALL p1; +v0(0) +aa::bb +DROP PROCEDURE p1; +# 2-Step + PACKAGE + Declarations in package PROCEDURE +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p1 AS +v0 pkg1.inet6_array; +BEGIN +v0(0):='AA::BB'; +SELECT v0(0); +END; +END; +$$ +CALL pkg2.p1; +v0(0) +aa::bb +DROP PACKAGE pkg2; +# 2-Step + PACKAGE + Declaration in PACKAGE BODY +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +v0 pkg1.inet6_array; +PROCEDURE p1 AS +BEGIN +v0(0):='AA::BB'; +SELECT v0(0); +END; +END; +$$ +CALL pkg2.p1; +v0(0) +aa::bb +DROP PACKAGE pkg2; +# 3-Step + PROCEDURE + Declarations in package PROCEDURE +CREATE DATABASE test1; +USE test1; +CREATE PROCEDURE p1 AS +v0 test.pkg1.inet6_array; +BEGIN +v0(0):='AA::BB'; +SELECT v0(0); +END; +$$ +CALL p1; +v0(0) +aa::bb +DROP PROCEDURE p1; +DROP DATABASE test1; +USE test; +# 3-Step + PACKAGE +CREATE DATABASE test1; +USE test1; +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p1 AS +v0 test.pkg1.inet6_array; +BEGIN +v0(0):='AA::BB'; +SELECT v0(0); +END; +END; +$$ +CALL pkg2.p1; +v0(0) +aa::bb +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +# 3-Step + PACKAGE + Declaration in PACKAGE BODY +CREATE DATABASE test1; +USE test1; +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +v0 test.pkg1.inet6_array; +PROCEDURE p1 AS +BEGIN +v0(0):='AA::BB'; +SELECT v0(0); +END; +END; +$$ +CALL pkg2.p1; +v0(0) +aa::bb +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg1; diff --git a/mysql-test/suite/compat/oracle/r/sp-package-spec-type-path.result b/mysql-test/suite/compat/oracle/r/sp-package-spec-type-path.result new file mode 100644 index 0000000000000..f6bd94c23825f --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/sp-package-spec-type-path.result @@ -0,0 +1,82 @@ +SET sql_mode=ORACLE; +# +# MDEV-39587 Package-wide TYPE for variable declarations +# +# PATH resolving not to CURRENT_SCHEMA +CREATE DATABASE test1; +CREATE PACKAGE test1.pkg1 AS +TYPE rec0_t IS RECORD (a INT, b_test1 VARCHAR(10)); +END; +$$ +CREATE DATABASE test2; +CREATE PACKAGE test2.pkg1 AS +TYPE rec0_t IS RECORD (a INT, b_test2 VARCHAR(10)); +END; +$$ +CREATE PROCEDURE p1 AS +a pkg1.rec0_t; +BEGIN +NULL; +END; +$$ +ERROR HY000: Unknown data type: '`pkg1`.`rec0_t`' +SET PATH 'CURRENT_SCHEMA,test1,test2'; +CREATE PROCEDURE p1 AS +a pkg1.rec0_t; +BEGIN +a.b_test1:= 10; +SELECT a.b_test1; +END; +$$ +CALL test.p1(); +a.b_test1 +10 +DROP PROCEDURE p1; +SET PATH 'CURRENT_SCHEMA,test2,test1'; +CREATE PROCEDURE p1 AS +a pkg1.rec0_t; +BEGIN +a.b_test2:= 10; +SELECT a.b_test2; +END; +$$ +CALL p1(); +a.b_test2 +10 +DROP PROCEDURE p1; +SET PATH DEFAULT; +DROP DATABASE test1; +DROP DATABASE test2; +# PATH resolving to CURRENT_SCHEMA +CREATE DATABASE test1; +CREATE PACKAGE test.pkg1 AS +TYPE rec0_t IS RECORD (a INT, b_test VARCHAR(10)); +END; +$$ +SET PATH 'test1,CURRENT_SCHEMA'; +CREATE PROCEDURE p1 AS +a pkg1.rec0_t; +BEGIN +a.b_test:= 10; +SELECT a.b_test; +END; +$$ +CALL p1(); +a.b_test +10 +DROP PROCEDURE p1; +SET PATH 'CURRENT_SCHEMA,test1'; +CREATE PROCEDURE p1 AS +a pkg1.rec0_t; +BEGIN +a.b_test:= 10; +SELECT a.b_test; +END; +$$ +CALL p1(); +a.b_test +10 +DROP PROCEDURE p1; +DROP PACKAGE pkg1; +DROP DATABASE test1; +SET PATH DEFAULT; diff --git a/mysql-test/suite/compat/oracle/r/sp-package-spec-type-record.result b/mysql-test/suite/compat/oracle/r/sp-package-spec-type-record.result new file mode 100644 index 0000000000000..6392018a3f534 --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/sp-package-spec-type-record.result @@ -0,0 +1,150 @@ +SET sql_mode=ORACLE; +# +# MDEV-39587 Package-wide TYPE for variable declarations +# +# RECORD cannot have attributes +# Currently this is not allowed by the parser in qualified types +# If we ever allow, make sure to call check_data_type_attributes() +# which will raise ER_UNSUPPORTED_DATA_TYPE_ATTRIBUTE +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); +END; +$$ +CREATE PROCEDURE p1 AS +r0 pkg1.rec0_t (0); -- Length attribute +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(0); -- Length attribute +BEGIN +NULL; +END' at line 2 +CREATE PROCEDURE p1 AS +r0 pkg1.rec0_t (0,0); -- Length and dec attributes +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(0,0); -- Length and dec attributes +BEGIN +NULL; +END' at line 2 +CREATE PROCEDURE p1 AS +r0 pkg1.rec0_t CHARACTER SET latin1; +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CHARACTER SET latin1; +BEGIN +NULL; +END' at line 2 +CREATE PROCEDURE p1 AS +r0 pkg1.rec0_t COLLATE latin1_bin; +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'COLLATE latin1_bin; +BEGIN +NULL; +END' at line 2 +DROP PACKAGE pkg1; +# PACKAGE spec types cannot be used in schema routine parameters +# and schema function RETURN +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +END; +$$ +CREATE PROCEDURE p1(a pkg1.rec0_t) AS +BEGIN +NULL; +END; +$$ +ERROR HY000: Incorrect usage of parameter_declaration and package_name.type_name +CREATE FUNCTION f1 RETURN pkg1.rec0_t AS +BEGIN +RETURN NULL; +END; +$$ +ERROR HY000: Incorrect usage of RETURN and package_name.type_name +DROP PACKAGE pkg1; +# RECORD as a package routine parameter and a package function RETURN +# 2-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +END; +$$ +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p2(r pkg1.rec0_t) AS +BEGIN +SELECT r.a, r.b; +END; +FUNCTION f1 RETURN pkg1.rec0_t AS +res pkg1.rec0_t; +BEGIN +res.a:= 10; +res.b:= 'b'; +RETURN res; +END; +PROCEDURE p1 AS +BEGIN +CALL p2(f1()); +END; +END; +$$ +CALL pkg2.p1(); +r.a r.b +10 b +DROP PACKAGE pkg2; +DROP PACKAGE pkg1; +# RECORD as a package routine parameter and a package function RETURN +# 3-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +END; +$$ +CREATE DATABASE test1; +USE test1; +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p2(r test.pkg1.rec0_t) AS +BEGIN +SELECT r.a, r.b; +END; +FUNCTION f1 RETURN test.pkg1.rec0_t AS +res test.pkg1.rec0_t; +BEGIN +res.a:= 10; +res.b:= 'b'; +RETURN res; +END; +PROCEDURE p1 AS +BEGIN +CALL p2(f1()); +END; +END; +$$ +CALL pkg2.p1(); +r.a r.b +10 b +CALL test1.pkg2.p1(); +r.a r.b +10 b +USE test; +CALL test1.pkg2.p1(); +r.a r.b +10 b +USE test1; +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg1; diff --git a/mysql-test/suite/compat/oracle/r/sp-package-spec-type-refcursor.result b/mysql-test/suite/compat/oracle/r/sp-package-spec-type-refcursor.result new file mode 100644 index 0000000000000..1d461ac8c6b00 --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/sp-package-spec-type-refcursor.result @@ -0,0 +1,539 @@ +SET sql_mode=ORACLE; +# +# MDEV-39587 Package-wide TYPE for variable declarations +# +# REFCURSOR cannot have attributes +# Currently this is not allowed by the parser in qualified types +# If we ever allow, make sure to call check_data_type_attributes() +# which will raise ER_UNSUPPORTED_DATA_TYPE_ATTRIBUTE +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); +TYPE cur0_t IS REF CURSOR RETURN rec0_t; +END; +$$ +CREATE PROCEDURE p1 AS +r0 pkg1.cur0_t (0); -- Length attribute +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(0); -- Length attribute +BEGIN +NULL; +END' at line 2 +CREATE PROCEDURE p1 AS +r0 pkg1.cur0_t (0,0); -- Length and dec attributes +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(0,0); -- Length and dec attributes +BEGIN +NULL; +END' at line 2 +CREATE PROCEDURE p1 AS +r0 pkg1.cur0_t CHARACTER SET latin1; +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CHARACTER SET latin1; +BEGIN +NULL; +END' at line 2 +CREATE PROCEDURE p1 AS +r0 pkg1.cur0_t COLLATE latin1_bin; +BEGIN +NULL; +END; +$$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'COLLATE latin1_bin; +BEGIN +NULL; +END' at line 2 +DROP PACKAGE pkg1; +# PACKAGE spec types cannot be used in schema routine parameters +# and schema function RETURN +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +TYPE cur0_t IS REF CURSOR RETURN rec0_t; +END; +$$ +CREATE PROCEDURE p1(a pkg1.cur0_t) AS +BEGIN +NULL; +END; +$$ +ERROR HY000: Incorrect usage of parameter_declaration and package_name.type_name +CREATE FUNCTION f1 RETURN pkg1.cur0_t AS +BEGIN +RETURN NULL; +END; +$$ +ERROR HY000: Incorrect usage of RETURN and package_name.type_name +DROP PACKAGE pkg1; +# A package routine parameter and a package function RETURN +# 2-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +TYPE cur0_t IS REF CURSOR RETURN rec0_t; +END; +$$ +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p2(c pkg1.cur0_t) AS +v0 INT; +v1 VARCHAR(32); +BEGIN +FETCH c INTO v0, v1; +SELECT v0, v1; +CLOSE c; +END; +FUNCTION f1 RETURN pkg1.cur0_t AS +res pkg1.cur0_t; +BEGIN +OPEN res FOR SELECT 1,'b'; +RETURN res; +END; +PROCEDURE p1 AS +BEGIN +CALL p2(f1()); +END; +END; +$$ +CALL pkg2.p1(); +v0 v1 +1 b +DROP PACKAGE pkg2; +DROP PACKAGE pkg1; +# A package routine parameter and a package function RETURN +# 3-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +TYPE cur0_t IS REF CURSOR RETURN rec0_t; +END; +$$ +CREATE DATABASE test1; +USE test1; +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p2(c test.pkg1.cur0_t) AS +v0 INT; +v1 VARCHAR(32); +BEGIN +FETCH c INTO v0, v1; +SELECT v0, v1; +CLOSE c; +END; +FUNCTION f1 RETURN test.pkg1.cur0_t AS +res test.pkg1.cur0_t; +BEGIN +OPEN res FOR SELECT 1, 'b'; +RETURN res; +END; +PROCEDURE p1 AS +BEGIN +CALL p2(f1()); +END; +END; +$$ +CALL pkg2.p1(); +v0 v1 +1 b +CALL test1.pkg2.p1(); +v0 v1 +1 b +USE test; +CALL test1.pkg2.p1(); +v0 v1 +1 b +USE test1; +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg1; +# A self-reference to the current spec with success: 2-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); +TYPE cur0_t IS REF CURSOR RETURN pkg1.rec0_t; -- Self ref +END; +$$ +# Using from the same database +CREATE PROCEDURE p1 AS +r0 pkg1.rec0_t; +c0 pkg1.cur0_t; +BEGIN +OPEN c0 FOR SELECT 1,'b'; +FETCH c0 INTO r0; +CLOSE c0; +SELECT r0.a, r0.b; +END; +$$ +CALL p1; +r0.a r0.b +1 b +DROP PROCEDURE p1; +# Using from a different database +CREATE DATABASE test1; +CREATE PROCEDURE test1.p1 AS +r0 test.pkg1.rec0_t; +c0 test.pkg1.cur0_t; +BEGIN +OPEN c0 FOR SELECT 1,'b'; +FETCH c0 INTO r0; +CLOSE c0; +SELECT r0.a, r0.b; +NULL; +END; +$$ +CALL test1.p1; +r0.a r0.b +1 b +DROP DATABASE test1; +DROP PACKAGE pkg1; +# A self-reference to the current spec with success: 3-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); +TYPE cur0_t IS REF CURSOR RETURN test.pkg1.rec0_t; -- Self ref +END; +$$ +# Using from the same database +CREATE PROCEDURE p1 AS +r0 test.pkg1.rec0_t; +c0 test.pkg1.cur0_t; +BEGIN +OPEN c0 FOR SELECT 1,'b'; +FETCH c0 INTO r0; +CLOSE c0; +SELECT r0.a, r0.b; +END; +$$ +CALL p1; +r0.a r0.b +1 b +DROP PROCEDURE p1; +# Using from a different database +CREATE DATABASE test1; +CREATE PROCEDURE test1.p1 AS +r0 test.pkg1.rec0_t; +c0 test.pkg1.cur0_t; +BEGIN +OPEN c0 FOR SELECT 1,'b'; +FETCH c0 INTO r0; +CLOSE c0; +SELECT r0.a, r0.b; +NULL; +END; +$$ +CALL test1.p1; +r0.a r0.b +1 b +DROP DATABASE test1; +DROP PACKAGE pkg1; +# Various working examples +CREATE TABLE t1 (a INT, b VARCHAR(30)); +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +TYPE cur0_t IS REF CURSOR; +TYPE cur1_t IS REF CURSOR RETURN rec0_t; +TYPE cur2_t IS REF CURSOR RETURN test.t1%ROWTYPE; +END; +$$ +# 2-Step + PROCEDURE +CREATE PROCEDURE p1 AS +v1 pkg1.rec0_t; +c0 pkg1.cur0_t; +c1 pkg1.cur1_t; +c2 pkg1.cur2_t; +fetch0 INT; +fetch1 VARCHAR(30); +BEGIN +v1.a:= 1; +v1.b:= 'b'; +OPEN c0 FOR SELECT 10,'bb0'; +FETCH c0 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c0; +OPEN c1 FOR SELECT 11,'bb1'; +FETCH c1 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c1; +OPEN c2 FOR SELECT 12,'bb2'; +FETCH c2 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c2; +END; +$$ +CALL p1; +fetch0 fetch1 +10 bb0 +fetch0 fetch1 +11 bb1 +fetch0 fetch1 +12 bb2 +DROP PROCEDURE p1; +# 3-Step + PROCEDURE +CREATE DATABASE test1; +USE test1; +CREATE PROCEDURE p1 AS +v1 test.pkg1.rec0_t; +c0 test.pkg1.cur0_t; +c1 test.pkg1.cur1_t; +c2 test.pkg1.cur2_t; +fetch0 INT; +fetch1 VARCHAR(30); +BEGIN +v1.a:= 1; +v1.b:= 'b'; +OPEN c0 FOR SELECT 10,'bb0'; +FETCH c0 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c0; +OPEN c1 FOR SELECT 11,'bb1'; +FETCH c1 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c1; +OPEN c2 FOR SELECT 12,'bb2'; +FETCH c2 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c2; +END; +$$ +CALL p1; +fetch0 fetch1 +10 bb0 +fetch0 fetch1 +11 bb1 +fetch0 fetch1 +12 bb2 +DROP PROCEDURE p1; +DROP DATABASE test1; +USE test; +# 2-Step + PACKAGE + Declarations in package PROCEDURE +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p1 AS +v1 pkg1.rec0_t; +c0 pkg1.cur0_t; +c1 pkg1.cur1_t; +c2 pkg1.cur2_t; +fetch0 INT; +fetch1 VARCHAR(30); +BEGIN +v1.a:= 1; +v1.b:= 'b'; +OPEN c0 FOR SELECT 10,'bb0'; +FETCH c0 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c0; +OPEN c1 FOR SELECT 11,'bb1'; +FETCH c1 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c1; +OPEN c2 FOR SELECT 12,'bb2'; +FETCH c2 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c2; +END; +END; +$$ +CALL pkg2.p1; +fetch0 fetch1 +10 bb0 +fetch0 fetch1 +11 bb1 +fetch0 fetch1 +12 bb2 +DROP PACKAGE pkg2; +# 3-Step + PACKAGE + Declarations in package PROCEDURE +CREATE DATABASE test1; +USE test1; +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +PROCEDURE p1 AS +v1 test.pkg1.rec0_t; +c0 test.pkg1.cur0_t; +c1 test.pkg1.cur1_t; +c2 test.pkg1.cur2_t; +fetch0 INT; +fetch1 VARCHAR(30); +BEGIN +v1.a:= 1; +v1.b:= 'b'; +OPEN c0 FOR SELECT 10,'bb0'; +FETCH c0 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c0; +OPEN c1 FOR SELECT 11,'bb1'; +FETCH c1 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c1; +OPEN c2 FOR SELECT 12,'bb2'; +FETCH c2 INTO fetch0, fetch1; +SELECT fetch0, fetch1; +CLOSE c2; +END; +END; +$$ +CALL pkg2.p1; +fetch0 fetch1 +10 bb0 +fetch0 fetch1 +11 bb1 +fetch0 fetch1 +12 bb2 +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +# 3-Step + PACKAGE + Declarations in PACKAGE BODY +CREATE DATABASE test1; +USE test1; +CREATE PACKAGE pkg2 AS +PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS +v1 test.pkg1.rec0_t; +c0 test.pkg1.cur0_t; +c1 test.pkg1.cur1_t; +c2 test.pkg1.cur2_t; +fetch0 INT; +fetch1 VARCHAR(30); +PROCEDURE p1 AS +BEGIN +NULL; +END; +END; +$$ +ERROR HY000: 'sys_refcursor' is not allowed in this context +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg1; +DROP TABLE t1; +# RECORD and REFCURSOR in different packages +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +END; +$$ +# 2-step type in RETURN in a schema procedure +CREATE PROCEDURE p1 AS +TYPE cur0_t IS REF CURSOR RETURN pkg1.rec0_t; +c0 cur0_t; +BEGIN +OPEN c0 FOR SELECT 1,'b',3; +END; +$$ +ERROR HY000: Illegal parameter data types row<2> and row<3> for operation 'OPEN..FOR' +CREATE PROCEDURE p1 AS +TYPE cur0_t IS REF CURSOR RETURN pkg1.rec0_t; +c0 cur0_t; +v0 INT; +v1 VARCHAR(10); +BEGIN +OPEN c0 FOR SELECT 1,'b'; +FETCH c0 INTO v0, v1; +SELECT v0, v1; +CLOSE c0; +END; +$$ +CALL p1; +v0 v1 +1 b +DROP PROCEDURE p1; +# 3-step type in RETURN in a schema procedure +CREATE PROCEDURE p1 AS +TYPE cur0_t IS REF CURSOR RETURN test.pkg1.rec0_t; +c0 cur0_t; +BEGIN +OPEN c0 FOR SELECT 1,'b',3; +END; +$$ +ERROR HY000: Illegal parameter data types row<2> and row<3> for operation 'OPEN..FOR' +CREATE PROCEDURE p1 AS +TYPE cur0_t IS REF CURSOR RETURN test.pkg1.rec0_t; +c0 cur0_t; +v0 INT; +v1 VARCHAR(10); +BEGIN +OPEN c0 FOR SELECT 1,'b'; +FETCH c0 INTO v0, v1; +SELECT v0, v1; +CLOSE c0; +END; +$$ +CALL p1; +v0 v1 +1 b +DROP PROCEDURE p1; +# 2-step type in RETURN in another package +CREATE PACKAGE pkg2 AS +TYPE cur0_t IS REF CURSOR RETURN pkg1.rec0_t; +END; +$$ +# 2-step cursor type with 2-step type in RETURN +CREATE PROCEDURE p1 AS +c0 pkg2.cur0_t; +v0 INT; +v1 VARCHAR(10); +BEGIN +OPEN c0 FOR SELECT 1,'b'; +FETCH c0 INTO v0, v1; +SELECT v0, v1; +CLOSE c0; +END; +$$ +CALL p1; +v0 v1 +1 b +DROP PROCEDURE p1; +# 3-step cursor type with 2-step type in RETURN +CREATE PROCEDURE p1 AS +c0 test.pkg2.cur0_t; +v0 INT; +v1 VARCHAR(10); +BEGIN +OPEN c0 FOR SELECT 1,'b'; +FETCH c0 INTO v0, v1; +SELECT v0, v1; +CLOSE c0; +END; +$$ +CALL p1; +v0 v1 +1 b +DROP PROCEDURE p1; +# 3-step cursor type (different db) with 2-step type in RETURN +CREATE DATABASE test1; +USE test1; +CREATE PROCEDURE p1 AS +c0 test.pkg2.cur0_t; +v0 INT; +v1 VARCHAR(10); +BEGIN +OPEN c0 FOR SELECT 1,'b'; +FETCH c0 INTO v0, v1; +SELECT v0, v1; +CLOSE c0; +END; +$$ +CALL p1; +v0 v1 +1 b +DROP PROCEDURE p1; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg2; +DROP PACKAGE pkg1; diff --git a/mysql-test/suite/compat/oracle/r/sp-package-spec-type.result b/mysql-test/suite/compat/oracle/r/sp-package-spec-type.result new file mode 100644 index 0000000000000..5aca893b8bbfe --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/sp-package-spec-type.result @@ -0,0 +1,64 @@ +SET sql_mode=ORACLE; +# +# MDEV-39587 Package-wide TYPE for variable declarations +# +# PACKAGE gets dropped making an orphan type reference: 2-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +END; +$$ +CREATE PROCEDURE p1 AS +r0 pkg1.rec0_t; +BEGIN +r0.a:= 10; +r0.b:= 'b'; +SELECT r0.a, r0.b; +END; +$$ +CALL p1; +r0.a r0.b +10 b +DROP PACKAGE pkg1; +CALL p1; +ERROR HY000: Failed to load routine test.p1 (internal code -6). For more details, run SHOW WARNINGS +SHOW WARNINGS; +Level Code Message +Error 4161 Unknown data type: '`pkg1`.`rec0_t`' +Error 1457 Failed to load routine test.p1 (internal code -6). For more details, run SHOW WARNINGS +DROP PROCEDURE p1; +# PACKAGE gets dropped making an orphan type reference: 3-step +CREATE PACKAGE pkg1 AS +TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +END; +$$ +CREATE DATABASE test1; +USE test1; +CREATE PROCEDURE p1 AS +r0 test.pkg1.rec0_t; +BEGIN +r0.a:= 10; +r0.b:= 'b'; +SELECT r0.a, r0.b; +END; +$$ +CALL p1; +r0.a r0.b +10 b +DROP PACKAGE test.pkg1; +CALL p1; +ERROR HY000: Failed to load routine test1.p1 (internal code -6). For more details, run SHOW WARNINGS +SHOW WARNINGS; +Level Code Message +Error 4161 Unknown data type: '`test`.`pkg1`.`rec0_t`' +Error 1457 Failed to load routine test1.p1 (internal code -6). For more details, run SHOW WARNINGS +DROP PROCEDURE p1; +DROP DATABASE test1; +USE test; +# Too long identifier chain +CREATE PROCEDURE p1 AS +v1 cat1.db1.pkg1.type1; +BEGIN +NULL; +END; +$$ +ERROR HY000: Unknown data type: '`cat1`.`db1`.`pkg1`' diff --git a/mysql-test/suite/compat/oracle/r/type_date.result b/mysql-test/suite/compat/oracle/r/type_date.result index 1d4a16c0d289a..ce3258a4142b7 100644 --- a/mysql-test/suite/compat/oracle/r/type_date.result +++ b/mysql-test/suite/compat/oracle/r/type_date.result @@ -126,7 +126,7 @@ DROP TABLE t1; # # Qualified syntax is not supported yet in SP # See MDEV-23353 Qualified data types in SP -# For now it's trying to parse as "RETURN mariadb_schema.DATE%ROWTYPE" +# For now it's trying to parse mariadb_schema as a package name # SET sql_mode=ORACLE; CREATE FUNCTION f1() RETURN mariadb_schema.DATE AS @@ -134,26 +134,17 @@ BEGIN RETURN CURRENT_DATE; END; $$ -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'AS -BEGIN -RETURN CURRENT_DATE; -END' at line 2 +ERROR HY000: Unknown data type: '`mariadb_schema`.`DATE`' CREATE PROCEDURE p1(a mariadb_schema.DATE) AS BEGIN NULL; END; $$ -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') AS -BEGIN -NULL; -END' at line 1 +ERROR HY000: Unknown data type: '`mariadb_schema`.`DATE`' CREATE PROCEDURE p1() AS a mariadb_schema.DATE; BEGIN NULL; END; $$ -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '; -BEGIN -NULL; -END' at line 2 +ERROR HY000: Unknown data type: '`mariadb_schema`.`DATE`' diff --git a/mysql-test/suite/compat/oracle/t/sp-package-spec-type-assoc.test b/mysql-test/suite/compat/oracle/t/sp-package-spec-type-assoc.test new file mode 100644 index 0000000000000..884d37c0cf1d5 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-spec-type-assoc.test @@ -0,0 +1,556 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-39587 Package-wide TYPE for variable declarations +--echo # + +--echo # A too long identifier chain in the TABLE OF type + +DELIMITER $$; +--error ER_UNKNOWN_DATA_TYPE +CREATE PACKAGE pkg1 AS + TYPE assoc0_t IS TABLE OF cat1.db1.pkg1.rec1_t INDEX BY INTEGER; +END; +$$ +DELIMITER ;$$ + + +--echo # Assoc array cannot have attributes +--echo # Currently this is not allowed by the parser in qualified types +--echo # If we ever allow, make sure to call check_data_type_attributes() +--echo # which will raise ER_UNSUPPORTED_DATA_TYPE_ATTRIBUTE + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); + TYPE assoc0_t IS TABLE OF rec0_t INDEX BY INTEGER; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.assoc0_t (0); -- Length attribute +BEGIN + NULL; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.assoc0_t (0,0); -- Length and dec attributes +BEGIN + NULL; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.assoc0_t CHARACTER SET latin1; +BEGIN + NULL; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.assoc0_t COLLATE latin1_bin; +BEGIN + NULL; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE pkg1; + + +--echo # PACKAGE spec types cannot be used in schema routine parameters +--echo # and schema function RETURN + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); + TYPE assoc0_t IS TABLE OF rec0_t INDEX BY INTEGER; +END; +$$ +--error ER_WRONG_USAGE +CREATE PROCEDURE p1(a pkg1.assoc0_t) AS +BEGIN + NULL; +END; +$$ +--error ER_WRONG_USAGE +CREATE FUNCTION f1 RETURN pkg1.assoc0_t AS +BEGIN + RETURN NULL; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE pkg1; + + +--echo # A package routine parameter and a package function RETURN +--echo # 2-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); + TYPE assoc0_t IS TABLE OF rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +# Assoc array is not supported as a routine parameter and RETURN anyway +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p2(a pkg1.assoc0_t) AS + BEGIN + SELECT a(0).a, a(0).b; + END; + FUNCTION f1 RETURN pkg1.assoc0_t AS + res pkg1.assoc0_t; + BEGIN + res(0).a:= 10; + res(0).b:= 'b'; + RETURN res; + END; + PROCEDURE p1 AS + BEGIN + CALL p2(f1()); + END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE pkg2; +DROP PACKAGE pkg1; + +--echo # RECORD as a package routine parameter and a package function RETURN +--echo # 3-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); + TYPE assoc0_t IS TABLE OF rec0_t INDEX BY INTEGER; +END; +$$ +DELIMITER ;$$ + +CREATE DATABASE test1; +USE test1; + +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +# Assoc array is not supported as a routine parameter and RETURN anyway +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p2(a test.pkg1.assoc0_t) AS + BEGIN + SELECT a(0).a, a(0).b; + END; + FUNCTION f1 RETURN test.pkg1.assoc0_t AS + res test.pkg1.assoc0_t; + BEGIN + res(0).a:= 10; + res(0).b:= 'b'; + RETURN res; + END; + PROCEDURE p1 AS + BEGIN + CALL p2(f1()); + END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg1; + + +--echo # A self-reference to the current spec with error: 2-step + +DELIMITER $$; +--error ER_UNKNOWN_DATA_TYPE +CREATE PACKAGE pkg1 AS + TYPE assoc0_t IS TABLE OF pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +DELIMITER ;$$ + +CREATE DATABASE test1; +DELIMITER $$; +--error ER_UNKNOWN_DATA_TYPE +CREATE PACKAGE test1.pkg1 AS + TYPE assoc0_t IS TABLE OF pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +DELIMITER ;$$ +DROP DATABASE test1; + + +--echo # A self-reference to the current spec with success: 2-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); + TYPE assoc0_t IS TABLE OF pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PROCEDURE p1 AS + r0 pkg1.rec0_t; + a0 pkg1.assoc0_t; +BEGIN + r0.a:= 10; + r0.b:= 'b'; + SELECT r0.a, r0.b; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; +DROP PACKAGE pkg1; + +CREATE DATABASE test1; +DELIMITER $$; +CREATE PACKAGE test1.pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); + TYPE assoc0_t IS TABLE OF pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PROCEDURE test1.p1 AS + r0 pkg1.rec0_t; -- This refers to test1.pkg1.rec0_t + a0 pkg1.assoc0_t; -- This refers to test1.pkg1.assoc0_t +BEGIN + r0.a:= 10; + r0.b:= 'b'; + SELECT r0.a, r0.b; +END; +$$ +DELIMITER ;$$ +CALL test1.p1; +DROP PROCEDURE test1.p1; +DROP PACKAGE test1.pkg1; +DROP DATABASE test1; +USE test; + + +--echo # A self-reference to the current spec with error: 3-step + +DELIMITER $$; +--error ER_UNKNOWN_DATA_TYPE +CREATE PACKAGE pkg1 AS + TYPE assoc0_t IS TABLE OF test.pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +DELIMITER ;$$ + +CREATE DATABASE test1; +DELIMITER $$; +--error ER_UNKNOWN_DATA_TYPE +CREATE PACKAGE test1.pkg1 AS + TYPE assoc0_t IS TABLE OF test1.pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +DELIMITER ;$$ +DROP DATABASE test1; + + +--echo # A self-reference to the current spec with success: 3-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); + TYPE assoc0_t IS TABLE OF test.pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PROCEDURE p1 AS + r0 pkg1.rec0_t; + a0 pkg1.assoc0_t; +BEGIN + r0.a:= 10; + r0.b:= 'b'; + SELECT r0.a, r0.b; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; +DROP PACKAGE pkg1; + + +CREATE DATABASE test1; +DELIMITER $$; +CREATE PACKAGE test1.pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); + TYPE assoc0_t IS TABLE OF test1.pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +CREATE PROCEDURE test1.p1 AS + r0 pkg1.rec0_t; -- This refers to test1.pkg1.rec0_t + a0 pkg1.assoc0_t; -- This refers to test1.pkg1.assoc0_t +BEGIN + r0.a:= 10; + r0.b:= 'b'; + SELECT r0.a, r0.b; +END; +$$ +DELIMITER ;$$ +CALL test1.p1; +DROP PROCEDURE test1.p1; +DROP PACKAGE test1.pkg1; +DROP DATABASE test1; + + +--echo # Various working examples +CREATE TABLE t1 (a INT, b VARCHAR(30)); + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE varchar_array IS TABLE OF VARCHAR(2000) INDEX BY INTEGER; + TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); + TYPE array0_t IS TABLE OF rec0_t INDEX BY INTEGER; + TYPE array1_t IS TABLE OF test.t1.a%TYPE INDEX BY INTEGER; + TYPE array2_t IS TABLE OF test.t1%ROWTYPE INDEX BY INTEGER; +END; +$$ +DELIMITER ;$$ + +--echo # 2-Step + PROCEDURE +DELIMITER $$; +CREATE PROCEDURE p1 AS + v0 pkg1.varchar_array; + v1 pkg1.rec0_t; + v2 pkg1.array0_t; + v3 pkg1.array1_t; + v4 pkg1.array2_t; +BEGIN + v0(0):='test'; + SELECT v0(0); + v1.a:= 1; + v1.b:= 'b'; + SELECT v1.a, v1.b; + v2(0):= v1; + SELECT v2(0).a, v2(0).b; + v3(0):= 10; + SELECT v3(0); + v4(0):= v1; + SELECT v4(0).a, v4(0).b; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; + +--echo # 3-Step + PROCEDURE +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PROCEDURE p1 AS + v0 test.pkg1.varchar_array; + v1 test.pkg1.rec0_t; + v2 test.pkg1.array0_t; + v3 test.pkg1.array1_t; + v4 test.pkg1.array2_t; +BEGIN + v0(0):='test'; + SELECT v0(0); + v1.a:= 1; + v1.b:= 'b'; + SELECT v1.a, v1.b; + v2(0):= v1; + SELECT v2(0).a, v2(0).b; + v3(0):= 10; + SELECT v3(0); + v4(0):= v1; + SELECT v4(0).a, v4(0).b; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; +DROP DATABASE test1; +USE test; + +--echo # 2-Step + PACKAGE + Declarations in package PROCEDURE +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p1 AS + v0 pkg1.varchar_array; + v1 pkg1.rec0_t; + v2 pkg1.array0_t; + v3 pkg1.array1_t; + v4 pkg1.array2_t; + BEGIN + v0(0):='test'; + SELECT v0(0); + v1.a:= 1; + v1.b:= 'b'; + SELECT v1.a, v1.b; + v2(0):= v1; + SELECT v2(0).a, v2(0).b; + v3(0):= 10; + SELECT v3(0); + v4(0):= v1; + SELECT v4(0).a, v4(0).b; + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1; +DROP PACKAGE pkg2; + +--echo # 3-Step + PACKAGE + Declarations in package PROCEDURE +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p1 AS + v0 test.pkg1.varchar_array; + v1 test.pkg1.rec0_t; + v2 test.pkg1.array0_t; + v3 test.pkg1.array1_t; + v4 test.pkg1.array2_t; + BEGIN + v0(0):='test'; + SELECT v0(0); + v1.a:= 1; + v1.b:= 'b'; + SELECT v1.a, v1.b; + v2(0):= v1; + SELECT v2(0).a, v2(0).b; + v3(0):= 10; + SELECT v3(0); + v4(0):= v1; + SELECT v4(0).a, v4(0).b; + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1; +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; + +--echo # 3-Step + PACKAGE + Declarations in PACKAGE BODY +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + v0 test.pkg1.varchar_array; + v1 test.pkg1.rec0_t; + v2 test.pkg1.array0_t; + v3 test.pkg1.array1_t; + v4 test.pkg1.array2_t; + PROCEDURE p1 AS + BEGIN + v0(0):='test'; + SELECT v0(0); + v1.a:= 1; + v1.b:= 'b'; + SELECT v1.a, v1.b; + v2(0):= v1; + SELECT v2(0).a, v2(0).b; + v3(0):= 10; + SELECT v3(0); + v4(0):= v1; + SELECT v4(0).a, v4(0).b; + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1; +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; + +DROP PACKAGE pkg1; +DROP TABLE t1; + + +--echo # RECORD + Assoc array in different packages: 2-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PACKAGE pkg2 AS + TYPE array0_t IS TABLE OF pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PROCEDURE p1 AS + r0 pkg1.rec0_t; + a0 pkg2.array0_t; +BEGIN + r0.a:= 10; + r0.b:= 'b'; + a0(0):= r0; + SELECT a0(0).a, a0(0).b; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; + +DROP PACKAGE pkg2; +DROP PACKAGE pkg1; + + +--echo # RECORD + Assoc array in different packages: 3-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +END; +$$ +DELIMITER ;$$ + +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PACKAGE pkg2 AS + TYPE array0_t IS TABLE OF test.pkg1.rec0_t INDEX BY INTEGER; +END; +$$ +DELIMITER ;$$ + +CREATE DATABASE test2; +USE test2; +DELIMITER $$; +CREATE PROCEDURE p1 AS + r0 test.pkg1.rec0_t; + a0 test1.pkg2.array0_t; +BEGIN + r0.a:= 10; + r0.b:= 'b'; + a0(0):= r0; + SELECT a0(0).a, a0(0).b; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; +DROP DATABASE test2; + +USE test1; +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg1; diff --git a/mysql-test/suite/compat/oracle/t/sp-package-spec-type-inet6.test b/mysql-test/suite/compat/oracle/t/sp-package-spec-type-inet6.test new file mode 100644 index 0000000000000..7020524dcfb10 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-spec-type-inet6.test @@ -0,0 +1,129 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-39587 Package-wide TYPE for variable declarations +--echo # + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE inet6_array IS TABLE OF INET6 INDEX BY INTEGER; +END; +$$ +DELIMITER ;$$ + +--echo # 2-Step + PROCEDURE +DELIMITER $$; +CREATE PROCEDURE p1 AS + v0 pkg1.inet6_array; +BEGIN + v0(0):='AA::BB'; + SELECT v0(0); +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; + +--echo # 2-Step + PACKAGE + Declarations in package PROCEDURE +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p1 AS + v0 pkg1.inet6_array; + BEGIN + v0(0):='AA::BB'; + SELECT v0(0); + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1; +DROP PACKAGE pkg2; + +--echo # 2-Step + PACKAGE + Declaration in PACKAGE BODY +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + v0 pkg1.inet6_array; + PROCEDURE p1 AS + BEGIN + v0(0):='AA::BB'; + SELECT v0(0); + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1; +DROP PACKAGE pkg2; + + +--echo # 3-Step + PROCEDURE + Declarations in package PROCEDURE +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PROCEDURE p1 AS + v0 test.pkg1.inet6_array; +BEGIN + v0(0):='AA::BB'; + SELECT v0(0); +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; +DROP DATABASE test1; +USE test; + +--echo # 3-Step + PACKAGE +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p1 AS + v0 test.pkg1.inet6_array; + BEGIN + v0(0):='AA::BB'; + SELECT v0(0); + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1; +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; + +--echo # 3-Step + PACKAGE + Declaration in PACKAGE BODY +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + v0 test.pkg1.inet6_array; + PROCEDURE p1 AS + BEGIN + v0(0):='AA::BB'; + SELECT v0(0); + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1; +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; + +DROP PACKAGE pkg1; diff --git a/mysql-test/suite/compat/oracle/t/sp-package-spec-type-path.test b/mysql-test/suite/compat/oracle/t/sp-package-spec-type-path.test new file mode 100644 index 0000000000000..dfb114ee644a4 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-spec-type-path.test @@ -0,0 +1,113 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-39587 Package-wide TYPE for variable declarations +--echo # + + +--echo # PATH resolving not to CURRENT_SCHEMA + +CREATE DATABASE test1; +DELIMITER $$; +CREATE PACKAGE test1.pkg1 AS + TYPE rec0_t IS RECORD (a INT, b_test1 VARCHAR(10)); +END; +$$ +DELIMITER ;$$ + +CREATE DATABASE test2; +DELIMITER $$; +CREATE PACKAGE test2.pkg1 AS + TYPE rec0_t IS RECORD (a INT, b_test2 VARCHAR(10)); +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_UNKNOWN_DATA_TYPE +CREATE PROCEDURE p1 AS + a pkg1.rec0_t; +BEGIN + NULL; +END; +$$ +DELIMITER ;$$ + + +# Have pkg1.rec0_t resolve to test1.pkg1.rec0_t +SET PATH 'CURRENT_SCHEMA,test1,test2'; + +DELIMITER $$; +CREATE PROCEDURE p1 AS + a pkg1.rec0_t; +BEGIN + a.b_test1:= 10; + SELECT a.b_test1; +END; +$$ +DELIMITER ;$$ +CALL test.p1(); +DROP PROCEDURE p1; + + +# Have pkg1.rec0_t resolve to test2.pkg1.rec0_t +SET PATH 'CURRENT_SCHEMA,test2,test1'; + +DELIMITER $$; +CREATE PROCEDURE p1 AS + a pkg1.rec0_t; +BEGIN + a.b_test2:= 10; + SELECT a.b_test2; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; + +SET PATH DEFAULT; + +DROP DATABASE test1; +DROP DATABASE test2; + + +--echo # PATH resolving to CURRENT_SCHEMA + +CREATE DATABASE test1; +DELIMITER $$; +CREATE PACKAGE test.pkg1 AS + TYPE rec0_t IS RECORD (a INT, b_test VARCHAR(10)); +END; +$$ +DELIMITER ;$$ + +SET PATH 'test1,CURRENT_SCHEMA'; +DELIMITER $$; +CREATE PROCEDURE p1 AS + a pkg1.rec0_t; +BEGIN + a.b_test:= 10; + SELECT a.b_test; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; + +SET PATH 'CURRENT_SCHEMA,test1'; +DELIMITER $$; +CREATE PROCEDURE p1 AS + a pkg1.rec0_t; +BEGIN + a.b_test:= 10; + SELECT a.b_test; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; + +DROP PACKAGE pkg1; +DROP DATABASE test1; + +SET PATH DEFAULT; diff --git a/mysql-test/suite/compat/oracle/t/sp-package-spec-type-record.test b/mysql-test/suite/compat/oracle/t/sp-package-spec-type-record.test new file mode 100644 index 0000000000000..dba685eba0ecd --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-spec-type-record.test @@ -0,0 +1,153 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-39587 Package-wide TYPE for variable declarations +--echo # + +--echo # RECORD cannot have attributes +--echo # Currently this is not allowed by the parser in qualified types +--echo # If we ever allow, make sure to call check_data_type_attributes() +--echo # which will raise ER_UNSUPPORTED_DATA_TYPE_ATTRIBUTE + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.rec0_t (0); -- Length attribute +BEGIN + NULL; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.rec0_t (0,0); -- Length and dec attributes +BEGIN + NULL; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.rec0_t CHARACTER SET latin1; +BEGIN + NULL; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.rec0_t COLLATE latin1_bin; +BEGIN + NULL; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE pkg1; + + +--echo # PACKAGE spec types cannot be used in schema routine parameters +--echo # and schema function RETURN + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +END; +$$ +--error ER_WRONG_USAGE +CREATE PROCEDURE p1(a pkg1.rec0_t) AS +BEGIN + NULL; +END; +$$ +--error ER_WRONG_USAGE +CREATE FUNCTION f1 RETURN pkg1.rec0_t AS +BEGIN + RETURN NULL; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE pkg1; + + +--echo # RECORD as a package routine parameter and a package function RETURN +--echo # 2-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +END; +$$ +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p2(r pkg1.rec0_t) AS + BEGIN + SELECT r.a, r.b; + END; + FUNCTION f1 RETURN pkg1.rec0_t AS + res pkg1.rec0_t; + BEGIN + res.a:= 10; + res.b:= 'b'; + RETURN res; + END; + PROCEDURE p1 AS + BEGIN + CALL p2(f1()); + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1(); +DROP PACKAGE pkg2; +DROP PACKAGE pkg1; + +--echo # RECORD as a package routine parameter and a package function RETURN +--echo # 3-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); +END; +$$ +DELIMITER ;$$ + +CREATE DATABASE test1; +USE test1; + +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p2(r test.pkg1.rec0_t) AS + BEGIN + SELECT r.a, r.b; + END; + FUNCTION f1 RETURN test.pkg1.rec0_t AS + res test.pkg1.rec0_t; + BEGIN + res.a:= 10; + res.b:= 'b'; + RETURN res; + END; + PROCEDURE p1 AS + BEGIN + CALL p2(f1()); + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1(); +CALL test1.pkg2.p1(); +USE test; +CALL test1.pkg2.p1(); +USE test1; +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg1; diff --git a/mysql-test/suite/compat/oracle/t/sp-package-spec-type-refcursor.test b/mysql-test/suite/compat/oracle/t/sp-package-spec-type-refcursor.test new file mode 100644 index 0000000000000..b0a32cf47e278 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-spec-type-refcursor.test @@ -0,0 +1,591 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-39587 Package-wide TYPE for variable declarations +--echo # + +--echo # REFCURSOR cannot have attributes +--echo # Currently this is not allowed by the parser in qualified types +--echo # If we ever allow, make sure to call check_data_type_attributes() +--echo # which will raise ER_UNSUPPORTED_DATA_TYPE_ATTRIBUTE + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); + TYPE cur0_t IS REF CURSOR RETURN rec0_t; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.cur0_t (0); -- Length attribute +BEGIN + NULL; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.cur0_t (0,0); -- Length and dec attributes +BEGIN + NULL; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.cur0_t CHARACTER SET latin1; +BEGIN + NULL; +END; +$$ +--error ER_PARSE_ERROR +CREATE PROCEDURE p1 AS + r0 pkg1.cur0_t COLLATE latin1_bin; +BEGIN + NULL; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE pkg1; + + + +--echo # PACKAGE spec types cannot be used in schema routine parameters +--echo # and schema function RETURN + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); + TYPE cur0_t IS REF CURSOR RETURN rec0_t; +END; +$$ +--error ER_WRONG_USAGE +CREATE PROCEDURE p1(a pkg1.cur0_t) AS +BEGIN + NULL; +END; +$$ +--error ER_WRONG_USAGE +CREATE FUNCTION f1 RETURN pkg1.cur0_t AS +BEGIN + RETURN NULL; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE pkg1; + + +--echo # A package routine parameter and a package function RETURN +--echo # 2-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); + TYPE cur0_t IS REF CURSOR RETURN rec0_t; +END; +$$ +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p2(c pkg1.cur0_t) AS + v0 INT; + v1 VARCHAR(32); + BEGIN + FETCH c INTO v0, v1; + SELECT v0, v1; + CLOSE c; + END; + FUNCTION f1 RETURN pkg1.cur0_t AS + res pkg1.cur0_t; + BEGIN + OPEN res FOR SELECT 1,'b'; + RETURN res; + END; + PROCEDURE p1 AS + BEGIN + CALL p2(f1()); + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1(); +DROP PACKAGE pkg2; +DROP PACKAGE pkg1; + + +--echo # A package routine parameter and a package function RETURN +--echo # 3-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(10)); + TYPE cur0_t IS REF CURSOR RETURN rec0_t; +END; +$$ +DELIMITER ;$$ + +CREATE DATABASE test1; +USE test1; + +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p2(c test.pkg1.cur0_t) AS + v0 INT; + v1 VARCHAR(32); + BEGIN + FETCH c INTO v0, v1; + SELECT v0, v1; + CLOSE c; + END; + FUNCTION f1 RETURN test.pkg1.cur0_t AS + res test.pkg1.cur0_t; + BEGIN + OPEN res FOR SELECT 1, 'b'; + RETURN res; + END; + PROCEDURE p1 AS + BEGIN + CALL p2(f1()); + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1(); +CALL test1.pkg2.p1(); +USE test; +CALL test1.pkg2.p1(); +USE test1; +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; +DROP PACKAGE pkg1; + + +--echo # A self-reference to the current spec with success: 2-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); + TYPE cur0_t IS REF CURSOR RETURN pkg1.rec0_t; -- Self ref +END; +$$ + +--echo # Using from the same database +CREATE PROCEDURE p1 AS + r0 pkg1.rec0_t; + c0 pkg1.cur0_t; +BEGIN + OPEN c0 FOR SELECT 1,'b'; + FETCH c0 INTO r0; + CLOSE c0; + SELECT r0.a, r0.b; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; + +--echo # Using from a different database +CREATE DATABASE test1; +DELIMITER $$; +CREATE PROCEDURE test1.p1 AS + r0 test.pkg1.rec0_t; + c0 test.pkg1.cur0_t; +BEGIN + OPEN c0 FOR SELECT 1,'b'; + FETCH c0 INTO r0; + CLOSE c0; + SELECT r0.a, r0.b; + NULL; +END; +$$ +DELIMITER ;$$ +CALL test1.p1; +DROP DATABASE test1; + +DROP PACKAGE pkg1; + + +--echo # A self-reference to the current spec with success: 3-step + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); + TYPE cur0_t IS REF CURSOR RETURN test.pkg1.rec0_t; -- Self ref +END; +$$ + +--echo # Using from the same database +CREATE PROCEDURE p1 AS + r0 test.pkg1.rec0_t; + c0 test.pkg1.cur0_t; +BEGIN + OPEN c0 FOR SELECT 1,'b'; + FETCH c0 INTO r0; + CLOSE c0; + SELECT r0.a, r0.b; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; + +--echo # Using from a different database +CREATE DATABASE test1; +DELIMITER $$; +CREATE PROCEDURE test1.p1 AS + r0 test.pkg1.rec0_t; + c0 test.pkg1.cur0_t; +BEGIN + OPEN c0 FOR SELECT 1,'b'; + FETCH c0 INTO r0; + CLOSE c0; + SELECT r0.a, r0.b; + NULL; +END; +$$ +DELIMITER ;$$ +CALL test1.p1; +DROP DATABASE test1; + +DROP PACKAGE pkg1; + + +--echo # Various working examples +CREATE TABLE t1 (a INT, b VARCHAR(30)); + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); + TYPE cur0_t IS REF CURSOR; + TYPE cur1_t IS REF CURSOR RETURN rec0_t; + TYPE cur2_t IS REF CURSOR RETURN test.t1%ROWTYPE; +END; +$$ +DELIMITER ;$$ + +--echo # 2-Step + PROCEDURE +DELIMITER $$; +CREATE PROCEDURE p1 AS + v1 pkg1.rec0_t; + c0 pkg1.cur0_t; + c1 pkg1.cur1_t; + c2 pkg1.cur2_t; + fetch0 INT; + fetch1 VARCHAR(30); +BEGIN + v1.a:= 1; + v1.b:= 'b'; + + OPEN c0 FOR SELECT 10,'bb0'; + FETCH c0 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c0; + + OPEN c1 FOR SELECT 11,'bb1'; + FETCH c1 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c1; + + OPEN c2 FOR SELECT 12,'bb2'; + FETCH c2 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c2; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; + +--echo # 3-Step + PROCEDURE +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PROCEDURE p1 AS + v1 test.pkg1.rec0_t; + c0 test.pkg1.cur0_t; + c1 test.pkg1.cur1_t; + c2 test.pkg1.cur2_t; + fetch0 INT; + fetch1 VARCHAR(30); +BEGIN + v1.a:= 1; + v1.b:= 'b'; + + OPEN c0 FOR SELECT 10,'bb0'; + FETCH c0 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c0; + + OPEN c1 FOR SELECT 11,'bb1'; + FETCH c1 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c1; + + OPEN c2 FOR SELECT 12,'bb2'; + FETCH c2 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c2; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; +DROP DATABASE test1; +USE test; + +--echo # 2-Step + PACKAGE + Declarations in package PROCEDURE +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p1 AS + v1 pkg1.rec0_t; + c0 pkg1.cur0_t; + c1 pkg1.cur1_t; + c2 pkg1.cur2_t; + fetch0 INT; + fetch1 VARCHAR(30); + BEGIN + v1.a:= 1; + v1.b:= 'b'; + + OPEN c0 FOR SELECT 10,'bb0'; + FETCH c0 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c0; + + OPEN c1 FOR SELECT 11,'bb1'; + FETCH c1 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c1; + + OPEN c2 FOR SELECT 12,'bb2'; + FETCH c2 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c2; + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1; +DROP PACKAGE pkg2; + +--echo # 3-Step + PACKAGE + Declarations in package PROCEDURE +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +CREATE PACKAGE BODY pkg2 AS + PROCEDURE p1 AS + v1 test.pkg1.rec0_t; + c0 test.pkg1.cur0_t; + c1 test.pkg1.cur1_t; + c2 test.pkg1.cur2_t; + fetch0 INT; + fetch1 VARCHAR(30); + BEGIN + v1.a:= 1; + v1.b:= 'b'; + + OPEN c0 FOR SELECT 10,'bb0'; + FETCH c0 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c0; + + OPEN c1 FOR SELECT 11,'bb1'; + FETCH c1 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c1; + + OPEN c2 FOR SELECT 12,'bb2'; + FETCH c2 INTO fetch0, fetch1; + SELECT fetch0, fetch1; + CLOSE c2; + END; +END; +$$ +DELIMITER ;$$ +CALL pkg2.p1; +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; + +--echo # 3-Step + PACKAGE + Declarations in PACKAGE BODY +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PACKAGE pkg2 AS + PROCEDURE p1; +END; +$$ +--error ER_NOT_ALLOWED_IN_THIS_CONTEXT +CREATE PACKAGE BODY pkg2 AS + v1 test.pkg1.rec0_t; + c0 test.pkg1.cur0_t; + c1 test.pkg1.cur1_t; + c2 test.pkg1.cur2_t; + fetch0 INT; + fetch1 VARCHAR(30); + PROCEDURE p1 AS + BEGIN + NULL; + END; +END; +$$ +DELIMITER ;$$ +DROP PACKAGE pkg2; +DROP DATABASE test1; +USE test; + +DROP PACKAGE pkg1; +DROP TABLE t1; + + +--echo # RECORD and REFCURSOR in different packages + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +END; +$$ +DELIMITER ;$$ + +--echo # 2-step type in RETURN in a schema procedure +DELIMITER $$; +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +CREATE PROCEDURE p1 AS + TYPE cur0_t IS REF CURSOR RETURN pkg1.rec0_t; + c0 cur0_t; +BEGIN + OPEN c0 FOR SELECT 1,'b',3; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PROCEDURE p1 AS + TYPE cur0_t IS REF CURSOR RETURN pkg1.rec0_t; + c0 cur0_t; + v0 INT; + v1 VARCHAR(10); +BEGIN + OPEN c0 FOR SELECT 1,'b'; + FETCH c0 INTO v0, v1; + SELECT v0, v1; + CLOSE c0; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; + + +--echo # 3-step type in RETURN in a schema procedure + +DELIMITER $$; +--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION +CREATE PROCEDURE p1 AS + TYPE cur0_t IS REF CURSOR RETURN test.pkg1.rec0_t; + c0 cur0_t; +BEGIN + OPEN c0 FOR SELECT 1,'b',3; +END; +$$ +DELIMITER ;$$ + + +DELIMITER $$; +CREATE PROCEDURE p1 AS + TYPE cur0_t IS REF CURSOR RETURN test.pkg1.rec0_t; + c0 cur0_t; + v0 INT; + v1 VARCHAR(10); +BEGIN + OPEN c0 FOR SELECT 1,'b'; + FETCH c0 INTO v0, v1; + SELECT v0, v1; + CLOSE c0; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; + + +--echo # 2-step type in RETURN in another package +DELIMITER $$; +CREATE PACKAGE pkg2 AS + TYPE cur0_t IS REF CURSOR RETURN pkg1.rec0_t; +END; +$$ +DELIMITER ;$$ + +--echo # 2-step cursor type with 2-step type in RETURN +DELIMITER $$; +CREATE PROCEDURE p1 AS + c0 pkg2.cur0_t; + v0 INT; + v1 VARCHAR(10); +BEGIN + OPEN c0 FOR SELECT 1,'b'; + FETCH c0 INTO v0, v1; + SELECT v0, v1; + CLOSE c0; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; + +--echo # 3-step cursor type with 2-step type in RETURN +DELIMITER $$; +CREATE PROCEDURE p1 AS + c0 test.pkg2.cur0_t; + v0 INT; + v1 VARCHAR(10); +BEGIN + OPEN c0 FOR SELECT 1,'b'; + FETCH c0 INTO v0, v1; + SELECT v0, v1; + CLOSE c0; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; + + +--echo # 3-step cursor type (different db) with 2-step type in RETURN +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PROCEDURE p1 AS + c0 test.pkg2.cur0_t; + v0 INT; + v1 VARCHAR(10); +BEGIN + OPEN c0 FOR SELECT 1,'b'; + FETCH c0 INTO v0, v1; + SELECT v0, v1; + CLOSE c0; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PROCEDURE p1; +DROP DATABASE test1; +USE test; + +DROP PACKAGE pkg2; + +DROP PACKAGE pkg1; diff --git a/mysql-test/suite/compat/oracle/t/sp-package-spec-type.test b/mysql-test/suite/compat/oracle/t/sp-package-spec-type.test new file mode 100644 index 0000000000000..fea995492c767 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-spec-type.test @@ -0,0 +1,73 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-39587 Package-wide TYPE for variable declarations +--echo # + +--echo # PACKAGE gets dropped making an orphan type reference: 2-step +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +CREATE PROCEDURE p1 AS + r0 pkg1.rec0_t; +BEGIN + r0.a:= 10; + r0.b:= 'b'; + SELECT r0.a, r0.b; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PACKAGE pkg1; +--error ER_SP_PROC_TABLE_CORRUPT +CALL p1; +SHOW WARNINGS; +DROP PROCEDURE p1; + + +--echo # PACKAGE gets dropped making an orphan type reference: 3-step +DELIMITER $$; +CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD(a INT, b VARCHAR(30)); +END; +$$ +DELIMITER ;$$ + +CREATE DATABASE test1; +USE test1; +DELIMITER $$; +CREATE PROCEDURE p1 AS + r0 test.pkg1.rec0_t; +BEGIN + r0.a:= 10; + r0.b:= 'b'; + SELECT r0.a, r0.b; +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP PACKAGE test.pkg1; +--error ER_SP_PROC_TABLE_CORRUPT +CALL p1; +SHOW WARNINGS; +DROP PROCEDURE p1; +DROP DATABASE test1; +USE test; + + +--echo # Too long identifier chain + +DELIMITER $$; +--error ER_UNKNOWN_DATA_TYPE +CREATE PROCEDURE p1 AS + v1 cat1.db1.pkg1.type1; +BEGIN + NULL; +END; +$$ +DELIMITER ;$$ diff --git a/mysql-test/suite/compat/oracle/t/type_date.test b/mysql-test/suite/compat/oracle/t/type_date.test index 31901a50722a3..a91b534cbb452 100644 --- a/mysql-test/suite/compat/oracle/t/type_date.test +++ b/mysql-test/suite/compat/oracle/t/type_date.test @@ -75,24 +75,24 @@ DROP TABLE t1; --echo # --echo # Qualified syntax is not supported yet in SP --echo # See MDEV-23353 Qualified data types in SP ---echo # For now it's trying to parse as "RETURN mariadb_schema.DATE%ROWTYPE" +--echo # For now it's trying to parse mariadb_schema as a package name --echo # SET sql_mode=ORACLE; DELIMITER $$; ---error ER_PARSE_ERROR +--error ER_UNKNOWN_DATA_TYPE CREATE FUNCTION f1() RETURN mariadb_schema.DATE AS BEGIN RETURN CURRENT_DATE; END; $$ ---error ER_PARSE_ERROR +--error ER_UNKNOWN_DATA_TYPE CREATE PROCEDURE p1(a mariadb_schema.DATE) AS BEGIN NULL; END; $$ ---error ER_PARSE_ERROR +--error ER_UNKNOWN_DATA_TYPE CREATE PROCEDURE p1() AS a mariadb_schema.DATE; BEGIN diff --git a/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-rowtype-of-table.result b/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-rowtype-of-table.result index 23ed048127f8d..b2f2c83a4f069 100644 --- a/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-rowtype-of-table.result +++ b/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-rowtype-of-table.result @@ -8,10 +8,7 @@ BEGIN NULL; END; $$ -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.v0%ROWTYPE; -BEGIN -NULL; -END' at line 2 +ERROR HY000: Unknown data type: '`cat1`.`db1`.`t1`' CREATE PROCEDURE p1 AS TYPE cur0_t IS REF CURSOR RETURN cat1.db1.t1%ROWTYPE; BEGIN diff --git a/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-rowtype-of-table.test b/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-rowtype-of-table.test index 30dbcda9d965b..687eac3dd8736 100644 --- a/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-rowtype-of-table.test +++ b/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-rowtype-of-table.test @@ -9,7 +9,7 @@ SET sql_mode=ORACLE; # DELIMITER $$; ---error ER_PARSE_ERROR +--error ER_UNKNOWN_DATA_TYPE CREATE PROCEDURE p1 AS TYPE cur0_t IS REF CURSOR RETURN cat1.db1.t1.v0%ROWTYPE; BEGIN diff --git a/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-type-of-var.result b/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-type-of-var.result index 1980db64be5b0..bbac678175012 100644 --- a/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-type-of-var.result +++ b/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-type-of-var.result @@ -11,10 +11,7 @@ BEGIN NULL; END; $$ -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.v0%TYPE; -BEGIN -NULL; -END' at line 2 +ERROR HY000: Unknown data type: '`cat1`.`db1`.`t1`' CREATE PROCEDURE p1 AS TYPE cur0_t IS REF CURSOR RETURN db1.t1.v0%TYPE; BEGIN diff --git a/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-type-of-var.test b/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-type-of-var.test index 1470281ec99ff..d0e5908287529 100644 --- a/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-type-of-var.test +++ b/plugin/type_cursor/mysql-test/type_cursor/sp-ref_cursor-return-type-of-var.test @@ -10,7 +10,7 @@ SET sql_mode=ORACLE; --echo # DELIMITER $$; ---error ER_PARSE_ERROR +--error ER_UNKNOWN_DATA_TYPE CREATE PROCEDURE p1 AS TYPE cur0_t IS REF CURSOR RETURN cat1.db1.t1.v0%TYPE; BEGIN diff --git a/sql/sp.cc b/sql/sp.cc index cbaf72b939814..d041fc310732f 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -2524,6 +2524,42 @@ Sp_handler::sp_cache_routine_reentrant(THD *thd, } +/* + Find and cache a routine in a parser safe mode and suppress all errors. +*/ +int +Sp_handler::sp_cache_routine_reentrant_suppress_errors(THD *thd, + const Database_qualified_name *name, + sp_head **sp) const +{ + Dummy_error_handler err_handler; + thd->push_internal_handler(&err_handler); + int ret= sp_cache_routine_reentrant(thd, name, sp); + thd->pop_internal_handler(); + return ret; +} + + +/* + Find and cache a PACKAGE spec in a parser-safe reentrant mode. + @param db - The database name + @param package - The package name + @retval - A null ptr if some error happened. + Or a pointer to the PACKAGE spec. +*/ +sp_package *Sp_handler::find_package_spec(THD *thd, + const Lex_ident_db &db, + const LEX_CSTRING &package) +{ + sp_head *sp= nullptr; + Database_qualified_name tmp(db, package); + bool ret= sp_handler_package_spec. + sp_cache_routine_reentrant_suppress_errors(thd, &tmp, &sp); + sp_package *spec= (!ret && sp) ? sp->get_package() : nullptr; + return spec; +} + + /** Check if a routine has a declaration in the CREATE PACKAGE statement, by looking up in thd->sp_package_spec_cache, and by loading from mysql.proc @@ -2557,15 +2593,7 @@ is_package_public_routine(THD *thd, const LEX_CSTRING &routine, enum_sp_type type) { - sp_head *sp= NULL; - Database_qualified_name tmp(db, package); - - Dummy_error_handler err_handler; - thd->push_internal_handler(&err_handler); - bool ret= sp_handler_package_spec.sp_cache_routine_reentrant(thd, &tmp, &sp); - thd->pop_internal_handler(); - - sp_package *spec= (!ret && sp) ? sp->get_package() : NULL; + sp_package *spec= Sp_handler::find_package_spec(thd, db, package); return spec && spec->m_routine_declarations.find(routine, type); } diff --git a/sql/sp.h b/sql/sp.h index 47f2495db3e26..05ea336996026 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -137,6 +137,9 @@ class Sp_handler const Sp_handler *sph= handler(type); return sph ? sph->sp_handler_mysql_proc() : NULL; } + static sp_package *find_package_spec(THD *thd, + const Lex_ident_db &db, + const LEX_CSTRING &package); const char *type_str() const { return type_lex_cstring().str; } virtual const char *show_create_routine_col1_caption() const @@ -211,6 +214,10 @@ class Sp_handler const Database_qualified_name *nm, sp_head **sp) const; + int sp_cache_routine_reentrant_suppress_errors(THD *thd, + const Database_qualified_name *nm, + sp_head **sp) const; + bool sp_exist_routines(THD *thd, TABLE_LIST *procs) const; bool sp_show_create_routine(THD *thd, const Database_qualified_name *name) const; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 5d52b7f109dac..68520011d6d38 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -4247,3 +4247,236 @@ ulong sp_head::sp_cache_version() const { return m_parent ? m_parent->sp_cache_version() : m_sp_cache_version; } + + +/* + Check if the column definition "def" with type "type" can be used in "this". + + These kind of declarations are not allowed in schema routines: + PROCEDURE p1(a pkg1.type1) - a schema routine parameter type + FUNCTION f1() RETURN pkg1.type1; - a schema function RETURN types + because they show up in INFORMATION_SCHEMA.PARAMETERS. + The code is not ready to handle this correctly. + + Note, using them for package routines are OK, because package routines + are not displayed in INFORMATION_SCHEMA. +*/ +bool sp_head::check_applicability(THD *thd, + const Lex_field_type_st &def, + column_definition_type_t type) +{ + if (def.foreign_module_type()) + { + if ((m_handler == &sp_handler_procedure || + m_handler == &sp_handler_function)/*i.e. not a package routine*/ && + (type == COLUMN_DEFINITION_ROUTINE_PARAM || + type == COLUMN_DEFINITION_FUNCTION_RETURN)) + { + my_error(ER_WRONG_USAGE, MYF(0), + type == COLUMN_DEFINITION_ROUTINE_PARAM ? + "parameter_declaration" : "RETURN", + "package_name.type_name"); + return true; + } + } + return false; +} + + +void sp_head::raise_unknown_data_type(const Lex_ident_db_normalized &db, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type) +{ + char buf[128]; + my_snprintf(buf, sizeof(buf), "%.*sQ.%.*sQ.%.*sQ", + (int) db.length, db.str, + (int) package.length, package.str, + (int) type.length, type.str); + my_error(ER_UNKNOWN_DATA_TYPE, MYF(0), buf); +} + + +void sp_head::raise_unknown_data_type(const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type) +{ + char buf[128]; + my_snprintf(buf, sizeof(buf), "%.*sQ.%.*sQ", + (int) package.length, package.str, + (int) type.length, type.str); + my_error(ER_UNKNOWN_DATA_TYPE, MYF(0), buf); +} + + +/* + Get the definition of the TYPE `dbn`.`package`.`type`. + If the definition is not found, then an error message is raises. + + @param OUT tdef - The pointer to the found TYPE definition + @param dbn - The nornamized database name (used for error messages) + @param package - The package name (used for error messages) + @param type - The data type name + + @retval false - If the TYPE definition was found and written to "tdef" + @retval true - If the data type was found found or some error happened. +*/ + +bool sp_package::get_typedef(THD *thd, + const sp_type_def **tdef, + const Lex_ident_db_normalized dbn, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type) +{ + if (!(tdef[0]= get_parse_context()->child_context(0)-> + find_type_def(type, false))) + { + if (dbn.str) + raise_unknown_data_type(dbn, package, type); + else + raise_unknown_data_type(package, type); + return true; + } + return false; +} + + +/* + Get a 2-step qualified TYPE defined in a PACKAGE + consisting by the package name and type name. + Handles the following cases: + - A PACKAGE refers to its own type using a qualified name + - A routine refers to the PACKAGE in the database of the routine + using a qualified type + - Otherwise, the database which contains a package "package" with the type + "type" is resolved using the @@PATH variable. + + @param OUT tdef - The pointer to the TYPE definition + @param package - The package name + @param type - The data type name + + @retval false - The package "package" with the data type "type" was found, + and tdef[0] was set to the pointer of the found type. + @retval true - The data type was not found, or some error happened + during type resolution. +*/ +bool sp_head::get_typedef_package_spec(THD *thd, + const sp_type_def **tdef, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type) +{ + /* + Catch a special case first: a reference to the current package spec. + Note, cast to Lex_ident_routine is safe below because m_name gets + to sp_head after Lex_ident_routine::check_name_with_error(). + */ + if (m_handler == &sp_handler_package_spec && + Lex_ident_routine(m_name).streq(package)) + { + /* + The data type pkg1.type1 refers the current package specifications + for the packge pkg1: + CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); + TYPE assoc0_t IS TABLE OF pkg1.rec0_t INDEX BY INTEGER; + END; + Avoid a recursive find_package_spec_type(). + */ + sp_package *spec= get_package(); + DBUG_ASSERT(spec); + return spec->get_typedef(thd, tdef, + Lex_ident_db_normalized(), package, type); + } + + /* + Another special case - a two step reference to a type + in the package of the db of the current routine (test1 in this example): + CREATE OR REPLACE PROCEDURE test1.p1 AS + r0 pkg1.rec0_t; -- A reference to test1.pkg1.rec0_t + BEGIN ... + */ + if (m_db.str) + { + Lex_ident_db_normalized ndb; + if (!(ndb= thd->to_ident_db_normalized_with_error(m_db)).str) + return true; + sp_package *spec; + if ((spec= Sp_handler::find_package_spec(thd, ndb, package)) && + (tdef[0]= spec->get_parse_context()->child_context(0)-> + find_type_def(type, false))) + { + return spec->get_typedef(thd, tdef, ndb, package, type); + } + } + + // Now go with the general case + Lex_ident_db_normalized resolved_db; + if (thd->variables.path.find_package_spec_type(thd, &resolved_db, + package, type)) + return true; // An internal error + if (!resolved_db.str) + { + raise_unknown_data_type(package, type); + return true; // 2-step package spec was not found + } + return get_typedef_package_spec(thd, tdef, + Lex_ident_sys(resolved_db.str, + resolved_db.length), + package, type); +} + + +/* + Get a 3-step qualified TYPE defines in a PACKAGE + + @param OUT tdef - The pointer to the TYPE definition + @param db - The database name + @param package - The package name + @param type - The data type name + + @retval false - The database "db" with the package "package" + with the data type "type" was found, + and tdef was set to the pointer of the found type. + @retval true - The data type was not found, or some error happened + during type resolution. +*/ +bool sp_head::get_typedef_package_spec(THD *thd, + const sp_type_def **tdef, + const Lex_ident_sys_st &db, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type) +{ + Lex_ident_db_normalized dbn= thd->to_ident_db_normalized_with_error(db); + if (!dbn.str) + return true; + + /* + Catch a special case first: a reference to the current package spec. + Note, cast to Lex_ident_routine is safe below because m_name gets + to sp_head after Lex_ident_routine::check_name_with_error(). + */ + if (m_handler == &sp_handler_package_spec && + dbn.streq(db) && + Lex_ident_routine(m_name).streq(package)) + { + /* + The data type db1.pkg1.type1 refers the current package specifications + for the packge pkg1: + USE db1; + CREATE PACKAGE pkg1 AS + TYPE rec0_t IS RECORD (a INT, b VARCHAR(32)); + TYPE assoc0_t IS TABLE OF db1.pkg1.rec0_t INDEX BY INTEGER; + END; + Avoid a recursive find_package_spec_type(). + */ + sp_package *spec= get_package(); + DBUG_ASSERT(spec); + return spec->get_typedef(thd, tdef, dbn, package, type); + } + + sp_package *spec= Sp_handler::find_package_spec(thd, dbn, package); + if (!spec) + { + raise_unknown_data_type(dbn, package, type); + return true; // 3-step package spec was not found + } + return spec->get_typedef(thd, tdef, dbn, package, type); +} diff --git a/sql/sp_head.h b/sql/sp_head.h index 7f7f14074a22c..1f20d6f66c426 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -1004,6 +1004,25 @@ class sp_head :private Query_arena, virtual void init_psi_share(); + static void raise_unknown_data_type(const Lex_ident_db_normalized &db, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type); + static void raise_unknown_data_type(const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type); + bool check_applicability(THD *thd, const Lex_field_type_st &def, + column_definition_type_t type); + + + bool get_typedef_package_spec(THD *thd, + const sp_type_def **tdef, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type); + + bool get_typedef_package_spec(THD *thd, + const sp_type_def **tdef, + const Lex_ident_sys_st &db, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type); protected: MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root @@ -1187,6 +1206,12 @@ class sp_package: public sp_head sp_pcontext *ctx= m_pcont->child_context(0); return ctx ? ctx->find_variable(name, true) : NULL; } + bool get_typedef(THD *thd, + const sp_type_def **tdef, + const Lex_ident_db_normalized dbn, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type); + bool validate_after_parser(THD *thd); bool instantiate_if_needed(THD *thd); }; diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index 2aeab10d7925b..7adfdff7b63fd 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -445,6 +445,20 @@ sp_type_def *sp_pcontext::find_type_def(const LEX_CSTRING &name, } +bool sp_pcontext::type_defs_add_ref_cursor(THD *thd, + const Lex_ident_column &name, + const Type_handler *th, + const Spvar_definition &return_def, + bool is_prepared) +{ + sp_type_def_ref *tdef= new (thd->mem_root) sp_type_def_ref(name, th, + return_def, is_prepared); + if (unlikely(!tdef || type_defs_add(thd, tdef))) + return true; // EOM + return false; +} + + sp_condition_value * sp_pcontext::find_declared_or_predefined_condition(THD *thd, const LEX_CSTRING *name) diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 421b708b9fa9d..5495f98856468 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -764,6 +764,25 @@ class sp_pcontext : public Sql_alloc, return sp_type_def_list::type_defs_add(def); } + /* + Add a new TYPE for REF CURSOR, e.g.: + TYPE type1 IS REF CURSOR; + TYPE type1 IS REF CURSOR RETURN t1%ROWTYPE; + TYPE type1 IS REF CURSOR RETURN pkg1.rec1; + @param THD - The THD + @param name - The name of the new data type + @param th - The type handler of the new TYPE + (usually &type_handler_sys_refcursor) + @param return_def - The definition of the RETURN type + @param is_prepared - If sp_prepare_create_field() has already + been called for return_def. + See details in class sp_type_def_ref. + */ + bool type_defs_add_ref_cursor(THD *thd, const Lex_ident_column &name, + const Type_handler *th, + const Spvar_definition &return_def, + bool is_prepared); + private: /// Constructor for a tree node. /// @param prev the parent parsing context diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 18f1ca7bb11e6..9295bdcee8331 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -6792,8 +6792,10 @@ sp_variable *LEX::sp_param_init(LEX_CSTRING *name) bool LEX::sp_param_fill_definition(sp_variable *spvar, const Lex_field_type_st &def) { + constexpr column_definition_type_t dtype= COLUMN_DEFINITION_ROUTINE_PARAM; return - last_field->set_attributes(thd, def, COLUMN_DEFINITION_ROUTINE_PARAM) || + sphead->check_applicability(thd, def, dtype) || + last_field->set_attributes(thd, def, dtype) || sphead->fill_spvar_definition(thd, last_field, &spvar->name); } @@ -6852,8 +6854,10 @@ bool LEX::sp_param_set_default_and_finalize(sp_variable *spvar, bool LEX::sf_return_fill_definition(const Lex_field_type_st &def) { + constexpr column_definition_type_t dtype= COLUMN_DEFINITION_FUNCTION_RETURN; return - last_field->set_attributes(thd, def, COLUMN_DEFINITION_FUNCTION_RETURN) || + sphead->check_applicability(thd, def, dtype) || + last_field->set_attributes(thd, def, dtype) || sphead->fill_field_definition(thd, last_field); } @@ -13270,9 +13274,89 @@ bool LEX::declare_type_assoc_array(THD *thd, } +/* + Declare a new REF CURSOR type with these semantics: + TYPE t IS REF CURSOR RETURN db.package.type; -- a 3-step package spec type + TYPE t IS REF CURSOR RETURN package.type; -- a 2-step package spec type + TYPE t IS REF CURSOR RETURN type; -- a 1-step semantic + I.e. the data type in RETURN refers to a previously defined TYPE. + + @param thd - The thd + @param type_name - The name of the new data type + @param db - The database name. Can be a null identifier {0,0}. + @param package - The package name. Can be a null identifier {0,0}. + @param type - The type name. + + @retval true - If could not create a new TYPE. Possible reasons: + * the data type specified by [db.]package.type + was not found + * something went wrong during mysql.proc reading. + * EOM happened + @retval false - If the new TYPE was successfully created. +*/ +bool LEX::declare_type_ref_cursor_return_typedef(THD *thd, + const Lex_ident_sys_st &type_name, + const Lex_ident_sys_st &db, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type) +{ + const Lex_ident_plugin sr= "sys_refcursor"_Lex_ident_plugin; + const Type_handler *th= Type_handler::handler_by_name_or_error(thd, sr); + if (unlikely(!th)) + return true; + + const sp_type_def *rt= nullptr; // The typedef of the RETURN type + if (db.str) // A 3-step RETURN + { + // TYPE c0 IS REF CURSOR RETURN db1.pkg1.rec1_t; + if (sphead->get_typedef_package_spec(thd, &rt, db, package, type)) + return true; + } + else if (package.str) // A 2-step RETURN + { + // TYPE c0 IS REF CURSOR RETURN pkg1.rec1_t; + if (sphead->get_typedef_package_spec(thd, &rt, package, type)) + return true; + } + else // A 1-step RETURN + { + // TYPE c0 IS REF CURSOR RETURN rec1_t; + if (!(rt= find_type_def(type))) + { + my_error(ER_UNKNOWN_DATA_TYPE, MYF(0), type.str); + return true; + } + } + if (!dynamic_cast(rt->type_handler()) || + !dynamic_cast(rt)) + { + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0), + type.str, "REF CURSOR RETURN"); + return true; + } + Row_definition_list *row= static_cast(rt)-> + field->deep_copy(thd); + if (!row) + return true; // EOM + + if (check_ref_cursor_components(row)) + return true; + + const Spvar_definition return_def(&type_handler_row, row); + return spcont->type_defs_add_ref_cursor(thd, Lex_ident_column(type_name), th, + return_def, false/*is_prepared*/); +} + + +/* + Declare a new REF CURSOR type with these semantics: + TYPE t IS REF CURSOR; + TYPE t IS REF CURSOR RETURN db1.t1%ROWTYPE; + TYPE t IS REF CURSOR RETURN t1%ROWTYPE; + TYPE t IS REF CURSOR RETURN rec_var%TYPE; +*/ bool LEX::declare_type_ref_cursor(THD *thd, const Lex_ident_sys_st &type_name, - const Lex_ident_sys_st &return_type_name, const Qualified_column_ident *rowtype, const Qualified_column_ident *vartype, const Lex_ident_cli_st &syntax_error_token) @@ -13346,41 +13430,9 @@ bool LEX::declare_type_ref_cursor(THD *thd, return_def= Spvar_definition(ti, sp_rcontext_addr(nullptr, 0)); } } - else if (!return_type_name.is_null()) - { - /* - An explicit data type in the RETURN clause: - TYPE c0 IS REF CURSOR RETURN rec0_t; - */ - const sp_type_def *rt= find_type_def(return_type_name); - if (!rt) - { - my_error(ER_UNKNOWN_DATA_TYPE, MYF(0), return_type_name.str); - return true; - } - if (!dynamic_cast(rt->type_handler())) - { - my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0), - return_type_name.str, "REF CURSOR RETURN"); - return true; - } - Row_definition_list *row= static_cast(rt)-> - field->deep_copy(thd); - if (!row) - return true; // EOM - if (check_ref_cursor_components(row)) - return true; - - return_def= Spvar_definition(&type_handler_row, row); - } - sp_type_def_ref *tdef= - new (thd->mem_root) sp_type_def_ref(Lex_ident_column(type_name), th, - return_def, is_prepared); - if (unlikely(!tdef || spcont->type_defs_add(thd, tdef))) - return true; // EOM - - return false; + return spcont->type_defs_add_ref_cursor(thd, Lex_ident_column(type_name), th, + return_def, is_prepared); } @@ -13491,6 +13543,68 @@ bool LEX::set_field_type_typedef(Lex_field_type_st *type, } +/* + Set a PACKAGE data type to "res" for a 2-step qualified name, + consisting by the package name and type name. + Handles the following cases: + - A PACKAGE refers to its own type using a qualified name + - A routine refers to the PACKAGE in the same database with the routine + using a qualified type + - Otherwise, the database which contains a package "package" with the type + "type" is resolved using the @@PATH variable. + + @param OUT res - The data type to write to + @param package - The package name + @param type - The data type name + + @retval false - The package "package" with the data type "type" was found, + and res[0] was set to the found type. + @retval true - The data type was not found, or some error happened + during type resolution. +*/ +bool LEX::set_field_type_typedef_package_spec(Lex_field_type_st *res, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type) +{ + const sp_type_def *tdef= nullptr; + if (sphead->get_typedef_package_spec(thd, &tdef, package, type)) + return true; + res->set(tdef->type_handler(), nullptr/*CHARSET_INFO*/); + res->set_foreign_module_type(true); + last_field->set_attr_const_generic_ptr(0, tdef); + return false; +} + + +/* + Set a PACKAGE data type to "res" by a 3-step qualified name, + consisting by the database name, package name and type name. + + @param OUT res - The data type to write to + @param db - The database name + @param package - The package name + @param type - The data type name + + @retval false - The package "package" with the data type "type" was found, + and res[0] was set to the found type. + @retval true - The data type was not found, or some error happened + during type resolution. +*/ +bool LEX::set_field_type_typedef_package_spec(Lex_field_type_st *res, + const Lex_ident_sys_st &db, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type) +{ + const sp_type_def *tdef= nullptr; + if (sphead->get_typedef_package_spec(thd, &tdef, db, package, type)) + return true; + res->set(tdef->type_handler(), nullptr/*CHARSET_INFO*/); + res->set_foreign_module_type(true); + last_field->set_attr_const_generic_ptr(0, tdef); + return false; +} + + bool sp_expr_lex::sp_repeat_loop_finalize(THD *thd) { uint ip= sphead->instructions(); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e86650716896d..9d94b1e851098 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -5135,10 +5135,14 @@ struct LEX: public Query_tables_list Spvar_definition *value); bool declare_type_ref_cursor(THD *thd, const Lex_ident_sys_st &type_name, - const Lex_ident_sys_st &return_type_name, const Qualified_column_ident *rowtype, const Qualified_column_ident *vartype, const Lex_ident_cli_st &syntax_error_token); + bool declare_type_ref_cursor_return_typedef(THD *thd, + const Lex_ident_sys_st &type_name, + const Lex_ident_sys_st &db/*can be null ident*/, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type); bool set_field_type_typedef(Lex_field_type_st *type, const LEX_CSTRING &name, const Lex_length_and_dec_st &attr, @@ -5148,6 +5152,13 @@ struct LEX: public Query_tables_list const LEX_CSTRING &name, const Lex_length_and_dec_st &attr, const Lex_column_charset_collation_attrs_st &coll); + bool set_field_type_typedef_package_spec(Lex_field_type_st *res, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type); + bool set_field_type_typedef_package_spec(Lex_field_type_st *res, + const Lex_ident_sys_st &db, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type); bool map_data_type(const Lex_ident_sys_st &schema, Lex_field_type_st *type) const; diff --git a/sql/sql_path.cc b/sql/sql_path.cc index 982fbffaf985e..a260aa7747b9e 100644 --- a/sql/sql_path.cc +++ b/sql/sql_path.cc @@ -172,6 +172,59 @@ bool Sql_path::resolve(THD *thd, sp_head *caller, sp_name *name, } +/* + Iterate through all schemas in @@path and find a package "package" with the + type "type" + + @param thd - The THD + @param OUT db - The found database which contains a type package.type + If db->str is nullptr the nothing was found. + @param package - The package to find. + @param type - The type to find. + @retval true - If error happened during resolution. + @retval false - If no errors happened during resolution. + Note, if nothing was found and no errors happened, + the return value is false. +*/ +bool Sql_path::find_package_spec_type(THD *thd, + Lex_ident_db_normalized *db, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type) +{ + *db= Lex_ident_db_normalized(); + for (size_t i= 0; i < m_count; i++) + { + sp_package *pkg; + Lex_ident_db_normalized ncdb; + if (is_cur_schema(i)) + { + if (!thd->db.str) + continue; + if (!(ncdb= thd->copy_db_normalized()).str) + return true; // EOM + } + else + { + /* + Conversion to Lex_ident_db_normalized is safe because + database names get into Sql_path in normalized form. + */ + ncdb= Lex_ident_db_normalized(m_schemas[i].str, m_schemas[i].length); + } + if (!(pkg= Sp_handler::find_package_spec(thd, ncdb, package))) + continue; + sp_type_def *tdef= pkg->get_parse_context()->child_context(0)-> + find_type_def(type, false); + if (tdef) + { + *db= ncdb; + return false; // Found a TYPE declaration in a CREATE PACKAGE + } + } + return false; // Nothing found +} + + void Sql_path::free() { if (m_count) diff --git a/sql/sql_path.h b/sql/sql_path.h index e6e40efdbeff4..0e063e3489a8f 100644 --- a/sql/sql_path.h +++ b/sql/sql_path.h @@ -38,6 +38,10 @@ struct Sql_path bool resolve(THD *thd, sp_head *caller, sp_name *name, const Sp_handler **sph, Database_qualified_name *pkgname) const; + + bool find_package_spec_type(THD *thd, Lex_ident_db_normalized *db, + const Lex_ident_sys_st &package, + const Lex_ident_sys_st &type); /* Initialize the path variable with default values */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 269d497058c2f..8273f98d80816 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6643,6 +6643,16 @@ field_type_all_with_typedefs: if (unlikely(Lex->set_field_type_udt_or_typedef(&$$, $1, $2, $4))) MYSQL_YYABORT; } + | sp_decl_ident '.' ident + { + if (Lex->set_field_type_typedef_package_spec(&$$, $1, $3)) + MYSQL_YYABORT; + } + | sp_decl_ident '.' ident '.' ident + { + if (Lex->set_field_type_typedef_package_spec(&$$, $1, $3, $5)) + MYSQL_YYABORT; + } ; field_type_numeric: @@ -20349,7 +20359,7 @@ package_implementation_routine_definition: pkg->m_current_routine= NULL; $$.init(); } - | package_specification_element { $$.init(); } + | package_specification_routine { $$.init(); } ; @@ -20402,7 +20412,7 @@ package_specification_element_list: | package_specification_element_list package_specification_element ; -package_specification_element: +package_specification_routine: FUNCTION_SYM package_specification_function ';' { sp_package *pkg= Lex->get_sp_package(); @@ -20419,6 +20429,13 @@ package_specification_element: } ; +package_specification_element: + package_specification_routine +%ifdef ORACLE + | sp_decl_type ';' +%endif + ; + %ifdef ORACLE @@ -20793,15 +20810,22 @@ sp_decl_type: } | typed_ident IS REF_SYM CURSOR_SYM { - if (unlikely(Lex->declare_type_ref_cursor(thd, $1, Lex_ident_sys(), + if (unlikely(Lex->declare_type_ref_cursor(thd, $1, nullptr, nullptr, $4))) MYSQL_YYABORT; $$.init(); } - | typed_ident IS REF_SYM CURSOR_SYM RETURN_ORACLE_SYM sp_decl_ident + | typed_ident IS REF_SYM CURSOR_SYM RETURN_ORACLE_SYM + optionally_qualified_column_ident { - if (unlikely(Lex->declare_type_ref_cursor(thd, $1, $6, - nullptr, nullptr, $5))) + /* + Conversion of $6 components to Lex_ident_sys is safe, + according to the grammar. + */ + if (unlikely(Lex->declare_type_ref_cursor_return_typedef(thd, $1, + Lex_ident_sys($6->db.str, $6->db.length), + Lex_ident_sys($6->table.str, $6->table.length), + Lex_ident_sys($6->m_column.str, $6->m_column.length)))) MYSQL_YYABORT; $$.init(); } @@ -20809,7 +20833,7 @@ sp_decl_type: optionally_qualified_column_ident PERCENT_ORACLE_SYM TYPE_SYM { - if (unlikely(Lex->declare_type_ref_cursor(thd, $1, Lex_ident_sys(), + if (unlikely(Lex->declare_type_ref_cursor(thd, $1, nullptr, $6, $8))) MYSQL_YYABORT; $$.init(); @@ -20818,7 +20842,7 @@ sp_decl_type: optionally_qualified_column_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM { - if (unlikely(Lex->declare_type_ref_cursor(thd, $1, Lex_ident_sys(), + if (unlikely(Lex->declare_type_ref_cursor(thd, $1, $6, nullptr, $8))) MYSQL_YYABORT; $$.init(); diff --git a/sql/structs.h b/sql/structs.h index 764d37eaf1cfa..85c9cce0f3891 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -665,6 +665,7 @@ struct Lex_length_and_dec_st bool m_has_explicit_dec:1; bool m_length_overflowed:1; bool m_dec_overflowed:1; + bool m_foreign_module_type:1; // Is a type from CREATE PACKAGE static_assert(LEX_CHARSET_COLLATION_TYPE_BITS <= 8, "Lex_length_and_dec_st::m_collation_type bits check"); @@ -685,6 +686,7 @@ struct Lex_length_and_dec_st m_has_explicit_dec= false; m_length_overflowed= false; m_dec_overflowed= false; + m_foreign_module_type= false; } void set_length_only(uint32 length) { @@ -695,6 +697,7 @@ struct Lex_length_and_dec_st m_has_explicit_dec= false; m_length_overflowed= false; m_dec_overflowed= false; + m_foreign_module_type= false; } void set_dec_only(uint8 dec) { @@ -705,6 +708,7 @@ struct Lex_length_and_dec_st m_has_explicit_dec= true; m_length_overflowed= false; m_dec_overflowed= false; + m_foreign_module_type= false; } void set_length_and_dec(uint32 length, uint8 dec) { @@ -715,8 +719,13 @@ struct Lex_length_and_dec_st m_has_explicit_dec= true; m_length_overflowed= false; m_dec_overflowed= false; + m_foreign_module_type= false; } void set(const char *length, const char *dec); + void set_foreign_module_type(bool value) + { + m_foreign_module_type= value; + } uint32 length() const { return m_length; @@ -741,6 +750,10 @@ struct Lex_length_and_dec_st { return m_dec_overflowed; } + bool foreign_module_type() const + { + return m_foreign_module_type; + } };