1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-39587 Package-wide TYPE for variable declarations

SET sql_mode=ORACLE;
DELIMITER $$
CREATE OR REPLACE PACKAGE pkg AS
  -- Declare a package public data type
  TYPE varchar_array IS TABLE OF VARCHAR(2000) INDEX BY INTEGER;
END;
$$
DELIMITER ;
DELIMITER $$

CREATE OR REPLACE PROCEDURE p1 AS
  v pkg.varchar_array; -- Use the package public data type
BEGIN
  v(0):='test';
  SELECT v(0);
END;
$$
DELIMITER ;

Note, the change is done only for sql_mode=ORACLE, because the TYPE
declaration is not available for the default mode.

Where package-wide types are available
--------------------------------------
- Variabe list type:
    DECLARE var pkg1.type1;

- RETURN type for a package routine:
    CREATE FUNCTION .. RETURN pkg1.type1 ...

- Parameter type for a package routine:
    PROCEDURE p1(param1 pkg1.type1);

- Assoc array element type:
    TYPE assoc1_t IS TABLE OF pkg1.type1 ...

- REF CURSOR RETURN type:
    TYPE cur1_t IS REF CURSOR RETURN pkg1.type1;

Change details
--------------

- Adding a member Lex_length_and_dec_st::m_foreign_module_type
  It's set to true when the data type was initialized from a TYPE
  in foreign routine (e.g. in PACKAGE spec).
  It's needed to prevent use of qualified identifiers in public contexts,
  i.e. in schema public routine parameter types and schema publuc function
  RETURN types.
  Adding a helper method sp_head::check_applicability() which prevents
  use of qualified types in public context.

- Adding a helper method sp_head::raise_unknown_data_type().

- Adding methods LEX::set_field_type_typedef_package_spec() for
  2-step and 3-step qualified indentifiers.
  It's used in field_type_all_with_typedefs which covers cases:
  - Variabe list type        : DECLARE var pkg1.type1;
  - RETURN type              : CREATE FUNCTION .. RETURN pkg1.type1 ...
  - Parameter type           : PROCEDURE p1(param1 pkg1.type1);
  - Assoc array element type : TYPE assoc1_t IS TABLE OF pkg1.type1 ...

- Adding a method LEX::declare_type_ref_cursor_return_typedef().
  It handles cases when a new TYPE REF CURSOR RETURN is declared,
  for both for qualified RETURN types and non-qualified RETURN types:
  - TYPE cur0_t IS REF CURSOR RETURN rec1_t;
  - TYPE cur0_t IS REF CURSOR RETURN pkg1.rec1_t;
  - TYPE cur0_t IS REF CURSOR RETURN db1.pkg1.rec1_t;

  The code was moved from LEX::declare_type_ref_cursor() into
  LEX::declare_type_ref_cursor_return_typedef() and extended
  to cover qualified RETURN types.

- Adding a method Sql_path::find_package_spec_type().
  It iterates through all schemas specified in @@path and searches
  for the given type in the given package.

- Adding a helper method sp_pcontext::type_defs_add_ref_cursor()
  to reuse the code.

- Adding a new method sp_package::get_typedef() to search
  for TYPE definitions in PACKAGE specifications.

- Adding a new method sp_head::get_typedef_package_spec()
  to search for TYPE definitions used by a PROCEDURE or FUNCTION.

- Adding a helper method
    Sp_handler::sp_cache_routine_reentrant_suppress_errors
  Adding a method Sp_handler::find_package_spec().
This commit is contained in:
Alexander Barkov
2026-05-13 11:06:40 +04:00
parent d87428a093
commit 0ee34e07bd
56 changed files with 7452 additions and 163 deletions

View File

@@ -2937,14 +2937,24 @@ static void print_blob_as_hex(FILE *output_file, const char *str, ulong len)
static uint dump_routines_for_db(char *db)
{
char query_buff[QUERY_LENGTH];
const char *routine_type[]= {"FUNCTION",
"PROCEDURE",
"PACKAGE",
"PACKAGE BODY"};
const char *create_caption_xml[]= {"Create Function",
"Create Procedure",
"Create Package",
"Create Package Body"};
struct routine_dump_param_st
{
const char *routine_type;
const char *create_caption_xml;
uint version;
};
/*
Package specifications can have public data type definitions.
So dump specifications first, before any other stored objects.
Note, before 10.3 packages are not supported.
*/
const routine_dump_param_st routine_dump_param_array[]=
{
{"PACKAGE", "Create Package", 100300},
{"FUNCTION", "Create Function", 0},
{"PROCEDURE", "Create Procedure", 0},
{"PACKAGE BODY", "Create Package Body", 100300}
};
char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
char *routine_name;
uint i;
@@ -2953,9 +2963,6 @@ static uint dump_routines_for_db(char *db)
char db_cl_name[MY_CS_COLLATION_NAME_SIZE];
int db_cl_altered= FALSE;
// before 10.3 packages are not supported
uint upper_bound= mysql_get_server_version(mysql) >= 100300 ?
array_elements(routine_type) : 2;
DBUG_ENTER("dump_routines_for_db");
DBUG_PRINT("enter", ("db: '%s'", db));
@@ -2985,11 +2992,14 @@ static uint dump_routines_for_db(char *db)
fputs("\t<routines>\n", sql_file);
/* 0, retrieve and dump functions, 1, procedures, etc. */
for (i= 0; i < upper_bound; i++)
for (i= 0; i < array_elements(routine_dump_param_array); i++)
{
const routine_dump_param_st *param= &routine_dump_param_array[i];
if (mysql_get_server_version(mysql) < param->version)
continue;
my_snprintf(query_buff, sizeof(query_buff),
"SHOW %s STATUS WHERE Db = '%s'",
routine_type[i], db_name_buff);
param->routine_type, db_name_buff);
if (mysql_query_with_error_report(mysql, &routine_list_res, query_buff))
DBUG_RETURN(1);
@@ -3000,10 +3010,10 @@ static uint dump_routines_for_db(char *db)
while ((routine_list_row= mysql_fetch_row(routine_list_res)))
{
routine_name= quote_name(routine_list_row[1], name_buff, 0);
DBUG_PRINT("info", ("retrieving CREATE %s for %s", routine_type[i],
DBUG_PRINT("info", ("retrieving CREATE %s for %s", param->routine_type,
name_buff));
my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s",
routine_type[i], routine_name);
param->routine_type, routine_name);
if (mysql_query_with_error_report(mysql, &routine_res, query_buff))
continue;
@@ -3032,7 +3042,7 @@ static uint dump_routines_for_db(char *db)
if (opt_xml)
{
print_xml_row(sql_file, "routine", routine_res, &row,
create_caption_xml[i]);
param->create_caption_xml);
continue;
}
@@ -3040,7 +3050,7 @@ static uint dump_routines_for_db(char *db)
if (opt_drop)
fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;\n",
routine_type[i], routine_name);
param->routine_type, routine_name);
if (mysql_num_fields(routine_res) >= 6)
{

View File

@@ -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

View File

@@ -48,27 +48,6 @@ $$
/*M!100616 SET @OLD_NOTE_VERBOSITY=@@NOTE_VERBOSITY, NOTE_VERBOSITY=0 */;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT' */ ;
/*!50003 DROP PROCEDURE IF EXISTS `p1` */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = latin1 */ ;
/*!50003 SET character_set_results = latin1 */ ;
/*!50003 SET collation_connection = latin1_swedish_ci */ ;
DELIMITER ;;
CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
AS
BEGIN
SELECT pkg1.f1(); -- a standalone routine calls a package routine
END
;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT' */ ;
/*!50003 DROP PACKAGE IF EXISTS `pkg1` */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
@@ -109,6 +88,27 @@ DELIMITER ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT' */ ;
/*!50003 DROP PROCEDURE IF EXISTS `p1` */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = latin1 */ ;
/*!50003 SET character_set_results = latin1 */ ;
/*!50003 SET collation_connection = latin1_swedish_ci */ ;
DELIMITER ;;
CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
AS
BEGIN
SELECT pkg1.f1(); -- a standalone routine calls a package routine
END
;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT' */ ;
/*!50003 DROP PACKAGE BODY IF EXISTS `pkg1` */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
@@ -147,15 +147,6 @@ DELIMITER ;
<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="test">
<routines>
<routine Procedure="p1" sql_mode="PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT" character_set_client="latin1" collation_connection="latin1_swedish_ci" Database_Collation="utf8mb4_uca1400_ai_ci">
<![CDATA[
CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
AS
BEGIN
SELECT pkg1.f1(); -- a standalone routine calls a package routine
END
]]>
</routine>
<routine Package="pkg1" sql_mode="PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT" character_set_client="latin1" collation_connection="latin1_swedish_ci" Database_Collation="utf8mb4_uca1400_ai_ci">
<![CDATA[
CREATE DEFINER="root"@"localhost" PACKAGE "pkg1" AS
@@ -170,6 +161,15 @@ CREATE DEFINER="root"@"localhost" PACKAGE "pkg2" AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END
]]>
</routine>
<routine Procedure="p1" sql_mode="PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT" character_set_client="latin1" collation_connection="latin1_swedish_ci" Database_Collation="utf8mb4_uca1400_ai_ci">
<![CDATA[
CREATE DEFINER="root"@"localhost" PROCEDURE "p1"()
AS
BEGIN
SELECT pkg1.f1(); -- a standalone routine calls a package routine
END
]]>
</routine>
<routine Package_body="pkg1" sql_mode="PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT" character_set_client="latin1" collation_connection="latin1_swedish_ci" Database_Collation="utf8mb4_uca1400_ai_ci">

View File

@@ -0,0 +1,117 @@
SET sql_mode=ORACLE;
#
# MDEV-39587 Package-wide TYPE for variable declarations
#
#
# MDEV-40148 Package spec RECORD-field %TYPE anchor is broken
#
CREATE TABLE t (id INT, name VARCHAR(100));
CREATE PACKAGE pkga AS
TYPE r IS RECORD (f t.id%TYPE);
END;
$$
CREATE PROCEDURE pa AS
v pkga.r; -- HERE
BEGIN
v.f := 1;
IF v.f = 1
THEN SELECT 'ok';
END IF;
END;
$$
CALL pa;
ok
ok
DROP PROCEDURE pa;
DROP PACKAGE pkga;
DROP TABLE t;
CREATE TABLE t (id INT, name VARCHAR(100));
CREATE PACKAGE pkga AS
TYPE r IS RECORD (f t.id%TYPE);
END;
$$
CREATE PROCEDURE pa AS
v test.pkga.r; -- HERE
BEGIN
v.f := 1;
IF v.f = 1
THEN SELECT 'ok';
END IF;
END;
$$
CALL pa;
ok
ok
DROP PROCEDURE pa;
DROP PACKAGE pkga;
DROP TABLE t;
CREATE TABLE t (id INT, name VARCHAR(100));
INSERT INTO t VALUES (10,'n10');
CREATE PACKAGE pkga AS
TYPE rec0_t IS RECORD (id t.id%TYPE, name t.name%TYPE);
TYPE cur0_t IS REF CURSOR RETURN pkga.rec0_t; -- HERE
END;
$$
CREATE PROCEDURE pa AS
c0 pkga.cur0_t;
r0 pkga.rec0_t;
BEGIN
OPEN c0 FOR SELECT id, name FROM t;
FETCH c0 INTO r0;
CLOSE c0;
SELECT r0.id, r0.name;
END;
$$
CALL pa;
r0.id r0.name
10 n10
DROP PROCEDURE pa;
DROP PACKAGE pkga;
DROP TABLE t;
CREATE TABLE t (id INT, name VARCHAR(100));
INSERT INTO t VALUES (10,'n10');
CREATE PACKAGE pkga AS
TYPE rec0_t IS RECORD (id t.id%TYPE, name t.name%TYPE);
TYPE cur0_t IS REF CURSOR RETURN test.pkga.rec0_t; -- HERE
END;
$$
CREATE PROCEDURE pa AS
c0 pkga.cur0_t;
r0 pkga.rec0_t;
BEGIN
OPEN c0 FOR SELECT id, name FROM t;
FETCH c0 INTO r0;
CLOSE c0;
SELECT r0.id, r0.name;
END;
$$
CALL pa;
r0.id r0.name
10 n10
DROP PROCEDURE pa;
DROP PACKAGE pkga;
DROP TABLE t;
#
# MDEV-40216 Assertion `thd->is_error() || thd->killed' failed in bool do_execute_sp(THD *, sp_head *)
#
CREATE TABLE tb (c_int INT);
CREATE PACKAGE pk AS
TYPE rec IS RECORD (f tb.c_int%TYPE);
TYPE aa IS TABLE OF INT INDEX BY INTEGER;
END;
$$
CREATE PROCEDURE p AS
r pk.rec;
v pk.aa;
BEGIN
r.f := 5;
v(r.f) := 99;
SELECT v(5);
END;
$$
CALL p;
v(5)
99
DROP PROCEDURE p;
DROP PACKAGE pk;
DROP TABLE tb;

View File

@@ -0,0 +1,632 @@
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 '<routine parameter>'
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 '<routine parameter>'
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;
#
# MDEV-40640 Assertion `li->sphead' failed in bool LEX::sp_package_spec_check_cyclic_dependency(THD *, const Lex_ident_sys_st &, const Lex_ident_sys_st &) const
#
CREATE PACKAGE p1 AS
TYPE rec0_t IS RECORD(x INT);
END;
$$
CREATE PACKAGE p2 AS
TYPE rec0_t IS RECORD(x INT);
TYPE assoc0_t IS TABLE OF p1.rec0_t INDEX BY INTEGER;
END;
$$
SHOW CREATE PACKAGE p2;
Package sql_mode Create Package character_set_client collation_connection Database Collation
p2 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" PACKAGE "p2" AS
TYPE rec0_t IS RECORD(x INT);
TYPE assoc0_t IS TABLE OF p1.rec0_t INDEX BY INTEGER;
END latin1 latin1_swedish_ci utf8mb4_uca1400_ai_ci
DROP PACKAGE p2;
DROP PACKAGE p1;
# Replacing the dependency package and removing the type
CREATE PACKAGE p1 AS
TYPE rec0_t IS RECORD(x INT);
END;
$$
CREATE PACKAGE p2 AS
TYPE rec0_t IS RECORD(x INT);
TYPE assoc0_t IS TABLE OF p1.rec0_t INDEX BY INTEGER;
END;
$$
CREATE OR REPLACE PACKAGE p1 AS
TYPE rec1_t IS RECORD(x INT); -- There is no type p1.rec0_t any more
END;
$$
SHOW CREATE PACKAGE p2;
ERROR HY000: Unknown data type: '`test`.`p1`.`rec0_t`'
DROP PACKAGE p2;
DROP PACKAGE p1;
# Dropping the dependency package
CREATE PACKAGE p1 AS
TYPE rec0_t IS RECORD(x INT);
END;
$$
CREATE PACKAGE p2 AS
TYPE rec0_t IS RECORD(x INT);
TYPE assoc0_t IS TABLE OF p1.rec0_t INDEX BY INTEGER;
END;
$$
DROP PACKAGE p1;
SHOW CREATE PACKAGE p2;
ERROR HY000: Unknown data type: '`p1`.`rec0_t`'
DROP PACKAGE p2;
#
# MDEV-40666 Cyclic package TYPE dependency built with associative array shows ERROR 1436 (HY000): Thread stack overrun
#
CREATE PACKAGE fa AS TYPE r IS RECORD(x INT); END;
$$
CREATE PACKAGE fb AS TYPE r2 IS RECORD(y INT); TYPE arr IS TABLE OF fa.r INDEX BY INTEGER; END;
$$
CREATE OR REPLACE PACKAGE fa AS TYPE r IS RECORD(x INT); TYPE arr2 IS TABLE OF fb.r2 INDEX BY INTEGER; END;
$$
ERROR HY000: Unknown data type: '`fb`.`r2`'
SHOW CREATE PACKAGE fa;
Package sql_mode Create Package character_set_client collation_connection Database Collation
fa PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" PACKAGE "fa" AS TYPE r IS RECORD(x INT); END latin1 latin1_swedish_ci utf8mb4_uca1400_ai_ci
SHOW CREATE PACKAGE fb;
Package sql_mode Create Package character_set_client collation_connection Database Collation
fb PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" PACKAGE "fb" AS TYPE r2 IS RECORD(y INT); TYPE arr IS TABLE OF fa.r INDEX BY INTEGER; END latin1 latin1_swedish_ci utf8mb4_uca1400_ai_ci
DROP PACKAGE fb;
DROP PACKAGE fa;
CREATE PACKAGE fa AS TYPE r IS RECORD(x INT); END;
$$
CREATE PACKAGE fb AS TYPE r2 IS RECORD(y INT); TYPE arr IS TABLE OF test.fa.r INDEX BY INTEGER; END;
$$
CREATE OR REPLACE PACKAGE fa AS TYPE r IS RECORD(x INT); TYPE arr2 IS TABLE OF test.fb.r2 INDEX BY INTEGER; END;
$$
ERROR HY000: Unknown data type: '`test`.`fb`.`r2`'
SHOW CREATE PACKAGE fa;
Package sql_mode Create Package character_set_client collation_connection Database Collation
fa PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" PACKAGE "fa" AS TYPE r IS RECORD(x INT); END latin1 latin1_swedish_ci utf8mb4_uca1400_ai_ci
SHOW CREATE PACKAGE fb;
Package sql_mode Create Package character_set_client collation_connection Database Collation
fb PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" PACKAGE "fb" AS TYPE r2 IS RECORD(y INT); TYPE arr IS TABLE OF test.fa.r INDEX BY INTEGER; END latin1 latin1_swedish_ci utf8mb4_uca1400_ai_ci
DROP PACKAGE fb;
DROP PACKAGE fa;
#
# MDEV-40685 Cyclic package TYPE dependency built with stored routine shows ERROR 1436 (HY000): Thread stack overrun
#
CREATE PACKAGE fa AS
TYPE r IS RECORD(x INT);
END;
$$
CREATE PACKAGE fb AS
TYPE r2 IS RECORD(y INT);
TYPE arr IS TABLE OF fa.r INDEX BY INTEGER;
END;
$$
CREATE OR REPLACE PACKAGE fa AS
TYPE r IS RECORD(x INT);
TYPE arr2 IS TABLE OF fb.r2 INDEX BY INTEGER;
END;
$$
ERROR HY000: Unknown data type: '`fb`.`r2`'
SHOW CREATE PACKAGE fa;
Package sql_mode Create Package character_set_client collation_connection Database Collation
fa PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" PACKAGE "fa" AS
TYPE r IS RECORD(x INT);
END latin1 latin1_swedish_ci utf8mb4_uca1400_ai_ci
DROP PACKAGE fa;
DROP PACKAGE fb;

View File

@@ -0,0 +1,31 @@
SET sql_mode=ORACLE;
#
# MDEV-39587 Package-wide TYPE for variable declarations
# MDEV-40114 Package-wide TYPE variable declarations fail during mariadb-dump restore
#
CREATE PACKAGE pkg1 AS
TYPE rec0_t IS RECORD (a INT, b VARCHAR(30));
END;
$$
CREATE PROCEDURE p1 AS
r pkg1.rec0_t;
BEGIN
r.a:=1;
SELECT r.a;
END;
$$
DROP DATABASE test;
CREATE DATABASE test;
USE test;
CALL p1;
r.a
1
SELECT routine_type, routine_name
FROM information_schema.routines
WHERE routine_schema='test'
ORDER BY routine_type, routine_name;
routine_type routine_name
PACKAGE pkg1
PROCEDURE p1
DROP PROCEDURE p1;
DROP PACKAGE pkg1;

View File

@@ -0,0 +1,20 @@
SET sql_mode=ORACLE;
#
# MDEV-39587 Package-wide TYPE for variable declarations
#
#
# MDEV-40686 Event using a package-defined type is silently lost during mariadb-dump / restore
#
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT);
END;
$$
CREATE EVENT ev ON SCHEDULE EVERY 1 HOUR DO
DECLARE
v pkg.rec;
BEGIN
NULL;
END;
$$
ERROR HY000: Incorrect usage of EVENT and `pkg`.`rec`
DROP PACKAGE pkg;

View File

@@ -0,0 +1,610 @@
#
# MDEV-39587 Package-wide TYPE for variable declarations
#
SET sql_mode=ORACLE;
CREATE DATABASE test1;
CREATE DATABASE test2;
CREATE USER user1@localhost;
CREATE USER user2@localhost;
GRANT CREATE ROUTINE ON test1.* TO user1@localhost;
GRANT CREATE ROUTINE ON test2.* TO user1@localhost;
GRANT CREATE ROUTINE ON test1.* TO user2@localhost;
GRANT CREATE ROUTINE ON test2.* TO user2@localhost;
connect conn_user1, localhost, user1,, test1;
SET sql_mode=ORACLE;
connect conn_user2, localhost, user2,, test1;
SET sql_mode=ORACLE;
connection conn_user1;
CREATE PACKAGE pkg1 AS
TYPE rec0_t IS RECORD (a INT, b VARCHAR(10));
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
END;
$$
connection conn_user1;
# Start of allowed.inc
SELECT CURRENT_USER;
CURRENT_USER
user1@localhost
#
# ACL_NONE + same user + same DB
#
USE test1;
# ACL_NONE + same user + same DB + PACKAGE type in the same PACKAGE BODY
CREATE PACKAGE BODY pkg1 AS
r0 pkg1.rec0_t;
END;
$$
DROP PACKAGE BODY pkg1;
CREATE PACKAGE BODY pkg1 AS
r0 test1.pkg1.rec0_t;
END;
$$
DROP PACKAGE BODY pkg1;
# ACL_NONE + same user + same DB + PACKAGE type in another PACKAGE
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
# ACL_NONE + same user + same DB + PACKAGE type in another PACKAGE BODY
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
# ACL_NONE + same user + same DB + PACKAGE type in a schema routine
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DROP PROCEDURE p1;
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DROP PROCEDURE p1;
#
# ACL_NONE + same user + different DB
#
USE test2;
# ACL_NONE + same user + different DB + PACKAGE type in another PACKAGE
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
# ACL_NONE + same user + different DB + PACKAGE type in another PACKAGE BODY
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
# ACL_NONE + same user + different DB + PACKAGE type in a schema routine
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DROP PROCEDURE p1;
# End of allowed.inc
connection conn_user2;
# Start of denied.inc
SELECT CURRENT_USER;
CURRENT_USER
user2@localhost
#
# ACL_NONE + different user + same DB
#
connection conn_user2;
USE test1;
# ACL_NONE + different user + same DB + PACKAGE type in the same PACKAGE BODY
CREATE PACKAGE BODY pkg1 AS
r0 pkg1.rec0_t;
END;
$$
ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'test1.pkg1'
CREATE PACKAGE BODY pkg1 AS
r0 test1.pkg1.rec0_t;
END;
$$
ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'test1.pkg1'
# ACL_NONE + different user + same DB + PACKAGE type in another PACKAGE
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END;
$$
ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'test1.pkg1'
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'test1.pkg1'
# ACL_NONE + different user + same DB + PACKAGE type in another PACKAGE BODY
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END;
$$
ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'test1.pkg1'
DROP PACKAGE pkg2;
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'test1.pkg1'
DROP PACKAGE pkg2;
# ACL_NONE + different user + same DB + PACKAGE type in a schema routine
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
BEGIN
NULL;
END;
$$
ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'test1.pkg1'
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
BEGIN
NULL;
END;
$$
ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'test1.pkg1'
#
# ACL_NONE + different user + different DB
#
USE test2;
ACL_NONE + different user + different DB + PACKAGE type in another PACKAGE
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'test1.pkg1'
ACL_NONE + different user + different DB + PACKAGE type in another PACKAGE BODY
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'test1.pkg1'
DROP PACKAGE pkg2;
ACL_NONE + different user + different DB + PACKAGE type in a schema routine
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
BEGIN
NULL;
END;
$$
ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'test1.pkg1'
# End of denied.inc
connection default;
GRANT EXECUTE ON PACKAGE test1.pkg1 TO user2@localhost;
connection conn_user2;
# Start of allowed.inc
SELECT CURRENT_USER;
CURRENT_USER
user2@localhost
#
# ACL_EXEC_test1.pkg1 + different user + same DB
#
USE test1;
# ACL_EXEC_test1.pkg1 + different user + same DB + PACKAGE type in the same PACKAGE BODY
CREATE PACKAGE BODY pkg1 AS
r0 pkg1.rec0_t;
END;
$$
DROP PACKAGE BODY pkg1;
CREATE PACKAGE BODY pkg1 AS
r0 test1.pkg1.rec0_t;
END;
$$
DROP PACKAGE BODY pkg1;
# ACL_EXEC_test1.pkg1 + different user + same DB + PACKAGE type in another PACKAGE
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
# ACL_EXEC_test1.pkg1 + different user + same DB + PACKAGE type in another PACKAGE BODY
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
# ACL_EXEC_test1.pkg1 + different user + same DB + PACKAGE type in a schema routine
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DROP PROCEDURE p1;
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DROP PROCEDURE p1;
#
# ACL_EXEC_test1.pkg1 + different user + different DB
#
USE test2;
# ACL_EXEC_test1.pkg1 + different user + different DB + PACKAGE type in another PACKAGE
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
# ACL_EXEC_test1.pkg1 + different user + different DB + PACKAGE type in another PACKAGE BODY
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DROP PACKAGE pkg2;
# ACL_EXEC_test1.pkg1 + different user + different DB + PACKAGE type in a schema routine
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DROP PROCEDURE p1;
# End of allowed.inc
connection default;
REVOKE EXECUTE ON PACKAGE test1.pkg1 FROM user2@localhost;
connection default;
disconnect conn_user1;
disconnect conn_user2;
DROP USER user1@localhost;
DROP USER user2@localhost;
DROP PACKAGE test1.pkg1;
DROP DATABASE test1;
DROP DATABASE test2;
#
# MDEV-40136 User without any privileges on the package schema can declare and use the package's record types
#
CREATE DATABASE secdb;
CREATE PACKAGE secdb.pkg AS
TYPE rec_t IS RECORD (a INT, secret VARCHAR(30));
FUNCTION f RETURN INT;
END;
$$
CREATE PACKAGE BODY secdb.pkg AS
FUNCTION f RETURN INT AS
BEGIN
RETURN 42;
END;
END;
$$
CREATE DATABASE appdb;
CREATE USER u_none@localhost;
GRANT ALL ON appdb.* TO u_none@localhost;
connect cnone, localhost, u_none,, appdb;
SET sql_mode=ORACLE;
CREATE PROCEDURE appdb.p AS r secdb.pkg.rec_t;
BEGIN
r.a:=1;
r.secret:='x';
SELECT r.a;
END;
$$
ERROR 42000: execute command denied to user 'u_none'@'localhost' for routine 'secdb.pkg'
connection default;
GRANT EXECUTE ON PACKAGE secdb.pkg TO u_none@localhost;
connection cnone;
CREATE PROCEDURE
appdb.p AS r secdb.pkg.rec_t;
BEGIN
r.a:=1;
r.secret:='x';
SELECT r.a;
END;
$$
CALL appdb.p;
r.a
1
SELECT secdb.pkg.f();
ERROR 42000: execute command denied to user 'u_none'@'localhost' for routine 'secdb.pkg'
connection default;
GRANT EXECUTE ON PACKAGE BODY secdb.pkg TO u_none@localhost;
connection cnone;
SELECT secdb.pkg.f();
secdb.pkg.f()
42
connection default;
disconnect cnone;
DROP USER u_none@localhost;
DROP DATABASE appdb;
DROP DATABASE secdb;
#
# MDEV-40278 Package type is wrongly DENIED when called by a low privilege invoker
#
CREATE DATABASE secdb;
CREATE DATABASE appdb;
CREATE USER low@localhost;
GRANT ALL ON appdb.* TO low@localhost;
CREATE PACKAGE secdb.vault AS
TYPE creds IS RECORD(username VARCHAR(64), pw VARCHAR(128));
FUNCTION f RETURN INT;
END;
$$
CREATE DEFINER=root@localhost PROCEDURE appdb.p_definer_root_security_none AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
CREATE PROCEDURE appdb.p_definer_none_security_none AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
CREATE DEFINER=low@localhost PROCEDURE appdb.p_definer_low_security_none AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
ERROR 42000: execute command denied to user 'low'@'localhost' for routine 'secdb.vault'
CREATE DEFINER=root@localhost PROCEDURE appdb.p_definer_root_security_invoker
SQL SECURITY INVOKER AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
CREATE PROCEDURE appdb.p_definer_none_security_invoker
SQL SECURITY INVOKER AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
CREATE DEFINER=low@localhost PROCEDURE appdb.p_definer_low_security_invoker
SQL SECURITY INVOKER AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
SELECT name, definer, security_type FROM mysql.proc
WHERE db='appdb' AND name LIKE 'p_%'
ORDER BY definer;
name definer security_type
p_definer_low_security_invoker low@localhost INVOKER
p_definer_root_security_none root@localhost DEFINER
p_definer_none_security_none root@localhost DEFINER
p_definer_root_security_invoker root@localhost INVOKER
p_definer_none_security_invoker root@localhost INVOKER
connect lowconn, localhost, low,,appdb;
SET sql_mode=ORACLE;
CREATE PROCEDURE appdb.p_definer_low1_security_none AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
ERROR 42000: execute command denied to user 'low'@'localhost' for routine 'secdb.vault'
CREATE PROCEDURE appdb.p_definer_low1_security_invoker
SQL SECURITY INVOKER AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
ERROR 42000: execute command denied to user 'low'@'localhost' for routine 'secdb.vault'
CALL appdb.p_definer_root_security_none();
r.username
admin
CALL appdb.p_definer_none_security_none();
r.username
admin
CALL appdb.p_definer_root_security_invoker();
ERROR 42000: execute command denied to user 'low'@'localhost' for routine 'secdb.vault'
CALL appdb.p_definer_none_security_invoker();
ERROR 42000: execute command denied to user 'low'@'localhost' for routine 'secdb.vault'
SHOW WARNINGS;
Level Code Message
Error 1370 execute command denied to user 'low'@'localhost' for routine 'secdb.vault'
connection default;
disconnect lowconn;
DROP USER low@localhost;
DROP DATABASE appdb;
DROP DATABASE secdb;
# Using secdb.vault package types in package procedure appdb.xxx.p1
SET sql_mode=ORACLE;
CREATE DATABASE secdb;
CREATE DATABASE appdb;
CREATE USER low@localhost;
GRANT ALL ON appdb.* TO low@localhost;
CREATE PACKAGE secdb.vault AS
TYPE creds IS RECORD(username VARCHAR(64), pw VARCHAR(128));
FUNCTION f RETURN INT;
END;
$$
CREATE PACKAGE appdb.pkg_definer_body_root_security_none AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=root@localhost PACKAGE BODY appdb.pkg_definer_body_root_security_none AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
CREATE PACKAGE appdb.pkg_definer_body_none_security_none AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY appdb.pkg_definer_body_none_security_none AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
CREATE PACKAGE appdb.pkg_definer_body_low_security_none AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=low@localhost PACKAGE BODY appdb.pkg_definer_body_low_security_none AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
ERROR 42000: execute command denied to user 'low'@'localhost' for routine 'secdb.vault'
DROP PACKAGE appdb.pkg_definer_body_low_security_none;
CREATE PACKAGE appdb.pkg_definer_body_root_security_invoker AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=root@localhost PACKAGE BODY appdb.pkg_definer_body_root_security_invoker
SQL SECURITY INVOKER AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
CREATE PACKAGE appdb.pkg_definer_body_none_security_invoker AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY appdb.pkg_definer_body_none_security_invoker
SQL SECURITY INVOKER AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
CREATE PACKAGE appdb.pkg_definer_body_low_security_invoker AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=low@localhost PACKAGE BODY appdb.pkg_definer_body_low_security_invoker
SQL SECURITY INVOKER AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
SELECT type, name, definer, security_type FROM mysql.proc
WHERE db='appdb' AND name LIKE 'pkg_%'
ORDER BY name, type, definer;
type name definer security_type
PACKAGE pkg_definer_body_low_security_invoker root@localhost DEFINER
PACKAGE BODY pkg_definer_body_low_security_invoker low@localhost INVOKER
PACKAGE pkg_definer_body_none_security_invoker root@localhost DEFINER
PACKAGE BODY pkg_definer_body_none_security_invoker root@localhost INVOKER
PACKAGE pkg_definer_body_none_security_none root@localhost DEFINER
PACKAGE BODY pkg_definer_body_none_security_none root@localhost DEFINER
PACKAGE pkg_definer_body_root_security_invoker root@localhost DEFINER
PACKAGE BODY pkg_definer_body_root_security_invoker root@localhost INVOKER
PACKAGE pkg_definer_body_root_security_none root@localhost DEFINER
PACKAGE BODY pkg_definer_body_root_security_none root@localhost DEFINER
connect lowconn, localhost, low,,appdb;
SET sql_mode=ORACLE;
CREATE PACKAGE appdb.pkg_definer_body_low_security_none AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=low@localhost PACKAGE BODY appdb.pkg_definer_body_low_security_none AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
ERROR 42000: execute command denied to user 'low'@'localhost' for routine 'secdb.vault'
CALL appdb.pkg_definer_body_root_security_none.p1();
r.username
admin
CALL appdb.pkg_definer_body_none_security_none.p1();
r.username
admin
CALL appdb.pkg_definer_body_root_security_invoker.p1();
ERROR 42000: execute command denied to user 'low'@'localhost' for routine 'secdb.vault'
CALL appdb.pkg_definer_body_none_security_invoker.p1();
ERROR 42000: execute command denied to user 'low'@'localhost' for routine 'secdb.vault'
connection default;
disconnect lowconn;
DROP USER low@localhost;
DROP DATABASE appdb;
DROP DATABASE secdb;

View File

@@ -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;

View File

@@ -0,0 +1,22 @@
SET sql_mode=ORACLE;
#
# MDEV-39587 Package-wide TYPE for variable declarations
#
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;
$$
DROP PACKAGE pkg1;
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;
$$
DROP PACKAGE pkg1;
CREATE PACKAGE pkg1 AS
TYPE rec0_t IS RECORD (a INT, b VARCHAR(32));
TYPE assoc0_t IS TABLE OF tttt.pkg1.rec0_t INDEX BY INTEGER;
END;
$$
ERROR HY000: Unknown data type: '`tttt`.`pkg1`.`rec0_t`'

View File

@@ -0,0 +1,22 @@
SET sql_mode=ORACLE;
#
# MDEV-39587 Package-wide TYPE for variable declarations
#
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;
$$
DROP PACKAGE pkg1;
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;
$$
ERROR HY000: Unknown data type: '`TEST`.`pkg1`.`rec0_t`'
CREATE PACKAGE pkg1 AS
TYPE rec0_t IS RECORD (a INT, b VARCHAR(32));
TYPE assoc0_t IS TABLE OF tttt.pkg1.rec0_t INDEX BY INTEGER;
END;
$$
ERROR HY000: Unknown data type: '`tttt`.`pkg1`.`rec0_t`'

View File

@@ -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;

View File

@@ -0,0 +1,330 @@
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;
# RECORD as a package routine parameter + 2-step self-reference
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
PROCEDURE q(v pkg1.no_such_type); -- 2-step self reference
END;
$$
ERROR HY000: Unknown data type: '`pkg1`.`no_such_type`'
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
PROCEDURE q(v pkg1.r); -- 2-step self reference
PROCEDURE exec();
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE q(v pkg1.r) AS
BEGIN
SELECT v.x;
END;
PROCEDURE exec() AS
v pkg1.r;
BEGIN
v.x:= 10;
q(v);
END;
END;
$$
CALL pkg1.exec();
v.x
10
DROP PACKAGE pkg1;
# RECORD as a package routine parameter + 3-step self-reference
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
PROCEDURE q(v test.pkg1.no_such_type); -- 3-step Self reference
END;
$$
ERROR HY000: Unknown data type: '`pkg1`.`no_such_type`'
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
PROCEDURE q(v test.pkg1.r); -- 3-step self reference
PROCEDURE exec();
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE q(v test.pkg1.r) AS
BEGIN
SELECT v.x;
END;
PROCEDURE exec() AS
v test.pkg1.r;
BEGIN
v.x:= 10;
q(v);
END;
END;
$$
CALL pkg1.exec();
v.x
10
DROP PACKAGE pkg1;
# RECORD as a package function RETURN type + 2-step self-reference
CREATE PACKAGE pkg1 AS
FUNCTION g RETURN pkg1.no_such_type; -- 2-step self-reference
END;
$$
ERROR HY000: Unknown data type: '`pkg1`.`no_such_type`'
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
FUNCTION g RETURN pkg1.r; -- 2-step self-reference
PROCEDURE exec;
END;
$$
CREATE PACKAGE BODY pkg1 AS
FUNCTION g RETURN pkg1.r AS
v pkg1.r;
BEGIN
v.x:= 10;
RETURN v;
END;
PROCEDURE exec AS
v pkg1.r;
BEGIN
v:= g();
SELECT v.x;
END;
END;
$$
CALL pkg1.exec();
v.x
10
DROP PACKAGE pkg1;
# RECORD as a package function RETURN type + 3-step self-reference
CREATE PACKAGE pkg1 AS
FUNCTION g RETURN test.pkg1.no_such_type; -- 3-step self-reference
END;
$$
ERROR HY000: Unknown data type: '`pkg1`.`no_such_type`'
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
FUNCTION g RETURN test.pkg1.r; -- 3-step self-reference
PROCEDURE exec;
END;
$$
CREATE PACKAGE BODY pkg1 AS
FUNCTION g RETURN test.pkg1.r AS
v test.pkg1.r;
BEGIN
v.x:= 10;
RETURN v;
END;
PROCEDURE exec AS
v test.pkg1.r;
BEGIN
v:= g();
SELECT v.x;
END;
END;
$$
CALL pkg1.exec();
v.x
10
DROP PACKAGE pkg1;
#
# MDEV-40721 SIGSEGV in LEX::sp_package_spec_check_cyclic_dependency | LEX::set_field_type_typedef_package_spec
#
CREATE PACKAGE emp_pkg AS
TYPE emp_rec IS RECORD (id INT);
FUNCTION get_emp(p_id INT) RETURN emp_rec;
END;
$$
CREATE PACKAGE BODY emp_pkg AS
FUNCTION get_emp(p_id INT) RETURN emp_pkg.emp_rec AS
v emp_pkg.emp_rec;
BEGIN
v.id := p_id;
RETURN v;
END;
END;
$$
CREATE PROCEDURE show_emp AS
v emp_pkg.emp_rec;
BEGIN
v := emp_pkg.get_emp(7);
SELECT v.id AS id;
END;
$$
CALL show_emp;
id
7
DROP PROCEDURE show_emp;
DROP PACKAGE emp_pkg;
CREATE PACKAGE emp_pkg AS
TYPE emp_rec IS RECORD (id INT);
PROCEDURE get_emp(p_id INT);
END;
$$
CREATE PACKAGE BODY emp_pkg AS
PROCEDURE get_emp(p_id INT) AS
v emp_pkg.emp_rec;
BEGIN
NULL;
END;
END;
$$
CREATE PROCEDURE show_emp AS
BEGIN
emp_pkg.get_emp(7);
END;
$$
CALL show_emp;
DROP PROCEDURE show_emp;
DROP PACKAGE emp_pkg;
CREATE PACKAGE t AS TYPE r IS RECORD (id INT); END; $$
CREATE PACKAGE a AS PROCEDURE q; END; $$
CREATE PACKAGE BODY a AS PROCEDURE q AS v t.r; BEGIN NULL; END; END; $$
CREATE PROCEDURE c AS BEGIN CALL a.q(); END; $$
CALL c;
DROP PROCEDURE c;
DROP PACKAGE a;
DROP PACKAGE t;

View File

@@ -0,0 +1,715 @@
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;
#
# MDEV-40420 ASAN : SIGSEGV in Sp_handler::db_find_routine | Sp_handler::db_find_and_cache_routine
#
CREATE DATABASE db1;
USE db1;
CREATE PACKAGE a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
END;
$$
CREATE PACKAGE b_pkg AS
TYPE brec IS RECORD (p INT, q VARCHAR(10));
TYPE bcur IS REF CURSOR RETURN a_pkg.arec;
END;
$$
CREATE PACKAGE a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
TYPE acur IS REF CURSOR RETURN b_pkg.brec;
END;
$$
ERROR HY000: Unknown data type: '`b_pkg`.`brec`'
# Inject manually a bad CREATE PACKAGE with cyclic dependency
SELECT `body` FROM mysql.proc WHERE db='db1' AND name='a_pkg';
body
AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
END
UPDATE mysql.proc SET `body`='AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
TYPE acur IS REF CURSOR RETURN b_pkg.brec;
END'
WHERE db='db1' AND name='a_pkg';
# Check that it's not allowed to create a PROCEDURE using a
# manually injected PACKAGE with a cycle dependency
CREATE PROCEDURE p_cycle AS
c a_pkg.acur;
BEGIN
NULL;
END;
$$
ERROR HY000: Thread stack overrun: XXX bytes used of a XXX byte stack, and XXX bytes needed. Consider increasing the thread_stack system variable.
# The same, after SP cache invalidating
SET sql_mode=DEFAULT;
# source invalidate_sp_cache.inc
SET sql_mode=ORACLE;
CREATE PROCEDURE p_cycle AS
c a_pkg.acur;
BEGIN
NULL;
END;
$$
ERROR HY000: Thread stack overrun: XXX bytes used of a XXX byte stack, and XXX bytes needed. Consider increasing the thread_stack system variable.
# Check that a manually injected PACKAGE with a cycle dependency
# can be fixed using CREATE OR REPLACE
CREATE OR REPLACE PACKAGE a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
END;
$$
DROP DATABASE db1;
USE test;
# The same layout, with 3-step data type references
CREATE DATABASE db1;
CREATE DATABASE db2;
CREATE PACKAGE db1.a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
END;
$$
CREATE PACKAGE db2.b_pkg AS
TYPE brec IS RECORD (p INT, q VARCHAR(10));
TYPE bcur IS REF CURSOR RETURN db1.a_pkg.arec;
END;
$$
CREATE OR REPLACE PACKAGE db1.a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
TYPE acur IS REF CURSOR RETURN db2.b_pkg.brec;
END;
$$
ERROR HY000: Unknown data type: '`db2`.`b_pkg`.`brec`'
DROP DATABASE db2;
DROP DATABASE db1;
#
# MDEV-40468 Package that contains a self reference package refcursor crashes the server
#
CREATE DATABASE db1;
USE db1;
CREATE TABLE t1 (a INT, b VARCHAR(32));
INSERT INTO t1 VALUES (1,'one'),(2,'two');
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT, b VARCHAR(32));
TYPE cur IS REF CURSOR RETURN pkg.rec; -- 2-step self reference
END;
$$
CREATE PROCEDURE p2 AS
TYPE localcur IS REF CURSOR RETURN pkg.rec;
c localcur;
v pkg.rec;
BEGIN
OPEN c FOR SELECT a,b FROM t1;
FETCH c INTO v;
CLOSE c;
END;
$$
CALL p2;
DROP DATABASE db1;
USE test;
CREATE DATABASE db1;
USE db1;
CREATE TABLE t1 (a INT, b VARCHAR(32));
INSERT INTO t1 VALUES (1,'one'),(2,'two');
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT, b VARCHAR(32));
TYPE cur IS REF CURSOR RETURN db1.pkg.rec; -- 3-step self-reference
END;
$$
CREATE PROCEDURE p2 AS
TYPE localcur IS REF CURSOR RETURN pkg.rec;
c localcur;
v pkg.rec;
BEGIN
OPEN c FOR SELECT a,b FROM t1;
FETCH c INTO v;
CLOSE c;
END;
$$
CALL p2;
DROP DATABASE db1;
USE test;
#
# MDEV-40640 Assertion `li->sphead' failed in bool LEX::sp_package_spec_check_cyclic_dependency(THD *, const Lex_ident_sys_st &, const Lex_ident_sys_st &) const
#
CREATE PACKAGE p1 AS TYPE r IS RECORD(x INT); END;$$
CREATE PACKAGE p2 AS TYPE r IS RECORD(x INT); TYPE c IS REF CURSOR RETURN p1.r; END;$$
SHOW CREATE PACKAGE p2;
Package sql_mode Create Package character_set_client collation_connection Database Collation
p2 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" PACKAGE "p2" AS TYPE r IS RECORD(x INT); TYPE c IS REF CURSOR RETURN p1.r; END latin1 latin1_swedish_ci utf8mb4_uca1400_ai_ci
DROP PACKAGE p2;
DROP PACKAGE p1;
# Replacing the dependency package and removing the type
CREATE PACKAGE pkg1 AS
TYPE rec0_t IS RECORD (a INT, b VARCHAR(10));
END;
$$
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END
$$
SHOW CREATE PACKAGE pkg2;
Package sql_mode Create Package character_set_client collation_connection Database Collation
pkg2 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" PACKAGE "pkg2" AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END latin1 latin1_swedish_ci utf8mb4_uca1400_ai_ci
CREATE OR REPLACE PACKAGE pkg1 AS
TYPE rec1_t IS RECORD (a INT, b VARCHAR(10)); -- There is no rec0_t any more
END;
$$
SHOW CREATE PACKAGE pkg2;
ERROR HY000: Unknown data type: '`test`.`pkg1`.`rec0_t`'
DROP PACKAGE pkg2;
DROP PACKAGE pkg1;
# Dropping the dependency package
CREATE PACKAGE pkg1 AS
TYPE rec0_t IS RECORD (a INT, b VARCHAR(10));
END;
$$
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END
$$
SHOW CREATE PACKAGE pkg2;
Package sql_mode Create Package character_set_client collation_connection Database Collation
pkg2 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" PACKAGE "pkg2" AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END latin1 latin1_swedish_ci utf8mb4_uca1400_ai_ci
DROP PACKAGE pkg1;
SHOW CREATE PACKAGE pkg2;
ERROR HY000: Unknown data type: '`pkg1`.`rec0_t`'
DROP PACKAGE pkg2;

View File

@@ -0,0 +1,13 @@
SET sql_mode=ORACLE;
#
# MDEV-39587 Package-wide TYPE for variable declarations
#
#
# MDEV-40597 UBSAN | SIGSEGV in ORAparse | parse_sql | sp_compile | Sp_handler::db_load_routine
#
CREATE DATABASE db1;
USE db1;
CREATE PACKAGE pkg1500 AS TYPE rec IS RECORD(x INT); END;$$
ER_STACK_OVERRUN_NEED_MORE reached;
DROP DATABASE db1;
USE test;

View File

@@ -0,0 +1,84 @@
SET sql_mode=ORACLE;
#
# MDEV-39587 Package-wide TYPE for variable declarations
#
#
# MDEV-40436 Trigger using a package-defined type is silently lost during mariadb-dump / restore
#
CREATE DATABASE db1;
USE db1;
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT, b VARCHAR(20));
END;
$$
CREATE TABLE t1 (id INT, val VARCHAR(20));
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
r pkg.rec;
BEGIN
:NEW.val := CONCAT('r-', :NEW.id);
END;
$$
ERROR HY000: Incorrect usage of TRIGGER and `pkg`.`rec`
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
r db1.pkg.rec;
BEGIN
:NEW.val := CONCAT('r-', :NEW.id);
END;
$$
ERROR HY000: Incorrect usage of TRIGGER and `db1`.`pkg`.`rec`
DROP DATABASE db1;
USE test;
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT);
END;
$$
CREATE TABLE t1 (a INT);
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
TYPE c IS REF CURSOR RETURN pkg.rec;
BEGIN
NULL;
END;
$$
ERROR HY000: Incorrect usage of TRIGGER and `pkg`.`rec`
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
TYPE c IS REF CURSOR RETURN test.pkg.rec;
BEGIN
NULL;
END;
$$
ERROR HY000: Incorrect usage of TRIGGER and `test`.`pkg`.`rec`
DROP TABLE t1;
DROP PACKAGE pkg;
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT);
END;
$$
CREATE TABLE t1 (a INT);
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
TYPE c IS TABLE OF pkg.rec INDEX BY int;
BEGIN
NULL;
END;
$$
ERROR HY000: Incorrect usage of TRIGGER and `pkg`.`rec`
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
TYPE c IS TABLE OF test.pkg.rec INDEX BY int;
BEGIN
NULL;
END;
$$
ERROR HY000: Incorrect usage of TRIGGER and `test`.`pkg`.`rec`
DROP TABLE t1;
DROP PACKAGE pkg;

View File

@@ -0,0 +1,156 @@
SET sql_mode=ORACLE;
SET NAMES utf8mb3;
#
# MDEV-39587 Package-wide TYPE for variable declarations
#
# raise_unknown_data_type
CREATE PROCEDURE p1 AS
a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
BEGIN
NULL;
END;
$$
ERROR HY000: Unknown data type: '`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`.`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`'
CREATE PROCEDURE p1 AS
a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
BEGIN
NULL;
END;
$$
ERROR HY000: Unknown data type: '`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`.`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`.`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`'
CREATE PROCEDURE p1 AS
a åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå.
åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå;
BEGIN
NULL;
END;
$$
ERROR HY000: Unknown data type: '`åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå`.`åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå`'
CREATE PROCEDURE p1 AS
a åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå.
åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå.
åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå;
BEGIN
NULL;
END;
$$
ERROR HY000: Unknown data type: '`åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå`.`åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå`.'
CREATE PROCEDURE p1 AS
a €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€.
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€;
BEGIN
NULL;
END;
$$
ERROR HY000: Unknown data type: '`€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€`.'
CREATE PROCEDURE p1 AS
a €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€.
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€.
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€;
BEGIN
NULL;
END;
$$
ERROR HY000: Unknown data type: '`€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€`..'
# 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`'
#
# MDEV-40155 Weak REF CURSOR without RETURN is not opened using a dynamic SQL statement
#
CREATE TABLE t (id INT, name VARCHAR(100));
INSERT INTO t VALUES (1,'Test');
CREATE PACKAGE pc AS TYPE wc IS REF CURSOR; END;
$$
CREATE PROCEDURE pdyn AS
c pc.wc;
vi INT;
vn VARCHAR(100);
BEGIN
OPEN c FOR 'SELECT id, name FROM t';
FETCH c INTO vi, vn;
SELECT vi, vn;
CLOSE c;
END;
$$
CALL pdyn;
vi vn
1 Test
DROP PROCEDURE pdyn;
DROP PACKAGE pc;
DROP TABLE t;
#
# MDEV-40153 Assertion `rec->field->head()->charset == nullptr' failed in virtual bool Type_handler_row::Column_definition_prepare_stage1(THD *, MEM_ROOT *, Column_definition *, column_definition_type_t, const Column_derived_attributes *) const
#
CREATE PACKAGE pk_crash AS
TYPE r IS RECORD (b BLOB);
FUNCTION f RETURN r;
END;
$$
DROP PACKAGE pk_crash;
CREATE PACKAGE pk_crash AS
TYPE rec0_t IS RECORD (b BLOB);
FUNCTION f(r rec0_t) RETURN INT;
END;
$$
DROP PACKAGE pk_crash;

View File

@@ -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`'

View File

@@ -0,0 +1,137 @@
SET sql_mode=ORACLE;
--echo #
--echo # MDEV-39587 Package-wide TYPE for variable declarations
--echo #
--echo #
--echo # MDEV-40148 Package spec RECORD-field %TYPE anchor is broken
--echo #
# Two step reference from a procedure to a package spec
CREATE TABLE t (id INT, name VARCHAR(100));
DELIMITER $$;
CREATE PACKAGE pkga AS
TYPE r IS RECORD (f t.id%TYPE);
END;
$$
CREATE PROCEDURE pa AS
v pkga.r; -- HERE
BEGIN
v.f := 1;
IF v.f = 1
THEN SELECT 'ok';
END IF;
END;
$$
DELIMITER ;$$
CALL pa;
DROP PROCEDURE pa;
DROP PACKAGE pkga;
DROP TABLE t;
# Three step reference from a procedure to a package spec
CREATE TABLE t (id INT, name VARCHAR(100));
DELIMITER $$;
CREATE PACKAGE pkga AS
TYPE r IS RECORD (f t.id%TYPE);
END;
$$
CREATE PROCEDURE pa AS
v test.pkga.r; -- HERE
BEGIN
v.f := 1;
IF v.f = 1
THEN SELECT 'ok';
END IF;
END;
$$
DELIMITER ;$$
CALL pa;
DROP PROCEDURE pa;
DROP PACKAGE pkga;
DROP TABLE t;
# Two step reference from a package spec to the same package spec
CREATE TABLE t (id INT, name VARCHAR(100));
INSERT INTO t VALUES (10,'n10');
DELIMITER $$;
CREATE PACKAGE pkga AS
TYPE rec0_t IS RECORD (id t.id%TYPE, name t.name%TYPE);
TYPE cur0_t IS REF CURSOR RETURN pkga.rec0_t; -- HERE
END;
$$
CREATE PROCEDURE pa AS
c0 pkga.cur0_t;
r0 pkga.rec0_t;
BEGIN
OPEN c0 FOR SELECT id, name FROM t;
FETCH c0 INTO r0;
CLOSE c0;
SELECT r0.id, r0.name;
END;
$$
DELIMITER ;$$
CALL pa;
DROP PROCEDURE pa;
DROP PACKAGE pkga;
DROP TABLE t;
# Three step reference from a package spec to the same package spec
CREATE TABLE t (id INT, name VARCHAR(100));
INSERT INTO t VALUES (10,'n10');
DELIMITER $$;
CREATE PACKAGE pkga AS
TYPE rec0_t IS RECORD (id t.id%TYPE, name t.name%TYPE);
TYPE cur0_t IS REF CURSOR RETURN test.pkga.rec0_t; -- HERE
END;
$$
CREATE PROCEDURE pa AS
c0 pkga.cur0_t;
r0 pkga.rec0_t;
BEGIN
OPEN c0 FOR SELECT id, name FROM t;
FETCH c0 INTO r0;
CLOSE c0;
SELECT r0.id, r0.name;
END;
$$
DELIMITER ;$$
CALL pa;
DROP PROCEDURE pa;
DROP PACKAGE pkga;
DROP TABLE t;
--echo #
--echo # MDEV-40216 Assertion `thd->is_error() || thd->killed' failed in bool do_execute_sp(THD *, sp_head *)
--echo #
CREATE TABLE tb (c_int INT);
DELIMITER $$;
CREATE PACKAGE pk AS
TYPE rec IS RECORD (f tb.c_int%TYPE);
TYPE aa IS TABLE OF INT INDEX BY INTEGER;
END;
$$
CREATE PROCEDURE p AS
r pk.rec;
v pk.aa;
BEGIN
r.f := 5;
v(r.f) := 99;
SELECT v(5);
END;
$$
DELIMITER ;$$
CALL p;
DROP PROCEDURE p;
DROP PACKAGE pk;
DROP TABLE tb;

View File

@@ -0,0 +1,675 @@
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;
--echo #
--echo # MDEV-40640 Assertion `li->sphead' failed in bool LEX::sp_package_spec_check_cyclic_dependency(THD *, const Lex_ident_sys_st &, const Lex_ident_sys_st &) const
--echo #
DELIMITER $$;
CREATE PACKAGE p1 AS
TYPE rec0_t IS RECORD(x INT);
END;
$$
CREATE PACKAGE p2 AS
TYPE rec0_t IS RECORD(x INT);
TYPE assoc0_t IS TABLE OF p1.rec0_t INDEX BY INTEGER;
END;
$$
DELIMITER ;$$
SHOW CREATE PACKAGE p2;
DROP PACKAGE p2;
DROP PACKAGE p1;
--echo # Replacing the dependency package and removing the type
DELIMITER $$;
CREATE PACKAGE p1 AS
TYPE rec0_t IS RECORD(x INT);
END;
$$
CREATE PACKAGE p2 AS
TYPE rec0_t IS RECORD(x INT);
TYPE assoc0_t IS TABLE OF p1.rec0_t INDEX BY INTEGER;
END;
$$
CREATE OR REPLACE PACKAGE p1 AS
TYPE rec1_t IS RECORD(x INT); -- There is no type p1.rec0_t any more
END;
$$
DELIMITER ;$$
--error ER_UNKNOWN_DATA_TYPE
SHOW CREATE PACKAGE p2;
DROP PACKAGE p2;
DROP PACKAGE p1;
--echo # Dropping the dependency package
DELIMITER $$;
CREATE PACKAGE p1 AS
TYPE rec0_t IS RECORD(x INT);
END;
$$
CREATE PACKAGE p2 AS
TYPE rec0_t IS RECORD(x INT);
TYPE assoc0_t IS TABLE OF p1.rec0_t INDEX BY INTEGER;
END;
$$
DELIMITER ;$$
DROP PACKAGE p1;
--error ER_UNKNOWN_DATA_TYPE
SHOW CREATE PACKAGE p2;
DROP PACKAGE p2;
--echo #
--echo # MDEV-40666 Cyclic package TYPE dependency built with associative array shows ERROR 1436 (HY000): Thread stack overrun
--echo #
DELIMITER $$;
CREATE PACKAGE fa AS TYPE r IS RECORD(x INT); END;
$$
CREATE PACKAGE fb AS TYPE r2 IS RECORD(y INT); TYPE arr IS TABLE OF fa.r INDEX BY INTEGER; END;
$$
--error ER_UNKNOWN_DATA_TYPE
CREATE OR REPLACE PACKAGE fa AS TYPE r IS RECORD(x INT); TYPE arr2 IS TABLE OF fb.r2 INDEX BY INTEGER; END;
$$
DELIMITER ;$$
SHOW CREATE PACKAGE fa;
SHOW CREATE PACKAGE fb;
DROP PACKAGE fb;
DROP PACKAGE fa;
DELIMITER $$;
CREATE PACKAGE fa AS TYPE r IS RECORD(x INT); END;
$$
CREATE PACKAGE fb AS TYPE r2 IS RECORD(y INT); TYPE arr IS TABLE OF test.fa.r INDEX BY INTEGER; END;
$$
--error ER_UNKNOWN_DATA_TYPE
CREATE OR REPLACE PACKAGE fa AS TYPE r IS RECORD(x INT); TYPE arr2 IS TABLE OF test.fb.r2 INDEX BY INTEGER; END;
$$
DELIMITER ;$$
SHOW CREATE PACKAGE fa;
SHOW CREATE PACKAGE fb;
DROP PACKAGE fb;
DROP PACKAGE fa;
--echo #
--echo # MDEV-40685 Cyclic package TYPE dependency built with stored routine shows ERROR 1436 (HY000): Thread stack overrun
--echo #
DELIMITER $$;
CREATE PACKAGE fa AS
TYPE r IS RECORD(x INT);
END;
$$
CREATE PACKAGE fb AS
TYPE r2 IS RECORD(y INT);
TYPE arr IS TABLE OF fa.r INDEX BY INTEGER;
END;
$$
--error ER_UNKNOWN_DATA_TYPE
CREATE OR REPLACE PACKAGE fa AS
TYPE r IS RECORD(x INT);
TYPE arr2 IS TABLE OF fb.r2 INDEX BY INTEGER;
END;
$$
DELIMITER ;$$
SHOW CREATE PACKAGE fa;
DROP PACKAGE fa;
DROP PACKAGE fb;

View File

@@ -0,0 +1,45 @@
# Embedded server doesn't support external clients
--source include/not_embedded.inc
SET sql_mode=ORACLE;
--echo #
--echo # MDEV-39587 Package-wide TYPE for variable declarations
--echo # MDEV-40114 Package-wide TYPE variable declarations fail during mariadb-dump restore
--echo #
DELIMITER $$;
CREATE PACKAGE pkg1 AS
TYPE rec0_t IS RECORD (a INT, b VARCHAR(30));
END;
$$
CREATE PROCEDURE p1 AS
r pkg1.rec0_t;
BEGIN
r.a:=1;
SELECT r.a;
END;
$$
DELIMITER ;$$
--exec $MYSQL_DUMP --skip-comments --routines --databases test > $MYSQLTEST_VARDIR/tmp/b40114.sql
DROP DATABASE test;
CREATE DATABASE test;
--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/b40114.sql 2>&1
USE test;
CALL p1;
SELECT routine_type, routine_name
FROM information_schema.routines
WHERE routine_schema='test'
ORDER BY routine_type, routine_name;
--remove_file $MYSQLTEST_VARDIR/tmp/b40114.sql
DROP PROCEDURE p1;
DROP PACKAGE pkg1;

View File

@@ -0,0 +1,25 @@
SET sql_mode=ORACLE;
--echo #
--echo # MDEV-39587 Package-wide TYPE for variable declarations
--echo #
--echo #
--echo # MDEV-40686 Event using a package-defined type is silently lost during mariadb-dump / restore
--echo #
DELIMITER $$;
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT);
END;
$$
--error ER_WRONG_USAGE
CREATE EVENT ev ON SCHEDULE EVERY 1 HOUR DO
DECLARE
v pkg.rec;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg;

View File

@@ -0,0 +1,145 @@
--echo # Start of allowed.inc
SELECT CURRENT_USER;
--echo #
--echo # $acl + $user + same DB
--echo #
USE test1;
--echo # $acl + $user + same DB + PACKAGE type in the same PACKAGE BODY
# Does not work !!!
#DELIMITER $$;
#CREATE PACKAGE BODY pkg1 AS
# r0 rec0_t;
#END;
#$$
#DELIMITER ;$$
DELIMITER $$;
CREATE PACKAGE BODY pkg1 AS
r0 pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DROP PACKAGE BODY pkg1;
DELIMITER $$;
CREATE PACKAGE BODY pkg1 AS
r0 test1.pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DROP PACKAGE BODY pkg1;
--echo # $acl + $user + same DB + PACKAGE type in another PACKAGE
DELIMITER $$;
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg2;
DELIMITER $$;
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg2;
--echo # $acl + $user + same DB + PACKAGE type in another PACKAGE BODY
DELIMITER $$;
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg2;
DELIMITER $$;
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg2;
--echo # $acl + $user + same DB + PACKAGE type in a schema routine
DELIMITER $$;
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DROP PROCEDURE p1;
DELIMITER $$;
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DROP PROCEDURE p1;
--echo #
--echo # $acl + $user + different DB
--echo #
USE test2;
--echo # $acl + $user + different DB + PACKAGE type in another PACKAGE
DELIMITER $$;
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg2;
--echo # $acl + $user + different DB + PACKAGE type in another PACKAGE BODY
DELIMITER $$;
CREATE PACKAGE pkg2 AS
END;
$$
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg2;
--echo # $acl + $user + different DB + PACKAGE type in a schema routine
DELIMITER $$;
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DROP PROCEDURE p1;
--echo # End of allowed.inc

View File

@@ -0,0 +1,150 @@
--echo # Start of denied.inc
SELECT CURRENT_USER;
--echo #
--echo # $acl + $user + same DB
--echo #
connection conn_user2;
USE test1;
--echo # $acl + $user + same DB + PACKAGE type in the same PACKAGE BODY
# Does not work !!!
#DELIMITER $$;
#CREATE PACKAGE BODY pkg1 AS
# r0 rec0_t;
#END;
#$$
#DELIMITER ;$$
DELIMITER $$;
--error ER_PROCACCESS_DENIED_ERROR
CREATE PACKAGE BODY pkg1 AS
r0 pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_PROCACCESS_DENIED_ERROR
CREATE PACKAGE BODY pkg1 AS
r0 test1.pkg1.rec0_t;
END;
$$
DELIMITER ;$$
--echo # $acl + $user + same DB + PACKAGE type in another PACKAGE
DELIMITER $$;
--error ER_PROCACCESS_DENIED_ERROR
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_PROCACCESS_DENIED_ERROR
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DELIMITER ;$$
--echo # $acl + $user + same DB + PACKAGE type in another PACKAGE BODY
DELIMITER $$;
CREATE PACKAGE pkg2 AS
END;
$$
--error ER_PROCACCESS_DENIED_ERROR
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg2;
DELIMITER $$;
CREATE PACKAGE pkg2 AS
END;
$$
--error ER_PROCACCESS_DENIED_ERROR
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg2;
--echo # $acl + $user + same DB + PACKAGE type in a schema routine
DELIMITER $$;
--error ER_PROCACCESS_DENIED_ERROR
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_PROCACCESS_DENIED_ERROR
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
--echo #
--echo # $acl + $user + different DB
--echo #
USE test2;
--echo $acl + $user + different DB + PACKAGE type in another PACKAGE
DELIMITER $$;
--error ER_PROCACCESS_DENIED_ERROR
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DELIMITER ;$$
--echo $acl + $user + different DB + PACKAGE type in another PACKAGE BODY
DELIMITER $$;
CREATE PACKAGE pkg2 AS
END;
$$
--error ER_PROCACCESS_DENIED_ERROR
CREATE PACKAGE BODY pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg2;
--echo $acl + $user + different DB + PACKAGE type in a schema routine
DELIMITER $$;
--error ER_PROCACCESS_DENIED_ERROR
CREATE PROCEDURE p1 AS
TYPE cur1_t IS REF CURSOR RETURN test1.pkg1.rec0_t;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
--echo # End of denied.inc

View File

@@ -0,0 +1,409 @@
# Grant tests not performed with embedded server
--source include/not_embedded.inc
--echo #
--echo # MDEV-39587 Package-wide TYPE for variable declarations
--echo #
SET sql_mode=ORACLE;
CREATE DATABASE test1;
CREATE DATABASE test2;
CREATE USER user1@localhost;
CREATE USER user2@localhost;
GRANT CREATE ROUTINE ON test1.* TO user1@localhost;
GRANT CREATE ROUTINE ON test2.* TO user1@localhost;
GRANT CREATE ROUTINE ON test1.* TO user2@localhost;
GRANT CREATE ROUTINE ON test2.* TO user2@localhost;
connect (conn_user1, localhost, user1,, test1);
SET sql_mode=ORACLE;
connect (conn_user2, localhost, user2,, test1);
SET sql_mode=ORACLE;
connection conn_user1;
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 ;$$
connection conn_user1;
--let acl=ACL_NONE
--let user=same user
--source sp-package-spec-type-grant-allowed.inc
connection conn_user2;
--let acl=ACL_NONE
--let user=different user
--source sp-package-spec-type-grant-denied.inc
connection default;
GRANT EXECUTE ON PACKAGE test1.pkg1 TO user2@localhost;
connection conn_user2;
--let acl=ACL_EXEC_test1.pkg1
--let user=different user
--source sp-package-spec-type-grant-allowed.inc
connection default;
REVOKE EXECUTE ON PACKAGE test1.pkg1 FROM user2@localhost;
connection default;
disconnect conn_user1;
disconnect conn_user2;
DROP USER user1@localhost;
DROP USER user2@localhost;
DROP PACKAGE test1.pkg1;
DROP DATABASE test1;
DROP DATABASE test2;
--echo #
--echo # MDEV-40136 User without any privileges on the package schema can declare and use the package's record types
--echo #
CREATE DATABASE secdb;
DELIMITER $$;
CREATE PACKAGE secdb.pkg AS
TYPE rec_t IS RECORD (a INT, secret VARCHAR(30));
FUNCTION f RETURN INT;
END;
$$
CREATE PACKAGE BODY secdb.pkg AS
FUNCTION f RETURN INT AS
BEGIN
RETURN 42;
END;
END;
$$
DELIMITER ;$$
CREATE DATABASE appdb;
CREATE USER u_none@localhost;
# No privilege on secdb
GRANT ALL ON appdb.* TO u_none@localhost;
connect (cnone, localhost, u_none,, appdb);
SET sql_mode=ORACLE;
# The server does not allow a package to be created using a record type
# defined in a package owned by another schema,
# as the user u_none has no EXECUTE privilege on the PACKAGE secdb.pkg.
DELIMITER $$;
--error ER_PROCACCESS_DENIED_ERROR
CREATE PROCEDURE appdb.p AS r secdb.pkg.rec_t;
BEGIN
r.a:=1;
r.secret:='x';
SELECT r.a;
END;
$$
DELIMITER ;$$
connection default;
GRANT EXECUTE ON PACKAGE secdb.pkg TO u_none@localhost;
connection cnone;
# Now u_none can use the data type secdb.pkg
DELIMITER $$;
CREATE PROCEDURE
appdb.p AS r secdb.pkg.rec_t;
BEGIN
r.a:=1;
r.secret:='x';
SELECT r.a;
END;
$$
DELIMITER ;$$
CALL appdb.p;
# However it cannot execute the routine without the EXECUTE privilege
# on the PACKAGE BODY secdb.pkg (privileges on a PACKAGE does not
# automatically give privileges on its PACKAGE BODY)
--error ER_PROCACCESS_DENIED_ERROR
SELECT secdb.pkg.f();
# Now grant privileges on PACKAGE BODY and execute a package routine
connection default;
GRANT EXECUTE ON PACKAGE BODY secdb.pkg TO u_none@localhost;
connection cnone;
SELECT secdb.pkg.f();
connection default;
disconnect cnone;
DROP USER u_none@localhost;
DROP DATABASE appdb;
DROP DATABASE secdb;
--echo #
--echo # MDEV-40278 Package type is wrongly DENIED when called by a low privilege invoker
--echo #
CREATE DATABASE secdb;
CREATE DATABASE appdb;
CREATE USER low@localhost;
GRANT ALL ON appdb.* TO low@localhost; # NO privilege on secdb
DELIMITER $$;
CREATE PACKAGE secdb.vault AS
TYPE creds IS RECORD(username VARCHAR(64), pw VARCHAR(128));
FUNCTION f RETURN INT;
END;
$$
CREATE DEFINER=root@localhost PROCEDURE appdb.p_definer_root_security_none AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
CREATE PROCEDURE appdb.p_definer_none_security_none AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
--error ER_PROCACCESS_DENIED_ERROR
CREATE DEFINER=low@localhost PROCEDURE appdb.p_definer_low_security_none AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
# With invoker
CREATE DEFINER=root@localhost PROCEDURE appdb.p_definer_root_security_invoker
SQL SECURITY INVOKER AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
CREATE PROCEDURE appdb.p_definer_none_security_invoker
SQL SECURITY INVOKER AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
CREATE DEFINER=low@localhost PROCEDURE appdb.p_definer_low_security_invoker
SQL SECURITY INVOKER AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
DELIMITER ;$$
SELECT name, definer, security_type FROM mysql.proc
WHERE db='appdb' AND name LIKE 'p_%'
ORDER BY definer;
connect(lowconn, localhost, low,,appdb);
SET sql_mode=ORACLE;
DELIMITER $$;
--error ER_PROCACCESS_DENIED_ERROR
CREATE PROCEDURE appdb.p_definer_low1_security_none AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_PROCACCESS_DENIED_ERROR
CREATE PROCEDURE appdb.p_definer_low1_security_invoker
SQL SECURITY INVOKER AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
$$
DELIMITER ;$$
CALL appdb.p_definer_root_security_none();
CALL appdb.p_definer_none_security_none();
--error ER_PROCACCESS_DENIED_ERROR
CALL appdb.p_definer_root_security_invoker();
--error ER_PROCACCESS_DENIED_ERROR
CALL appdb.p_definer_none_security_invoker();
SHOW WARNINGS;
--connection default
--disconnect lowconn
DROP USER low@localhost;
DROP DATABASE appdb;
DROP DATABASE secdb;
--echo # Using secdb.vault package types in package procedure appdb.xxx.p1
SET sql_mode=ORACLE;
CREATE DATABASE secdb;
CREATE DATABASE appdb;
CREATE USER low@localhost;
GRANT ALL ON appdb.* TO low@localhost; # NO privilege on secdb
DELIMITER $$;
CREATE PACKAGE secdb.vault AS
TYPE creds IS RECORD(username VARCHAR(64), pw VARCHAR(128));
FUNCTION f RETURN INT;
END;
$$
CREATE PACKAGE appdb.pkg_definer_body_root_security_none AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=root@localhost PACKAGE BODY appdb.pkg_definer_body_root_security_none AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
CREATE PACKAGE appdb.pkg_definer_body_none_security_none AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY appdb.pkg_definer_body_none_security_none AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
CREATE PACKAGE appdb.pkg_definer_body_low_security_none AS
PROCEDURE p1;
END;
$$
--error ER_PROCACCESS_DENIED_ERROR
CREATE DEFINER=low@localhost PACKAGE BODY appdb.pkg_definer_body_low_security_none AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
DELIMITER ;$$
DROP PACKAGE appdb.pkg_definer_body_low_security_none;
DELIMITER $$;
CREATE PACKAGE appdb.pkg_definer_body_root_security_invoker AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=root@localhost PACKAGE BODY appdb.pkg_definer_body_root_security_invoker
SQL SECURITY INVOKER AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
CREATE PACKAGE appdb.pkg_definer_body_none_security_invoker AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY appdb.pkg_definer_body_none_security_invoker
SQL SECURITY INVOKER AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
CREATE PACKAGE appdb.pkg_definer_body_low_security_invoker AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=low@localhost PACKAGE BODY appdb.pkg_definer_body_low_security_invoker
SQL SECURITY INVOKER AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
DELIMITER ;$$
SELECT type, name, definer, security_type FROM mysql.proc
WHERE db='appdb' AND name LIKE 'pkg_%'
ORDER BY name, type, definer;
connect(lowconn, localhost, low,,appdb);
SET sql_mode=ORACLE;
DELIMITER $$;
CREATE PACKAGE appdb.pkg_definer_body_low_security_none AS
PROCEDURE p1;
END;
$$
--error ER_PROCACCESS_DENIED_ERROR
CREATE DEFINER=low@localhost PACKAGE BODY appdb.pkg_definer_body_low_security_none AS
PROCEDURE p1 AS
r secdb.vault.creds;
BEGIN
r.username:='admin';
SELECT r.username;
END;
END;
$$
DELIMITER ;$$
CALL appdb.pkg_definer_body_root_security_none.p1();
CALL appdb.pkg_definer_body_none_security_none.p1();
--error ER_PROCACCESS_DENIED_ERROR
CALL appdb.pkg_definer_body_root_security_invoker.p1();
--error ER_PROCACCESS_DENIED_ERROR
CALL appdb.pkg_definer_body_none_security_invoker.p1();
--connection default
--disconnect lowconn
DROP USER low@localhost;
DROP DATABASE appdb;
DROP DATABASE secdb;

View File

@@ -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;

View File

@@ -0,0 +1,38 @@
if (`SELECT @@lower_case_table_names=0`)
{
--skip Test requires: lower_case_table_names>0
}
SET sql_mode=ORACLE;
--echo #
--echo # MDEV-39587 Package-wide TYPE for variable declarations
--echo #
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;
$$
DELIMITER ;$$
DROP PACKAGE pkg1;
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;
$$
DELIMITER ;$$
DROP PACKAGE pkg1;
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE
CREATE PACKAGE pkg1 AS
TYPE rec0_t IS RECORD (a INT, b VARCHAR(32));
TYPE assoc0_t IS TABLE OF tttt.pkg1.rec0_t INDEX BY INTEGER;
END;
$$
DELIMITER ;$$

View File

@@ -0,0 +1,38 @@
if (`SELECT @@lower_case_table_names>0`)
{
--skip Test requires: lower_case_table_names=0
}
SET sql_mode=ORACLE;
--echo #
--echo # MDEV-39587 Package-wide TYPE for variable declarations
--echo #
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;
$$
DELIMITER ;$$
DROP PACKAGE pkg1;
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE
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;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE
CREATE PACKAGE pkg1 AS
TYPE rec0_t IS RECORD (a INT, b VARCHAR(32));
TYPE assoc0_t IS TABLE OF tttt.pkg1.rec0_t INDEX BY INTEGER;
END;
$$
DELIMITER ;$$

View File

@@ -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;

View File

@@ -0,0 +1,371 @@
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;
--echo # RECORD as a package routine parameter + 2-step self-reference
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
PROCEDURE q(v pkg1.no_such_type); -- 2-step self reference
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
PROCEDURE q(v pkg1.r); -- 2-step self reference
PROCEDURE exec();
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE q(v pkg1.r) AS
BEGIN
SELECT v.x;
END;
PROCEDURE exec() AS
v pkg1.r;
BEGIN
v.x:= 10;
q(v);
END;
END;
$$
DELIMITER ;$$
CALL pkg1.exec();
DROP PACKAGE pkg1;
--echo # RECORD as a package routine parameter + 3-step self-reference
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
PROCEDURE q(v test.pkg1.no_such_type); -- 3-step Self reference
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
PROCEDURE q(v test.pkg1.r); -- 3-step self reference
PROCEDURE exec();
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE q(v test.pkg1.r) AS
BEGIN
SELECT v.x;
END;
PROCEDURE exec() AS
v test.pkg1.r;
BEGIN
v.x:= 10;
q(v);
END;
END;
$$
DELIMITER ;$$
CALL pkg1.exec();
DROP PACKAGE pkg1;
--echo # RECORD as a package function RETURN type + 2-step self-reference
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE
CREATE PACKAGE pkg1 AS
FUNCTION g RETURN pkg1.no_such_type; -- 2-step self-reference
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
FUNCTION g RETURN pkg1.r; -- 2-step self-reference
PROCEDURE exec;
END;
$$
CREATE PACKAGE BODY pkg1 AS
FUNCTION g RETURN pkg1.r AS
v pkg1.r;
BEGIN
v.x:= 10;
RETURN v;
END;
PROCEDURE exec AS
v pkg1.r;
BEGIN
v:= g();
SELECT v.x;
END;
END;
$$
DELIMITER ;$$
CALL pkg1.exec();
DROP PACKAGE pkg1;
--echo # RECORD as a package function RETURN type + 3-step self-reference
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE
CREATE PACKAGE pkg1 AS
FUNCTION g RETURN test.pkg1.no_such_type; -- 3-step self-reference
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PACKAGE pkg1 AS
TYPE r IS RECORD(x INT);
FUNCTION g RETURN test.pkg1.r; -- 3-step self-reference
PROCEDURE exec;
END;
$$
CREATE PACKAGE BODY pkg1 AS
FUNCTION g RETURN test.pkg1.r AS
v test.pkg1.r;
BEGIN
v.x:= 10;
RETURN v;
END;
PROCEDURE exec AS
v test.pkg1.r;
BEGIN
v:= g();
SELECT v.x;
END;
END;
$$
DELIMITER ;$$
CALL pkg1.exec();
DROP PACKAGE pkg1;
--echo #
--echo # MDEV-40721 SIGSEGV in LEX::sp_package_spec_check_cyclic_dependency | LEX::set_field_type_typedef_package_spec
--echo #
DELIMITER $$;
CREATE PACKAGE emp_pkg AS
TYPE emp_rec IS RECORD (id INT);
FUNCTION get_emp(p_id INT) RETURN emp_rec;
END;
$$
CREATE PACKAGE BODY emp_pkg AS
FUNCTION get_emp(p_id INT) RETURN emp_pkg.emp_rec AS
v emp_pkg.emp_rec;
BEGIN
v.id := p_id;
RETURN v;
END;
END;
$$
CREATE PROCEDURE show_emp AS
v emp_pkg.emp_rec;
BEGIN
v := emp_pkg.get_emp(7);
SELECT v.id AS id;
END;
$$
DELIMITER ;$$
CALL show_emp;
DROP PROCEDURE show_emp;
DROP PACKAGE emp_pkg;
DELIMITER $$;
CREATE PACKAGE emp_pkg AS
TYPE emp_rec IS RECORD (id INT);
PROCEDURE get_emp(p_id INT);
END;
$$
CREATE PACKAGE BODY emp_pkg AS
PROCEDURE get_emp(p_id INT) AS
v emp_pkg.emp_rec;
BEGIN
NULL;
END;
END;
$$
CREATE PROCEDURE show_emp AS
BEGIN
emp_pkg.get_emp(7);
END;
$$
DELIMITER ;$$
CALL show_emp;
DROP PROCEDURE show_emp;
DROP PACKAGE emp_pkg;
DELIMITER $$;
CREATE PACKAGE t AS TYPE r IS RECORD (id INT); END; $$
CREATE PACKAGE a AS PROCEDURE q; END; $$
CREATE PACKAGE BODY a AS PROCEDURE q AS v t.r; BEGIN NULL; END; END; $$
CREATE PROCEDURE c AS BEGIN CALL a.q(); END; $$
DELIMITER ;$$
CALL c;
DROP PROCEDURE c;
DROP PACKAGE a;
DROP PACKAGE t;

View File

@@ -0,0 +1,808 @@
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;
--echo #
--echo # MDEV-40420 ASAN : SIGSEGV in Sp_handler::db_find_routine | Sp_handler::db_find_and_cache_routine
--echo #
CREATE DATABASE db1;
USE db1;
DELIMITER $$;
CREATE PACKAGE a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
END;
$$
CREATE PACKAGE b_pkg AS
TYPE brec IS RECORD (p INT, q VARCHAR(10));
TYPE bcur IS REF CURSOR RETURN a_pkg.arec;
END;
$$
--error ER_UNKNOWN_DATA_TYPE
CREATE PACKAGE a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
TYPE acur IS REF CURSOR RETURN b_pkg.brec;
END;
$$
DELIMITER ;$$
--echo # Inject manually a bad CREATE PACKAGE with cyclic dependency
SELECT `body` FROM mysql.proc WHERE db='db1' AND name='a_pkg';
UPDATE mysql.proc SET `body`='AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
TYPE acur IS REF CURSOR RETURN b_pkg.brec;
END'
WHERE db='db1' AND name='a_pkg';
--echo # Check that it's not allowed to create a PROCEDURE using a
--echo # manually injected PACKAGE with a cycle dependency
DELIMITER $$;
--replace_regex /[0-9]* bytes used of a [0-9]* byte stack, and [0-9]* bytes needed/XXX bytes used of a XXX byte stack, and XXX bytes needed/
--error ER_STACK_OVERRUN_NEED_MORE
CREATE PROCEDURE p_cycle AS
c a_pkg.acur;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
--echo # The same, after SP cache invalidating
SET sql_mode=DEFAULT;
--source include/invalidate_sp_cache.inc
SET sql_mode=ORACLE;
DELIMITER $$;
--replace_regex /[0-9]* bytes used of a [0-9]* byte stack, and [0-9]* bytes needed/XXX bytes used of a XXX byte stack, and XXX bytes needed/
--error ER_STACK_OVERRUN_NEED_MORE
CREATE PROCEDURE p_cycle AS
c a_pkg.acur;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
--echo # Check that a manually injected PACKAGE with a cycle dependency
--echo # can be fixed using CREATE OR REPLACE
DELIMITER $$;
CREATE OR REPLACE PACKAGE a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
END;
$$
DELIMITER ;$$
DROP DATABASE db1;
USE test;
--echo # The same layout, with 3-step data type references
CREATE DATABASE db1;
CREATE DATABASE db2;
DELIMITER $$;
CREATE PACKAGE db1.a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
END;
$$
CREATE PACKAGE db2.b_pkg AS
TYPE brec IS RECORD (p INT, q VARCHAR(10));
TYPE bcur IS REF CURSOR RETURN db1.a_pkg.arec;
END;
$$
--error ER_UNKNOWN_DATA_TYPE
CREATE OR REPLACE PACKAGE db1.a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
TYPE acur IS REF CURSOR RETURN db2.b_pkg.brec;
END;
$$
DELIMITER ;$$
DROP DATABASE db2;
DROP DATABASE db1;
--echo #
--echo # MDEV-40468 Package that contains a self reference package refcursor crashes the server
--echo #
# 2-step qualified self-reference
CREATE DATABASE db1;
USE db1;
CREATE TABLE t1 (a INT, b VARCHAR(32));
INSERT INTO t1 VALUES (1,'one'),(2,'two');
DELIMITER $$;
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT, b VARCHAR(32));
TYPE cur IS REF CURSOR RETURN pkg.rec; -- 2-step self reference
END;
$$
CREATE PROCEDURE p2 AS
TYPE localcur IS REF CURSOR RETURN pkg.rec;
c localcur;
v pkg.rec;
BEGIN
OPEN c FOR SELECT a,b FROM t1;
FETCH c INTO v;
CLOSE c;
END;
$$
DELIMITER ;$$
CALL p2;
DROP DATABASE db1;
USE test;
# 3-step qualified reference
CREATE DATABASE db1;
USE db1;
CREATE TABLE t1 (a INT, b VARCHAR(32));
INSERT INTO t1 VALUES (1,'one'),(2,'two');
DELIMITER $$;
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT, b VARCHAR(32));
TYPE cur IS REF CURSOR RETURN db1.pkg.rec; -- 3-step self-reference
END;
$$
CREATE PROCEDURE p2 AS
TYPE localcur IS REF CURSOR RETURN pkg.rec;
c localcur;
v pkg.rec;
BEGIN
OPEN c FOR SELECT a,b FROM t1;
FETCH c INTO v;
CLOSE c;
END;
$$
DELIMITER ;$$
CALL p2;
DROP DATABASE db1;
USE test;
--echo #
--echo # MDEV-40640 Assertion `li->sphead' failed in bool LEX::sp_package_spec_check_cyclic_dependency(THD *, const Lex_ident_sys_st &, const Lex_ident_sys_st &) const
--echo #
DELIMITER $$;
CREATE PACKAGE p1 AS TYPE r IS RECORD(x INT); END;$$
CREATE PACKAGE p2 AS TYPE r IS RECORD(x INT); TYPE c IS REF CURSOR RETURN p1.r; END;$$
DELIMITER ;$$
SHOW CREATE PACKAGE p2;
DROP PACKAGE p2;
DROP PACKAGE p1;
--echo # Replacing the dependency package and removing the type
DELIMITER $$;
CREATE PACKAGE pkg1 AS
TYPE rec0_t IS RECORD (a INT, b VARCHAR(10));
END;
$$
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END
$$
DELIMITER ;$$
SHOW CREATE PACKAGE pkg2;
DELIMITER $$;
CREATE OR REPLACE PACKAGE pkg1 AS
TYPE rec1_t IS RECORD (a INT, b VARCHAR(10)); -- There is no rec0_t any more
END;
$$
DELIMITER ;$$
--error ER_UNKNOWN_DATA_TYPE
SHOW CREATE PACKAGE pkg2;
DROP PACKAGE pkg2;
DROP PACKAGE pkg1;
--echo # Dropping the dependency package
DELIMITER $$;
CREATE PACKAGE pkg1 AS
TYPE rec0_t IS RECORD (a INT, b VARCHAR(10));
END;
$$
CREATE PACKAGE pkg2 AS
TYPE cur1_t IS REF CURSOR RETURN pkg1.rec0_t;
END
$$
DELIMITER ;$$
SHOW CREATE PACKAGE pkg2;
DROP PACKAGE pkg1;
--error ER_UNKNOWN_DATA_TYPE
SHOW CREATE PACKAGE pkg2;
DROP PACKAGE pkg2;

View File

@@ -0,0 +1,35 @@
SET sql_mode=ORACLE;
--echo #
--echo # MDEV-39587 Package-wide TYPE for variable declarations
--echo #
--echo #
--echo # MDEV-40597 UBSAN | SIGSEGV in ORAparse | parse_sql | sp_compile | Sp_handler::db_load_routine
--echo #
CREATE DATABASE db1;
USE db1;
DELIMITER $$;
CREATE PACKAGE pkg1500 AS TYPE rec IS RECORD(x INT); END;$$
DELIMITER ;$$
--disable_query_log
--let $i= 1500
while ($i)
{
--let $prev= $i
--dec $i
--error 0,ER_STACK_OVERRUN_NEED_MORE
--eval CREATE PACKAGE pkg$i AS TYPE rec IS RECORD(x INT); TYPE cur IS REF CURSOR RETURN pkg$prev.rec; END;
if ($mysql_errname == "ER_STACK_OVERRUN_NEED_MORE")
{
--echo $mysql_errname reached;
--let $i= 0;
}
}
--enable_query_log
DROP DATABASE db1;
USE test;

View File

@@ -0,0 +1,148 @@
SET sql_mode=ORACLE;
--echo #
--echo # MDEV-39587 Package-wide TYPE for variable declarations
--echo #
#--echo #
#--echo # MDEV-40430 Cross db package type inside a trigger crashes the server
#--echo #
#
#CREATE DATABASE db1;
#CREATE DATABASE db2;
#CREATE TABLE db2.t1 (id INT, note VARCHAR(40));
#DELIMITER $$;
#CREATE PACKAGE db1.pkg AS
# TYPE rec IS RECORD (a INT, b VARCHAR(20));
#END;
#$$
#CREATE TRIGGER db2.trg BEFORE INSERT ON db2.t1
#FOR EACH ROW
#DECLARE
# r db1.pkg.rec;
#BEGIN
# r.a := :NEW.id;
# :NEW.note := 'x';
#END;
#$$
#DELIMITER ;$$
#INSERT INTO db2.t1 (id) VALUES (1);
#DROP DATABASE db2;
#DROP DATABASE db1;
--echo #
--echo # MDEV-40436 Trigger using a package-defined type is silently lost during mariadb-dump / restore
--echo #
# Using package types inside triggers is not yet allowed because
# of dump/restore problems (MDEV-40436)
CREATE DATABASE db1;
USE db1;
DELIMITER $$;
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT, b VARCHAR(20));
END;
$$
DELIMITER ;$$
CREATE TABLE t1 (id INT, val VARCHAR(20));
DELIMITER $$;
--error ER_WRONG_USAGE
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
r pkg.rec;
BEGIN
:NEW.val := CONCAT('r-', :NEW.id);
END;
$$
--error ER_WRONG_USAGE
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
r db1.pkg.rec;
BEGIN
:NEW.val := CONCAT('r-', :NEW.id);
END;
$$
DELIMITER ;$$
DROP DATABASE db1;
USE test;
# Package type in a REF CURSOR RETURN
DELIMITER $$;
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT);
END;
$$
DELIMITER ;$$
CREATE TABLE t1 (a INT);
DELIMITER $$;
--error ER_WRONG_USAGE
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
TYPE c IS REF CURSOR RETURN pkg.rec;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_WRONG_USAGE
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
TYPE c IS REF CURSOR RETURN test.pkg.rec;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DROP TABLE t1;
DROP PACKAGE pkg;
# Package TYPE in a assoc array
DELIMITER $$;
CREATE PACKAGE pkg AS
TYPE rec IS RECORD (a INT);
END;
$$
DELIMITER ;$$
CREATE TABLE t1 (a INT);
DELIMITER $$;
--error ER_WRONG_USAGE
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
TYPE c IS TABLE OF pkg.rec INDEX BY int;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_WRONG_USAGE
CREATE TRIGGER trg BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
TYPE c IS TABLE OF test.pkg.rec INDEX BY int;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DROP TABLE t1;
DROP PACKAGE pkg;

View File

@@ -0,0 +1,205 @@
SET sql_mode=ORACLE;
SET NAMES utf8mb3;
--echo #
--echo # MDEV-39587 Package-wide TYPE for variable declarations
--echo #
--echo # raise_unknown_data_type
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE
CREATE PROCEDURE p1 AS
a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE,
CREATE PROCEDURE p1 AS
a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE
CREATE PROCEDURE p1 AS
a åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå.
åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE,
CREATE PROCEDURE p1 AS
a åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå.
åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå.
åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE
CREATE PROCEDURE p1 AS
a €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€.
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_UNKNOWN_DATA_TYPE,
CREATE PROCEDURE p1 AS
a €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€.
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€.
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€;
BEGIN
NULL;
END;
$$
DELIMITER ;$$
--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 ;$$
--echo #
--echo # MDEV-40155 Weak REF CURSOR without RETURN is not opened using a dynamic SQL statement
--echo #
CREATE TABLE t (id INT, name VARCHAR(100));
INSERT INTO t VALUES (1,'Test');
DELIMITER $$;
CREATE PACKAGE pc AS TYPE wc IS REF CURSOR; END;
$$
CREATE PROCEDURE pdyn AS
c pc.wc;
vi INT;
vn VARCHAR(100);
BEGIN
OPEN c FOR 'SELECT id, name FROM t';
FETCH c INTO vi, vn;
SELECT vi, vn;
CLOSE c;
END;
$$
DELIMITER ;$$
CALL pdyn;
DROP PROCEDURE pdyn;
DROP PACKAGE pc;
DROP TABLE t;
--echo #
--echo # MDEV-40153 Assertion `rec->field->head()->charset == nullptr' failed in virtual bool Type_handler_row::Column_definition_prepare_stage1(THD *, MEM_ROOT *, Column_definition *, column_definition_type_t, const Column_derived_attributes *) const
--echo #
DELIMITER $$;
CREATE PACKAGE pk_crash AS
TYPE r IS RECORD (b BLOB);
FUNCTION f RETURN r;
END;
$$
DELIMITER ;$$
DROP PACKAGE pk_crash;
DELIMITER $$;
CREATE PACKAGE pk_crash AS
TYPE rec0_t IS RECORD (b BLOB);
FUNCTION f(r rec0_t) RETURN INT;
END;
$$
DELIMITER ;$$
DROP PACKAGE pk_crash;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -31,6 +31,7 @@
template<size_t buff_sz>
class CharBuffer
{
protected:
char m_buff[buff_sz + 1 /* one extra byte for '\0' */];
size_t m_length;
bool is_sane() const

View File

@@ -20,6 +20,7 @@
#include "lex_ident_cli.h"
#include "sql_alloc.h"
#include "char_buffer.h"
extern "C" MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info;
@@ -60,9 +61,9 @@ public:
LEX_CSTRING tmp= {name, length};
set_valid_utf8(&tmp);
}
Lex_ident_sys(const THD *thd, const LEX_CSTRING *str)
explicit Lex_ident_sys(const LEX_CSTRING &str)
{
set_valid_utf8(str);
set_valid_utf8(&str);
}
Lex_ident_sys & operator=(const Lex_ident_sys_st &name)
{
@@ -72,4 +73,36 @@ public:
};
/*
A buffer to print a qualified data type.
It does not derive from ErrConv because it does not need lazy calculation yet.
Also it's size is defined according to the error message in errmsg-utf8.txt:
"Unknown data type: '%-.384s'" in errmsg-utf8.txt
*/
#define DATA_TYPE_FORMAT_LENGTH 384
class QTypeErrBuffer: public CharBuffer<DATA_TYPE_FORMAT_LENGTH>
{
public:
QTypeErrBuffer(const Lex_ident_sys_st &db, const Lex_ident_sys_st &package,
const Lex_ident_sys_st &type)
{
DBUG_ASSERT(db.str);
DBUG_ASSERT(package.str);
DBUG_ASSERT(type.str);
my_snprintf(m_buff, sizeof(m_buff), "%.*sQ.%.*sQ.%.*sQ",
(int) db.length, db.str,
(int) package.length, package.str,
(int) type.length, type.str);
}
QTypeErrBuffer(const Lex_ident_sys_st &package, const Lex_ident_sys_st &type)
{
DBUG_ASSERT(package.str);
DBUG_ASSERT(type.str);
my_snprintf(m_buff, sizeof(m_buff), "%.*sQ.%.*sQ",
(int) package.length, package.str,
(int) type.length, type.str);
}
};
#endif // LEX_IDENT_SYS

View File

@@ -12135,9 +12135,9 @@ ER_TOO_LONG_DATABASE_COMMENT
spa "El comentario para la base de datos '%-.64s' es demasiado largo (máx = %u)"
sw "Maoni kwa hifadhidata '%-.64s' ni ndefu sana (max = %u)"
ER_UNKNOWN_DATA_TYPE
eng "Unknown data type: '%-.64s'"
spa "Tipo de datos desconocido: '%-.64s'"
sw "Aina ya data isiyojulikana: '%-.64s'"
eng "Unknown data type: '%-.384s'"
spa "Tipo de datos desconocido: '%-.384s'"
sw "Aina ya data isiyojulikana: '%-.384s'"
ER_UNKNOWN_OPERATOR
eng "Operator does not exist: '%-.128s'"
spa "El operador no existe: '%-.128s'"

View File

@@ -95,11 +95,19 @@ bool Sp_handler_procedure::add_instr_preturn(THD *thd, sp_head *sp,
}
bool Sp_handler_event::add_instr_preturn(THD *thd, sp_head *sp,
sp_pcontext *spcont) const
{
return sp->add_instr_preturn(thd, spcont);
}
Sp_handler_procedure sp_handler_procedure;
Sp_handler_function sp_handler_function;
Sp_handler_package_spec sp_handler_package_spec;
Sp_handler_package_body sp_handler_package_body;
Sp_handler_trigger sp_handler_trigger;
Sp_handler_event sp_handler_event;
Sp_handler_package_procedure sp_handler_package_procedure;
Sp_handler_package_function sp_handler_package_function;
@@ -878,7 +886,10 @@ static sp_head *sp_compile(THD *thd, String *defstr, sql_mode_t sql_mode,
LEX_STRING definition_string;
lex_start(thd);
DBUG_ASSERT(thd->lex->stmt_lex);
LEX *old_stmt_lex= thd->lex->stmt_lex;
lex_start(thd); // This changes thd->lex->stmt_lex
thd->lex->stmt_lex= old_stmt_lex;
init_sql_alloc(key_memory_sp_head_main_root, &thd->lex->sp_mem_root,
MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC, MYF(0));
@@ -980,6 +991,8 @@ Sp_handler::db_load_routine(THD *thd, const Database_qualified_name *name,
Stored_program_creation_ctx *creation_ctx) const
{
LEX *old_lex= thd->lex, newlex;
DBUG_ASSERT(thd->lex->stmt_lex);
newlex.stmt_lex= thd->lex->stmt_lex;
String defstr;
char saved_cur_db_buf[SAFE_NAME_LEN+1];
LEX_STRING saved_cur_db= { saved_cur_db_buf, sizeof(saved_cur_db_buf) };
@@ -989,7 +1002,6 @@ Sp_handler::db_load_routine(THD *thd, const Database_qualified_name *name,
int ret= 0;
thd->lex= &newlex;
newlex.current_select= NULL;
defstr.set_charset(creation_ctx->get_client_cs());
defstr.set_thread_specific();
@@ -2527,6 +2539,43 @@ 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)
{
DBUG_ASSERT(!thd->is_fatal_error);
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
@@ -2560,15 +2609,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);
}
@@ -2994,8 +3035,22 @@ int Sp_handler::sp_cache_routine(THD *thd, const Database_qualified_name *name,
Any error when loading an existing routine is either some problem
with the mysql.proc table, or a parse error because the contents
has been tampered with (in which case we clear that error).
Other scenarios when we want to preserve the original error
instead of ER_SP_PROC_TABLE_CORRUPT, for better readability:
- A routine uses a TYPE from a PACKAGE specification
but does not have EXECUTE privilege on the PACKAGE specification.
Let's preserve the ER_PROCACCESS_DENIED_ERROR error,
- Packages use types in a long cycle (MDEV-40597):
* Package pkg1499 uses a type from pkg1500
* Package pkg1498 uses a type from pkg1499
* Package pkg1497 uses a type from pkg1488
and so on. This can cause a thread stack overrun.
Let's preserve the ER_STACK_OVERRUN_NEED_MORE error.
*/
if (ret == SP_PARSE_ERROR)
if (ret == SP_PARSE_ERROR &&
(!thd->is_error() ||
(thd->get_stmt_da()->sql_errno() != ER_PROCACCESS_DENIED_ERROR &&
thd->get_stmt_da()->sql_errno() != ER_STACK_OVERRUN_NEED_MORE)))
thd->clear_error();
/*
If we cleared the parse error, or when db_find_routine() flagged
@@ -3233,6 +3288,8 @@ Sp_handler::sp_load_for_information_schema(THD *thd, TABLE *proc_table,
}
LEX *old_lex= thd->lex, newlex;
DBUG_ASSERT(thd->lex->stmt_lex);
newlex.stmt_lex= thd->lex->stmt_lex;
Stored_program_creation_ctx *creation_ctx=
Stored_routine_creation_ctx::load_from_db(thd, &sp_name_obj, proc_table);
defstr.set_charset(creation_ctx->get_client_cs());

View File

@@ -137,6 +137,9 @@ public:
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 @@ public:
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;
@@ -249,6 +256,44 @@ public:
};
class Sp_handler_event: public Sp_handler
{
public:
enum_sp_type type() const override { return SP_TYPE_EVENT; }
LEX_CSTRING type_lex_cstring() const override
{
static LEX_CSTRING m_type_str= { STRING_WITH_LEN("EVENT")};
return m_type_str;
}
enum_sql_command sqlcom_create() const override
{
DBUG_ASSERT(0);
return SQLCOM_CREATE_EVENT;
}
enum_sql_command sqlcom_drop() const override
{
DBUG_ASSERT(0);
return SQLCOM_DROP_EVENT;
}
const char *show_create_routine_col1_caption() const override
{
DBUG_ASSERT(0);
return "Event";
}
const char *show_create_routine_col3_caption() const override
{
DBUG_ASSERT(0);
return "Create Event";
}
MDL_key::enum_mdl_namespace get_mdl_type() const override
{
DBUG_ASSERT(0);
return MDL_key::EVENT;
}
bool add_instr_preturn(THD *thd, sp_head *sp, sp_pcontext *spcont) const override;
};
class Sp_handler_procedure: public Sp_handler
{
public:
@@ -499,6 +544,7 @@ extern MYSQL_PLUGIN_IMPORT Sp_handler_package_body sp_handler_package_body;
extern MYSQL_PLUGIN_IMPORT Sp_handler_package_function sp_handler_package_function;
extern MYSQL_PLUGIN_IMPORT Sp_handler_package_procedure sp_handler_package_procedure;
extern MYSQL_PLUGIN_IMPORT Sp_handler_trigger sp_handler_trigger;
extern MYSQL_PLUGIN_IMPORT Sp_handler_event sp_handler_event;
inline const Sp_handler *Sp_handler::handler(enum_sql_command cmd)

View File

@@ -570,6 +570,7 @@ sp_head::sp_head(MEM_ROOT *mem_root_arg, sp_package *parent,
m_body(null_clex_str),
m_body_utf8(null_clex_str),
m_defstr(null_clex_str),
m_definer{null_clex_str,null_clex_str},
m_sp_cache_version(0),
m_creation_ctx(0),
unsafe_flags(0),
@@ -4316,3 +4317,351 @@ ulong sp_head::sp_cache_version() const
{
return m_parent ? m_parent->sp_cache_version() : m_sp_cache_version;
}
/*
Package data types are not allowed in triggers and events yet
because of the dump/restore problems (MDEV-40436, MDEV-40686).
Disallow qualified types.
@param db - The database. Can be {nullptr,0}
@param package - The package. Can be {nullptr,0}
@param type - The type name. Cannot be {nullptr,0}
*/
bool sp_head::check_maybe_qualified_type_context(const Lex_ident_sys_st &db,
const Lex_ident_sys_st &package,
const Lex_ident_sys_st &type) const
{
DBUG_ASSERT(type.str);
if ((m_handler == &sp_handler_trigger ||
m_handler == &sp_handler_event) && package.str)
{
my_error(ER_WRONG_USAGE, MYF(0), m_handler->type_lex_cstring().str,
db.str ? QTypeErrBuffer(db, package, type).ptr() :
QTypeErrBuffer(package, type).ptr());
return true;
}
return false;
}
/*
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_maybe_foreign_type_context(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)
{
my_error(ER_UNKNOWN_DATA_TYPE, MYF(0),
QTypeErrBuffer(Lex_ident_sys(db.str, db.length),
package, type).ptr());
}
void sp_head::raise_unknown_data_type(const Lex_ident_sys_st &package,
const Lex_ident_sys_st &type)
{
my_error(ER_UNKNOWN_DATA_TYPE, MYF(0), QTypeErrBuffer(package, type).ptr());
}
/*
Get the definition of the TYPE `dbn`.`package`.`type`.
If the definition is not found, then an error message is raises.
@param thd - The thd
@param OUT tdef - The pointer to the found TYPE definition
@param spec - The package specification
@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_head::get_typedef_package_spec_or_error(THD *thd,
const sp_type_def **tdef,
sp_package *spec,
const Lex_ident_db_normalized &dbn,
const Lex_ident_sys_st &package,
const Lex_ident_sys_st &type)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *save_security_ctx= nullptr;
if ((m_parent ? m_parent->suid() : suid()) != SP_IS_NOT_SUID &&
m_definer.user.length/*Explicit DEFINER was given in CREATE*/)
m_security_ctx.change_security_context(thd, &m_definer.user,
&m_definer.host,
&m_db,
&save_security_ctx);
#endif
bool rc= check_routine_access(thd, EXECUTE_ACL,
&spec->m_db, &spec->m_name,
&sp_handler_package_spec, false);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (save_security_ctx)
m_security_ctx.restore_security_context(thd, save_security_ctx);
#endif
if (rc)
return true;
if (!(tdef[0]= spec->find_type_def(type)))
{
if (dbn.str)
raise_unknown_data_type(dbn, package, type);
else
raise_unknown_data_type(package, type);
return true;
}
m_flags|= spec->m_flags & HAS_COLUMN_TYPE_REFS;
return false;
}
/*
Find a package-wide TYPE definition.
No errors are raised on failure.
*/
sp_type_def *sp_package::find_type_def(const Lex_ident_sys_st &type)
{
if (!get_parse_context() || !get_parse_context()->child_context(0))
return nullptr;
return get_parse_context()->child_context(0)->find_type_def(type, 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_or_error(THD *thd,
const sp_type_def **tdef,
const Lex_ident_sys_st &package,
const Lex_ident_sys_st &type)
{
DBUG_ASSERT(!package.is_null());
DBUG_ASSERT(!type.is_null());
/*
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);
if (!(tdef[0]= spec->find_type_def(type)))
{
raise_unknown_data_type(package, type);
return true;
}
return false;
}
/*
Another special case: a reference to the current package specification
from a package routine parameter or a package function RETURN:
CREATE PACKAGE p2 AS
TYPE r IS RECORD(x INT);
PROCEDURE q(v p2.r); -- here
FUNCTION f RETURN p2.r; -- here
END;
*/
if ((m_handler == &sp_handler_package_function ||
m_handler == &sp_handler_package_procedure))
{
DBUG_ASSERT(m_parent);
if (m_parent->m_handler == &sp_handler_package_spec &&
Lex_ident_routine(m_parent->m_name).streq(package))
{
if (!(tdef[0]= m_parent->find_type_def(type)))
{
raise_unknown_data_type(package, type);
return true;
}
return false;
}
}
/*
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)))
return get_typedef_package_spec_or_error(thd, tdef, spec,
ndb, package, type);
if (thd->is_fatal_error)
return true; // E.g. ER_STACK_OVERRUN_NEED_MORE raised
}
// 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_or_error(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_or_error(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)
{
DBUG_ASSERT(!db.is_null());
DBUG_ASSERT(!package.is_null());
DBUG_ASSERT(!type.is_null());
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(m_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);
if (!(tdef[0]= spec->find_type_def(type)))
{
raise_unknown_data_type(dbn, package, type);
return true;
}
return false;
}
/*
Another special case: a reference to the current package specification
from a package routine parameter or a package function RETURN:
CREATE PACKAGE p2 AS
TYPE r IS RECORD(x INT);
PROCEDURE q(v test.p2.r); -- here
FUNCTION f RETURN test.p2.r; -- here
END;
*/
if ((m_handler == &sp_handler_package_function ||
m_handler == &sp_handler_package_procedure))
{
DBUG_ASSERT(m_parent);
if (m_parent->m_handler == &sp_handler_package_spec &&
dbn.streq(m_parent->m_db) &&
Lex_ident_routine(m_parent->m_name).streq(package))
{
if (!(tdef[0]= m_parent->find_type_def(type)))
{
raise_unknown_data_type(package, type);
return true;
}
return false;
}
}
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 get_typedef_package_spec_or_error(thd, tdef, spec, dbn, package, type);
}

View File

@@ -1021,6 +1021,32 @@ public:
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_maybe_qualified_type_context(const Lex_ident_sys_st &db,
const Lex_ident_sys_st &package,
const Lex_ident_sys_st &type) const;
bool check_maybe_foreign_type_context(THD *thd, const Lex_field_type_st &def,
column_definition_type_t type);
bool get_typedef_package_spec_or_error(THD *thd,
const sp_type_def **tdef,
const Lex_ident_sys_st &package,
const Lex_ident_sys_st &type);
bool get_typedef_package_spec_or_error(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);
bool get_typedef_package_spec_or_error(THD *thd,
const sp_type_def **tdef,
sp_package *spec,
const Lex_ident_db_normalized &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
@@ -1204,6 +1230,8 @@ public:
sp_pcontext *ctx= m_pcont->child_context(0);
return ctx ? ctx->find_variable(name, true) : NULL;
}
sp_type_def *find_type_def(const Lex_ident_sys_st &type);
bool validate_after_parser(THD *thd);
bool instantiate_if_needed(THD *thd);
};

View File

@@ -69,7 +69,7 @@ public:
bool sp_cursor_stmt_finalize(THD *thd, const Lex_ident_sys_st &ps_name,
const char *beg, const char *end)
{
m_ps_name= Lex_ident_sys(thd, &ps_name);
m_ps_name= Lex_ident_sys(ps_name);
pop_select(); //main select
if (unlikely(stmt_finalize(thd)))
return true;

View File

@@ -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)

View File

@@ -789,6 +789,25 @@ public:
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

View File

@@ -6824,8 +6824,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_maybe_foreign_type_context(thd, def, dtype) ||
last_field->set_attributes(thd, def, dtype) ||
sphead->fill_spvar_definition(thd, last_field, &spvar->name);
}
@@ -6884,8 +6886,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_maybe_foreign_type_context(thd, def, dtype) ||
last_field->set_attributes(thd, def, dtype) ||
sphead->fill_field_definition(thd, last_field);
}
@@ -6940,12 +6944,61 @@ void LEX::set_stmt_init()
};
/*
Check if the current CREATE PACKAGE statement does not recursively depend on:
CREATE PACKAGE db.name
This method is called to avoid cyclic dependencies:
CREATE PACKAGE a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
END;
$$
CREATE PACKAGE b_pkg AS
TYPE brec IS RECORD (p INT, q VARCHAR(10));
TYPE bcur IS REF CURSOR RETURN a_pkg.arec; -- b_pkg -> a_pkg
END;
$$
-- The next statement would replace a_pkg and cause a cyclic dependency:
CREATE OR REPLACE PACKAGE a_pkg AS
TYPE arec IS RECORD (x INT, y VARCHAR(10));
TYPE acur IS REF CURSOR RETURN b_pkg.brec; -- a_pkg -> b_pkg -> a_pkg
END;
$$
*/
bool LEX::check_create_package_cycle_dependency(const Lex_ident_sys_st &db,
const Lex_ident_sys_st &name)
const
{
if (this != stmt_lex &&
stmt_lex->sql_command == SQLCOM_CREATE_PACKAGE &&
stmt_lex->sphead &&
stmt_lex->sphead->m_handler == &sp_handler_package_spec)
{
if (sphead->m_handler != &sp_handler_package_spec)
return false; // e.g. a package routine inside a package specification
if (stmt_lex->sphead->m_db.streq(db) &&
Lex_ident_routine(stmt_lex->sphead->m_name).streq(name))
{
/*
The exact raised error is not important here.
It will be overriden to: Unknown data type: '`pkg`.`type`'
*/
DBUG_ASSERT(thd->get_internal_handler());
my_error(ER_UNKNOWN_ERROR, MYF(0), "Cycle found in TYPE definition");
return true;
}
}
return false;
}
/**
Find a local or a package body type declaration by name
@param IN name - the data type name
@retval - the data type (if found), or NULL otherwise.
*/
const sp_type_def *LEX::find_type_def(const LEX_CSTRING &name) const
const sp_type_def *LEX::find_type_def(const Lex_ident_sys_st &name) const
{
DBUG_ASSERT(spcont);
const sp_type_def *def= spcont->find_type_def(name, false);
@@ -6954,8 +7007,7 @@ const sp_type_def *LEX::find_type_def(const LEX_CSTRING &name) const
if (sphead->m_parent)
{
// Find a package body type definition
return sphead->m_parent->get_parse_context()->
child_context(0)->find_type_def(name, true);
return sphead->m_parent->find_type_def(name);
}
return nullptr;
}
@@ -8272,7 +8324,8 @@ sp_lex_local *LEX::package_routine_start(THD *thd,
enum_sp_aggregate_type atype= sublex->sql_command == SQLCOM_CREATE_FUNCTION ?
NOT_AGGREGATE : DEFAULT_AGGREGATE;
if (unlikely(!sublex->make_sp_head_no_recursive(thd, spname, sph, atype)))
if (unlikely(!sublex->make_sp_head_no_recursive(thd, spname, definer,
sph, atype)))
return NULL;
sphead->get_package()->m_current_routine= sublex;
return sublex;
@@ -8312,6 +8365,7 @@ sp_head *LEX::make_sp_head(THD *thd, const sp_name *name,
sp_head *LEX::make_sp_head_no_recursive(THD *thd, const sp_name *name,
const LEX_USER *definer_arg,
const Sp_handler *sph,
enum_sp_aggregate_type agg_type)
{
@@ -8330,7 +8384,12 @@ sp_head *LEX::make_sp_head_no_recursive(THD *thd, const sp_name *name,
if (!sphead || (package &&
(sph == &sp_handler_package_procedure ||
sph == &sp_handler_package_function)))
return make_sp_head(thd, name, sph, agg_type);
{
sp_head *res= make_sp_head(thd, name, sph, agg_type);
if (res && definer_arg)
res->set_definer(&definer_arg->user, &definer_arg->host);
return res;
}
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), sph->type_str());
return NULL;
}
@@ -9676,8 +9735,7 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name,
*/
bool got_error;
Item *trigger_specific_item=
create_item_ident_trigger_specific(thd,
Lex_ident_sys(thd, name), &got_error);
create_item_ident_trigger_specific(thd, Lex_ident_sys(*name), &got_error);
if (trigger_specific_item)
/*
trigger_specific_item != nullptr if the argument 'name' equals one of
@@ -12956,7 +13014,7 @@ bool st_select_lex::save_item_list_names(THD *thd)
while ((item= li++))
{
Lex_ident_sys *name= new (thd->mem_root) Lex_ident_sys(thd, &item->name);
Lex_ident_sys *name= new (thd->mem_root) Lex_ident_sys(item->name);
if (unlikely(!name ||
orig_names_of_item_list_elems->push_back(name, thd->mem_root)))
{
@@ -13182,7 +13240,7 @@ bool LEX::stmt_create_stored_function_start(const DDL_options_st &options,
const sp_name *spname)
{
if (stmt_create_function_start(options) ||
unlikely(!make_sp_head_no_recursive(thd, spname,
unlikely(!make_sp_head_no_recursive(thd, spname, definer,
&sp_handler_function, agg_type)))
return true;
return false;
@@ -13404,9 +13462,96 @@ 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)
{
if (sphead->check_maybe_qualified_type_context(db, package, type))
return true;
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 (check_create_package_cycle_dependency(db, package) ||
sphead->get_typedef_package_spec_or_error(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 (check_create_package_cycle_dependency(Lex_ident_sys(sphead->m_db),
package) ||
sphead->get_typedef_package_spec_or_error(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;
}
}
const sp_type_def_record *type_def_rec=
dynamic_cast<const sp_type_def_record*>(rt);
if (!type_def_rec ||
!dynamic_cast<const Type_handler_row*>(rt->type_handler()))
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
type.str, "REF CURSOR RETURN");
return true;
}
Row_definition_list *row= type_def_rec->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)
@@ -13480,41 +13625,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<const Type_handler_row*>(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<const sp_type_def_record*>(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);
}
@@ -13537,7 +13650,7 @@ bool LEX::check_ref_cursor_components(Row_definition_list *row) const
bool LEX::set_field_type_udt_or_typedef(Lex_field_type_st *type,
const LEX_CSTRING &name,
const Lex_ident_sys_st &name,
const Lex_length_and_dec_st &attr,
const Lex_column_charset_collation_attrs_st &coll)
{
@@ -13598,7 +13711,7 @@ bool LEX::set_cast_type_udt(Lex_cast_type_st *type,
bool LEX::set_field_type_typedef(Lex_field_type_st *type,
const LEX_CSTRING &name,
const Lex_ident_sys_st &name,
const Lex_length_and_dec_st &attr,
const Lex_column_charset_collation_attrs_st &coll,
bool *is_typedef)
@@ -13625,6 +13738,78 @@ 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->check_maybe_qualified_type_context(Lex_ident_sys(),
package, type))
return true;
if (check_create_package_cycle_dependency(Lex_ident_sys(sphead->m_db),
package))
return true;
if (sphead->get_typedef_package_spec_or_error(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->check_maybe_qualified_type_context(db, package, type))
return true;
if (check_create_package_cycle_dependency(db, package))
return true;
if (sphead->get_typedef_package_spec_or_error(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();

View File

@@ -4111,6 +4111,7 @@ public:
sp_head *make_sp_head(THD *thd, const sp_name *name, const Sp_handler *sph,
enum_sp_aggregate_type agg_type);
sp_head *make_sp_head_no_recursive(THD *thd, const sp_name *name,
const LEX_USER *definer,
const Sp_handler *sph,
enum_sp_aggregate_type agg_type);
bool sp_body_finalize_routine(THD *);
@@ -4151,7 +4152,10 @@ public:
bool direct_call(THD *thd, const Qualified_ident *ident, List<Item> *args);
bool assoc_assign_start(THD *thd, Qualified_ident *ident);
const sp_type_def *find_type_def(const LEX_CSTRING &name) const;
const sp_type_def *find_type_def(const Lex_ident_sys_st& name) const;
bool check_create_package_cycle_dependency(const Lex_ident_sys_st &db,
const Lex_ident_sys_st &name)
const;
sp_variable *find_variable(const LEX_CSTRING *name,
sp_pcontext **ctx,
const Sp_rcontext_handler **rh) const;
@@ -5277,20 +5281,32 @@ public:
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_ident_sys_st &name,
const Lex_length_and_dec_st &attr,
const Lex_column_charset_collation_attrs_st &coll,
bool *is_typedef);
bool set_field_type_udt_or_typedef(Lex_field_type_st *type,
const LEX_CSTRING &name,
const Lex_ident_sys_st &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;

View File

@@ -172,6 +172,63 @@ 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)
{
DBUG_ASSERT(!thd->is_fatal_error);
*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)))
{
if (thd->is_fatal_error)
return true; // E.g. ER_STACK_OVERRUN_NEED_MORE raised
continue;
}
sp_type_def *tdef= pkg->find_type_def(type);
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)

View File

@@ -38,6 +38,10 @@ public:
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
*/

View File

@@ -1791,8 +1791,27 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db,
thd->lex= &lex;
save_db= thd->db;
thd->reset_db(db);
/*
Let's set thd->db to a my_alloc-ed copy of "db".
We cannot just call thd->reset_db(db) here for the following reasons:
In case if a trigger uses package TYPEs, e.g.:
CREATE TRIGGER db2.trg BEFORE INSERT ON db2.t1 FOR EACH ROW
DECLARE
r db1.pkg.rec; -- package TYPE
BEGIN
...
END;
we'll call Sp_hadler::db_load_routine() for the PACKAGE db1.pkg when
parsing the trigger body. It'll call mysql_change_db() which will:
- set thd->db to a my_alloc'ed copy of "db1"
(which is the database of the TYPE db1.pkg.rec)
- on success, call my_free() to the previous value thd->db.str.
So let's set thd->db to a copy of "db", which can be my_free'd.
*/
save_db= thd->db; // Make a thd->db backup
thd->reset_db(&null_clex_str); // Reset thd->db without freeing it
thd->set_db(db); // Set thd->db to a my_alloc copy of "db"
while ((trg_create_str= it++))
{
sp_head *sp;
@@ -2035,7 +2054,14 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db,
sp->m_trg= trigger;
lex_end(&lex);
}
thd->reset_db(&save_db);
/*
Now thd->db should point to a my_alloc-ed copy of "db",
even if we loaded PACKAGEs during the parsing of the trigger.
See comments about package TYPEs above. Let's my_free thd->db.str
and restore the backed copy of thd->db.
*/
thd->set_db(&null_clex_str); // It'll call my_free() for thd->db.str
thd->reset_db(&save_db); // Restore thd->db
thd->lex= old_lex;
thd->spcont= save_spcont;
thd->variables.sql_mode= save_sql_mode;

View File

@@ -1379,7 +1379,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
sp_opt_label BIN_NUM TEXT_STRING_filesystem
opt_constraint constraint opt_ident
sp_block_label sp_control_label opt_place opt_db opt_nls_param
udt_name
%ifdef ORACLE
%type <lex_str>
@@ -1398,6 +1397,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
ident_for_loop_index
select_or_ps_name
fetch_statement_source
udt_name
%type <lex_string_with_metadata>
TEXT_STRING
@@ -3336,7 +3336,7 @@ ev_sql_stmt:
if (unlikely(!lex->make_sp_head(thd,
lex->event_parse_data->identifier,
&sp_handler_procedure,
&sp_handler_event,
DEFAULT_AGGREGATE)))
MYSQL_YYABORT;
@@ -6717,8 +6717,8 @@ qualified_field_type:
udt_name:
IDENT_sys { $$= $1; }
| reserved_keyword_udt { $$= $1; }
| non_reserved_keyword_udt { $$= $1; }
| reserved_keyword_udt { $$= Lex_ident_sys($1.str, $1.length); }
| non_reserved_keyword_udt { $$= Lex_ident_sys($1.str, $1.length); }
;
field_type_all_builtin:
@@ -6748,6 +6748,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:
@@ -13926,7 +13936,7 @@ select_outvar:
}
| ident_or_text
{
const Lex_ident_sys name(thd, &$1);
const Lex_ident_sys name($1);
if (unlikely(!($$= Lex->create_outvar(thd, name)) && Lex->result))
MYSQL_YYABORT;
}
@@ -19811,7 +19821,7 @@ sf_c_chistics_and_body_standalone:
sp_tail_standalone:
sp_name
{
if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1,
if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1, Lex->definer,
&sp_handler_procedure,
DEFAULT_AGGREGATE)))
MYSQL_YYABORT;
@@ -20571,7 +20581,7 @@ package_implementation_routine_definition:
pkg->m_current_routine= NULL;
$$.init();
}
| package_specification_element { $$.init(); }
| package_specification_routine { $$.init(); }
;
@@ -20624,7 +20634,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();
@@ -20641,6 +20651,13 @@ package_specification_element:
}
;
package_specification_element:
package_specification_routine
%ifdef ORACLE
| sp_decl_type ';'
%endif
;
%ifdef ORACLE
@@ -20728,7 +20745,7 @@ sf_c_chistics_and_body_standalone:
sp_tail_standalone:
sp_name
{
if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1,
if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1, Lex->definer,
&sp_handler_procedure,
DEFAULT_AGGREGATE)))
MYSQL_YYABORT;
@@ -21015,15 +21032,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();
}
@@ -21031,7 +21055,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();
@@ -21040,7 +21064,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();

View File

@@ -665,6 +665,7 @@ protected:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
{
return m_dec_overflowed;
}
bool foreign_module_type() const
{
return m_foreign_module_type;
}
};