1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-11952 Oracle-style packages: stage#5

Backporting from bb-10.2-compatibility to bb-10.2-ext

Version: 2018-01-26

- CREATE PACKAGE [BODY] statements are now
  entirely written to mysql.proc with type='PACKAGE' and type='PACKAGE BODY'.
- CREATE PACKAGE BODY now supports IF NOT EXISTS
- DROP PACKAGE BODY now supports IF EXISTS
- CREATE OR REPLACE PACKAGE [BODY] is now supported
- CREATE PACKAGE [BODY] now support the DEFINER clause:

    CREATE DEFINER user@host PACKAGE pkg ... END;
    CREATE DEFINER user@host PACKAGE BODY pkg ... END;

- CREATE PACKAGE [BODY] now supports SQL SECURITY and COMMENT clauses, e.g.:

    CREATE PACKAGE p1 SQL SECURITY INVOKER COMMENT "comment" AS ... END;

- Package routines are now created from the package CREATE PACKAGE BODY
  statement and don't produce individual records in mysql.proc.

- CREATE PACKAGE BODY now supports package-wide variables.
  Package variables can be read and set inside package routines.
  Package variables are stored in a separate sp_rcontext,
  which is cached in THD on the first packate routine call.

- CREATE PACKAGE BODY now supports the initialization section.

- All public routines (i.e. declared in CREATE PACKAGE)
  must have implementations in CREATE PACKAGE BODY

- Only public package routines are available outside of the package

- {CREATE|DROP} PACKAGE [BODY] now respects CREATE ROUTINE and ALTER ROUTINE
  privileges

- "GRANT EXECUTE ON PACKAGE BODY pkg" is now supported

- SHOW CREATE PACKAGE [BODY] is now supported

- SHOW PACKAGE [BODY] STATUS is now supported

- CREATE and DROP for PACKAGE [BODY] now works for non-current databases

- mysqldump now supports packages

- "SHOW {PROCEDURE|FUNCTION) CODE pkg.routine" now works for package routines

- "SHOW PACKAGE BODY CODE pkg" now works (the package initialization section)

- A new package body level MDL was added

- Recursive calls for package procedures are now possible

- Routine forward declarations in CREATE PACKATE BODY are now supported.

- Package body variables now work as SP OUT parameters

- Package body variables now work as SELECT INTO targets

- Package body variables now support ROW, %ROWTYPE, %TYPE
This commit is contained in:
Alexander Barkov
2017-08-18 23:36:42 +04:00
parent b8af22af15
commit 5f7c764fe7
84 changed files with 11055 additions and 278 deletions

View File

@@ -2478,7 +2478,14 @@ static void print_blob_as_hex(FILE *output_file, const char *str, ulong len)
static uint dump_routines_for_db(char *db) static uint dump_routines_for_db(char *db)
{ {
char query_buff[QUERY_LENGTH]; char query_buff[QUERY_LENGTH];
const char *routine_type[]= {"FUNCTION", "PROCEDURE"}; const char *routine_type[]= {"FUNCTION",
"PROCEDURE",
"PACKAGE",
"PACKAGE BODY"};
const char *create_caption_xml[]= {"Create Function",
"Create Procedure",
"Create Package",
"Create Package Body"};
char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3]; char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
char *routine_name; char *routine_name;
int i; int i;
@@ -2516,8 +2523,8 @@ static uint dump_routines_for_db(char *db)
if (opt_xml) if (opt_xml)
fputs("\t<routines>\n", sql_file); fputs("\t<routines>\n", sql_file);
/* 0, retrieve and dump functions, 1, procedures */ /* 0, retrieve and dump functions, 1, procedures, etc. */
for (i= 0; i <= 1; i++) for (i= 0; i < 4; i++)
{ {
my_snprintf(query_buff, sizeof(query_buff), my_snprintf(query_buff, sizeof(query_buff),
"SHOW %s STATUS WHERE Db = '%s'", "SHOW %s STATUS WHERE Db = '%s'",
@@ -2567,12 +2574,8 @@ static uint dump_routines_for_db(char *db)
{ {
if (opt_xml) if (opt_xml)
{ {
if (i) /* Procedures. */ print_xml_row(sql_file, "routine", routine_res, &row,
print_xml_row(sql_file, "routine", routine_res, &row, create_caption_xml[i]);
"Create Procedure");
else /* Functions. */
print_xml_row(sql_file, "routine", routine_res, &row,
"Create Function");
continue; continue;
} }
if (opt_drop) if (opt_drop)

View File

@@ -647,7 +647,7 @@ select * from t115;
table_name column_name column_type table_name column_name column_type
proc db char(64) proc db char(64)
proc name char(64) proc name char(64)
proc type enum('FUNCTION','PROCEDURE') proc type enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY')
proc specific_name char(64) proc specific_name char(64)
proc language enum('SQL') proc language enum('SQL')
proc sql_data_access enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') proc sql_data_access enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA')

View File

@@ -9,7 +9,7 @@ ROUTINES CREATE TEMPORARY TABLE `ROUTINES` (
`ROUTINE_CATALOG` varchar(512) NOT NULL DEFAULT '', `ROUTINE_CATALOG` varchar(512) NOT NULL DEFAULT '',
`ROUTINE_SCHEMA` varchar(64) NOT NULL DEFAULT '', `ROUTINE_SCHEMA` varchar(64) NOT NULL DEFAULT '',
`ROUTINE_NAME` varchar(64) NOT NULL DEFAULT '', `ROUTINE_NAME` varchar(64) NOT NULL DEFAULT '',
`ROUTINE_TYPE` varchar(9) NOT NULL DEFAULT '', `ROUTINE_TYPE` varchar(13) NOT NULL DEFAULT '',
`DATA_TYPE` varchar(64) NOT NULL DEFAULT '', `DATA_TYPE` varchar(64) NOT NULL DEFAULT '',
`CHARACTER_MAXIMUM_LENGTH` int(21) DEFAULT NULL, `CHARACTER_MAXIMUM_LENGTH` int(21) DEFAULT NULL,
`CHARACTER_OCTET_LENGTH` int(21) DEFAULT NULL, `CHARACTER_OCTET_LENGTH` int(21) DEFAULT NULL,
@@ -137,14 +137,14 @@ ORDINAL_POSITION 5
COLUMN_DEFAULT '' COLUMN_DEFAULT ''
IS_NULLABLE NO IS_NULLABLE NO
DATA_TYPE varchar DATA_TYPE varchar
CHARACTER_MAXIMUM_LENGTH 9 CHARACTER_MAXIMUM_LENGTH 13
CHARACTER_OCTET_LENGTH 27 CHARACTER_OCTET_LENGTH 39
NUMERIC_PRECISION NULL NUMERIC_PRECISION NULL
NUMERIC_SCALE NULL NUMERIC_SCALE NULL
DATETIME_PRECISION NULL DATETIME_PRECISION NULL
CHARACTER_SET_NAME utf8 CHARACTER_SET_NAME utf8
COLLATION_NAME utf8_general_ci COLLATION_NAME utf8_general_ci
COLUMN_TYPE varchar(9) COLUMN_TYPE varchar(13)
COLUMN_KEY COLUMN_KEY
EXTRA EXTRA
PRIVILEGES # PRIVILEGES #
@@ -729,7 +729,7 @@ SPECIFIC_NAME varchar(64) NO
ROUTINE_CATALOG varchar(512) NO ROUTINE_CATALOG varchar(512) NO
ROUTINE_SCHEMA varchar(64) NO ROUTINE_SCHEMA varchar(64) NO
ROUTINE_NAME varchar(64) NO ROUTINE_NAME varchar(64) NO
ROUTINE_TYPE varchar(9) NO ROUTINE_TYPE varchar(13) NO
DATA_TYPE varchar(64) NO DATA_TYPE varchar(64) NO
CHARACTER_MAXIMUM_LENGTH int(21) YES NULL CHARACTER_MAXIMUM_LENGTH int(21) YES NULL
CHARACTER_OCTET_LENGTH int(21) YES NULL CHARACTER_OCTET_LENGTH int(21) YES NULL

View File

@@ -1421,7 +1421,7 @@ performance-schema-max-rwlock-instances -1
performance-schema-max-socket-classes 10 performance-schema-max-socket-classes 10
performance-schema-max-socket-instances -1 performance-schema-max-socket-instances -1
performance-schema-max-stage-classes 160 performance-schema-max-stage-classes 160
performance-schema-max-statement-classes 191 performance-schema-max-statement-classes 200
performance-schema-max-table-handles -1 performance-schema-max-table-handles -1
performance-schema-max-table-instances -1 performance-schema-max-table-instances -1
performance-schema-max-thread-classes 50 performance-schema-max-thread-classes 50

View File

@@ -1131,7 +1131,7 @@ def information_schema ROUTINES ROUTINES SPECIFIC_NAME SPECIFIC_NAME 253 192 2 N
def information_schema ROUTINES ROUTINES ROUTINE_CATALOG ROUTINE_CATALOG 253 1536 3 N 1 0 33 def information_schema ROUTINES ROUTINES ROUTINE_CATALOG ROUTINE_CATALOG 253 1536 3 N 1 0 33
def information_schema ROUTINES ROUTINES ROUTINE_SCHEMA ROUTINE_SCHEMA 253 192 4 N 1 0 33 def information_schema ROUTINES ROUTINES ROUTINE_SCHEMA ROUTINE_SCHEMA 253 192 4 N 1 0 33
def information_schema ROUTINES ROUTINES ROUTINE_NAME ROUTINE_NAME 253 192 2 N 1 0 33 def information_schema ROUTINES ROUTINES ROUTINE_NAME ROUTINE_NAME 253 192 2 N 1 0 33
def information_schema ROUTINES ROUTINES ROUTINE_TYPE ROUTINE_TYPE 253 27 9 N 1 0 33 def information_schema ROUTINES ROUTINES ROUTINE_TYPE ROUTINE_TYPE 253 39 9 N 1 0 33
def information_schema ROUTINES ROUTINES DTD_IDENTIFIER DTD_IDENTIFIER 252 589815 0 Y 16 0 33 def information_schema ROUTINES ROUTINES DTD_IDENTIFIER DTD_IDENTIFIER 252 589815 0 Y 16 0 33
def information_schema ROUTINES ROUTINES ROUTINE_BODY ROUTINE_BODY 253 24 3 N 1 0 33 def information_schema ROUTINES ROUTINES ROUTINE_BODY ROUTINE_BODY 253 24 3 N 1 0 33
def information_schema ROUTINES ROUTINES ROUTINE_DEFINITION ROUTINE_DEFINITION 252 589815 8 Y 16 0 33 def information_schema ROUTINES ROUTINES ROUTINE_DEFINITION ROUTINE_DEFINITION 252 589815 8 Y 16 0 33
@@ -1186,7 +1186,7 @@ def information_schema ROUTINES ROUTINES SPECIFIC_NAME SPECIFIC_NAME 253 192 2 N
def information_schema ROUTINES ROUTINES ROUTINE_CATALOG ROUTINE_CATALOG 253 1536 3 N 1 0 33 def information_schema ROUTINES ROUTINES ROUTINE_CATALOG ROUTINE_CATALOG 253 1536 3 N 1 0 33
def information_schema ROUTINES ROUTINES ROUTINE_SCHEMA ROUTINE_SCHEMA 253 192 4 N 1 0 33 def information_schema ROUTINES ROUTINES ROUTINE_SCHEMA ROUTINE_SCHEMA 253 192 4 N 1 0 33
def information_schema ROUTINES ROUTINES ROUTINE_NAME ROUTINE_NAME 253 192 2 N 1 0 33 def information_schema ROUTINES ROUTINES ROUTINE_NAME ROUTINE_NAME 253 192 2 N 1 0 33
def information_schema ROUTINES ROUTINES ROUTINE_TYPE ROUTINE_TYPE 253 27 8 N 1 0 33 def information_schema ROUTINES ROUTINES ROUTINE_TYPE ROUTINE_TYPE 253 39 8 N 1 0 33
def information_schema ROUTINES ROUTINES DTD_IDENTIFIER DTD_IDENTIFIER 252 589815 7 Y 16 0 33 def information_schema ROUTINES ROUTINES DTD_IDENTIFIER DTD_IDENTIFIER 252 589815 7 Y 16 0 33
def information_schema ROUTINES ROUTINES ROUTINE_BODY ROUTINE_BODY 253 24 3 N 1 0 33 def information_schema ROUTINES ROUTINES ROUTINE_BODY ROUTINE_BODY 253 24 3 N 1 0 33
def information_schema ROUTINES ROUTINES ROUTINE_DEFINITION ROUTINE_DEFINITION 252 589815 8 Y 16 0 33 def information_schema ROUTINES ROUTINES ROUTINE_DEFINITION ROUTINE_DEFINITION 252 589815 8 Y 16 0 33

View File

@@ -88,6 +88,8 @@ Acl_column_grants 0
Acl_database_grants 0 Acl_database_grants 0
Acl_function_grants 0 Acl_function_grants 0
Acl_procedure_grants 0 Acl_procedure_grants 0
Acl_package_spec_grants 0
Acl_package_body_grants 0
Acl_proxy_users 0 Acl_proxy_users 0
Acl_role_grants 0 Acl_role_grants 0
Acl_roles 0 Acl_roles 0

View File

@@ -176,7 +176,7 @@ procs_priv CREATE TABLE `procs_priv` (
`Db` char(64) COLLATE utf8_bin NOT NULL DEFAULT '', `Db` char(64) COLLATE utf8_bin NOT NULL DEFAULT '',
`User` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', `User` char(80) COLLATE utf8_bin NOT NULL DEFAULT '',
`Routine_name` char(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `Routine_name` char(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
`Routine_type` enum('FUNCTION','PROCEDURE') COLLATE utf8_bin NOT NULL, `Routine_type` enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') COLLATE utf8_bin NOT NULL,
`Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '', `Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '',
`Proc_priv` set('Execute','Alter Routine','Grant') CHARACTER SET utf8 NOT NULL DEFAULT '', `Proc_priv` set('Execute','Alter Routine','Grant') CHARACTER SET utf8 NOT NULL DEFAULT '',
`Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), `Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
@@ -202,7 +202,7 @@ Table Create Table
proc CREATE TABLE `proc` ( proc CREATE TABLE `proc` (
`db` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', `db` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
`name` char(64) NOT NULL DEFAULT '', `name` char(64) NOT NULL DEFAULT '',
`type` enum('FUNCTION','PROCEDURE') NOT NULL, `type` enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') NOT NULL,
`specific_name` char(64) NOT NULL DEFAULT '', `specific_name` char(64) NOT NULL DEFAULT '',
`language` enum('SQL') NOT NULL DEFAULT 'SQL', `language` enum('SQL') NOT NULL DEFAULT 'SQL',
`sql_data_access` enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') NOT NULL DEFAULT 'CONTAINS_SQL', `sql_data_access` enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') NOT NULL DEFAULT 'CONTAINS_SQL',

View File

@@ -176,7 +176,7 @@ procs_priv CREATE TABLE `procs_priv` (
`Db` char(64) COLLATE utf8_bin NOT NULL DEFAULT '', `Db` char(64) COLLATE utf8_bin NOT NULL DEFAULT '',
`User` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', `User` char(80) COLLATE utf8_bin NOT NULL DEFAULT '',
`Routine_name` char(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `Routine_name` char(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
`Routine_type` enum('FUNCTION','PROCEDURE') COLLATE utf8_bin NOT NULL, `Routine_type` enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') COLLATE utf8_bin NOT NULL,
`Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '', `Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '',
`Proc_priv` set('Execute','Alter Routine','Grant') CHARACTER SET utf8 NOT NULL DEFAULT '', `Proc_priv` set('Execute','Alter Routine','Grant') CHARACTER SET utf8 NOT NULL DEFAULT '',
`Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), `Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
@@ -202,7 +202,7 @@ Table Create Table
proc CREATE TABLE `proc` ( proc CREATE TABLE `proc` (
`db` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', `db` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
`name` char(64) NOT NULL DEFAULT '', `name` char(64) NOT NULL DEFAULT '',
`type` enum('FUNCTION','PROCEDURE') NOT NULL, `type` enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') NOT NULL,
`specific_name` char(64) NOT NULL DEFAULT '', `specific_name` char(64) NOT NULL DEFAULT '',
`language` enum('SQL') NOT NULL DEFAULT 'SQL', `language` enum('SQL') NOT NULL DEFAULT 'SQL',
`sql_data_access` enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') NOT NULL DEFAULT 'CONTAINS_SQL', `sql_data_access` enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') NOT NULL DEFAULT 'CONTAINS_SQL',

View File

@@ -176,7 +176,7 @@ procs_priv CREATE TABLE `procs_priv` (
`Db` char(64) COLLATE utf8_bin NOT NULL DEFAULT '', `Db` char(64) COLLATE utf8_bin NOT NULL DEFAULT '',
`User` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', `User` char(80) COLLATE utf8_bin NOT NULL DEFAULT '',
`Routine_name` char(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `Routine_name` char(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
`Routine_type` enum('FUNCTION','PROCEDURE') COLLATE utf8_bin NOT NULL, `Routine_type` enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') COLLATE utf8_bin NOT NULL,
`Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '', `Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '',
`Proc_priv` set('Execute','Alter Routine','Grant') CHARACTER SET utf8 NOT NULL DEFAULT '', `Proc_priv` set('Execute','Alter Routine','Grant') CHARACTER SET utf8 NOT NULL DEFAULT '',
`Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), `Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
@@ -202,7 +202,7 @@ Table Create Table
proc CREATE TABLE `proc` ( proc CREATE TABLE `proc` (
`db` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', `db` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
`name` char(64) NOT NULL DEFAULT '', `name` char(64) NOT NULL DEFAULT '',
`type` enum('FUNCTION','PROCEDURE') NOT NULL, `type` enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') NOT NULL,
`specific_name` char(64) NOT NULL DEFAULT '', `specific_name` char(64) NOT NULL DEFAULT '',
`language` enum('SQL') NOT NULL DEFAULT 'SQL', `language` enum('SQL') NOT NULL DEFAULT 'SQL',
`sql_data_access` enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') NOT NULL DEFAULT 'CONTAINS_SQL', `sql_data_access` enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') NOT NULL DEFAULT 'CONTAINS_SQL',

View File

@@ -176,7 +176,7 @@ procs_priv CREATE TABLE `procs_priv` (
`Db` char(64) COLLATE utf8_bin NOT NULL DEFAULT '', `Db` char(64) COLLATE utf8_bin NOT NULL DEFAULT '',
`User` char(80) COLLATE utf8_bin NOT NULL DEFAULT '', `User` char(80) COLLATE utf8_bin NOT NULL DEFAULT '',
`Routine_name` char(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `Routine_name` char(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
`Routine_type` enum('FUNCTION','PROCEDURE') COLLATE utf8_bin NOT NULL, `Routine_type` enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') COLLATE utf8_bin NOT NULL,
`Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '', `Grantor` char(141) COLLATE utf8_bin NOT NULL DEFAULT '',
`Proc_priv` set('Execute','Alter Routine','Grant') CHARACTER SET utf8 NOT NULL DEFAULT '', `Proc_priv` set('Execute','Alter Routine','Grant') CHARACTER SET utf8 NOT NULL DEFAULT '',
`Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), `Timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
@@ -202,7 +202,7 @@ Table Create Table
proc CREATE TABLE `proc` ( proc CREATE TABLE `proc` (
`db` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', `db` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
`name` char(64) NOT NULL DEFAULT '', `name` char(64) NOT NULL DEFAULT '',
`type` enum('FUNCTION','PROCEDURE') NOT NULL, `type` enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') NOT NULL,
`specific_name` char(64) NOT NULL DEFAULT '', `specific_name` char(64) NOT NULL DEFAULT '',
`language` enum('SQL') NOT NULL DEFAULT 'SQL', `language` enum('SQL') NOT NULL DEFAULT 'SQL',
`sql_data_access` enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') NOT NULL DEFAULT 'CONTAINS_SQL', `sql_data_access` enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') NOT NULL DEFAULT 'CONTAINS_SQL',

View File

@@ -0,0 +1,268 @@
SET sql_mode=ORACLE;
CREATE PACKAGE p1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
CREATE PACKAGE IF NOT EXISTS p1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
Warnings:
Note 1304 PACKAGE p1 already exists
CREATE PACKAGE BODY p1 AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 10;
END;
END;
$$
DROP PACKAGE BODY p1;
DROP PACKAGE p1;
DROP PACKAGE IF EXISTS p1;
Warnings:
Note 1305 PACKAGE test.p1 does not exist
#
# Creating a package with a COMMENT clause
#
CREATE PACKAGE p1 COMMENT 'package-p1-comment' AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY p1 COMMENT 'package-body-p1-comment' AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
DROP PACKAGE p1;
#
# Creating a package with a different DEFINER
#
CREATE DEFINER=xxx@localhost PACKAGE p1 AS
PROCEDURE p1;
END;
$$
Warnings:
Note 1449 The user specified as a definer ('xxx'@'localhost') does not exist
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
Warnings:
Note 1449 The user specified as a definer ('xxx'@'localhost') does not exist
DROP PACKAGE p1;
#
# Creating a package with a different DEFINER, with SQL SECURITY INVOKER
#
CREATE DEFINER=xxx@localhost PACKAGE p1 SQL SECURITY INVOKER AS
PROCEDURE p1;
END;
$$
Warnings:
Note 1449 The user specified as a definer ('xxx'@'localhost') does not exist
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 SQL SECURITY INVOKER AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
Warnings:
Note 1449 The user specified as a definer ('xxx'@'localhost') does not exist
DROP PACKAGE p1;
#
# Creating a new package in a remote database
#
CREATE DATABASE test2;
CREATE PACKAGE test2.test2 COMMENT 'package-test2-comment' AS
FUNCTION f1 RETURN INT;
PROCEDURE p1;
END
$$
CREATE PACKAGE BODY test2.test2 COMMENT 'package-body-test2-comment' AS
FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END;
PROCEDURE p1 AS BEGIN SELECT f1(); END;
END;
$$
DROP PACKAGE BODY test2.test2;
DROP PACKAGE test2.test2;
DROP DATABASE test2;
#
# MDEV-13139 Package-wide variables in CREATE PACKAGE
#
CREATE TABLE t1 (a INT);
CREATE PACKAGE p1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY p1 AS
a INT:=0;
PROCEDURE p1 AS
BEGIN
INSERT INTO t1 VALUES (a);
a:=a+1;
END;
BEGIN
a:=10;
END;
$$
CALL p1.p1();
CALL p1.p1();
SELECT * FROM t1;
a
10
11
# sp-cache-invalidate
CALL p1.p1();
CALL p1.p1();
SELECT * FROM t1;
a
10
11
10
11
DROP PACKAGE p1;
DROP TABLE t1;
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PACKAGE "p1" AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PACKAGE IF NOT EXISTS "p1" AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PACKAGE BODY "p1" AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 10;
END;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP PACKAGE BODY p1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP PACKAGE p1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP PACKAGE IF EXISTS p1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PACKAGE "p1" COMMENT 'package-p1-comment'
AS
PROCEDURE p1;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PACKAGE BODY "p1" COMMENT 'package-body-p1-comment'
AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP PACKAGE p1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="xxx"@"localhost" PACKAGE "p1" AS
PROCEDURE p1;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="xxx"@"localhost" PACKAGE BODY "p1" AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP PACKAGE p1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="xxx"@"localhost" PACKAGE "p1" SQL SECURITY INVOKER
AS
PROCEDURE p1;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="xxx"@"localhost" PACKAGE BODY "p1" SQL SECURITY INVOKER
AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP PACKAGE p1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # CREATE DATABASE test2
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PACKAGE "test2"."test2" COMMENT 'package-test2-comment'
AS
FUNCTION f1 RETURN INT;
PROCEDURE p1;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PACKAGE BODY "test2"."test2" COMMENT 'package-body-test2-comment'
AS
FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END;
PROCEDURE p1 AS BEGIN SELECT f1(); END;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP PACKAGE BODY test2.test2
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP PACKAGE test2.test2
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # DROP DATABASE test2
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT)
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PACKAGE "p1" AS
PROCEDURE p1;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="root"@"localhost" PACKAGE BODY "p1" AS
a INT:=0;
PROCEDURE p1 AS
BEGIN
INSERT INTO t1 VALUES (a);
a:=a+1;
END;
BEGIN
a:=10;
END
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('a',10))
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('a',11))
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE DEFINER="root"@"localhost" FUNCTION "dummy"() RETURN int(11)
AS
BEGIN
RETURN 1;
END
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP FUNCTION dummy
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('a',10))
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('a',11))
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP PACKAGE p1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP TABLE "t1" /* generated by server */

View File

@@ -0,0 +1,181 @@
include/master-slave.inc
[connection master]
connection master;
SET sql_mode=ORACLE;
CREATE PACKAGE pack AS
FUNCTION f1 RETURN INT;
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pack AS
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 10;
END;
PROCEDURE p1 AS
BEGIN
SELECT f1();
END;
END pack;
$$
connection slave;
connection slave;
SELECT * FROM mysql.proc WHERE db='test' AND name='pack';
db test
name pack
type PACKAGE
specific_name pack
language SQL
sql_data_access CONTAINS_SQL
is_deterministic NO
security_type DEFINER
param_list
returns
body AS
FUNCTION f1 RETURN INT;
PROCEDURE p1;
END
definer root@localhost
created #
modified #
sql_mode PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER
comment
character_set_client latin1
collation_connection latin1_swedish_ci
db_collation latin1_swedish_ci
body_utf8
db test
name pack
type PACKAGE BODY
specific_name pack
language SQL
sql_data_access CONTAINS_SQL
is_deterministic NO
security_type DEFINER
param_list
returns
body AS
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 10;
END;
PROCEDURE p1 AS
BEGIN
SELECT f1();
END;
END
definer root@localhost
created #
modified #
sql_mode PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER
comment
character_set_client latin1
collation_connection latin1_swedish_ci
db_collation latin1_swedish_ci
body_utf8
SELECT * FROM mysql.proc WHERE db='test' AND name LIKE 'pack.%';
SET @@sql_mode=ORACLE;
SELECT pack.f1();
pack.f1()
10
CALL pack.p1();
f1()
10
SET @@sql_mode=DEFAULT;
connection master;
DROP PACKAGE pack;
connection slave;
connection slave;
SELECT COUNT(*) FROM mysql.proc WHERE db='test' AND name='pack';
COUNT(*)
0
#
# Creating a package with a COMMENT
#
connection master;
CREATE PACKAGE p1 COMMENT 'package-p1-comment' AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY p1 COMMENT 'package-body-p1-comment' AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
SELECT definer, name, security_type, type, `comment` FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
definer name security_type type comment
root@localhost p1 DEFINER PACKAGE package-p1-comment
root@localhost p1 DEFINER PACKAGE BODY package-body-p1-comment
connection slave;
SELECT definer, name, security_type, type, `comment` FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
definer name security_type type comment
root@localhost p1 DEFINER PACKAGE package-p1-comment
root@localhost p1 DEFINER PACKAGE BODY package-body-p1-comment
connection master;
DROP PACKAGE p1;
connection slave;
#
# Creating a package with a different DEFINER
#
connection master;
CREATE DEFINER=xxx@localhost PACKAGE p1 AS
PROCEDURE p1;
END;
$$
Warnings:
Note 1449 The user specified as a definer ('xxx'@'localhost') does not exist
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
Warnings:
Note 1449 The user specified as a definer ('xxx'@'localhost') does not exist
SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
definer name security_type type
xxx@localhost p1 DEFINER PACKAGE
xxx@localhost p1 DEFINER PACKAGE BODY
connection slave;
SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
definer name security_type type
xxx@localhost p1 DEFINER PACKAGE
xxx@localhost p1 DEFINER PACKAGE BODY
connection master;
DROP PACKAGE p1;
connection slave;
#
# Creating a package with a different DEFINER + SQL SECURITY INVOKER
#
connection master;
CREATE DEFINER=xxx@localhost PACKAGE p1 SQL SECURITY INVOKER AS
PROCEDURE p1;
END;
$$
Warnings:
Note 1449 The user specified as a definer ('xxx'@'localhost') does not exist
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 SQL SECURITY INVOKER AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
Warnings:
Note 1449 The user specified as a definer ('xxx'@'localhost') does not exist
SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
definer name security_type type
xxx@localhost p1 INVOKER PACKAGE
xxx@localhost p1 INVOKER PACKAGE BODY
connection slave;
SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
definer name security_type type
xxx@localhost p1 INVOKER PACKAGE
xxx@localhost p1 INVOKER PACKAGE BODY
connection master;
DROP PACKAGE p1;
connection slave;
include/rpl_end.inc

View File

@@ -0,0 +1,38 @@
include/master-slave.inc
[connection master]
connection master;
SET sql_mode=ORACLE;
#
# MDEV-13139 Package-wide variables in CREATE PACKAGE
#
connection master;
CREATE PACKAGE p1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY p1 AS
va INT:=10;
PROCEDURE p1 AS
BEGIN
INSERT INTO t1 VALUES (va);
END;
BEGIN
CREATE OR REPLACE TABLE t1 (a INT);
END;
$$
CALL p1.p1();
CALL p1.p1();
SELECT * FROM t1;
a
10
10
connection slave;
SELECT * FROM t1;
a
10
10
connection master;
DROP PACKAGE p1;
DROP TABLE t1;
connection slave;
include/rpl_end.inc

View File

@@ -0,0 +1,245 @@
SET sql_mode=ORACLE;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
PROCEDURE p2show;
PROCEDURE p2public;
FUNCTION f2public RETURN TEXT;
END;
$$
CREATE PACKAGE BODY pkg1 AS
a INT:=10;
PROCEDURE p1 AS
b INT:=20;
BEGIN
b:=a;
b:=a+1;
a:=b;
a:=b+1;
a:=a+1;
SET @a:=@a+2;
SELECT f1() FROM DUAL;
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN a;
END;
PROCEDURE p2private AS
BEGIN
SELECT 'This is p2private';
END;
PROCEDURE p2public AS
BEGIN
SELECT 'This is p2public';
END;
FUNCTION f2private RETURN TEXT AS
BEGIN
RETURN 'This is f2private';
END;
FUNCTION f2public RETURN TEXT AS
BEGIN
RETURN 'This is f2public';
END;
PROCEDURE p2show AS
BEGIN
SHOW FUNCTION CODE f2public;
SHOW FUNCTION CODE f2private;
SHOW PROCEDURE CODE p2public;
SHOW PROCEDURE CODE p2private;
SHOW PROCEDURE CODE p2show;
END;
BEGIN
a:=a+1;
DECLARE
b INT;
BEGIN
b:=a;
b:=a+1;
a:=b;
a:=b+1;
END;
END;
$$
SHOW PROCEDURE CODE pkg1.p1;
Pos Instruction
0 set b@0 20
1 set b@0 PACKAGE_BODY.a@0
2 set b@0 PACKAGE_BODY.a@0 + 1
3 set PACKAGE_BODY.a@0 b@0
4 set PACKAGE_BODY.a@0 b@0 + 1
5 set PACKAGE_BODY.a@0 PACKAGE_BODY.a@0 + 1
6 stmt 31 "SET @a:=@a+2"
7 stmt 0 "SELECT f1() FROM DUAL"
SHOW FUNCTION CODE pkg1.f1;
Pos Instruction
0 freturn int PACKAGE_BODY.a@0
SHOW PACKAGE BODY CODE pkg1;
Pos Instruction
0 set a@0 10
1 set a@0 a@0 + 1
2 set b@1 NULL
3 set b@1 a@0
4 set b@1 a@0 + 1
5 set a@0 b@1
6 set a@0 b@1 + 1
7 jump 11
CALL pkg1.p2show;
Pos Instruction
0 freturn blob 'This is f2public'
Pos Instruction
0 freturn blob 'This is f2private'
Pos Instruction
0 stmt 0 "SELECT 'This is p2public'"
Pos Instruction
0 stmt 0 "SELECT 'This is p2private'"
Pos Instruction
0 stmt 110 "SHOW FUNCTION CODE f2public"
1 stmt 110 "SHOW FUNCTION CODE f2private"
2 stmt 109 "SHOW PROCEDURE CODE p2public"
3 stmt 109 "SHOW PROCEDURE CODE p2private"
4 stmt 109 "SHOW PROCEDURE CODE p2show"
DROP PACKAGE pkg1;
CREATE TABLE t1 (a INT);
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
a t1.a%TYPE:=10;
PROCEDURE p1 AS
b t1.a%TYPE:=20;
BEGIN
b:=a;
b:=a+1;
b:=b+1;
a:=b;
a:=b+1;
a:=a+1;
END;
BEGIN
a:=a+1;
DECLARE
b t1.a%TYPE;
BEGIN
b:=a;
b:=a+1;
a:=b;
a:=b+1;
END;
END;
$$
SHOW PROCEDURE CODE pkg1.p1;
Pos Instruction
0 set b@0 20
1 set b@0 PACKAGE_BODY.a@0
2 set b@0 PACKAGE_BODY.a@0 + 1
3 set b@0 b@0 + 1
4 set PACKAGE_BODY.a@0 b@0
5 set PACKAGE_BODY.a@0 b@0 + 1
6 set PACKAGE_BODY.a@0 PACKAGE_BODY.a@0 + 1
SHOW PACKAGE BODY CODE pkg1;
Pos Instruction
0 set a@0 10
1 set a@0 a@0 + 1
2 set b@1 NULL
3 set b@1 a@0
4 set b@1 a@0 + 1
5 set a@0 b@1
6 set a@0 b@1 + 1
7 jump 11
DROP PACKAGE pkg1;
DROP TABLE t1;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
a ROW(a INT,b TEXT):=ROW(10,'x10');
PROCEDURE p1 AS
b ROW(a INT,b TEXT):=ROW(20,'x20');
BEGIN
b:=a;
a:=b;
b.a:=a.a+1;
a.a:=b.a+1;
a.a:=a.a+1;
END;
BEGIN
a.a:=a.a+1;
DECLARE
b ROW(a INT,b TEXT):=ROW(30,'x30');
BEGIN
b:=a;
b.a:=a.a+1;
a:=b;
a.a:=b.a+1;
END;
END;
$$
SHOW PROCEDURE CODE pkg1.p1;
Pos Instruction
0 set b@0 (20,'x20')
1 set b@0 PACKAGE_BODY.a@0
2 set PACKAGE_BODY.a@0 b@0
3 set b.a@0[0] PACKAGE_BODY.a.a@0[0] + 1
4 set PACKAGE_BODY.a.a@0[0] b.a@0[0] + 1
5 set PACKAGE_BODY.a.a@0[0] PACKAGE_BODY.a.a@0[0] + 1
SHOW PACKAGE BODY CODE pkg1;
Pos Instruction
0 set a@0 (10,'x10')
1 set a.a@0[0] a.a@0[0] + 1
2 set b@1 (30,'x30')
3 set b@1 a@0
4 set b.a@1[0] a.a@0[0] + 1
5 set a@0 b@1
6 set a.a@0[0] b.a@1[0] + 1
7 jump 11
DROP PACKAGE pkg1;
CREATE TABLE t1 (a INT, b TEXT);
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
a t1%ROWTYPE:=ROW(10,'x10');
PROCEDURE p1 AS
b t1%ROWTYPE:=ROW(20,'x20');
BEGIN
b:=a;
a:=b;
b.a:=a.a+1;
a.a:=b.a+1;
a.a:=a.a+1;
END;
BEGIN
a.a:=a.a+1;
DECLARE
b t1%ROWTYPE:=ROW(30,'x30');
BEGIN
b:=a;
b.a:=a.a+1;
a:=b;
a.a:=b.a+1;
END;
END;
$$
SHOW PROCEDURE CODE pkg1.p1;
Pos Instruction
0 set b@0 (20,'x20')
1 set b@0 PACKAGE_BODY.a@0
2 set PACKAGE_BODY.a@0 b@0
3 set b.a@0["a"] PACKAGE_BODY.a.a@0["a"] + 1
4 set PACKAGE_BODY.a.a@0["a"] b.a@0["a"] + 1
5 set PACKAGE_BODY.a.a@0["a"] PACKAGE_BODY.a.a@0["a"] + 1
SHOW PACKAGE BODY CODE pkg1;
Pos Instruction
0 set a@0 (10,'x10')
1 set a.a@0["a"] a.a@0["a"] + 1
2 set b@1 (30,'x30')
3 set b@1 a@0
4 set b.a@1["a"] a.a@0["a"] + 1
5 set a@0 b@1
6 set a.a@0["a"] b.a@1["a"] + 1
7 jump 11
DROP PACKAGE pkg1;
DROP TABLE t1;

View File

@@ -0,0 +1,43 @@
#
# MDEV-15070 Crash when doing a CREATE VIEW inside a package routine
#
SET @object_type='db';
#
# Start of sp-package-concurrent-dml.inc
#
SET sql_mode=ORACLE;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p2 AS
BEGIN
SELECT 'This is p2' AS msg;
END;
PROCEDURE p1 AS
BEGIN
SELECT 'This is p1' AS msg;
DO GET_LOCK('mdev15070',120);
CALL p2();
DO RELEASE_LOCK('mdev15070');
END;
END;
$$
connect con2,localhost,root;
connection con2;
DO GET_LOCK('mdev15070', 120);
connection default;
CALL pkg1.p1;
connection con2;
CREATE DATABASE test1;
CREATE FUNCTION test1.f1() RETURNS INT RETURN 10;
DROP DATABASE test1;
DO RELEASE_LOCK('mdev15070');
disconnect con2;
connection default;
msg
This is p1
msg
This is p2
DROP PACKAGE IF EXISTS pkg1;

View File

@@ -0,0 +1,96 @@
#
# MDEV-15070 Crash when doing a CREATE VIEW inside a package routine
#
SET @object_type='package_replace_pkg1';
#
# Start of sp-package-concurrent-dml.inc
#
SET sql_mode=ORACLE;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p2 AS
BEGIN
SELECT 'This is p2' AS msg;
END;
PROCEDURE p1 AS
BEGIN
SELECT 'This is p1' AS msg;
DO GET_LOCK('mdev15070',120);
CALL p2();
DO RELEASE_LOCK('mdev15070');
END;
END;
$$
connect con2,localhost,root;
connection con2;
DO GET_LOCK('mdev15070', 120);
connection default;
CALL pkg1.p1;
connection con2;
SET sql_mode=ORACLE;
CREATE OR REPLACE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
DROP PACKAGE pkg1;
DO RELEASE_LOCK('mdev15070');
disconnect con2;
connection default;
msg
This is p1
msg
This is p2
DROP PACKAGE IF EXISTS pkg1;
Warnings:
Note 1305 PACKAGE test.pkg1 does not exist
SET @object_type='package_body_replace_pkg1';
#
# Start of sp-package-concurrent-dml.inc
#
SET sql_mode=ORACLE;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p2 AS
BEGIN
SELECT 'This is p2' AS msg;
END;
PROCEDURE p1 AS
BEGIN
SELECT 'This is p1' AS msg;
DO GET_LOCK('mdev15070',120);
CALL p2();
DO RELEASE_LOCK('mdev15070');
END;
END;
$$
connect con2,localhost,root;
connection con2;
DO GET_LOCK('mdev15070', 120);
connection default;
CALL pkg1.p1;
connection con2;
SET sql_mode=ORACLE;
CREATE OR REPLACE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
SELECT 'This is p1 version 2' AS msg;
END;
END;
$$
DROP PACKAGE pkg1;
DO RELEASE_LOCK('mdev15070');
disconnect con2;
connection default;
msg
This is p1
msg
This is p2
DROP PACKAGE IF EXISTS pkg1;
Warnings:
Note 1305 PACKAGE test.pkg1 does not exist

View File

@@ -0,0 +1,44 @@
#
# MDEV-15070 Crash when doing a CREATE VIEW inside a package routine
#
SET @object_type='trigger';
#
# Start of sp-package-concurrent-dml.inc
#
SET sql_mode=ORACLE;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p2 AS
BEGIN
SELECT 'This is p2' AS msg;
END;
PROCEDURE p1 AS
BEGIN
SELECT 'This is p1' AS msg;
DO GET_LOCK('mdev15070',120);
CALL p2();
DO RELEASE_LOCK('mdev15070');
END;
END;
$$
connect con2,localhost,root;
connection con2;
DO GET_LOCK('mdev15070', 120);
connection default;
CALL pkg1.p1;
connection con2;
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=1;
DROP TRIGGER tr1;
DROP TABLE t1;
DO RELEASE_LOCK('mdev15070');
disconnect con2;
connection default;
msg
This is p1
msg
This is p2
DROP PACKAGE IF EXISTS pkg1;

View File

@@ -0,0 +1,42 @@
#
# MDEV-15070 Crash when doing a CREATE VIEW inside a package routine
#
SET @object_type='view';
#
# Start of sp-package-concurrent-dml.inc
#
SET sql_mode=ORACLE;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p2 AS
BEGIN
SELECT 'This is p2' AS msg;
END;
PROCEDURE p1 AS
BEGIN
SELECT 'This is p1' AS msg;
DO GET_LOCK('mdev15070',120);
CALL p2();
DO RELEASE_LOCK('mdev15070');
END;
END;
$$
connect con2,localhost,root;
connection con2;
DO GET_LOCK('mdev15070', 120);
connection default;
CALL pkg1.p1;
connection con2;
CREATE VIEW v1 AS SELECT 1 AS c;
DROP VIEW v1;
DO RELEASE_LOCK('mdev15070');
disconnect con2;
connection default;
msg
This is p1
msg
This is p2
DROP PACKAGE IF EXISTS pkg1;

View File

@@ -0,0 +1,75 @@
SET default_storage_engine=InnoDB;
SET sql_mode=ORACLE;
CREATE TABLE t1 (a INT, routine TEXT);
SELECT ENGINE FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
ENGINE
InnoDB
INSERT INTO t1 VALUES (10,'none');
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
a INT;
PROCEDURE p1 AS
BEGIN
a:=a+1;
INSERT INTO t1 VALUES (a,'p1');
END;
BEGIN
SELECT MAX(t1.a) FROM t1 INTO a;
a:=a+1;
INSERT INTO t1 VALUES (a,'pkg1 initialization');
END;
$$
CALL pkg1.p1;
SELECT * FROM t1 ORDER BY a;
a routine
10 none
11 pkg1 initialization
12 p1
DELETE FROM t1;
# sp-cache-invalidate
START TRANSACTION;
CALL pkg1.p1;
SELECT * FROM t1 ORDER BY a;
a routine
NULL pkg1 initialization
NULL p1
ROLLBACK;
SELECT * FROM t1 ORDER BY a;
a routine
DELETE FROM t1;
# sp-cache-invalidate
INSERT INTO t1 VALUES (20,'none');
START TRANSACTION;
CALL pkg1.p1;
SELECT * FROM t1 ORDER BY a;
a routine
20 none
21 pkg1 initialization
22 p1
COMMIT;
SELECT * FROM t1 ORDER BY a;
a routine
20 none
21 pkg1 initialization
22 p1
DELETE FROM t1;
# sp-cache-invalidate
INSERT INTO t1 VALUES (20,'none');
START TRANSACTION;
CALL pkg1.p1;
SELECT * FROM t1 ORDER BY a;
a routine
20 none
21 pkg1 initialization
22 p1
ROLLBACK;
SELECT * FROM t1 ORDER BY a;
a routine
20 none
DELETE FROM t1;
DROP PACKAGE pkg1;
DROP TABLE t1;

View File

@@ -0,0 +1,80 @@
SET sql_mode=ORACLE;
DO GET_LOCK('lock',300);
connect conn1,localhost,root,,;
SET sql_mode=ORACLE;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
DO GET_LOCK('lock',300);
END;
FUNCTION f1 RETURN INT AS
BEGIN
CALL p1;
RETURN 1;
END;
END;
$$
SELECT pkg1.f1();
connection default;
connect conn2,localhost,root,,;
SET sql_mode=ORACLE;
DROP PACKAGE pkg1;
connection default;
SELECT ID-CONNECTION_ID() AS CONN,INFO,STATE,LOCK_MODE,LOCK_TYPE,TABLE_NAME
FROM INFORMATION_SCHEMA.PROCESSLIST
LEFT JOIN INFORMATION_SCHEMA.METADATA_LOCK_INFO
ON (ID=THREAD_ID)
ORDER BY ID,TABLE_NAME,LOCK_MODE,LOCK_TYPE;
CONN 0
INFO SELECT ID-CONNECTION_ID() AS CONN,INFO,STATE,LOCK_MODE,LOCK_TYPE,TABLE_NAME
FROM INFORMATION_SCHEMA.PROCESSLIST
LEFT JOIN INFORMATION_SCHEMA.METADATA_LOCK_INFO
ON (ID=THREAD_ID)
ORDER BY ID,TABLE_NAME,LOCK_MODE,LOCK_TYPE
STATE Filling schema table
LOCK_MODE MDL_SHARED_NO_WRITE
LOCK_TYPE User lock
TABLE_NAME
CONN 1
INFO DO GET_LOCK('lock',300)
STATE User lock
LOCK_MODE MDL_SHARED
LOCK_TYPE Stored package body metadata lock
TABLE_NAME pkg1
CONN 1
INFO DO GET_LOCK('lock',300)
STATE User lock
LOCK_MODE MDL_SHARED
LOCK_TYPE Stored function metadata lock
TABLE_NAME pkg1.f1
CONN 1
INFO DO GET_LOCK('lock',300)
STATE User lock
LOCK_MODE MDL_SHARED
LOCK_TYPE Stored procedure metadata lock
TABLE_NAME pkg1.p1
CONN 2
INFO DROP PACKAGE pkg1
STATE Waiting for stored package body metadata lock
LOCK_MODE MDL_INTENTION_EXCLUSIVE
LOCK_TYPE Global read lock
TABLE_NAME
CONN 2
INFO DROP PACKAGE pkg1
STATE Waiting for stored package body metadata lock
LOCK_MODE MDL_INTENTION_EXCLUSIVE
LOCK_TYPE Schema metadata lock
TABLE_NAME
DO RELEASE_LOCK('lock');
connection conn1;
pkg1.f1()
1
disconnect conn1;
connection conn2;
disconnect conn2;
connection default;

View File

@@ -0,0 +1,261 @@
SET sql_mode=ORACLE;
CREATE PROCEDURE p1 AS
BEGIN
SELECT pkg1.f1(); -- a standalone routine calls a package routine
END;
$$
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
CALL test.p1; -- a package routine calls a standalone routine
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 10;
END;
END;
$$
CALL p1;
pkg1.f1()
10
CALL pkg1.p1;
pkg1.f1()
10
SELECT pkg1.f1();
pkg1.f1()
10
CREATE PACKAGE pkg2 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*!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 */ ;
/*!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' */ ;
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 DROP PACKAGE IF EXISTS `pkg1` */;
/*!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 */ ;
/*!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' */ ;
DELIMITER ;;
CREATE DEFINER="root"@"localhost" PACKAGE "pkg1" AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
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 DROP PACKAGE IF EXISTS `pkg2` */;
/*!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 */ ;
/*!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' */ ;
DELIMITER ;;
CREATE DEFINER="root"@"localhost" PACKAGE "pkg2" AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
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 DROP PACKAGE BODY IF EXISTS `pkg1` */;
/*!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 */ ;
/*!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' */ ;
DELIMITER ;;
CREATE DEFINER="root"@"localhost" PACKAGE BODY "pkg1" AS
PROCEDURE p1 AS
BEGIN
CALL test.p1; -- a package routine calls a standalone routine
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 10;
END;
END ;;
DELIMITER ;
/*!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 */ ;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
<?xml version="1.0"?>
<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" character_set_client="latin1" collation_connection="latin1_swedish_ci" Database_Collation="latin1_swedish_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" character_set_client="latin1" collation_connection="latin1_swedish_ci" Database_Collation="latin1_swedish_ci">
<![CDATA[
CREATE DEFINER="root"@"localhost" PACKAGE "pkg1" AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END
]]>
</routine>
<routine Package="pkg2" sql_mode="PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER" character_set_client="latin1" collation_connection="latin1_swedish_ci" Database_Collation="latin1_swedish_ci">
<![CDATA[
CREATE DEFINER="root"@"localhost" PACKAGE "pkg2" AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
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" character_set_client="latin1" collation_connection="latin1_swedish_ci" Database_Collation="latin1_swedish_ci">
<![CDATA[
CREATE DEFINER="root"@"localhost" PACKAGE BODY "pkg1" AS
PROCEDURE p1 AS
BEGIN
CALL test.p1; -- a package routine calls a standalone routine
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 10;
END;
END
]]>
</routine>
</routines>
</database>
</mysqldump>
DROP PACKAGE pkg1;
DROP PACKAGE pkg2;
DROP PROCEDURE p1;
SHOW PACKAGE STATUS;
Db test
Name pkg1
Type PACKAGE
Definer root@localhost
Modified 0000-00-00 00:00:00
Created 0000-00-00 00:00:00
Security_type DEFINER
Comment
character_set_client latin1
collation_connection latin1_swedish_ci
Database Collation latin1_swedish_ci
Db test
Name pkg2
Type PACKAGE
Definer root@localhost
Modified 0000-00-00 00:00:00
Created 0000-00-00 00:00:00
Security_type DEFINER
Comment
character_set_client latin1
collation_connection latin1_swedish_ci
Database Collation latin1_swedish_ci
SHOW PACKAGE BODY STATUS;
Db test
Name pkg1
Type PACKAGE BODY
Definer root@localhost
Modified 0000-00-00 00:00:00
Created 0000-00-00 00:00:00
Security_type DEFINER
Comment
character_set_client latin1
collation_connection latin1_swedish_ci
Database Collation latin1_swedish_ci
SHOW CREATE PACKAGE pkg1;
Package sql_mode Create Package character_set_client collation_connection Database Collation
pkg1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="root"@"localhost" PACKAGE "pkg1" AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END latin1 latin1_swedish_ci latin1_swedish_ci
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 CREATE DEFINER="root"@"localhost" PACKAGE "pkg2" AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END latin1 latin1_swedish_ci latin1_swedish_ci
SHOW CREATE PACKAGE BODY pkg1;
Package body sql_mode Create Package Body character_set_client collation_connection Database Collation
pkg1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="root"@"localhost" PACKAGE BODY "pkg1" AS
PROCEDURE p1 AS
BEGIN
CALL test.p1;
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 10;
END;
END latin1 latin1_swedish_ci latin1_swedish_ci
CALL p1;
pkg1.f1()
10
CALL pkg1.p1;
pkg1.f1()
10
SELECT pkg1.f1();
pkg1.f1()
10
DROP PACKAGE pkg1;
DROP PACKAGE pkg2;
DROP PROCEDURE p1;
# removing the dump file

View File

@@ -0,0 +1,322 @@
SET sql_mode=ORACLE;
CREATE DATABASE db1;
CREATE USER u1@localhost IDENTIFIED BY '';
GRANT SELECT ON db1.* TO u1@localhost;
connect conn1,localhost,u1,,db1;
SELECT CURRENT_USER;
CURRENT_USER
u1@localhost
SET sql_mode=ORACLE;
#
# User u1 cannot drop PROCEDURE, PACKAGE, PACKAGE BODY by default
#
DROP PROCEDURE p1;
ERROR 42000: alter routine command denied to user 'u1'@'localhost' for routine 'db1.p1'
DROP PACKAGE pkg1;
ERROR 42000: alter routine command denied to user 'u1'@'localhost' for routine 'db1.pkg1'
DROP PACKAGE BODY pkg1;
ERROR 42000: alter routine command denied to user 'u1'@'localhost' for routine 'db1.pkg1'
#
# User u1 cannot create PROCEDURE, PACKAGE, PACKAGE BODY by default
#
CREATE PROCEDURE p1 AS
BEGIN
NULL;
END;
$$
ERROR 42000: Access denied for user 'u1'@'localhost' to database 'db1'
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
ERROR 42000: Access denied for user 'u1'@'localhost' to database 'db1'
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
END;
$$
ERROR 42000: PACKAGE db1.pkg1 does not exist
#
# Now create a PACKAGE by root
#
connection default;
USE db1;
CREATE PROCEDURE p1root AS
BEGIN
SELECT 1;
END;
$$
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN TEXT;
END;
$$
SHOW CREATE PACKAGE pkg1;
Package sql_mode Create Package character_set_client collation_connection Database Collation
pkg1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="root"@"localhost" PACKAGE "pkg1" AS
PROCEDURE p1;
FUNCTION f1 RETURN TEXT;
END latin1 latin1_swedish_ci latin1_swedish_ci
#
# u1 cannot SHOW yet:
# - the standalone procedure earlier created by root
# - the package specifications earlier create by root
#
connection conn1;
SHOW CREATE PROCEDURE p1root;
ERROR 42000: PROCEDURE p1root does not exist
SHOW CREATE PACKAGE pkg1;
ERROR 42000: PACKAGE pkg1 does not exist
#
# User u1 still cannot create a PACKAGE BODY
#
connection conn1;
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is f1'; END;
END;
$$
ERROR 42000: Access denied for user 'u1'@'localhost' to database 'db1'
#
# Now grant EXECUTE:
# - on the standalone procedure earlier created by root
# - on the package specification earlier created by root
#
connection default;
GRANT EXECUTE ON PROCEDURE db1.p1root TO u1@localhost;
GRANT EXECUTE ON PACKAGE db1.pkg1 TO u1@localhost;
#
# Now u1 can do SHOW for:
# - the standalone procedure earlier created by root
# - the package specification earlier created by root
#
disconnect conn1;
connect conn1,localhost,u1,,db1;
SET sql_mode=ORACLE;
SHOW CREATE PROCEDURE db1.p1root;
Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
p1root PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER NULL latin1 latin1_swedish_ci latin1_swedish_ci
SHOW CREATE PACKAGE db1.pkg1;
Package sql_mode Create Package character_set_client collation_connection Database Collation
pkg1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER NULL latin1 latin1_swedish_ci latin1_swedish_ci
#
# Now revoke EXECUTE and grant CREATE ROUTINE instead
#
connection default;
REVOKE EXECUTE ON PROCEDURE db1.p1root FROM u1@localhost;
REVOKE EXECUTE ON PACKAGE db1.pkg1 FROM u1@localhost;
GRANT CREATE ROUTINE ON db1.* TO u1@localhost;
#
# Reconnect u1 to make new grants have effect
#
disconnect conn1;
connect conn1,localhost,u1,,db1;
SET sql_mode=ORACLE;
#
# Now u1 can SHOW:
# - standalone routines earlier created by root
# - package specifications earlier created by root
#
SHOW CREATE PROCEDURE p1root;
Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
p1root PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER NULL latin1 latin1_swedish_ci latin1_swedish_ci
SHOW CREATE PACKAGE pkg1;
Package sql_mode Create Package character_set_client collation_connection Database Collation
pkg1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER NULL latin1 latin1_swedish_ci latin1_swedish_ci
#
# Now u1 can CREATE, DROP and EXECUTE its own standalone procedures
#
CREATE PROCEDURE p1 AS
BEGIN
NULL;
END;
$$
SHOW GRANTS;
Grants for u1@localhost
GRANT USAGE ON *.* TO 'u1'@'localhost'
GRANT SELECT, CREATE ROUTINE ON "db1".* TO 'u1'@'localhost'
GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE "db1"."p1" TO 'u1'@'localhost'
CALL p1;
DROP PROCEDURE p1;
SHOW GRANTS;
Grants for u1@localhost
GRANT USAGE ON *.* TO 'u1'@'localhost'
GRANT SELECT, CREATE ROUTINE ON "db1".* TO 'u1'@'localhost'
#
# Now u1 can also CREATE, DROP its own package specifications
#
CREATE PACKAGE pkg2 AS
PROCEDURE p1;
FUNCTION f1 RETURN TEXT;
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 CREATE DEFINER="u1"@"localhost" PACKAGE "pkg2" AS
PROCEDURE p1;
FUNCTION f1 RETURN TEXT;
END latin1 latin1_swedish_ci latin1_swedish_ci
SHOW GRANTS;
Grants for u1@localhost
GRANT USAGE ON *.* TO 'u1'@'localhost'
GRANT SELECT, CREATE ROUTINE ON "db1".* TO 'u1'@'localhost'
GRANT EXECUTE, ALTER ROUTINE ON PACKAGE "db1"."pkg2" TO 'u1'@'localhost'
DROP PACKAGE pkg2;
SHOW GRANTS;
Grants for u1@localhost
GRANT USAGE ON *.* TO 'u1'@'localhost'
GRANT SELECT, CREATE ROUTINE ON "db1".* TO 'u1'@'localhost'
#
# Now u1 can also CREATE, DROP package bodies and EXECUTE package body routines
#
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS BEGIN SELECT 'This is pkg1.p1' AS `comment`; END;
FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is pkg1.f1'; END;
END;
$$
SHOW CREATE PACKAGE pkg1;
Package sql_mode Create Package character_set_client collation_connection Database Collation
pkg1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER NULL latin1 latin1_swedish_ci latin1_swedish_ci
SHOW CREATE PACKAGE BODY pkg1;
Package body sql_mode Create Package Body character_set_client collation_connection Database Collation
pkg1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER CREATE DEFINER="u1"@"localhost" PACKAGE BODY "pkg1" AS
PROCEDURE p1 AS BEGIN SELECT 'This is pkg1.p1' AS `comment`; END;
FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is pkg1.f1'; END;
END latin1 latin1_swedish_ci latin1_swedish_ci
SHOW GRANTS;
Grants for u1@localhost
GRANT USAGE ON *.* TO 'u1'@'localhost'
GRANT SELECT, CREATE ROUTINE ON "db1".* TO 'u1'@'localhost'
GRANT EXECUTE, ALTER ROUTINE ON PACKAGE BODY "db1"."pkg1" TO 'u1'@'localhost'
CALL pkg1.p1;
comment
This is pkg1.p1
SELECT pkg1.f1();
pkg1.f1()
This is pkg1.f1
DROP PACKAGE BODY pkg1;
SHOW GRANTS;
Grants for u1@localhost
GRANT USAGE ON *.* TO 'u1'@'localhost'
GRANT SELECT, CREATE ROUTINE ON "db1".* TO 'u1'@'localhost'
#
# Now create a PACKAGE BODY by root.
# u1 does not have EXECUTE access by default.
#
connection default;
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS BEGIN SELECT 'This is pkg1.p1' AS `comment`; END;
FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is pkg1.f1'; END;
END;
$$
connection conn1;
SHOW CREATE PACKAGE pkg1;
Package sql_mode Create Package character_set_client collation_connection Database Collation
pkg1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER NULL latin1 latin1_swedish_ci latin1_swedish_ci
SHOW CREATE PACKAGE BODY pkg1;
Package body sql_mode Create Package Body character_set_client collation_connection Database Collation
pkg1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER NULL latin1 latin1_swedish_ci latin1_swedish_ci
CALL pkg1.p1;
ERROR 42000: execute command denied to user 'u1'@'localhost' for routine 'db1.pkg1'
SELECT pkg1.f1();
ERROR 42000: execute command denied to user 'u1'@'localhost' for routine 'db1.pkg1'
#
# Now grant EXECUTE to u1 on the PACKAGE BODY created by root
#
connection default;
GRANT EXECUTE ON PACKAGE BODY db1.pkg1 TO u1@localhost;
disconnect conn1;
connect conn1,localhost,u1,,db1;
SELECT CURRENT_USER;
CURRENT_USER
u1@localhost
SET sql_mode=ORACLE;
SHOW GRANTS;
Grants for u1@localhost
GRANT USAGE ON *.* TO 'u1'@'localhost'
GRANT SELECT, CREATE ROUTINE ON "db1".* TO 'u1'@'localhost'
GRANT EXECUTE ON PACKAGE BODY "db1"."pkg1" TO 'u1'@'localhost'
CALL pkg1.p1;
comment
This is pkg1.p1
SELECT pkg1.f1();
pkg1.f1()
This is pkg1.f1
connection default;
DROP PACKAGE BODY pkg1;
#
# u1 still cannot DROP the package specification earlier created by root.
#
connection conn1;
DROP PACKAGE pkg1;
ERROR 42000: alter routine command denied to user 'u1'@'localhost' for routine 'db1.pkg1'
#
# Grant ALTER ROUTINE to u1
#
connection default;
GRANT ALTER ROUTINE ON db1.* TO u1@localhost;
#
# Now u1 can DROP:
# - the standalone procedure earlier created by root
# - the package specification earlier created by root
#
disconnect conn1;
connect conn1,localhost,u1,,db1;
SET sql_mode=ORACLE;
DROP PACKAGE pkg1;
DROP PROCEDURE p1root;
disconnect conn1;
connection default;
DROP USER u1@localhost;
DROP DATABASE db1;
USE test;
#
# Creator=root, definer=xxx
#
CREATE USER xxx@localhost;
CREATE DEFINER=xxx@localhost PACKAGE p1 AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 AS
PROCEDURE p1 AS
BEGIN
SELECT SESSION_USER(), CURRENT_USER(), 'p1.p1' AS msg;
END;
BEGIN
SELECT SESSION_USER(), CURRENT_USER(), 'package body p1' AS msg;
END;
$$
CALL p1.p1;
ERROR 42000: execute command denied to user 'xxx'@'localhost' for routine 'test.p1'
GRANT EXECUTE ON PACKAGE BODY test.p1 TO xxx@localhost;
CALL p1.p1;
SESSION_USER() CURRENT_USER() msg
root@localhost xxx@localhost package body p1
SESSION_USER() CURRENT_USER() msg
root@localhost xxx@localhost p1.p1
DROP PACKAGE p1;
DROP USER xxx@localhost;
#
# Creator=root, definer=xxx, SQL SECURITY INVOKER
#
CREATE USER xxx@localhost;
CREATE DEFINER=xxx@localhost PACKAGE p1 AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 SQL SECURITY INVOKER AS
PROCEDURE p1 AS
BEGIN
SELECT SESSION_USER(), CURRENT_USER(), 'p1.p1' AS msg;
END;
BEGIN
SELECT SESSION_USER(), CURRENT_USER(), 'package body p1' AS msg;
END;
$$
CALL p1.p1;
SESSION_USER() CURRENT_USER() msg
root@localhost root@localhost package body p1
SESSION_USER() CURRENT_USER() msg
root@localhost root@localhost p1.p1
DROP PACKAGE p1;
DROP USER xxx@localhost;

File diff suppressed because it is too large Load Diff

View File

@@ -166,6 +166,13 @@ IF a=10 THEN NULL; ELSE NULL; END IF;
END; END;
/ /
DROP PROCEDURE p1; DROP PROCEDURE p1;
# Keywords that are OK for table names, but not for SP variables
CREATE TABLE function (function int);
INSERT INTO function SET function=10;
SELECT function.function FROM function;
function
10
DROP TABLE function;
# Testing that (some) keyword_sp are allowed in Oracle-style assignments # Testing that (some) keyword_sp are allowed in Oracle-style assignments
CREATE PROCEDURE p1 (action OUT INT) AS BEGIN action:=10; END;/ CREATE PROCEDURE p1 (action OUT INT) AS BEGIN action:=10; END;/
DROP PROCEDURE p1/ DROP PROCEDURE p1/

View File

@@ -0,0 +1,158 @@
--source include/not_embedded.inc
--source include/have_binlog_format_statement.inc
--disable_query_log
reset master; # get rid of previous tests binlog
--enable_query_log
SET sql_mode=ORACLE;
DELIMITER $$;
CREATE PACKAGE p1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
CREATE PACKAGE IF NOT EXISTS p1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
CREATE PACKAGE BODY p1 AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 10;
END;
END;
$$
DELIMITER ;$$
DROP PACKAGE BODY p1;
DROP PACKAGE p1;
DROP PACKAGE IF EXISTS p1;
--echo #
--echo # Creating a package with a COMMENT clause
--echo #
DELIMITER $$;
CREATE PACKAGE p1 COMMENT 'package-p1-comment' AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY p1 COMMENT 'package-body-p1-comment' AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
DELIMITER ;$$
DROP PACKAGE p1;
--echo #
--echo # Creating a package with a different DEFINER
--echo #
DELIMITER $$;
CREATE DEFINER=xxx@localhost PACKAGE p1 AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
DELIMITER ;$$
DROP PACKAGE p1;
--echo #
--echo # Creating a package with a different DEFINER, with SQL SECURITY INVOKER
--echo #
DELIMITER $$;
CREATE DEFINER=xxx@localhost PACKAGE p1 SQL SECURITY INVOKER AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 SQL SECURITY INVOKER AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
DELIMITER ;$$
DROP PACKAGE p1;
--echo #
--echo # Creating a new package in a remote database
--echo #
CREATE DATABASE test2;
DELIMITER $$;
CREATE PACKAGE test2.test2 COMMENT 'package-test2-comment' AS
FUNCTION f1 RETURN INT;
PROCEDURE p1;
END
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PACKAGE BODY test2.test2 COMMENT 'package-body-test2-comment' AS
FUNCTION f1 RETURN INT AS BEGIN RETURN 10; END;
PROCEDURE p1 AS BEGIN SELECT f1(); END;
END;
$$
DELIMITER ;$$
DROP PACKAGE BODY test2.test2;
DROP PACKAGE test2.test2;
DROP DATABASE test2;
--echo #
--echo # MDEV-13139 Package-wide variables in CREATE PACKAGE
--echo #
CREATE TABLE t1 (a INT);
DELIMITER $$;
CREATE PACKAGE p1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY p1 AS
a INT:=0;
PROCEDURE p1 AS
BEGIN
INSERT INTO t1 VALUES (a);
a:=a+1;
END;
BEGIN
a:=10;
END;
$$
DELIMITER ;$$
CALL p1.p1();
CALL p1.p1();
SELECT * FROM t1;
--source sp-cache-invalidate.inc
CALL p1.p1();
CALL p1.p1();
SELECT * FROM t1;
DROP PACKAGE p1;
DROP TABLE t1;
--let $binlog_file = LAST
source include/show_binlog_events.inc;

View File

@@ -0,0 +1,134 @@
--source include/master-slave.inc
connection master;
SET sql_mode=ORACLE;
DELIMITER $$;
CREATE PACKAGE pack AS
FUNCTION f1 RETURN INT;
PROCEDURE p1;
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PACKAGE BODY pack AS
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 10;
END;
PROCEDURE p1 AS
BEGIN
SELECT f1();
END;
END pack;
$$
DELIMITER ;$$
sync_slave_with_master;
connection slave;
--vertical_results
--replace_column 13 # 14 #
SELECT * FROM mysql.proc WHERE db='test' AND name='pack';
--replace_column 13 # 14 #
SELECT * FROM mysql.proc WHERE db='test' AND name LIKE 'pack.%';
--horizontal_results
SET @@sql_mode=ORACLE;
SELECT pack.f1();
CALL pack.p1();
SET @@sql_mode=DEFAULT;
connection master;
DROP PACKAGE pack;
sync_slave_with_master;
connection slave;
SELECT COUNT(*) FROM mysql.proc WHERE db='test' AND name='pack';
--echo #
--echo # Creating a package with a COMMENT
--echo #
connection master;
DELIMITER $$;
CREATE PACKAGE p1 COMMENT 'package-p1-comment' AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY p1 COMMENT 'package-body-p1-comment' AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
DELIMITER ;$$
SELECT definer, name, security_type, type, `comment` FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
sync_slave_with_master;
SELECT definer, name, security_type, type, `comment` FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
connection master;
DROP PACKAGE p1;
sync_slave_with_master;
--echo #
--echo # Creating a package with a different DEFINER
--echo #
connection master;
DELIMITER $$;
CREATE DEFINER=xxx@localhost PACKAGE p1 AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
DELIMITER ;$$
SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
sync_slave_with_master;
SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
connection master;
DROP PACKAGE p1;
sync_slave_with_master;
--echo #
--echo # Creating a package with a different DEFINER + SQL SECURITY INVOKER
--echo #
connection master;
DELIMITER $$;
CREATE DEFINER=xxx@localhost PACKAGE p1 SQL SECURITY INVOKER AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 SQL SECURITY INVOKER AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
END;
$$
DELIMITER ;$$
SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
sync_slave_with_master;
SELECT definer, name, security_type, type FROM mysql.proc WHERE name LIKE 'p1%' ORDER BY definer, name, type;
connection master;
DROP PACKAGE p1;
sync_slave_with_master;
--source include/rpl_end.inc

View File

@@ -0,0 +1,36 @@
--source include/master-slave.inc
connection master;
SET sql_mode=ORACLE;
--echo #
--echo # MDEV-13139 Package-wide variables in CREATE PACKAGE
--echo #
connection master;
DELIMITER $$;
CREATE PACKAGE p1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY p1 AS
va INT:=10;
PROCEDURE p1 AS
BEGIN
INSERT INTO t1 VALUES (va);
END;
BEGIN
CREATE OR REPLACE TABLE t1 (a INT);
END;
$$
DELIMITER ;$$
CALL p1.p1();
CALL p1.p1();
SELECT * FROM t1;
sync_slave_with_master;
SELECT * FROM t1;
connection master;
DROP PACKAGE p1;
DROP TABLE t1;
sync_slave_with_master;
--source include/rpl_end.inc

View File

@@ -0,0 +1,11 @@
--echo # sp-cache-invalidate
--disable_query_log
DELIMITER $$;
CREATE FUNCTION dummy RETURN INT AS
BEGIN
RETURN 1;
END;
$$
DELIMITER ;$$
DROP FUNCTION dummy;
--enable_query_log

View File

@@ -0,0 +1,182 @@
-- source include/have_debug.inc
SET sql_mode=ORACLE;
DELIMITER $$;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
PROCEDURE p2show;
PROCEDURE p2public;
FUNCTION f2public RETURN TEXT;
END;
$$
CREATE PACKAGE BODY pkg1 AS
a INT:=10;
PROCEDURE p1 AS
b INT:=20;
BEGIN
b:=a;
b:=a+1;
a:=b;
a:=b+1;
a:=a+1;
SET @a:=@a+2;
SELECT f1() FROM DUAL;
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN a;
END;
PROCEDURE p2private AS
BEGIN
SELECT 'This is p2private';
END;
PROCEDURE p2public AS
BEGIN
SELECT 'This is p2public';
END;
FUNCTION f2private RETURN TEXT AS
BEGIN
RETURN 'This is f2private';
END;
FUNCTION f2public RETURN TEXT AS
BEGIN
RETURN 'This is f2public';
END;
PROCEDURE p2show AS
BEGIN
SHOW FUNCTION CODE f2public;
SHOW FUNCTION CODE f2private;
SHOW PROCEDURE CODE p2public;
SHOW PROCEDURE CODE p2private;
SHOW PROCEDURE CODE p2show;
END;
BEGIN
a:=a+1;
DECLARE
b INT;
BEGIN
b:=a;
b:=a+1;
a:=b;
a:=b+1;
END;
END;
$$
DELIMITER ;$$
SHOW PROCEDURE CODE pkg1.p1;
SHOW FUNCTION CODE pkg1.f1;
SHOW PACKAGE BODY CODE pkg1;
CALL pkg1.p2show;
DROP PACKAGE pkg1;
CREATE TABLE t1 (a INT);
DELIMITER $$;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
a t1.a%TYPE:=10;
PROCEDURE p1 AS
b t1.a%TYPE:=20;
BEGIN
b:=a;
b:=a+1;
b:=b+1;
a:=b;
a:=b+1;
a:=a+1;
END;
BEGIN
a:=a+1;
DECLARE
b t1.a%TYPE;
BEGIN
b:=a;
b:=a+1;
a:=b;
a:=b+1;
END;
END;
$$
DELIMITER ;$$
SHOW PROCEDURE CODE pkg1.p1;
SHOW PACKAGE BODY CODE pkg1;
DROP PACKAGE pkg1;
DROP TABLE t1;
DELIMITER $$;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
a ROW(a INT,b TEXT):=ROW(10,'x10');
PROCEDURE p1 AS
b ROW(a INT,b TEXT):=ROW(20,'x20');
BEGIN
b:=a;
a:=b;
b.a:=a.a+1;
a.a:=b.a+1;
a.a:=a.a+1;
END;
BEGIN
a.a:=a.a+1;
DECLARE
b ROW(a INT,b TEXT):=ROW(30,'x30');
BEGIN
b:=a;
b.a:=a.a+1;
a:=b;
a.a:=b.a+1;
END;
END;
$$
DELIMITER ;$$
SHOW PROCEDURE CODE pkg1.p1;
SHOW PACKAGE BODY CODE pkg1;
DROP PACKAGE pkg1;
CREATE TABLE t1 (a INT, b TEXT);
DELIMITER $$;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
a t1%ROWTYPE:=ROW(10,'x10');
PROCEDURE p1 AS
b t1%ROWTYPE:=ROW(20,'x20');
BEGIN
b:=a;
a:=b;
b.a:=a.a+1;
a.a:=b.a+1;
a.a:=a.a+1;
END;
BEGIN
a.a:=a.a+1;
DECLARE
b t1%ROWTYPE:=ROW(30,'x30');
BEGIN
b:=a;
b.a:=a.a+1;
a:=b;
a.a:=b.a+1;
END;
END;
$$
DELIMITER ;$$
SHOW PROCEDURE CODE pkg1.p1;
SHOW PACKAGE BODY CODE pkg1;
DROP PACKAGE pkg1;
DROP TABLE t1;

View File

@@ -0,0 +1,6 @@
--echo #
--echo # MDEV-15070 Crash when doing a CREATE VIEW inside a package routine
--echo #
SET @object_type='db';
--source sp-package-concurrent-dml.inc

View File

@@ -0,0 +1,10 @@
--echo #
--echo # MDEV-15070 Crash when doing a CREATE VIEW inside a package routine
--echo #
SET @object_type='package_replace_pkg1';
--source sp-package-concurrent-dml.inc
SET @object_type='package_body_replace_pkg1';
--source sp-package-concurrent-dml.inc

View File

@@ -0,0 +1,6 @@
--echo #
--echo # MDEV-15070 Crash when doing a CREATE VIEW inside a package routine
--echo #
SET @object_type='trigger';
--source sp-package-concurrent-dml.inc

View File

@@ -0,0 +1,6 @@
--echo #
--echo # MDEV-15070 Crash when doing a CREATE VIEW inside a package routine
--echo #
SET @object_type='view';
--source sp-package-concurrent-dml.inc

View File

@@ -0,0 +1,107 @@
--echo #
--echo # Start of sp-package-concurrent-dml.inc
--echo #
--source include/count_sessions.inc
let $object_type= `SELECT @object_type`;
SET sql_mode=ORACLE;
DELIMITER $$;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p2 AS
BEGIN
SELECT 'This is p2' AS msg;
END;
PROCEDURE p1 AS
BEGIN
SELECT 'This is p1' AS msg;
DO GET_LOCK('mdev15070',120);
CALL p2();
DO RELEASE_LOCK('mdev15070');
END;
END;
$$
DELIMITER ;$$
connect (con2,localhost,root);
connection con2;
DO GET_LOCK('mdev15070', 120);
connection default;
send CALL pkg1.p1;
connection con2;
let $wait_condition=
SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE state = "User lock" AND info LIKE "%GET_LOCK%mdev15070%";
--source include/wait_condition.inc
if ($object_type==view)
{
CREATE VIEW v1 AS SELECT 1 AS c;
DROP VIEW v1;
}
if ($object_type==package_replace_pkg1)
{
SET sql_mode=ORACLE;
DELIMITER $$;
CREATE OR REPLACE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg1;
}
if ($object_type==package_body_replace_pkg1)
{
SET sql_mode=ORACLE;
DELIMITER $$;
CREATE OR REPLACE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
SELECT 'This is p1 version 2' AS msg;
END;
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg1;
}
if ($object_type==trigger)
{
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=1;
DROP TRIGGER tr1;
DROP TABLE t1;
}
if ($object_type=='db')
{
CREATE DATABASE test1;
CREATE FUNCTION test1.f1() RETURNS INT RETURN 10;
DROP DATABASE test1;
}
DO RELEASE_LOCK('mdev15070');
disconnect con2;
connection default;
reap;
DROP PACKAGE IF EXISTS pkg1;
--source include/wait_until_count_sessions.inc

View File

@@ -0,0 +1,62 @@
-- source include/have_innodb.inc
SET default_storage_engine=InnoDB;
SET sql_mode=ORACLE;
CREATE TABLE t1 (a INT, routine TEXT);
SELECT ENGINE FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
INSERT INTO t1 VALUES (10,'none');
DELIMITER $$;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY pkg1 AS
a INT;
PROCEDURE p1 AS
BEGIN
a:=a+1;
INSERT INTO t1 VALUES (a,'p1');
END;
BEGIN
SELECT MAX(t1.a) FROM t1 INTO a;
a:=a+1;
INSERT INTO t1 VALUES (a,'pkg1 initialization');
END;
$$
DELIMITER ;$$
CALL pkg1.p1;
SELECT * FROM t1 ORDER BY a;
DELETE FROM t1;
--source sp-cache-invalidate.inc
START TRANSACTION;
CALL pkg1.p1;
SELECT * FROM t1 ORDER BY a;
ROLLBACK;
SELECT * FROM t1 ORDER BY a;
DELETE FROM t1;
--source sp-cache-invalidate.inc
INSERT INTO t1 VALUES (20,'none');
START TRANSACTION;
CALL pkg1.p1;
SELECT * FROM t1 ORDER BY a;
COMMIT;
SELECT * FROM t1 ORDER BY a;
DELETE FROM t1;
--source sp-cache-invalidate.inc
INSERT INTO t1 VALUES (20,'none');
START TRANSACTION;
CALL pkg1.p1;
SELECT * FROM t1 ORDER BY a;
ROLLBACK;
SELECT * FROM t1 ORDER BY a;
DELETE FROM t1;
DROP PACKAGE pkg1;
DROP TABLE t1;

View File

@@ -0,0 +1,110 @@
--source include/have_metadata_lock_info.inc
#
# This test demonstrates that:
# - A call to a package routine acquires a shared MDL lock on the entire package
# - "DROP PACKAGE" waits until the currently running package routines end
#
SET sql_mode=ORACLE;
DO GET_LOCK('lock',300);
#
# conn1 will execute package pkg1 routines and
# and therefore acquire a shared MDL on "package body pkg1"
#
connect (conn1,localhost,root,,);
SET sql_mode=ORACLE;
let $conn1_id= `SELECT CONNECTION_ID()`;
DELIMITER $$;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
DO GET_LOCK('lock',300);
END;
FUNCTION f1 RETURN INT AS
BEGIN
CALL p1;
RETURN 1;
END;
END;
$$
DELIMITER ;$$
send SELECT pkg1.f1();
#
# wait for conn1 to actually start execution of pkg1.p1
#
connection default;
let $wait_timeout= 60;
let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE ID=$conn1_id AND INFO LIKE '%GET_LOCK%' AND STATE='User lock';
--source include/wait_condition.inc
#
# conn2 will do "DROP PACKAGE pkg1".
# It will acquire an exclusive MDL on "package body pkg1", and therefore
# it should wait until conn1 ends the package routine execution
#
connect (conn2,localhost,root,,);
let $conn2_id= `SELECT CONNECTION_ID()`;
SET sql_mode=ORACLE;
send DROP PACKAGE pkg1;
#
# wait for conn2 to actually enter the "DROP" statement and get locked by conn1
#
connection default;
let $wait_timeout= 60;
let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE ID=$conn2_id
AND INFO LIKE '%DROP PACKAGE%'
AND STATE='Waiting for stored package body metadata lock';
--source include/wait_condition.inc
#
# Now we have three threads involved.
# The following I_S query will check that the threads are in these states:
#
# default (0) - is holding a user lock 'lock'
# conn1 (1) - is executing the package procedure test.pkg1.p1,
# is holding a shared MDL on 'package body pkg1',
# is waiting for the user lock 'lock' to be released
# conn2 (2) - is waiting for 'conn1' to end execution of test.pkg1.* routines,
# to acquire an exclusive MDL on 'package body pkg1',
# to DROP the package pkg1
#
--vertical_results
SELECT ID-CONNECTION_ID() AS CONN,INFO,STATE,LOCK_MODE,LOCK_TYPE,TABLE_NAME
FROM INFORMATION_SCHEMA.PROCESSLIST
LEFT JOIN INFORMATION_SCHEMA.METADATA_LOCK_INFO
ON (ID=THREAD_ID)
ORDER BY ID,TABLE_NAME,LOCK_MODE,LOCK_TYPE;
--horizontal_results
#
# Now let conn1 finish the package routine execution
#
DO RELEASE_LOCK('lock');
connection conn1;
reap;
disconnect conn1;
#
# Now conn2 should actually DROP the package
#
connection conn2;
reap;
disconnect conn2;
connection default;

View File

@@ -0,0 +1,93 @@
--source include/not_embedded.inc
SET sql_mode=ORACLE;
#
# Create a standalone procedure test.p1 and a package pkg1.
# The standalone routine test.p1 and the package routines call each other.
#
DELIMITER $$;
CREATE PROCEDURE p1 AS
BEGIN
SELECT pkg1.f1(); -- a standalone routine calls a package routine
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
CALL test.p1; -- a package routine calls a standalone routine
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 10;
END;
END;
$$
DELIMITER ;$$
CALL p1;
CALL pkg1.p1;
SELECT pkg1.f1();
#
# Create specifications for one more package, without a BODY
#
DELIMITER $$;
CREATE PACKAGE pkg2 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
DELIMITER ;$$
--exec $MYSQL_DUMP --skip-comments --routines test
--exec $MYSQL_DUMP --skip-comments --routines --xml test
let $dump = $MYSQLTEST_VARDIR/tmp/sp-package-mysqldump.sql;
--exec $MYSQL_DUMP --compact --routines test > $dump
DROP PACKAGE pkg1;
DROP PACKAGE pkg2;
DROP PROCEDURE p1;
--exec $MYSQL test < $dump
--vertical_results
--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
SHOW PACKAGE STATUS;
--replace_column 4 'root@localhost' 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
SHOW PACKAGE BODY STATUS;
--horizontal_results
SHOW CREATE PACKAGE pkg1;
SHOW CREATE PACKAGE pkg2;
SHOW CREATE PACKAGE BODY pkg1;
CALL p1;
CALL pkg1.p1;
SELECT pkg1.f1();
DROP PACKAGE pkg1;
DROP PACKAGE pkg2;
DROP PROCEDURE p1;
--echo # removing the dump file
--error 0,1
--remove_file $dump

View File

@@ -0,0 +1,331 @@
--source include/not_embedded.inc
SET sql_mode=ORACLE;
CREATE DATABASE db1;
CREATE USER u1@localhost IDENTIFIED BY '';
GRANT SELECT ON db1.* TO u1@localhost;
connect (conn1,localhost,u1,,db1);
SELECT CURRENT_USER;
SET sql_mode=ORACLE;
--echo #
--echo # User u1 cannot drop PROCEDURE, PACKAGE, PACKAGE BODY by default
--echo #
--error ER_PROCACCESS_DENIED_ERROR
DROP PROCEDURE p1;
--error ER_PROCACCESS_DENIED_ERROR
DROP PACKAGE pkg1;
--error ER_PROCACCESS_DENIED_ERROR
DROP PACKAGE BODY pkg1;
--echo #
--echo # User u1 cannot create PROCEDURE, PACKAGE, PACKAGE BODY by default
--echo #
DELIMITER $$;
--error ER_DBACCESS_DENIED_ERROR
CREATE PROCEDURE p1 AS
BEGIN
NULL;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_DBACCESS_DENIED_ERROR
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
END;
$$
DELIMITER ;$$
# TODO: this should probably return ER_DBACCESS_DENIED_ERROR
DELIMITER $$;
--error ER_SP_DOES_NOT_EXIST
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
END;
$$
DELIMITER ;$$
--echo #
--echo # Now create a PACKAGE by root
--echo #
connection default;
USE db1;
DELIMITER $$;
CREATE PROCEDURE p1root AS
BEGIN
SELECT 1;
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN TEXT;
END;
$$
DELIMITER ;$$
SHOW CREATE PACKAGE pkg1;
--echo #
--echo # u1 cannot SHOW yet:
--echo # - the standalone procedure earlier created by root
--echo # - the package specifications earlier create by root
--echo #
connection conn1;
--error ER_SP_DOES_NOT_EXIST
SHOW CREATE PROCEDURE p1root;
--error ER_SP_DOES_NOT_EXIST
SHOW CREATE PACKAGE pkg1;
--echo #
--echo # User u1 still cannot create a PACKAGE BODY
--echo #
connection conn1;
DELIMITER $$;
--error ER_DBACCESS_DENIED_ERROR
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is f1'; END;
END;
$$
DELIMITER ;$$
--echo #
--echo # Now grant EXECUTE:
--echo # - on the standalone procedure earlier created by root
--echo # - on the package specification earlier created by root
--echo #
connection default;
GRANT EXECUTE ON PROCEDURE db1.p1root TO u1@localhost;
GRANT EXECUTE ON PACKAGE db1.pkg1 TO u1@localhost;
--echo #
--echo # Now u1 can do SHOW for:
--echo # - the standalone procedure earlier created by root
--echo # - the package specification earlier created by root
--echo #
disconnect conn1;
connect (conn1,localhost,u1,,db1);
SET sql_mode=ORACLE;
SHOW CREATE PROCEDURE db1.p1root;
SHOW CREATE PACKAGE db1.pkg1;
--echo #
--echo # Now revoke EXECUTE and grant CREATE ROUTINE instead
--echo #
connection default;
REVOKE EXECUTE ON PROCEDURE db1.p1root FROM u1@localhost;
REVOKE EXECUTE ON PACKAGE db1.pkg1 FROM u1@localhost;
GRANT CREATE ROUTINE ON db1.* TO u1@localhost;
--echo #
--echo # Reconnect u1 to make new grants have effect
--echo #
disconnect conn1;
connect (conn1,localhost,u1,,db1);
SET sql_mode=ORACLE;
--echo #
--echo # Now u1 can SHOW:
--echo # - standalone routines earlier created by root
--echo # - package specifications earlier created by root
--echo #
SHOW CREATE PROCEDURE p1root;
SHOW CREATE PACKAGE pkg1;
--echo #
--echo # Now u1 can CREATE, DROP and EXECUTE its own standalone procedures
--echo #
DELIMITER $$;
CREATE PROCEDURE p1 AS
BEGIN
NULL;
END;
$$
DELIMITER ;$$
SHOW GRANTS;
CALL p1;
DROP PROCEDURE p1;
SHOW GRANTS;
--echo #
--echo # Now u1 can also CREATE, DROP its own package specifications
--echo #
DELIMITER $$;
CREATE PACKAGE pkg2 AS
PROCEDURE p1;
FUNCTION f1 RETURN TEXT;
END;
$$
DELIMITER ;$$
SHOW CREATE PACKAGE pkg2;
SHOW GRANTS;
DROP PACKAGE pkg2;
SHOW GRANTS;
--echo #
--echo # Now u1 can also CREATE, DROP package bodies and EXECUTE package body routines
--echo #
DELIMITER $$;
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS BEGIN SELECT 'This is pkg1.p1' AS `comment`; END;
FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is pkg1.f1'; END;
END;
$$
DELIMITER ;$$
SHOW CREATE PACKAGE pkg1;
SHOW CREATE PACKAGE BODY pkg1;
SHOW GRANTS;
CALL pkg1.p1;
SELECT pkg1.f1();
DROP PACKAGE BODY pkg1;
SHOW GRANTS;
--echo #
--echo # Now create a PACKAGE BODY by root.
--echo # u1 does not have EXECUTE access by default.
--echo #
connection default;
DELIMITER $$;
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS BEGIN SELECT 'This is pkg1.p1' AS `comment`; END;
FUNCTION f1 RETURN TEXT AS BEGIN RETURN 'This is pkg1.f1'; END;
END;
$$
DELIMITER ;$$
connection conn1;
SHOW CREATE PACKAGE pkg1;
SHOW CREATE PACKAGE BODY pkg1;
--error ER_PROCACCESS_DENIED_ERROR
CALL pkg1.p1;
--error ER_PROCACCESS_DENIED_ERROR
SELECT pkg1.f1();
--echo #
--echo # Now grant EXECUTE to u1 on the PACKAGE BODY created by root
--echo #
connection default;
GRANT EXECUTE ON PACKAGE BODY db1.pkg1 TO u1@localhost;
disconnect conn1;
connect (conn1,localhost,u1,,db1);
SELECT CURRENT_USER;
SET sql_mode=ORACLE;
SHOW GRANTS;
CALL pkg1.p1;
SELECT pkg1.f1();
connection default;
DROP PACKAGE BODY pkg1;
--echo #
--echo # u1 still cannot DROP the package specification earlier created by root.
--echo #
connection conn1;
--error ER_PROCACCESS_DENIED_ERROR
DROP PACKAGE pkg1;
--echo #
--echo # Grant ALTER ROUTINE to u1
--echo #
connection default;
GRANT ALTER ROUTINE ON db1.* TO u1@localhost;
--echo #
--echo # Now u1 can DROP:
--echo # - the standalone procedure earlier created by root
--echo # - the package specification earlier created by root
--echo #
disconnect conn1;
connect (conn1,localhost,u1,,db1);
SET sql_mode=ORACLE;
DROP PACKAGE pkg1;
DROP PROCEDURE p1root;
disconnect conn1;
connection default;
DROP USER u1@localhost;
DROP DATABASE db1;
USE test;
--echo #
--echo # Creator=root, definer=xxx
--echo #
CREATE USER xxx@localhost;
DELIMITER $$;
CREATE DEFINER=xxx@localhost PACKAGE p1 AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 AS
PROCEDURE p1 AS
BEGIN
SELECT SESSION_USER(), CURRENT_USER(), 'p1.p1' AS msg;
END;
BEGIN
SELECT SESSION_USER(), CURRENT_USER(), 'package body p1' AS msg;
END;
$$
DELIMITER ;$$
--error ER_PROCACCESS_DENIED_ERROR
CALL p1.p1;
GRANT EXECUTE ON PACKAGE BODY test.p1 TO xxx@localhost;
CALL p1.p1;
DROP PACKAGE p1;
DROP USER xxx@localhost;
--echo #
--echo # Creator=root, definer=xxx, SQL SECURITY INVOKER
--echo #
CREATE USER xxx@localhost;
DELIMITER $$;
CREATE DEFINER=xxx@localhost PACKAGE p1 AS
PROCEDURE p1;
END;
$$
CREATE DEFINER=xxx@localhost PACKAGE BODY p1 SQL SECURITY INVOKER AS
PROCEDURE p1 AS
BEGIN
SELECT SESSION_USER(), CURRENT_USER(), 'p1.p1' AS msg;
END;
BEGIN
SELECT SESSION_USER(), CURRENT_USER(), 'package body p1' AS msg;
END;
$$
DELIMITER ;$$
CALL p1.p1;
DROP PACKAGE p1;
DROP USER xxx@localhost;

File diff suppressed because it is too large Load Diff

View File

@@ -170,6 +170,11 @@ END;
DELIMITER ;/ DELIMITER ;/
DROP PROCEDURE p1; DROP PROCEDURE p1;
--echo # Keywords that are OK for table names, but not for SP variables
CREATE TABLE function (function int);
INSERT INTO function SET function=10;
SELECT function.function FROM function;
DROP TABLE function;
--echo # Testing that (some) keyword_sp are allowed in Oracle-style assignments --echo # Testing that (some) keyword_sp are allowed in Oracle-style assignments
DELIMITER /; DELIMITER /;

View File

@@ -308,7 +308,7 @@ def information_schema ROUTINES ROUTINE_COMMENT 27 '' NO longtext 4294967295 429
def information_schema ROUTINES ROUTINE_DEFINITION 16 NULL YES longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext select NEVER NULL def information_schema ROUTINES ROUTINE_DEFINITION 16 NULL YES longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext select NEVER NULL
def information_schema ROUTINES ROUTINE_NAME 4 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL def information_schema ROUTINES ROUTINE_NAME 4 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
def information_schema ROUTINES ROUTINE_SCHEMA 3 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL def information_schema ROUTINES ROUTINE_SCHEMA 3 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
def information_schema ROUTINES ROUTINE_TYPE 5 '' NO varchar 9 27 NULL NULL NULL utf8 utf8_general_ci varchar(9) select NEVER NULL def information_schema ROUTINES ROUTINE_TYPE 5 '' NO varchar 13 39 NULL NULL NULL utf8 utf8_general_ci varchar(13) select NEVER NULL
def information_schema ROUTINES SECURITY_TYPE 23 '' NO varchar 7 21 NULL NULL NULL utf8 utf8_general_ci varchar(7) select NEVER NULL def information_schema ROUTINES SECURITY_TYPE 23 '' NO varchar 7 21 NULL NULL NULL utf8 utf8_general_ci varchar(7) select NEVER NULL
def information_schema ROUTINES SPECIFIC_NAME 1 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL def information_schema ROUTINES SPECIFIC_NAME 1 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
def information_schema ROUTINES SQL_DATA_ACCESS 21 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL def information_schema ROUTINES SQL_DATA_ACCESS 21 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
@@ -820,7 +820,7 @@ NULL information_schema PROCESSLIST TID bigint NULL NULL NULL NULL bigint(4)
3.0000 information_schema ROUTINES ROUTINE_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512) 3.0000 information_schema ROUTINES ROUTINE_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512)
3.0000 information_schema ROUTINES ROUTINE_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema ROUTINES ROUTINE_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema ROUTINES ROUTINE_NAME varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema ROUTINES ROUTINE_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema ROUTINES ROUTINE_TYPE varchar 9 27 utf8 utf8_general_ci varchar(9) 3.0000 information_schema ROUTINES ROUTINE_TYPE varchar 13 39 utf8 utf8_general_ci varchar(13)
3.0000 information_schema ROUTINES DATA_TYPE varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema ROUTINES DATA_TYPE varchar 64 192 utf8 utf8_general_ci varchar(64)
NULL information_schema ROUTINES CHARACTER_MAXIMUM_LENGTH int NULL NULL NULL NULL int(21) NULL information_schema ROUTINES CHARACTER_MAXIMUM_LENGTH int NULL NULL NULL NULL int(21)
NULL information_schema ROUTINES CHARACTER_OCTET_LENGTH int NULL NULL NULL NULL int(21) NULL information_schema ROUTINES CHARACTER_OCTET_LENGTH int NULL NULL NULL NULL int(21)

View File

@@ -308,7 +308,7 @@ def information_schema ROUTINES ROUTINE_COMMENT 27 '' NO longtext 4294967295 429
def information_schema ROUTINES ROUTINE_DEFINITION 16 NULL YES longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext NEVER NULL def information_schema ROUTINES ROUTINE_DEFINITION 16 NULL YES longtext 4294967295 4294967295 NULL NULL NULL utf8 utf8_general_ci longtext NEVER NULL
def information_schema ROUTINES ROUTINE_NAME 4 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL def information_schema ROUTINES ROUTINE_NAME 4 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
def information_schema ROUTINES ROUTINE_SCHEMA 3 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL def information_schema ROUTINES ROUTINE_SCHEMA 3 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
def information_schema ROUTINES ROUTINE_TYPE 5 '' NO varchar 9 27 NULL NULL NULL utf8 utf8_general_ci varchar(9) NEVER NULL def information_schema ROUTINES ROUTINE_TYPE 5 '' NO varchar 13 39 NULL NULL NULL utf8 utf8_general_ci varchar(13) NEVER NULL
def information_schema ROUTINES SECURITY_TYPE 23 '' NO varchar 7 21 NULL NULL NULL utf8 utf8_general_ci varchar(7) NEVER NULL def information_schema ROUTINES SECURITY_TYPE 23 '' NO varchar 7 21 NULL NULL NULL utf8 utf8_general_ci varchar(7) NEVER NULL
def information_schema ROUTINES SPECIFIC_NAME 1 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL def information_schema ROUTINES SPECIFIC_NAME 1 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
def information_schema ROUTINES SQL_DATA_ACCESS 21 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL def information_schema ROUTINES SQL_DATA_ACCESS 21 '' NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
@@ -820,7 +820,7 @@ NULL information_schema PROCESSLIST TID bigint NULL NULL NULL NULL bigint(4)
3.0000 information_schema ROUTINES ROUTINE_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512) 3.0000 information_schema ROUTINES ROUTINE_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512)
3.0000 information_schema ROUTINES ROUTINE_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema ROUTINES ROUTINE_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema ROUTINES ROUTINE_NAME varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema ROUTINES ROUTINE_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema ROUTINES ROUTINE_TYPE varchar 9 27 utf8 utf8_general_ci varchar(9) 3.0000 information_schema ROUTINES ROUTINE_TYPE varchar 13 39 utf8 utf8_general_ci varchar(13)
3.0000 information_schema ROUTINES DATA_TYPE varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema ROUTINES DATA_TYPE varchar 64 192 utf8 utf8_general_ci varchar(64)
NULL information_schema ROUTINES CHARACTER_MAXIMUM_LENGTH int NULL NULL NULL NULL int(21) NULL information_schema ROUTINES CHARACTER_MAXIMUM_LENGTH int NULL NULL NULL NULL int(21)
NULL information_schema ROUTINES CHARACTER_OCTET_LENGTH int NULL NULL NULL NULL int(21) NULL information_schema ROUTINES CHARACTER_OCTET_LENGTH int NULL NULL NULL NULL int(21)

View File

@@ -152,13 +152,13 @@ def mysql proc security_type 8 'DEFINER' NO enum 7 21 NULL NULL NULL utf8 utf8_g
def mysql proc specific_name 4 '' NO char 64 192 NULL NULL NULL utf8 utf8_general_ci char(64) select,insert,update,references NEVER NULL def mysql proc specific_name 4 '' NO char 64 192 NULL NULL NULL utf8 utf8_general_ci char(64) select,insert,update,references NEVER NULL
def mysql proc sql_data_access 6 'CONTAINS_SQL' NO enum 17 51 NULL NULL NULL utf8 utf8_general_ci enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') select,insert,update,references NEVER NULL def mysql proc sql_data_access 6 'CONTAINS_SQL' NO enum 17 51 NULL NULL NULL utf8 utf8_general_ci enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') select,insert,update,references NEVER NULL
def mysql proc sql_mode 15 '' NO set 515 1545 NULL NULL NULL utf8 utf8_general_ci set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','IGNORE_BAD_TABLE_OPTIONS','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','EMPTY_STRING_IS_NULL') select,insert,update,references NEVER NULL def mysql proc sql_mode 15 '' NO set 515 1545 NULL NULL NULL utf8 utf8_general_ci set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','IGNORE_BAD_TABLE_OPTIONS','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','EMPTY_STRING_IS_NULL') select,insert,update,references NEVER NULL
def mysql proc type 3 NULL NO enum 9 27 NULL NULL NULL utf8 utf8_general_ci enum('FUNCTION','PROCEDURE') PRI select,insert,update,references NEVER NULL def mysql proc type 3 NULL NO enum 12 36 NULL NULL NULL utf8 utf8_general_ci enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') PRI select,insert,update,references NEVER NULL
def mysql procs_priv Db 2 '' NO char 64 192 NULL NULL NULL utf8 utf8_bin char(64) PRI select,insert,update,references NEVER NULL def mysql procs_priv Db 2 '' NO char 64 192 NULL NULL NULL utf8 utf8_bin char(64) PRI select,insert,update,references NEVER NULL
def mysql procs_priv Grantor 6 '' NO char 141 423 NULL NULL NULL utf8 utf8_bin char(141) MUL select,insert,update,references NEVER NULL def mysql procs_priv Grantor 6 '' NO char 141 423 NULL NULL NULL utf8 utf8_bin char(141) MUL select,insert,update,references NEVER NULL
def mysql procs_priv Host 1 '' NO char 60 180 NULL NULL NULL utf8 utf8_bin char(60) PRI select,insert,update,references NEVER NULL def mysql procs_priv Host 1 '' NO char 60 180 NULL NULL NULL utf8 utf8_bin char(60) PRI select,insert,update,references NEVER NULL
def mysql procs_priv Proc_priv 7 '' NO set 27 81 NULL NULL NULL utf8 utf8_general_ci set('Execute','Alter Routine','Grant') select,insert,update,references NEVER NULL def mysql procs_priv Proc_priv 7 '' NO set 27 81 NULL NULL NULL utf8 utf8_general_ci set('Execute','Alter Routine','Grant') select,insert,update,references NEVER NULL
def mysql procs_priv Routine_name 4 '' NO char 64 192 NULL NULL NULL utf8 utf8_general_ci char(64) PRI select,insert,update,references NEVER NULL def mysql procs_priv Routine_name 4 '' NO char 64 192 NULL NULL NULL utf8 utf8_general_ci char(64) PRI select,insert,update,references NEVER NULL
def mysql procs_priv Routine_type 5 NULL NO enum 9 27 NULL NULL NULL utf8 utf8_bin enum('FUNCTION','PROCEDURE') PRI select,insert,update,references NEVER NULL def mysql procs_priv Routine_type 5 NULL NO enum 12 36 NULL NULL NULL utf8 utf8_bin enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') PRI select,insert,update,references NEVER NULL
def mysql procs_priv Timestamp 8 current_timestamp() NO timestamp NULL NULL NULL NULL 0 NULL NULL timestamp on update current_timestamp() select,insert,update,references NEVER NULL def mysql procs_priv Timestamp 8 current_timestamp() NO timestamp NULL NULL NULL NULL 0 NULL NULL timestamp on update current_timestamp() select,insert,update,references NEVER NULL
def mysql procs_priv User 3 '' NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI select,insert,update,references NEVER NULL def mysql procs_priv User 3 '' NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI select,insert,update,references NEVER NULL
def mysql proxies_priv Grantor 6 '' NO char 141 423 NULL NULL NULL utf8 utf8_bin char(141) MUL select,insert,update,references NEVER NULL def mysql proxies_priv Grantor 6 '' NO char 141 423 NULL NULL NULL utf8 utf8_bin char(141) MUL select,insert,update,references NEVER NULL
@@ -470,7 +470,7 @@ NULL mysql innodb_table_stats sum_of_other_index_sizes bigint NULL NULL NULL NUL
3.0000 mysql plugin dl varchar 128 384 utf8 utf8_general_ci varchar(128) 3.0000 mysql plugin dl varchar 128 384 utf8 utf8_general_ci varchar(128)
3.0000 mysql proc db char 64 192 utf8 utf8_bin char(64) 3.0000 mysql proc db char 64 192 utf8 utf8_bin char(64)
3.0000 mysql proc name char 64 192 utf8 utf8_general_ci char(64) 3.0000 mysql proc name char 64 192 utf8 utf8_general_ci char(64)
3.0000 mysql proc type enum 9 27 utf8 utf8_general_ci enum('FUNCTION','PROCEDURE') 3.0000 mysql proc type enum 12 36 utf8 utf8_general_ci enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY')
3.0000 mysql proc specific_name char 64 192 utf8 utf8_general_ci char(64) 3.0000 mysql proc specific_name char 64 192 utf8 utf8_general_ci char(64)
3.0000 mysql proc language enum 3 9 utf8 utf8_general_ci enum('SQL') 3.0000 mysql proc language enum 3 9 utf8 utf8_general_ci enum('SQL')
3.0000 mysql proc sql_data_access enum 17 51 utf8 utf8_general_ci enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') 3.0000 mysql proc sql_data_access enum 17 51 utf8 utf8_general_ci enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA')
@@ -492,7 +492,7 @@ NULL mysql proc modified timestamp NULL NULL NULL NULL timestamp
3.0000 mysql procs_priv Db char 64 192 utf8 utf8_bin char(64) 3.0000 mysql procs_priv Db char 64 192 utf8 utf8_bin char(64)
3.0000 mysql procs_priv User char 80 240 utf8 utf8_bin char(80) 3.0000 mysql procs_priv User char 80 240 utf8 utf8_bin char(80)
3.0000 mysql procs_priv Routine_name char 64 192 utf8 utf8_general_ci char(64) 3.0000 mysql procs_priv Routine_name char 64 192 utf8 utf8_general_ci char(64)
3.0000 mysql procs_priv Routine_type enum 9 27 utf8 utf8_bin enum('FUNCTION','PROCEDURE') 3.0000 mysql procs_priv Routine_type enum 12 36 utf8 utf8_bin enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY')
3.0000 mysql procs_priv Grantor char 141 423 utf8 utf8_bin char(141) 3.0000 mysql procs_priv Grantor char 141 423 utf8 utf8_bin char(141)
3.0000 mysql procs_priv Proc_priv set 27 81 utf8 utf8_general_ci set('Execute','Alter Routine','Grant') 3.0000 mysql procs_priv Proc_priv set 27 81 utf8 utf8_general_ci set('Execute','Alter Routine','Grant')
NULL mysql procs_priv Timestamp timestamp NULL NULL NULL NULL timestamp NULL mysql procs_priv Timestamp timestamp NULL NULL NULL NULL timestamp

View File

@@ -138,13 +138,13 @@ def mysql proc security_type 8 'DEFINER' NO enum 7 21 NULL NULL NULL utf8 utf8_g
def mysql proc specific_name 4 '' NO char 64 192 NULL NULL NULL utf8 utf8_general_ci char(64) NEVER NULL def mysql proc specific_name 4 '' NO char 64 192 NULL NULL NULL utf8 utf8_general_ci char(64) NEVER NULL
def mysql proc sql_data_access 6 'CONTAINS_SQL' NO enum 17 51 NULL NULL NULL utf8 utf8_general_ci enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') NEVER NULL def mysql proc sql_data_access 6 'CONTAINS_SQL' NO enum 17 51 NULL NULL NULL utf8 utf8_general_ci enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') NEVER NULL
def mysql proc sql_mode 15 '' NO set 515 1545 NULL NULL NULL utf8 utf8_general_ci set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','IGNORE_BAD_TABLE_OPTIONS','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','EMPTY_STRING_IS_NULL') NEVER NULL def mysql proc sql_mode 15 '' NO set 515 1545 NULL NULL NULL utf8 utf8_general_ci set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','IGNORE_BAD_TABLE_OPTIONS','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH','EMPTY_STRING_IS_NULL') NEVER NULL
def mysql proc type 3 NULL NO enum 9 27 NULL NULL NULL utf8 utf8_general_ci enum('FUNCTION','PROCEDURE') PRI NEVER NULL def mysql proc type 3 NULL NO enum 12 36 NULL NULL NULL utf8 utf8_general_ci enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') PRI NEVER NULL
def mysql procs_priv Db 2 '' NO char 64 192 NULL NULL NULL utf8 utf8_bin char(64) PRI NEVER NULL def mysql procs_priv Db 2 '' NO char 64 192 NULL NULL NULL utf8 utf8_bin char(64) PRI NEVER NULL
def mysql procs_priv Grantor 6 '' NO char 141 423 NULL NULL NULL utf8 utf8_bin char(141) MUL NEVER NULL def mysql procs_priv Grantor 6 '' NO char 141 423 NULL NULL NULL utf8 utf8_bin char(141) MUL NEVER NULL
def mysql procs_priv Host 1 '' NO char 60 180 NULL NULL NULL utf8 utf8_bin char(60) PRI NEVER NULL def mysql procs_priv Host 1 '' NO char 60 180 NULL NULL NULL utf8 utf8_bin char(60) PRI NEVER NULL
def mysql procs_priv Proc_priv 7 '' NO set 27 81 NULL NULL NULL utf8 utf8_general_ci set('Execute','Alter Routine','Grant') NEVER NULL def mysql procs_priv Proc_priv 7 '' NO set 27 81 NULL NULL NULL utf8 utf8_general_ci set('Execute','Alter Routine','Grant') NEVER NULL
def mysql procs_priv Routine_name 4 '' NO char 64 192 NULL NULL NULL utf8 utf8_general_ci char(64) PRI NEVER NULL def mysql procs_priv Routine_name 4 '' NO char 64 192 NULL NULL NULL utf8 utf8_general_ci char(64) PRI NEVER NULL
def mysql procs_priv Routine_type 5 NULL NO enum 9 27 NULL NULL NULL utf8 utf8_bin enum('FUNCTION','PROCEDURE') PRI NEVER NULL def mysql procs_priv Routine_type 5 NULL NO enum 12 36 NULL NULL NULL utf8 utf8_bin enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') PRI NEVER NULL
def mysql procs_priv Timestamp 8 current_timestamp() NO timestamp NULL NULL NULL NULL 0 NULL NULL timestamp on update current_timestamp() NEVER NULL def mysql procs_priv Timestamp 8 current_timestamp() NO timestamp NULL NULL NULL NULL 0 NULL NULL timestamp on update current_timestamp() NEVER NULL
def mysql procs_priv User 3 '' NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI NEVER NULL def mysql procs_priv User 3 '' NO char 80 240 NULL NULL NULL utf8 utf8_bin char(80) PRI NEVER NULL
def mysql proxies_priv Grantor 6 '' NO char 141 423 NULL NULL NULL utf8 utf8_bin char(141) MUL NEVER NULL def mysql proxies_priv Grantor 6 '' NO char 141 423 NULL NULL NULL utf8 utf8_bin char(141) MUL NEVER NULL
@@ -454,7 +454,7 @@ NULL mysql index_stats avg_frequency decimal NULL NULL NULL NULL decimal(12,4)
3.0000 mysql plugin dl varchar 128 384 utf8 utf8_general_ci varchar(128) 3.0000 mysql plugin dl varchar 128 384 utf8 utf8_general_ci varchar(128)
3.0000 mysql proc db char 64 192 utf8 utf8_bin char(64) 3.0000 mysql proc db char 64 192 utf8 utf8_bin char(64)
3.0000 mysql proc name char 64 192 utf8 utf8_general_ci char(64) 3.0000 mysql proc name char 64 192 utf8 utf8_general_ci char(64)
3.0000 mysql proc type enum 9 27 utf8 utf8_general_ci enum('FUNCTION','PROCEDURE') 3.0000 mysql proc type enum 12 36 utf8 utf8_general_ci enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY')
3.0000 mysql proc specific_name char 64 192 utf8 utf8_general_ci char(64) 3.0000 mysql proc specific_name char 64 192 utf8 utf8_general_ci char(64)
3.0000 mysql proc language enum 3 9 utf8 utf8_general_ci enum('SQL') 3.0000 mysql proc language enum 3 9 utf8 utf8_general_ci enum('SQL')
3.0000 mysql proc sql_data_access enum 17 51 utf8 utf8_general_ci enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') 3.0000 mysql proc sql_data_access enum 17 51 utf8 utf8_general_ci enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA')
@@ -476,7 +476,7 @@ NULL mysql proc modified timestamp NULL NULL NULL NULL timestamp
3.0000 mysql procs_priv Db char 64 192 utf8 utf8_bin char(64) 3.0000 mysql procs_priv Db char 64 192 utf8 utf8_bin char(64)
3.0000 mysql procs_priv User char 80 240 utf8 utf8_bin char(80) 3.0000 mysql procs_priv User char 80 240 utf8 utf8_bin char(80)
3.0000 mysql procs_priv Routine_name char 64 192 utf8 utf8_general_ci char(64) 3.0000 mysql procs_priv Routine_name char 64 192 utf8 utf8_general_ci char(64)
3.0000 mysql procs_priv Routine_type enum 9 27 utf8 utf8_bin enum('FUNCTION','PROCEDURE') 3.0000 mysql procs_priv Routine_type enum 12 36 utf8 utf8_bin enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY')
3.0000 mysql procs_priv Grantor char 141 423 utf8 utf8_bin char(141) 3.0000 mysql procs_priv Grantor char 141 423 utf8 utf8_bin char(141)
3.0000 mysql procs_priv Proc_priv set 27 81 utf8 utf8_general_ci set('Execute','Alter Routine','Grant') 3.0000 mysql procs_priv Proc_priv set 27 81 utf8 utf8_general_ci set('Execute','Alter Routine','Grant')
NULL mysql procs_priv Timestamp timestamp NULL NULL NULL NULL timestamp NULL mysql procs_priv Timestamp timestamp NULL NULL NULL NULL timestamp

View File

@@ -33,7 +33,7 @@ SPECIFIC_NAME varchar(64) NO
ROUTINE_CATALOG varchar(512) NO ROUTINE_CATALOG varchar(512) NO
ROUTINE_SCHEMA varchar(64) NO ROUTINE_SCHEMA varchar(64) NO
ROUTINE_NAME varchar(64) NO ROUTINE_NAME varchar(64) NO
ROUTINE_TYPE varchar(9) NO ROUTINE_TYPE varchar(13) NO
DATA_TYPE varchar(64) NO DATA_TYPE varchar(64) NO
CHARACTER_MAXIMUM_LENGTH int(21) YES NULL CHARACTER_MAXIMUM_LENGTH int(21) YES NULL
CHARACTER_OCTET_LENGTH int(21) YES NULL CHARACTER_OCTET_LENGTH int(21) YES NULL
@@ -67,7 +67,7 @@ ROUTINES CREATE TEMPORARY TABLE `ROUTINES` (
`ROUTINE_CATALOG` varchar(512) NOT NULL DEFAULT '', `ROUTINE_CATALOG` varchar(512) NOT NULL DEFAULT '',
`ROUTINE_SCHEMA` varchar(64) NOT NULL DEFAULT '', `ROUTINE_SCHEMA` varchar(64) NOT NULL DEFAULT '',
`ROUTINE_NAME` varchar(64) NOT NULL DEFAULT '', `ROUTINE_NAME` varchar(64) NOT NULL DEFAULT '',
`ROUTINE_TYPE` varchar(9) NOT NULL DEFAULT '', `ROUTINE_TYPE` varchar(13) NOT NULL DEFAULT '',
`DATA_TYPE` varchar(64) NOT NULL DEFAULT '', `DATA_TYPE` varchar(64) NOT NULL DEFAULT '',
`CHARACTER_MAXIMUM_LENGTH` int(21) DEFAULT NULL, `CHARACTER_MAXIMUM_LENGTH` int(21) DEFAULT NULL,
`CHARACTER_OCTET_LENGTH` int(21) DEFAULT NULL, `CHARACTER_OCTET_LENGTH` int(21) DEFAULT NULL,
@@ -101,7 +101,7 @@ SPECIFIC_NAME varchar(64) NO
ROUTINE_CATALOG varchar(512) NO ROUTINE_CATALOG varchar(512) NO
ROUTINE_SCHEMA varchar(64) NO ROUTINE_SCHEMA varchar(64) NO
ROUTINE_NAME varchar(64) NO ROUTINE_NAME varchar(64) NO
ROUTINE_TYPE varchar(9) NO ROUTINE_TYPE varchar(13) NO
DATA_TYPE varchar(64) NO DATA_TYPE varchar(64) NO
CHARACTER_MAXIMUM_LENGTH int(21) YES NULL CHARACTER_MAXIMUM_LENGTH int(21) YES NULL
CHARACTER_OCTET_LENGTH int(21) YES NULL CHARACTER_OCTET_LENGTH int(21) YES NULL

View File

@@ -33,7 +33,7 @@ SPECIFIC_NAME varchar(64) NO
ROUTINE_CATALOG varchar(512) NO ROUTINE_CATALOG varchar(512) NO
ROUTINE_SCHEMA varchar(64) NO ROUTINE_SCHEMA varchar(64) NO
ROUTINE_NAME varchar(64) NO ROUTINE_NAME varchar(64) NO
ROUTINE_TYPE varchar(9) NO ROUTINE_TYPE varchar(13) NO
DATA_TYPE varchar(64) NO DATA_TYPE varchar(64) NO
CHARACTER_MAXIMUM_LENGTH int(21) YES NULL CHARACTER_MAXIMUM_LENGTH int(21) YES NULL
CHARACTER_OCTET_LENGTH int(21) YES NULL CHARACTER_OCTET_LENGTH int(21) YES NULL
@@ -67,7 +67,7 @@ ROUTINES CREATE TEMPORARY TABLE `ROUTINES` (
`ROUTINE_CATALOG` varchar(512) NOT NULL DEFAULT '', `ROUTINE_CATALOG` varchar(512) NOT NULL DEFAULT '',
`ROUTINE_SCHEMA` varchar(64) NOT NULL DEFAULT '', `ROUTINE_SCHEMA` varchar(64) NOT NULL DEFAULT '',
`ROUTINE_NAME` varchar(64) NOT NULL DEFAULT '', `ROUTINE_NAME` varchar(64) NOT NULL DEFAULT '',
`ROUTINE_TYPE` varchar(9) NOT NULL DEFAULT '', `ROUTINE_TYPE` varchar(13) NOT NULL DEFAULT '',
`DATA_TYPE` varchar(64) NOT NULL DEFAULT '', `DATA_TYPE` varchar(64) NOT NULL DEFAULT '',
`CHARACTER_MAXIMUM_LENGTH` int(21) DEFAULT NULL, `CHARACTER_MAXIMUM_LENGTH` int(21) DEFAULT NULL,
`CHARACTER_OCTET_LENGTH` int(21) DEFAULT NULL, `CHARACTER_OCTET_LENGTH` int(21) DEFAULT NULL,
@@ -101,7 +101,7 @@ SPECIFIC_NAME varchar(64) NO
ROUTINE_CATALOG varchar(512) NO ROUTINE_CATALOG varchar(512) NO
ROUTINE_SCHEMA varchar(64) NO ROUTINE_SCHEMA varchar(64) NO
ROUTINE_NAME varchar(64) NO ROUTINE_NAME varchar(64) NO
ROUTINE_TYPE varchar(9) NO ROUTINE_TYPE varchar(13) NO
DATA_TYPE varchar(64) NO DATA_TYPE varchar(64) NO
CHARACTER_MAXIMUM_LENGTH int(21) YES NULL CHARACTER_MAXIMUM_LENGTH int(21) YES NULL
CHARACTER_OCTET_LENGTH int(21) YES NULL CHARACTER_OCTET_LENGTH int(21) YES NULL

View File

@@ -4,6 +4,8 @@ Acl_column_grants 0
Acl_database_grants 2 Acl_database_grants 2
Acl_function_grants 0 Acl_function_grants 0
Acl_procedure_grants 0 Acl_procedure_grants 0
Acl_package_spec_grants 0
Acl_package_body_grants 0
Acl_proxy_users 2 Acl_proxy_users 2
Acl_role_grants 0 Acl_role_grants 0
Acl_roles 0 Acl_roles 0
@@ -67,6 +69,8 @@ Acl_column_grants 2
Acl_database_grants 4 Acl_database_grants 4
Acl_function_grants 3 Acl_function_grants 3
Acl_procedure_grants 2 Acl_procedure_grants 2
Acl_package_spec_grants 0
Acl_package_body_grants 0
Acl_proxy_users 3 Acl_proxy_users 3
Acl_role_grants 4 Acl_role_grants 4
Acl_roles 2 Acl_roles 2

View File

@@ -2868,9 +2868,9 @@ READ_ONLY YES
COMMAND_LINE_ARGUMENT REQUIRED COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES
SESSION_VALUE NULL SESSION_VALUE NULL
GLOBAL_VALUE 191 GLOBAL_VALUE 200
GLOBAL_VALUE_ORIGIN COMPILE-TIME GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 191 DEFAULT_VALUE 200
VARIABLE_SCOPE GLOBAL VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Maximum number of statement instruments. VARIABLE_COMMENT Maximum number of statement instruments.

View File

@@ -3064,9 +3064,9 @@ READ_ONLY YES
COMMAND_LINE_ARGUMENT REQUIRED COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES
SESSION_VALUE NULL SESSION_VALUE NULL
GLOBAL_VALUE 191 GLOBAL_VALUE 200
GLOBAL_VALUE_ORIGIN COMPILE-TIME GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 191 DEFAULT_VALUE 200
VARIABLE_SCOPE GLOBAL VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Maximum number of statement instruments. VARIABLE_COMMENT Maximum number of statement instruments.

View File

@@ -26,6 +26,7 @@ static const LEX_STRING metadata_lock_info_lock_name[] = {
{ C_STRING_WITH_LEN("Table metadata lock") }, { C_STRING_WITH_LEN("Table metadata lock") },
{ C_STRING_WITH_LEN("Stored function metadata lock") }, { C_STRING_WITH_LEN("Stored function metadata lock") },
{ C_STRING_WITH_LEN("Stored procedure metadata lock") }, { C_STRING_WITH_LEN("Stored procedure metadata lock") },
{ C_STRING_WITH_LEN("Stored package body metadata lock") },
{ C_STRING_WITH_LEN("Trigger metadata lock") }, { C_STRING_WITH_LEN("Trigger metadata lock") },
{ C_STRING_WITH_LEN("Event metadata lock") }, { C_STRING_WITH_LEN("Event metadata lock") },
{ C_STRING_WITH_LEN("Commit lock") }, { C_STRING_WITH_LEN("Commit lock") },
@@ -53,7 +54,7 @@ static ST_FIELD_INFO i_s_metadata_lock_info_fields_info[] =
MY_I_S_MAYBE_NULL, "lock_mode", SKIP_OPEN_TABLE}, MY_I_S_MAYBE_NULL, "lock_mode", SKIP_OPEN_TABLE},
{"LOCK_DURATION", 30, MYSQL_TYPE_STRING, 0, {"LOCK_DURATION", 30, MYSQL_TYPE_STRING, 0,
MY_I_S_MAYBE_NULL, "lock_duration", SKIP_OPEN_TABLE}, MY_I_S_MAYBE_NULL, "lock_duration", SKIP_OPEN_TABLE},
{"LOCK_TYPE", 30, MYSQL_TYPE_STRING, 0, {"LOCK_TYPE", 33, MYSQL_TYPE_STRING, 0,
MY_I_S_MAYBE_NULL, "lock_type", SKIP_OPEN_TABLE}, MY_I_S_MAYBE_NULL, "lock_type", SKIP_OPEN_TABLE},
{"TABLE_SCHEMA", 64, MYSQL_TYPE_STRING, 0, {"TABLE_SCHEMA", 64, MYSQL_TYPE_STRING, 0,
MY_I_S_MAYBE_NULL, "table_schema", SKIP_OPEN_TABLE}, MY_I_S_MAYBE_NULL, "table_schema", SKIP_OPEN_TABLE},

View File

@@ -80,9 +80,9 @@ CREATE TABLE IF NOT EXISTS time_zone_transition_type ( Time_zone_id int unsign
CREATE TABLE IF NOT EXISTS time_zone_leap_second ( Transition_time bigint signed NOT NULL, Correction int signed NOT NULL, PRIMARY KEY TranTime (Transition_time) ) engine=MyISAM CHARACTER SET utf8 comment='Leap seconds information for time zones'; CREATE TABLE IF NOT EXISTS time_zone_leap_second ( Transition_time bigint signed NOT NULL, Correction int signed NOT NULL, PRIMARY KEY TranTime (Transition_time) ) engine=MyISAM CHARACTER SET utf8 comment='Leap seconds information for time zones';
CREATE TABLE IF NOT EXISTS proc (db char(64) collate utf8_bin DEFAULT '' NOT NULL, name char(64) DEFAULT '' NOT NULL, type enum('FUNCTION','PROCEDURE') NOT NULL, specific_name char(64) DEFAULT '' NOT NULL, language enum('SQL') DEFAULT 'SQL' NOT NULL, sql_data_access enum( 'CONTAINS_SQL', 'NO_SQL', 'READS_SQL_DATA', 'MODIFIES_SQL_DATA') DEFAULT 'CONTAINS_SQL' NOT NULL, is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, param_list blob NOT NULL, returns longblob NOT NULL, body longblob NOT NULL, definer char(141) collate utf8_bin DEFAULT '' NOT NULL, created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, modified timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', sql_mode set( 'REAL_AS_FLOAT', 'PIPES_AS_CONCAT', 'ANSI_QUOTES', 'IGNORE_SPACE', 'IGNORE_BAD_TABLE_OPTIONS', 'ONLY_FULL_GROUP_BY', 'NO_UNSIGNED_SUBTRACTION', 'NO_DIR_IN_CREATE', 'POSTGRESQL', 'ORACLE', 'MSSQL', 'DB2', 'MAXDB', 'NO_KEY_OPTIONS', 'NO_TABLE_OPTIONS', 'NO_FIELD_OPTIONS', 'MYSQL323', 'MYSQL40', 'ANSI', 'NO_AUTO_VALUE_ON_ZERO', 'NO_BACKSLASH_ESCAPES', 'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE', 'INVALID_DATES', 'ERROR_FOR_DIVISION_BY_ZERO', 'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE', 'NO_ENGINE_SUBSTITUTION', 'PAD_CHAR_TO_FULL_LENGTH', 'EMPTY_STRING_IS_NULL') DEFAULT '' NOT NULL, comment text collate utf8_bin NOT NULL, character_set_client char(32) collate utf8_bin, collation_connection char(32) collate utf8_bin, db_collation char(32) collate utf8_bin, body_utf8 longblob, PRIMARY KEY (db,name,type)) engine=MyISAM character set utf8 comment='Stored Procedures'; CREATE TABLE IF NOT EXISTS proc (db char(64) collate utf8_bin DEFAULT '' NOT NULL, name char(64) DEFAULT '' NOT NULL, type enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') NOT NULL, specific_name char(64) DEFAULT '' NOT NULL, language enum('SQL') DEFAULT 'SQL' NOT NULL, sql_data_access enum( 'CONTAINS_SQL', 'NO_SQL', 'READS_SQL_DATA', 'MODIFIES_SQL_DATA') DEFAULT 'CONTAINS_SQL' NOT NULL, is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, param_list blob NOT NULL, returns longblob NOT NULL, body longblob NOT NULL, definer char(141) collate utf8_bin DEFAULT '' NOT NULL, created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, modified timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', sql_mode set( 'REAL_AS_FLOAT', 'PIPES_AS_CONCAT', 'ANSI_QUOTES', 'IGNORE_SPACE', 'IGNORE_BAD_TABLE_OPTIONS', 'ONLY_FULL_GROUP_BY', 'NO_UNSIGNED_SUBTRACTION', 'NO_DIR_IN_CREATE', 'POSTGRESQL', 'ORACLE', 'MSSQL', 'DB2', 'MAXDB', 'NO_KEY_OPTIONS', 'NO_TABLE_OPTIONS', 'NO_FIELD_OPTIONS', 'MYSQL323', 'MYSQL40', 'ANSI', 'NO_AUTO_VALUE_ON_ZERO', 'NO_BACKSLASH_ESCAPES', 'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE', 'INVALID_DATES', 'ERROR_FOR_DIVISION_BY_ZERO', 'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE', 'NO_ENGINE_SUBSTITUTION', 'PAD_CHAR_TO_FULL_LENGTH', 'EMPTY_STRING_IS_NULL') DEFAULT '' NOT NULL, comment text collate utf8_bin NOT NULL, character_set_client char(32) collate utf8_bin, collation_connection char(32) collate utf8_bin, db_collation char(32) collate utf8_bin, body_utf8 longblob, PRIMARY KEY (db,name,type)) engine=MyISAM character set utf8 comment='Stored Procedures';
CREATE TABLE IF NOT EXISTS procs_priv ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(80) binary DEFAULT '' NOT NULL, Routine_name char(64) COLLATE utf8_general_ci DEFAULT '' NOT NULL, Routine_type enum('FUNCTION','PROCEDURE') NOT NULL, Grantor char(141) DEFAULT '' NOT NULL, Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (Host,Db,User,Routine_name,Routine_type), KEY Grantor (Grantor) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges'; CREATE TABLE IF NOT EXISTS procs_priv ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(80) binary DEFAULT '' NOT NULL, Routine_name char(64) COLLATE utf8_general_ci DEFAULT '' NOT NULL, Routine_type enum('FUNCTION','PROCEDURE','PACKAGE','PACKAGE BODY') NOT NULL, Grantor char(141) DEFAULT '' NOT NULL, Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (Host,Db,User,Routine_name,Routine_type), KEY Grantor (Grantor) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges';
-- Create general_log if CSV is enabled. -- Create general_log if CSV is enabled.

View File

@@ -469,6 +469,16 @@ ALTER TABLE proc ADD character_set_client
ALTER TABLE proc MODIFY character_set_client ALTER TABLE proc MODIFY character_set_client
char(32) collate utf8_bin DEFAULT NULL; char(32) collate utf8_bin DEFAULT NULL;
ALTER TABLE proc MODIFY type enum('FUNCTION',
'PROCEDURE',
'PACKAGE',
'PACKAGE BODY') NOT NULL;
ALTER TABLE procs_priv MODIFY Routine_type enum('FUNCTION',
'PROCEDURE',
'PACKAGE',
'PACKAGE BODY') NOT NULL;
SELECT CASE WHEN COUNT(*) > 0 THEN SELECT CASE WHEN COUNT(*) > 0 THEN
CONCAT ("WARNING: NULL values of the 'character_set_client' column ('mysql.proc' table) have been updated with a default value (", @@character_set_client, "). Please verify if necessary.") CONCAT ("WARNING: NULL values of the 'character_set_client' column ('mysql.proc' table) have been updated with a default value (", @@character_set_client, "). Please verify if necessary.")
ELSE NULL ELSE NULL

View File

@@ -1784,13 +1784,16 @@ void Item_sp_variable::make_field(THD *thd, Send_field *field)
Item_splocal methods Item_splocal methods
*****************************************************************************/ *****************************************************************************/
Item_splocal::Item_splocal(THD *thd, const LEX_CSTRING *sp_var_name, Item_splocal::Item_splocal(THD *thd,
const Sp_rcontext_handler *rh,
const LEX_CSTRING *sp_var_name,
uint sp_var_idx, uint sp_var_idx,
const Type_handler *handler, const Type_handler *handler,
uint pos_in_q, uint len_in_q): uint pos_in_q, uint len_in_q):
Item_sp_variable(thd, sp_var_name), Item_sp_variable(thd, sp_var_name),
Rewritable_query_parameter(pos_in_q, len_in_q), Rewritable_query_parameter(pos_in_q, len_in_q),
Type_handler_hybrid_field_type(handler), Type_handler_hybrid_field_type(handler),
m_rcontext_handler(rh),
m_var_idx(sp_var_idx) m_var_idx(sp_var_idx)
{ {
maybe_null= TRUE; maybe_null= TRUE;
@@ -1798,9 +1801,21 @@ Item_splocal::Item_splocal(THD *thd, const LEX_CSTRING *sp_var_name,
} }
sp_rcontext *Item_splocal::get_rcontext(sp_rcontext *local_ctx) const
{
return m_rcontext_handler->get_rcontext(local_ctx);
}
Item_field *Item_splocal::get_variable(sp_rcontext *ctx) const
{
return get_rcontext(ctx)->get_variable(m_var_idx);
}
bool Item_splocal::fix_fields(THD *thd, Item **ref) bool Item_splocal::fix_fields(THD *thd, Item **ref)
{ {
Item_field *item= thd->spcont->get_variable(m_var_idx); Item *item= get_variable(thd->spcont);
set_handler(item->type_handler()); set_handler(item->type_handler());
return fix_fields_from_item(thd, ref, item); return fix_fields_from_item(thd, ref, item);
} }
@@ -1811,7 +1826,7 @@ Item_splocal::this_item()
{ {
DBUG_ASSERT(m_sp == m_thd->spcont->m_sp); DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
DBUG_ASSERT(fixed); DBUG_ASSERT(fixed);
return m_thd->spcont->get_variable(m_var_idx); return get_variable(m_thd->spcont);
} }
const Item * const Item *
@@ -1819,7 +1834,7 @@ Item_splocal::this_item() const
{ {
DBUG_ASSERT(m_sp == m_thd->spcont->m_sp); DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
DBUG_ASSERT(fixed); DBUG_ASSERT(fixed);
return m_thd->spcont->get_variable(m_var_idx); return get_variable(m_thd->spcont);
} }
@@ -1828,13 +1843,15 @@ Item_splocal::this_item_addr(THD *thd, Item **)
{ {
DBUG_ASSERT(m_sp == thd->spcont->m_sp); DBUG_ASSERT(m_sp == thd->spcont->m_sp);
DBUG_ASSERT(fixed); DBUG_ASSERT(fixed);
return thd->spcont->get_variable_addr(m_var_idx); return get_rcontext(thd->spcont)->get_variable_addr(m_var_idx);
} }
void Item_splocal::print(String *str, enum_query_type) void Item_splocal::print(String *str, enum_query_type)
{ {
str->reserve(m_name.length+8); const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
str->reserve(m_name.length + 8 + prefix->length);
str->append(prefix);
str->append(m_name.str, m_name.length); str->append(m_name.str, m_name.length);
str->append('@'); str->append('@');
str->qs_append(m_var_idx); str->qs_append(m_var_idx);
@@ -1843,7 +1860,7 @@ void Item_splocal::print(String *str, enum_query_type)
bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it) bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it)
{ {
return ctx->set_variable(thd, get_var_idx(), it); return get_rcontext(ctx)->set_variable(thd, get_var_idx(), it);
} }
@@ -1925,7 +1942,7 @@ bool Item_splocal::check_cols(uint n)
bool Item_splocal_row_field::fix_fields(THD *thd, Item **ref) bool Item_splocal_row_field::fix_fields(THD *thd, Item **ref)
{ {
Item *item= thd->spcont->get_variable(m_var_idx)->element_index(m_field_idx); Item *item= get_variable(thd->spcont)->element_index(m_field_idx);
return fix_fields_from_item(thd, ref, item); return fix_fields_from_item(thd, ref, item);
} }
@@ -1935,7 +1952,7 @@ Item_splocal_row_field::this_item()
{ {
DBUG_ASSERT(m_sp == m_thd->spcont->m_sp); DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
DBUG_ASSERT(fixed); DBUG_ASSERT(fixed);
return m_thd->spcont->get_variable(m_var_idx)->element_index(m_field_idx); return get_variable(m_thd->spcont)->element_index(m_field_idx);
} }
@@ -1944,7 +1961,7 @@ Item_splocal_row_field::this_item() const
{ {
DBUG_ASSERT(m_sp == m_thd->spcont->m_sp); DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
DBUG_ASSERT(fixed); DBUG_ASSERT(fixed);
return m_thd->spcont->get_variable(m_var_idx)->element_index(m_field_idx); return get_variable(m_thd->spcont)->element_index(m_field_idx);
} }
@@ -1953,13 +1970,15 @@ Item_splocal_row_field::this_item_addr(THD *thd, Item **)
{ {
DBUG_ASSERT(m_sp == thd->spcont->m_sp); DBUG_ASSERT(m_sp == thd->spcont->m_sp);
DBUG_ASSERT(fixed); DBUG_ASSERT(fixed);
return thd->spcont->get_variable(m_var_idx)->addr(m_field_idx); return get_variable(thd->spcont)->addr(m_field_idx);
} }
void Item_splocal_row_field::print(String *str, enum_query_type) void Item_splocal_row_field::print(String *str, enum_query_type)
{ {
str->reserve(m_name.length + m_field_name.length + 8); const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
str->reserve(m_name.length + m_field_name.length + 8 + prefix->length);
str->append(prefix);
str->append(m_name.str, m_name.length); str->append(m_name.str, m_name.length);
str->append('.'); str->append('.');
str->append(m_field_name.str, m_field_name.length); str->append(m_field_name.str, m_field_name.length);
@@ -1973,18 +1992,19 @@ void Item_splocal_row_field::print(String *str, enum_query_type)
bool Item_splocal_row_field::set_value(THD *thd, sp_rcontext *ctx, Item **it) bool Item_splocal_row_field::set_value(THD *thd, sp_rcontext *ctx, Item **it)
{ {
return ctx->set_variable_row_field(thd, m_var_idx, m_field_idx, it); return get_rcontext(ctx)->set_variable_row_field(thd, m_var_idx, m_field_idx,
it);
} }
bool Item_splocal_row_field_by_name::fix_fields(THD *thd, Item **it) bool Item_splocal_row_field_by_name::fix_fields(THD *thd, Item **it)
{ {
m_thd= thd; m_thd= thd;
if (thd->spcont->find_row_field_by_name_or_error(&m_field_idx, if (get_rcontext(thd->spcont)->find_row_field_by_name_or_error(&m_field_idx,
m_var_idx, m_var_idx,
m_field_name)) m_field_name))
return true; return true;
Item *item= thd->spcont->get_variable(m_var_idx)->element_index(m_field_idx); Item *item= get_variable(thd->spcont)->element_index(m_field_idx);
set_handler(item->type_handler()); set_handler(item->type_handler());
return fix_fields_from_item(thd, it, item); return fix_fields_from_item(thd, it, item);
} }
@@ -1992,9 +2012,12 @@ bool Item_splocal_row_field_by_name::fix_fields(THD *thd, Item **it)
void Item_splocal_row_field_by_name::print(String *str, enum_query_type) void Item_splocal_row_field_by_name::print(String *str, enum_query_type)
{ {
const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
// +16 should be enough for .NNN@[""] // +16 should be enough for .NNN@[""]
if (str->reserve(m_name.length + 2 * m_field_name.length + 16)) if (str->reserve(m_name.length + 2 * m_field_name.length +
prefix->length + 16))
return; return;
str->qs_append(prefix->str, prefix->length);
str->qs_append(m_name.str, m_name.length); str->qs_append(m_name.str, m_name.length);
str->qs_append('.'); str->qs_append('.');
str->qs_append(m_field_name.str, m_field_name.length); str->qs_append(m_field_name.str, m_field_name.length);

View File

@@ -347,6 +347,39 @@ typedef enum monotonicity_info
class sp_rcontext; class sp_rcontext;
class Sp_rcontext_handler
{
public:
virtual ~Sp_rcontext_handler() {}
virtual const LEX_CSTRING *get_name_prefix() const= 0;
virtual sp_rcontext *get_rcontext(sp_rcontext *ctx) const= 0;
};
class Sp_rcontext_handler_local: public Sp_rcontext_handler
{
public:
const LEX_CSTRING *get_name_prefix() const;
sp_rcontext *get_rcontext(sp_rcontext *ctx) const;
};
class Sp_rcontext_handler_package_body: public Sp_rcontext_handler
{
public:
const LEX_CSTRING *get_name_prefix() const;
sp_rcontext *get_rcontext(sp_rcontext *ctx) const;
};
extern MYSQL_PLUGIN_IMPORT
Sp_rcontext_handler_local sp_rcontext_handler_local;
extern MYSQL_PLUGIN_IMPORT
Sp_rcontext_handler_package_body sp_rcontext_handler_package_body;
class Item_equal; class Item_equal;
@@ -2355,13 +2388,20 @@ class Item_splocal :public Item_sp_variable,
public Type_handler_hybrid_field_type public Type_handler_hybrid_field_type
{ {
protected: protected:
const Sp_rcontext_handler *m_rcontext_handler;
uint m_var_idx; uint m_var_idx;
Type m_type; Type m_type;
bool append_value_for_log(THD *thd, String *str); bool append_value_for_log(THD *thd, String *str);
sp_rcontext *get_rcontext(sp_rcontext *local_ctx) const;
Item_field *get_variable(sp_rcontext *ctx) const;
public: public:
Item_splocal(THD *thd, const LEX_CSTRING *sp_var_name, uint sp_var_idx, Item_splocal(THD *thd, const Sp_rcontext_handler *rh,
const LEX_CSTRING *sp_var_name, uint sp_var_idx,
const Type_handler *handler, const Type_handler *handler,
uint pos_in_q= 0, uint len_in_q= 0); uint pos_in_q= 0, uint len_in_q= 0);
@@ -2423,10 +2463,11 @@ class Item_splocal_with_delayed_data_type: public Item_splocal
{ {
public: public:
Item_splocal_with_delayed_data_type(THD *thd, Item_splocal_with_delayed_data_type(THD *thd,
const Sp_rcontext_handler *rh,
const LEX_CSTRING *sp_var_name, const LEX_CSTRING *sp_var_name,
uint sp_var_idx, uint sp_var_idx,
uint pos_in_q, uint len_in_q) uint pos_in_q, uint len_in_q)
:Item_splocal(thd, sp_var_name, sp_var_idx, &type_handler_null, :Item_splocal(thd, rh, sp_var_name, sp_var_idx, &type_handler_null,
pos_in_q, len_in_q) pos_in_q, len_in_q)
{ } { }
}; };
@@ -2445,13 +2486,13 @@ protected:
bool set_value(THD *thd, sp_rcontext *ctx, Item **it); bool set_value(THD *thd, sp_rcontext *ctx, Item **it);
public: public:
Item_splocal_row_field(THD *thd, Item_splocal_row_field(THD *thd,
const Sp_rcontext_handler *rh,
const LEX_CSTRING *sp_var_name, const LEX_CSTRING *sp_var_name,
const LEX_CSTRING *sp_field_name, const LEX_CSTRING *sp_field_name,
uint sp_var_idx, uint sp_field_idx, uint sp_var_idx, uint sp_field_idx,
const Type_handler *handler, const Type_handler *handler,
uint pos_in_q= 0, uint len_in_q= 0) uint pos_in_q= 0, uint len_in_q= 0)
:Item_splocal(thd, sp_var_name, sp_var_idx, handler, :Item_splocal(thd, rh, sp_var_name, sp_var_idx, handler, pos_in_q, len_in_q),
pos_in_q, len_in_q),
m_field_name(*sp_field_name), m_field_name(*sp_field_name),
m_field_idx(sp_field_idx) m_field_idx(sp_field_idx)
{ } { }
@@ -2469,12 +2510,13 @@ class Item_splocal_row_field_by_name :public Item_splocal_row_field
bool set_value(THD *thd, sp_rcontext *ctx, Item **it); bool set_value(THD *thd, sp_rcontext *ctx, Item **it);
public: public:
Item_splocal_row_field_by_name(THD *thd, Item_splocal_row_field_by_name(THD *thd,
const Sp_rcontext_handler *rh,
const LEX_CSTRING *sp_var_name, const LEX_CSTRING *sp_var_name,
const LEX_CSTRING *sp_field_name, const LEX_CSTRING *sp_field_name,
uint sp_var_idx, uint sp_var_idx,
const Type_handler *handler, const Type_handler *handler,
uint pos_in_q= 0, uint len_in_q= 0) uint pos_in_q= 0, uint len_in_q= 0)
:Item_splocal_row_field(thd, sp_var_name, sp_field_name, :Item_splocal_row_field(thd, rh, sp_var_name, sp_field_name,
sp_var_idx, 0 /* field index will be set later */, sp_var_idx, 0 /* field index will be set later */,
handler, pos_in_q, len_in_q) handler, pos_in_q, len_in_q)
{ } { }

View File

@@ -3431,6 +3431,8 @@ Create_sp_func::create_with_db(THD *thd, LEX_CSTRING *db, LEX_CSTRING *name,
Item *func= NULL; Item *func= NULL;
LEX *lex= thd->lex; LEX *lex= thd->lex;
sp_name *qname; sp_name *qname;
const Sp_handler *sph= &sp_handler_function;
Database_qualified_name pkgname(&null_clex_str, &null_clex_str);
if (has_named_parameters(item_list)) if (has_named_parameters(item_list))
{ {
@@ -3451,13 +3453,18 @@ Create_sp_func::create_with_db(THD *thd, LEX_CSTRING *db, LEX_CSTRING *name,
arg_count= item_list->elements; arg_count= item_list->elements;
qname= new (thd->mem_root) sp_name(db, name, use_explicit_name); qname= new (thd->mem_root) sp_name(db, name, use_explicit_name);
sp_handler_function.add_used_routine(lex, thd, qname); if (sph->sp_resolve_package_routine(thd, thd->lex->sphead,
qname, &sph, &pkgname))
return NULL;
sph->add_used_routine(lex, thd, qname);
if (pkgname.m_name.length)
sp_handler_package_body.add_used_routine(lex, thd, &pkgname);
if (arg_count > 0) if (arg_count > 0)
func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(), qname, func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(),
*item_list); qname, sph, *item_list);
else else
func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(), qname); func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(),
qname, sph);
lex->safe_to_cache_query= 0; lex->safe_to_cache_query= 0;
return func; return func;

View File

@@ -6281,8 +6281,9 @@ longlong Item_func_row_count::val_int()
Item_func_sp::Item_func_sp(THD *thd, Name_resolution_context *context_arg, Item_func_sp::Item_func_sp(THD *thd, Name_resolution_context *context_arg,
sp_name *name): sp_name *name, const Sp_handler *sph):
Item_func(thd), context(context_arg), m_name(name), m_sp(NULL), sp_result_field(NULL) Item_func(thd), context(context_arg), m_name(name), m_handler(sph),
m_sp(NULL), sp_result_field(NULL)
{ {
maybe_null= 1; maybe_null= 1;
dummy_table= (TABLE*) thd->calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE)); dummy_table= (TABLE*) thd->calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE));
@@ -6291,9 +6292,11 @@ Item_func_sp::Item_func_sp(THD *thd, Name_resolution_context *context_arg,
Item_func_sp::Item_func_sp(THD *thd, Name_resolution_context *context_arg, Item_func_sp::Item_func_sp(THD *thd, Name_resolution_context *context_arg,
sp_name *name_arg, List<Item> &list): sp_name *name_arg, const Sp_handler *sph,
Item_func(thd, list), context(context_arg), m_name(name_arg), m_sp(NULL), List<Item> &list):
sp_result_field(NULL) Item_func(thd, list), context(context_arg),
m_name(name_arg), m_handler(sph),
m_sp(NULL), sp_result_field(NULL)
{ {
maybe_null= 1; maybe_null= 1;
dummy_table= (TABLE*) thd->calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE)); dummy_table= (TABLE*) thd->calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE));
@@ -6634,7 +6637,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
bool res; bool res;
DBUG_ENTER("Item_func_sp::fix_fields"); DBUG_ENTER("Item_func_sp::fix_fields");
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
sp_head *sp= sp_handler_function.sp_find_routine(thd, m_name, true); sp_head *sp= m_handler->sp_find_routine(thd, m_name, true);
/* /*
Checking privileges to execute the function while creating view and Checking privileges to execute the function while creating view and

View File

@@ -2774,6 +2774,7 @@ class Item_func_sp :public Item_func
private: private:
Name_resolution_context *context; Name_resolution_context *context;
sp_name *m_name; sp_name *m_name;
const Sp_handler *m_handler;
mutable sp_head *m_sp; mutable sp_head *m_sp;
TABLE *dummy_table; TABLE *dummy_table;
uchar result_buf[64]; uchar result_buf[64];
@@ -2797,10 +2798,11 @@ protected:
} }
public: public:
Item_func_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name); Item_func_sp(THD *thd, Name_resolution_context *context_arg,
sp_name *name, const Sp_handler *sph);
Item_func_sp(THD *thd, Name_resolution_context *context_arg, Item_func_sp(THD *thd, Name_resolution_context *context_arg,
sp_name *name, List<Item> &list); sp_name *name, const Sp_handler *sph, List<Item> &list);
virtual ~Item_func_sp() virtual ~Item_func_sp()
{} {}

View File

@@ -2630,14 +2630,13 @@ my_xpath_parse_VariableReference(MY_XPATH *xpath)
else else
{ {
sp_variable *spv; sp_variable *spv;
sp_pcontext *spc; const Sp_rcontext_handler *rh;
LEX *lex; LEX *lex;
if ((lex= thd->lex) && if ((lex= thd->lex) &&
(spc= lex->spcont) && (spv= lex->find_variable(&name, &rh)))
(spv= spc->find_variable(&name, false)))
{ {
Item_splocal *splocal= new (thd->mem_root) Item_splocal *splocal= new (thd->mem_root)
Item_splocal(thd, &name, spv->offset, spv->type_handler(), 0); Item_splocal(thd, rh, &name, spv->offset, spv->type_handler(), 0);
#ifndef DBUG_OFF #ifndef DBUG_OFF
if (splocal) if (splocal)
splocal->m_sp= lex->sphead; splocal->m_sp= lex->sphead;

View File

@@ -90,6 +90,7 @@ static SYMBOL symbols[] = {
{ "BIT", SYM(BIT_SYM)}, { "BIT", SYM(BIT_SYM)},
{ "BLOB", SYM(BLOB_SYM)}, { "BLOB", SYM(BLOB_SYM)},
{ "BLOCK", SYM(BLOCK_SYM)}, { "BLOCK", SYM(BLOCK_SYM)},
{ "BODY", SYM(BODY_SYM)},
{ "BOOL", SYM(BOOL_SYM)}, { "BOOL", SYM(BOOL_SYM)},
{ "BOOLEAN", SYM(BOOLEAN_SYM)}, { "BOOLEAN", SYM(BOOLEAN_SYM)},
{ "BOTH", SYM(BOTH)}, { "BOTH", SYM(BOTH)},
@@ -453,6 +454,7 @@ static SYMBOL symbols[] = {
{ "OUTFILE", SYM(OUTFILE)}, { "OUTFILE", SYM(OUTFILE)},
{ "OVER", SYM(OVER_SYM)}, { "OVER", SYM(OVER_SYM)},
{ "OWNER", SYM(OWNER_SYM)}, { "OWNER", SYM(OWNER_SYM)},
{ "PACKAGE", SYM(PACKAGE_SYM)},
{ "PACK_KEYS", SYM(PACK_KEYS_SYM)}, { "PACK_KEYS", SYM(PACK_KEYS_SYM)},
{ "PAGE", SYM(PAGE_SYM)}, { "PAGE", SYM(PAGE_SYM)},
{ "PAGE_CHECKSUM", SYM(PAGE_CHECKSUM_SYM)}, { "PAGE_CHECKSUM", SYM(PAGE_CHECKSUM_SYM)},

View File

@@ -84,6 +84,7 @@ PSI_stage_info MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END]=
{0, "Waiting for table metadata lock", 0}, {0, "Waiting for table metadata lock", 0},
{0, "Waiting for stored function metadata lock", 0}, {0, "Waiting for stored function metadata lock", 0},
{0, "Waiting for stored procedure metadata lock", 0}, {0, "Waiting for stored procedure metadata lock", 0},
{0, "Waiting for stored package body metadata lock", 0},
{0, "Waiting for trigger metadata lock", 0}, {0, "Waiting for trigger metadata lock", 0},
{0, "Waiting for event metadata lock", 0}, {0, "Waiting for event metadata lock", 0},
{0, "Waiting for commit lock", 0}, {0, "Waiting for commit lock", 0},
@@ -3034,6 +3035,7 @@ const char *wsrep_get_mdl_namespace_name(MDL_key::enum_mdl_namespace ns)
case MDL_key::TABLE : return "TABLE"; case MDL_key::TABLE : return "TABLE";
case MDL_key::FUNCTION : return "FUNCTION"; case MDL_key::FUNCTION : return "FUNCTION";
case MDL_key::PROCEDURE : return "PROCEDURE"; case MDL_key::PROCEDURE : return "PROCEDURE";
case MDL_key::PACKAGE_BODY: return "PACKAGE BODY";
case MDL_key::TRIGGER : return "TRIGGER"; case MDL_key::TRIGGER : return "TRIGGER";
case MDL_key::EVENT : return "EVENT"; case MDL_key::EVENT : return "EVENT";
case MDL_key::COMMIT : return "COMMIT"; case MDL_key::COMMIT : return "COMMIT";

View File

@@ -299,6 +299,7 @@ public:
TABLE, TABLE,
FUNCTION, FUNCTION,
PROCEDURE, PROCEDURE,
PACKAGE_BODY,
TRIGGER, TRIGGER,
EVENT, EVENT,
COMMIT, COMMIT,

View File

@@ -3788,6 +3788,8 @@ SHOW_VAR com_status_vars[]= {
{"create_event", STMT_STATUS(SQLCOM_CREATE_EVENT)}, {"create_event", STMT_STATUS(SQLCOM_CREATE_EVENT)},
{"create_function", STMT_STATUS(SQLCOM_CREATE_SPFUNCTION)}, {"create_function", STMT_STATUS(SQLCOM_CREATE_SPFUNCTION)},
{"create_index", STMT_STATUS(SQLCOM_CREATE_INDEX)}, {"create_index", STMT_STATUS(SQLCOM_CREATE_INDEX)},
{"create_package", STMT_STATUS(SQLCOM_CREATE_PACKAGE)},
{"create_package_body", STMT_STATUS(SQLCOM_CREATE_PACKAGE_BODY)},
{"create_procedure", STMT_STATUS(SQLCOM_CREATE_PROCEDURE)}, {"create_procedure", STMT_STATUS(SQLCOM_CREATE_PROCEDURE)},
{"create_role", STMT_STATUS(SQLCOM_CREATE_ROLE)}, {"create_role", STMT_STATUS(SQLCOM_CREATE_ROLE)},
{"create_sequence", STMT_STATUS(SQLCOM_CREATE_SEQUENCE)}, {"create_sequence", STMT_STATUS(SQLCOM_CREATE_SEQUENCE)},
@@ -3807,6 +3809,8 @@ SHOW_VAR com_status_vars[]= {
{"drop_function", STMT_STATUS(SQLCOM_DROP_FUNCTION)}, {"drop_function", STMT_STATUS(SQLCOM_DROP_FUNCTION)},
{"drop_index", STMT_STATUS(SQLCOM_DROP_INDEX)}, {"drop_index", STMT_STATUS(SQLCOM_DROP_INDEX)},
{"drop_procedure", STMT_STATUS(SQLCOM_DROP_PROCEDURE)}, {"drop_procedure", STMT_STATUS(SQLCOM_DROP_PROCEDURE)},
{"drop_package", STMT_STATUS(SQLCOM_DROP_PACKAGE)},
{"drop_package_body", STMT_STATUS(SQLCOM_DROP_PACKAGE_BODY)},
{"drop_role", STMT_STATUS(SQLCOM_DROP_ROLE)}, {"drop_role", STMT_STATUS(SQLCOM_DROP_ROLE)},
{"drop_server", STMT_STATUS(SQLCOM_DROP_SERVER)}, {"drop_server", STMT_STATUS(SQLCOM_DROP_SERVER)},
{"drop_sequence", STMT_STATUS(SQLCOM_DROP_SEQUENCE)}, {"drop_sequence", STMT_STATUS(SQLCOM_DROP_SEQUENCE)},
@@ -3863,6 +3867,8 @@ SHOW_VAR com_status_vars[]= {
{"show_create_db", STMT_STATUS(SQLCOM_SHOW_CREATE_DB)}, {"show_create_db", STMT_STATUS(SQLCOM_SHOW_CREATE_DB)},
{"show_create_event", STMT_STATUS(SQLCOM_SHOW_CREATE_EVENT)}, {"show_create_event", STMT_STATUS(SQLCOM_SHOW_CREATE_EVENT)},
{"show_create_func", STMT_STATUS(SQLCOM_SHOW_CREATE_FUNC)}, {"show_create_func", STMT_STATUS(SQLCOM_SHOW_CREATE_FUNC)},
{"show_create_package", STMT_STATUS(SQLCOM_SHOW_CREATE_PACKAGE)},
{"show_create_package_body",STMT_STATUS(SQLCOM_SHOW_CREATE_PACKAGE_BODY)},
{"show_create_proc", STMT_STATUS(SQLCOM_SHOW_CREATE_PROC)}, {"show_create_proc", STMT_STATUS(SQLCOM_SHOW_CREATE_PROC)},
{"show_create_table", STMT_STATUS(SQLCOM_SHOW_CREATE)}, {"show_create_table", STMT_STATUS(SQLCOM_SHOW_CREATE)},
{"show_create_trigger", STMT_STATUS(SQLCOM_SHOW_CREATE_TRIGGER)}, {"show_create_trigger", STMT_STATUS(SQLCOM_SHOW_CREATE_TRIGGER)},
@@ -3884,6 +3890,11 @@ SHOW_VAR com_status_vars[]= {
{"show_keys", STMT_STATUS(SQLCOM_SHOW_KEYS)}, {"show_keys", STMT_STATUS(SQLCOM_SHOW_KEYS)},
{"show_master_status", STMT_STATUS(SQLCOM_SHOW_MASTER_STAT)}, {"show_master_status", STMT_STATUS(SQLCOM_SHOW_MASTER_STAT)},
{"show_open_tables", STMT_STATUS(SQLCOM_SHOW_OPEN_TABLES)}, {"show_open_tables", STMT_STATUS(SQLCOM_SHOW_OPEN_TABLES)},
{"show_package_status", STMT_STATUS(SQLCOM_SHOW_STATUS_PACKAGE)},
#ifndef DBUG_OFF
{"show_package_body_code", STMT_STATUS(SQLCOM_SHOW_PACKAGE_BODY_CODE)},
#endif
{"show_package_body_status", STMT_STATUS(SQLCOM_SHOW_STATUS_PACKAGE_BODY)},
{"show_plugins", STMT_STATUS(SQLCOM_SHOW_PLUGINS)}, {"show_plugins", STMT_STATUS(SQLCOM_SHOW_PLUGINS)},
{"show_privileges", STMT_STATUS(SQLCOM_SHOW_PRIVILEGES)}, {"show_privileges", STMT_STATUS(SQLCOM_SHOW_PRIVILEGES)},
#ifndef DBUG_OFF #ifndef DBUG_OFF

View File

@@ -7788,3 +7788,7 @@ ER_WRONG_INSERT_INTO_SEQUENCE
eng "Wrong INSERT into a SEQUENCE. One can only do single table INSERT into a squence object (like with mysqldump). If you want to change the SEQUENCE, use ALTER SEQUENCE instead." eng "Wrong INSERT into a SEQUENCE. One can only do single table INSERT into a squence object (like with mysqldump). If you want to change the SEQUENCE, use ALTER SEQUENCE instead."
ER_SP_STACK_TRACE ER_SP_STACK_TRACE
eng "At line %u in %s" eng "At line %u in %s"
ER_PACKAGE_ROUTINE_IN_SPEC_NOT_DEFINED_IN_BODY
eng "Subroutine '%-.192s' is declared in the package specification but is not defined in the package body"
ER_PACKAGE_ROUTINE_FORWARD_DECLARATION_NOT_DEFINED
eng "Subroutine '%-.192s' has a forward declaration but is not defined"

667
sql/sp.cc
View File

@@ -46,6 +46,17 @@ sp_cache **Sp_handler_function::get_cache(THD *thd) const
return &thd->sp_func_cache; return &thd->sp_func_cache;
} }
sp_cache **Sp_handler_package_spec::get_cache(THD *thd) const
{
return &thd->sp_package_spec_cache;
}
sp_cache **Sp_handler_package_body::get_cache(THD *thd) const
{
return &thd->sp_package_body_cache;
}
ulong Sp_handler_procedure::recursion_depth(THD *thd) const ulong Sp_handler_procedure::recursion_depth(THD *thd) const
{ {
return thd->variables.max_sp_recursion_depth; return thd->variables.max_sp_recursion_depth;
@@ -86,7 +97,23 @@ bool Sp_handler_procedure::add_instr_preturn(THD *thd, sp_head *sp,
Sp_handler_procedure sp_handler_procedure; Sp_handler_procedure sp_handler_procedure;
Sp_handler_function sp_handler_function; 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_trigger sp_handler_trigger;
Sp_handler_package_procedure sp_handler_package_procedure;
Sp_handler_package_function sp_handler_package_function;
const Sp_handler *Sp_handler_procedure::package_routine_handler() const
{
return &sp_handler_package_procedure;
}
const Sp_handler *Sp_handler_function::package_routine_handler() const
{
return &sp_handler_package_function;
}
static const static const
@@ -670,7 +697,7 @@ Sp_handler::db_find_routine(THD *thd,
table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root, table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root,
&params); &params);
if (type() == TYPE_ENUM_PROCEDURE) if (type() != TYPE_ENUM_FUNCTION)
returns= empty_clex_str; returns= empty_clex_str;
else if (table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root, else if (table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
&returns)) &returns))
@@ -698,7 +725,7 @@ Sp_handler::db_find_routine(THD *thd,
ret= db_load_routine(thd, name, sphp, ret= db_load_routine(thd, name, sphp,
sql_mode, params, returns, body, chistics, definer, sql_mode, params, returns, body, chistics, definer,
created, modified, creation_ctx); created, modified, NULL, creation_ctx);
done: done:
/* /*
Restore the time zone flag as the timezone usage in proc table Restore the time zone flag as the timezone usage in proc table
@@ -768,6 +795,8 @@ Silence_deprecated_warning::handle_condition(
@param[in] thd Thread handler @param[in] thd Thread handler
@param[in] defstr CREATE... string @param[in] defstr CREATE... string
@param[in] sql_mode SQL mode @param[in] sql_mode SQL mode
@param[in] parent The owner package for package routines,
or NULL for standalone routines.
@param[in] creation_ctx Creation context of stored routines @param[in] creation_ctx Creation context of stored routines
@return Pointer on sp_head struct @return Pointer on sp_head struct
@@ -776,6 +805,7 @@ Silence_deprecated_warning::handle_condition(
*/ */
static sp_head *sp_compile(THD *thd, String *defstr, sql_mode_t sql_mode, static sp_head *sp_compile(THD *thd, String *defstr, sql_mode_t sql_mode,
sp_package *parent,
Stored_program_creation_ctx *creation_ctx) Stored_program_creation_ctx *creation_ctx)
{ {
sp_head *sp; sp_head *sp;
@@ -796,6 +826,7 @@ static sp_head *sp_compile(THD *thd, String *defstr, sql_mode_t sql_mode,
} }
lex_start(thd); lex_start(thd);
thd->lex->sphead= parent;
thd->push_internal_handler(&warning_handler); thd->push_internal_handler(&warning_handler);
thd->spcont= 0; thd->spcont= 0;
@@ -866,6 +897,7 @@ Sp_handler::db_load_routine(THD *thd, const Database_qualified_name *name,
const st_sp_chistics &chistics, const st_sp_chistics &chistics,
const AUTHID &definer, const AUTHID &definer,
longlong created, longlong modified, longlong created, longlong modified,
sp_package *parent,
Stored_program_creation_ctx *creation_ctx) const Stored_program_creation_ctx *creation_ctx) const
{ {
LEX *old_lex= thd->lex, newlex; LEX *old_lex= thd->lex, newlex;
@@ -922,7 +954,7 @@ Sp_handler::db_load_routine(THD *thd, const Database_qualified_name *name,
} }
{ {
*sphp= sp_compile(thd, &defstr, sql_mode, creation_ctx); *sphp= sp_compile(thd, &defstr, sql_mode, parent, creation_ctx);
/* /*
Force switching back to the saved current database (if changed), Force switching back to the saved current database (if changed),
because it may be NULL. In this case, mysql_change_db() would because it may be NULL. In this case, mysql_change_db() would
@@ -947,6 +979,22 @@ Sp_handler::db_load_routine(THD *thd, const Database_qualified_name *name,
(*sphp)->set_info(created, modified, chistics, sql_mode); (*sphp)->set_info(created, modified, chistics, sql_mode);
(*sphp)->set_creation_ctx(creation_ctx); (*sphp)->set_creation_ctx(creation_ctx);
(*sphp)->optimize(); (*sphp)->optimize();
if (type() == TYPE_ENUM_PACKAGE_BODY)
{
sp_package *package= sphp[0]->get_package();
List_iterator<LEX> it(package->m_routine_implementations);
for (LEX *lex; (lex= it++); )
{
DBUG_ASSERT(lex->sphead);
lex->sphead->set_definer(&definer.user, &definer.host);
lex->sphead->set_suid(package->suid());
lex->sphead->m_sql_mode= sql_mode;
lex->sphead->set_creation_ctx(creation_ctx);
lex->sphead->optimize();
}
}
/* /*
Not strictly necessary to invoke this method here, since we know Not strictly necessary to invoke this method here, since we know
that we've parsed CREATE PROCEDURE/FUNCTION and not an that we've parsed CREATE PROCEDURE/FUNCTION and not an
@@ -1038,6 +1086,32 @@ Sp_handler::sp_drop_routine_internal(THD *thd,
} }
int
Sp_handler::sp_find_and_drop_routine(THD *thd, TABLE *table,
const Database_qualified_name *name) const
{
int ret;
if (SP_OK != (ret= db_find_routine_aux(thd, name, table)))
return ret;
return sp_drop_routine_internal(thd, name, table);
}
int
Sp_handler_package_spec::
sp_find_and_drop_routine(THD *thd, TABLE *table,
const Database_qualified_name *name) const
{
int ret;
if (SP_OK != (ret= db_find_routine_aux(thd, name, table)))
return ret;
ret= sp_handler_package_body.sp_find_and_drop_routine(thd, table, name);
if (ret != SP_KEY_NOT_FOUND && ret != SP_OK)
return ret;
return Sp_handler::sp_find_and_drop_routine(thd, table, name);
}
/** /**
Write stored-routine object into mysql.proc. Write stored-routine object into mysql.proc.
@@ -1122,7 +1196,22 @@ Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
{ {
if (lex->create_info.or_replace()) if (lex->create_info.or_replace())
{ {
if ((ret= sp_drop_routine_internal(thd, sp, table))) switch (type()) {
case TYPE_ENUM_PACKAGE:
// Drop together with its PACKAGE BODY mysql.proc record
ret= sp_handler_package_spec.sp_find_and_drop_routine(thd, table, sp);
break;
case TYPE_ENUM_PACKAGE_BODY:
case TYPE_ENUM_FUNCTION:
case TYPE_ENUM_PROCEDURE:
ret= sp_drop_routine_internal(thd, sp, table);
break;
case TYPE_ENUM_TRIGGER:
case TYPE_ENUM_PROXY:
DBUG_ASSERT(0);
ret= SP_OK;
}
if (ret)
goto done; goto done;
} }
else if (lex->create_info.if_not_exists()) else if (lex->create_info.if_not_exists())
@@ -1373,6 +1462,49 @@ append_comment(String *buf, const LEX_CSTRING &comment)
} }
static bool
append_package_chistics(String *buf, const st_sp_chistics &chistics)
{
return append_suid(buf, chistics.suid) ||
append_comment(buf, chistics.comment);
}
bool
Sp_handler_package::show_create_sp(THD *thd, String *buf,
const LEX_CSTRING &db,
const LEX_CSTRING &name,
const LEX_CSTRING &params,
const LEX_CSTRING &returns,
const LEX_CSTRING &body,
const st_sp_chistics &chistics,
const AUTHID &definer,
const DDL_options_st ddl_options,
sql_mode_t sql_mode) const
{
sql_mode_t old_sql_mode= thd->variables.sql_mode;
thd->variables.sql_mode= sql_mode;
bool rc=
buf->append(STRING_WITH_LEN("CREATE ")) ||
(ddl_options.or_replace() &&
buf->append(STRING_WITH_LEN("OR REPLACE "))) ||
append_definer(thd, buf, &definer.user, &definer.host) ||
buf->append(type_lex_cstring()) ||
buf->append(" ", 1) ||
(ddl_options.if_not_exists() &&
buf->append(STRING_WITH_LEN("IF NOT EXISTS "))) ||
(db.length > 0 &&
(append_identifier(thd, buf, db.str, db.length) ||
buf->append('.'))) ||
append_identifier(thd, buf, name.str, name.length) ||
append_package_chistics(buf, chistics) ||
buf->append(" ", 1) ||
buf->append(body.str, body.length);
thd->variables.sql_mode= old_sql_mode;
return rc;
}
/** /**
Delete the record for the stored routine object from mysql.proc Delete the record for the stored routine object from mysql.proc
and do binary logging. and do binary logging.
@@ -1406,10 +1538,7 @@ Sp_handler::sp_drop_routine(THD *thd,
if (!(table= open_proc_table_for_update(thd))) if (!(table= open_proc_table_for_update(thd)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED); DBUG_RETURN(SP_OPEN_TABLE_FAILED);
if ((ret= db_find_routine_aux(thd, name, table)) == SP_OK) if (SP_OK == (ret= sp_find_and_drop_routine(thd, table, name)) &&
ret= sp_drop_routine_internal(thd, name, table);
if (ret == SP_OK &&
write_bin_log(thd, TRUE, thd->query(), thd->query_length())) write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
ret= SP_INTERNAL_ERROR; ret= SP_INTERNAL_ERROR;
/* /*
@@ -1601,9 +1730,12 @@ bool lock_db_routines(THD *thd, const char *db)
longlong sp_type= table->field[MYSQL_PROC_MYSQL_TYPE]->val_int(); longlong sp_type= table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
MDL_request *mdl_request= new (thd->mem_root) MDL_request; MDL_request *mdl_request= new (thd->mem_root) MDL_request;
mdl_request->init(sp_type == TYPE_ENUM_FUNCTION ? const Sp_handler *sph= Sp_handler::handler((stored_procedure_type)
MDL_key::FUNCTION : MDL_key::PROCEDURE, sp_type);
db, sp_name, MDL_EXCLUSIVE, MDL_TRANSACTION); if (!sph)
sph= &sp_handler_procedure;
mdl_request->init(sph->get_mdl_type(), db, sp_name,
MDL_EXCLUSIVE, MDL_TRANSACTION);
mdl_requests.push_front(mdl_request); mdl_requests.push_front(mdl_request);
} while (! (nxtres= table->file->ha_index_next_same(table->record[0], keybuf, key_len))); } while (! (nxtres= table->file->ha_index_next_same(table->record[0], keybuf, key_len)));
} }
@@ -1749,6 +1881,34 @@ Sp_handler::sp_show_create_routine(THD *thd,
} }
/*
A helper class to split package name from a dot-qualified name
and return it as a 0-terminated string
'pkg.name' -> 'pkg\0'
*/
class Prefix_name_buf: public LEX_CSTRING
{
char m_buf[SAFE_NAME_LEN + 1];
public:
Prefix_name_buf(const THD *thd, const LEX_CSTRING &name)
{
const char *end;
if (!(end= strrchr(name.str, '.')))
{
static_cast<LEX_CSTRING*>(this)[0]= null_clex_str;
}
else
{
str= m_buf;
length= end - name.str;
set_if_smaller(length, sizeof(m_buf) - 1);
memcpy(m_buf, name.str, length);
m_buf[length]= '\0';
}
}
};
/* /*
In case of recursions, we create multiple copies of the same SP. In case of recursions, we create multiple copies of the same SP.
This methods checks the current recursion depth. This methods checks the current recursion depth.
@@ -1764,9 +1924,17 @@ Sp_handler::sp_clone_and_link_routine(THD *thd,
sp_head *sp) const sp_head *sp) const
{ {
DBUG_ENTER("sp_link_routine"); DBUG_ENTER("sp_link_routine");
int rc;
ulong level; ulong level;
sp_head *new_sp; sp_head *new_sp;
LEX_CSTRING returns= empty_clex_str; LEX_CSTRING returns= empty_clex_str;
Database_qualified_name lname(name->m_db, name->m_name);
#ifndef DBUG_OFF
uint parent_subroutine_count=
!sp->m_parent ? 0 :
sp->m_parent->m_routine_declarations.elements +
sp->m_parent->m_routine_implementations.elements;
#endif
/* /*
String buffer for RETURNS data type must have system charset; String buffer for RETURNS data type must have system charset;
@@ -1808,13 +1976,63 @@ Sp_handler::sp_clone_and_link_routine(THD *thd,
sp_returns_type(thd, retstr, sp); sp_returns_type(thd, retstr, sp);
returns= retstr.lex_cstring(); returns= retstr.lex_cstring();
} }
if (db_load_routine(thd, name, &new_sp,
if (sp->m_parent)
{
/*
If we're cloning a recursively called package routine,
we need to take some special measures:
1. Cut the package name prefix from the routine name: 'pkg1.p1' -> 'p1',
to have db_load_routine() generate and parse a query like this:
CREATE PROCEDURE p1 ...;
rether than:
CREATE PROCEDURE pkg1.p1 ...;
The latter would be misinterpreted by the parser as a standalone
routine 'p1' in the database 'pkg1', which is not what we need.
2. We pass m_parent to db_load_routine() to have it set
thd->lex->sphead to sp->m_parent before calling parse_sql().
These two measures allow to parse a package subroutine using
the grammar for standalone routines, e.g.:
CREATE PROCEDURE p1 ... END;
instead of going through a more complex query, e.g.:
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 ... END;
END;
*/
size_t prefix_length= sp->m_parent->m_name.length + 1;
DBUG_ASSERT(prefix_length < lname.m_name.length);
DBUG_ASSERT(lname.m_name.str[sp->m_parent->m_name.length] == '.');
lname.m_name.str+= prefix_length;
lname.m_name.length-= prefix_length;
sp->m_parent->m_is_cloning_routine= true;
}
rc= db_load_routine(thd, &lname, &new_sp,
sp->m_sql_mode, sp->m_params, returns, sp->m_sql_mode, sp->m_params, returns,
sp->m_body, sp->chistics(), sp->m_body, sp->chistics(),
sp->m_definer, sp->m_definer,
sp->m_created, sp->m_modified, sp->m_created, sp->m_modified,
sp->get_creation_ctx()) == SP_OK) sp->m_parent,
sp->get_creation_ctx());
if (sp->m_parent)
sp->m_parent->m_is_cloning_routine= false;
if (rc == SP_OK)
{ {
#ifndef DBUG_OFF
/*
We've just called the parser to clone the routine.
In case of a package routine, make sure that the parser
has not added any new subroutines directly to the parent package.
The cloned subroutine instances get linked below to the first instance,
they must have no direct links from the parent package.
*/
DBUG_ASSERT(!sp->m_parent ||
parent_subroutine_count ==
sp->m_parent->m_routine_declarations.elements +
sp->m_parent->m_routine_implementations.elements);
#endif
sp->m_last_cached_sp->m_next_cached_sp= new_sp; sp->m_last_cached_sp->m_next_cached_sp= new_sp;
new_sp->m_recursion_level= level; new_sp->m_recursion_level= level;
new_sp->m_first_instance= sp; new_sp->m_first_instance= sp;
@@ -1848,7 +2066,7 @@ sp_head *
Sp_handler::sp_find_routine(THD *thd, const Database_qualified_name *name, Sp_handler::sp_find_routine(THD *thd, const Database_qualified_name *name,
bool cache_only) const bool cache_only) const
{ {
DBUG_ENTER("sp_find_routine"); DBUG_ENTER("Sp_handler::sp_find_routine");
DBUG_PRINT("enter", ("name: %.*s.%.*s type: %s cache only %d", DBUG_PRINT("enter", ("name: %.*s.%.*s type: %s cache only %d",
(int) name->m_db.length, name->m_db.str, (int) name->m_db.length, name->m_db.str,
(int) name->m_name.length, name->m_name.str, (int) name->m_name.length, name->m_name.str,
@@ -1864,6 +2082,74 @@ Sp_handler::sp_find_routine(THD *thd, const Database_qualified_name *name,
} }
/**
Find a package routine.
See sp_cache_routine() for more information on parameters and return value.
@param thd - current THD
@param pkgname_str - package name
@param name - a mixed qualified name, with:
* name->m_db set to the database, e.g. "dbname"
* name->m_name set to a package-qualified name,
e.g. "pkgname.spname".
@param cache_only - don't load mysql.proc if not cached
@retval non-NULL - a pointer to an sp_head object
@retval NULL - an error happened.
*/
sp_head *
Sp_handler::sp_find_package_routine(THD *thd,
const LEX_CSTRING pkgname_str,
const Database_qualified_name *name,
bool cache_only) const
{
DBUG_ENTER("sp_find_package_routine");
Database_qualified_name pkgname(&name->m_db, &pkgname_str);
sp_head *ph= sp_cache_lookup(&thd->sp_package_body_cache, &pkgname);
if (!ph && !cache_only)
sp_handler_package_body.db_find_and_cache_routine(thd, &pkgname, &ph);
if (ph)
{
LEX_CSTRING tmp= name->m_name;
const char *dot= strrchr(tmp.str, '.');
size_t prefix_length= dot ? dot - tmp.str + 1 : 0;
sp_package *pkg= ph->get_package();
tmp.str+= prefix_length;
tmp.length-= prefix_length;
LEX *plex= pkg ? pkg->m_routine_implementations.find(tmp, type()) : NULL;
sp_head *sp= plex ? plex->sphead : NULL;
if (sp)
DBUG_RETURN(sp_clone_and_link_routine(thd, name, sp));
}
DBUG_RETURN(NULL);
}
/**
Find a package routine.
See sp_cache_routine() for more information on parameters and return value.
@param thd - current THD
@param name - Qualified name with the following format:
* name->m_db is set to the database name, e.g. "dbname"
* name->m_name is set to a package-qualified name,
e.g. "pkgname.spname", as a single string with a
dot character as a separator.
@param cache_only - don't load mysql.proc if not cached
@retval non-NULL - a pointer to an sp_head object
@retval NULL - an error happened
*/
sp_head *
Sp_handler::sp_find_package_routine(THD *thd,
const Database_qualified_name *name,
bool cache_only) const
{
DBUG_ENTER("Sp_handler::sp_find_package_routine");
Prefix_name_buf pkgname(thd, name->m_name);
DBUG_ASSERT(pkgname.length);
DBUG_RETURN(sp_find_package_routine(thd, pkgname, name, cache_only));
}
/** /**
This is used by sql_acl.cc:mysql_routine_grant() and is used to find This is used by sql_acl.cc:mysql_routine_grant() and is used to find
the routines in 'routines'. the routines in 'routines'.
@@ -1947,7 +2233,9 @@ extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
*/ */
bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena, bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
const MDL_key *key, TABLE_LIST *belong_to_view) const MDL_key *key,
const Sp_handler *handler,
TABLE_LIST *belong_to_view)
{ {
my_hash_init_opt(&prelocking_ctx->sroutines, system_charset_info, my_hash_init_opt(&prelocking_ctx->sroutines, system_charset_info,
Query_tables_list::START_SROUTINES_HASH_SIZE, Query_tables_list::START_SROUTINES_HASH_SIZE,
@@ -1964,6 +2252,7 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
return FALSE; return FALSE;
prelocking_ctx->sroutines_list.link_in_list(rn, &rn->next); prelocking_ctx->sroutines_list.link_in_list(rn, &rn->next);
rn->belong_to_view= belong_to_view; rn->belong_to_view= belong_to_view;
rn->m_handler= handler;
rn->m_sp_cache_version= 0; rn->m_sp_cache_version= 0;
return TRUE; return TRUE;
} }
@@ -1971,6 +2260,268 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
} }
/*
Find and cache a routine in a parser-safe reentrant mode.
If sp_head is not in the cache,
its loaded from mysql.proc, parsed using parse_sql(), and cached.
Note, as it is called from inside parse_sql() itself,
we need to preserve and restore the parser state.
It's used during parsing of CREATE PACKAGE BODY,
to load the corresponding CREATE PACKAGE.
*/
int
Sp_handler::sp_cache_routine_reentrant(THD *thd,
const Database_qualified_name *name,
sp_head **sp) const
{
int ret;
Parser_state *oldps= thd->m_parser_state;
thd->m_parser_state= NULL;
ret= sp_cache_routine(thd, name, false, sp);
thd->m_parser_state= oldps;
return ret;
}
/*
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
if needed.
@param thd current thd
@param db the database name
@param package the package name
@param name the routine name
@param type the routine type
@retval true, if the routine has a declaration
@retval false, if the routine does not have a declaration
This function can be called in arbitrary context:
- inside a package routine
- inside a standalone routine
- inside a anonymous block
- outside of any routines
The state of the package specification (i.e. the CREATE PACKAGE statement)
for "package" before the call of this function is not known:
it can be cached, or not cached.
After the call of this function, the package specification is always cached,
unless a fatal error happens.
*/
static bool
is_package_public_routine(THD *thd,
const LEX_CSTRING &db,
const LEX_CSTRING &package,
const LEX_CSTRING &routine,
stored_procedure_type type)
{
sp_head *sp= NULL;
Database_qualified_name tmp(db, package);
bool ret= sp_handler_package_spec.
sp_cache_routine_reentrant(thd, &tmp, &sp);
sp_package *spec= (!ret && sp) ? sp->get_package() : NULL;
return spec && spec->m_routine_declarations.find(routine, type);
}
/*
Check if a routine has a declaration in the CREATE PACKAGE statement
by looking up in sp_package_spec_cache.
@param thd current thd
@param db the database name
@param pkgname the package name
@param name the routine name
@param type the routine type
@retval true, if the routine has a declaration
@retval false, if the routine does not have a declaration
This function is called in the middle of CREATE PACKAGE BODY parsing,
to lookup the current package routines.
The package specification (i.e. the CREATE PACKAGE statement) for
the current package body must already be loaded and cached at this point.
*/
static bool
is_package_public_routine_quick(THD *thd,
const LEX_CSTRING &db,
const LEX_CSTRING &pkgname,
const LEX_CSTRING &name,
stored_procedure_type type)
{
Database_qualified_name tmp(db, pkgname);
sp_head *sp= sp_cache_lookup(&thd->sp_package_spec_cache, &tmp);
sp_package *pkg= sp ? sp->get_package() : NULL;
DBUG_ASSERT(pkg); // Must already be cached
return pkg && pkg->m_routine_declarations.find(name, type);
}
/*
Check if a qualified name, e.g. "CALL name1.name2",
refers to a known routine in the package body "pkg".
*/
static bool
is_package_body_routine(THD *thd, sp_package *pkg,
const LEX_CSTRING &name1,
const LEX_CSTRING &name2,
stored_procedure_type type)
{
return Sp_handler::eq_routine_name(pkg->m_name, name1) &&
(pkg->m_routine_declarations.find(name2, type) ||
pkg->m_routine_implementations.find(name2, type));
}
/*
Resolve a qualified routine reference xxx.yyy(), between:
- A standalone routine: xxx.yyy
- A package routine: current_database.xxx.yyy
*/
bool Sp_handler::
sp_resolve_package_routine_explicit(THD *thd,
sp_head *caller,
sp_name *name,
const Sp_handler **pkg_routine_handler,
Database_qualified_name *pkgname) const
{
sp_package *pkg;
/*
If a qualified routine name was used, e.g. xxx.yyy(),
we possibly have a call to a package routine.
Rewrite name if name->m_db (xxx) is a known package,
and name->m_name (yyy) is a known routine in this package.
*/
LEX_CSTRING tmpdb= thd->db_lex_cstring();
if (is_package_public_routine(thd, tmpdb, name->m_db, name->m_name, type()) ||
// Check if a package routine calls a private routine
(caller && caller->m_parent &&
is_package_body_routine(thd, caller->m_parent,
name->m_db, name->m_name, type())) ||
// Check if a package initialization sections calls a private routine
(caller && (pkg= caller->get_package()) &&
is_package_body_routine(thd, pkg, name->m_db, name->m_name, type())))
{
pkgname->m_db= tmpdb;
pkgname->m_name= name->m_db;
*pkg_routine_handler= package_routine_handler();
return name->make_package_routine_name(thd->mem_root, tmpdb,
name->m_db, name->m_name);
}
return false;
}
/*
Resolve a non-qualified routine reference yyy(), between:
- A standalone routine: current_database.yyy
- A package routine: current_database.current_package.yyy
*/
bool Sp_handler::
sp_resolve_package_routine_implicit(THD *thd,
sp_head *caller,
sp_name *name,
const Sp_handler **pkg_routine_handler,
Database_qualified_name *pkgname) const
{
sp_package *pkg;
if (!caller || !caller->m_name.length)
{
/*
We are either in a an anonymous block,
or not in a routine at all.
*/
return false; // A standalone routine is called
}
if (caller->m_parent)
{
// A package routine calls a non-qualified routine
int ret= SP_OK;
Prefix_name_buf pkgstr(thd, caller->m_name);
DBUG_ASSERT(pkgstr.length);
LEX_CSTRING tmpname; // Non-qualified m_name
tmpname.str= caller->m_name.str + pkgstr.length + 1;
tmpname.length= caller->m_name.length - pkgstr.length - 1;
/*
We're here if a package routine calls another non-qualified
function or procedure, e.g. yyy().
We need to distinguish two cases:
- yyy() is another routine from the same package
- yyy() is a standalone routine from the same database
To detect if yyy() is a package (rather than a standalone) routine,
we check if:
- yyy() recursively calls itself
- yyy() is earlier implemented in the current CREATE PACKAGE BODY
- yyy() has a forward declaration
- yyy() is declared in the corresponding CREATE PACKAGE
*/
if (eq_routine_name(tmpname, name->m_name) ||
caller->m_parent->m_routine_implementations.find(name->m_name, type()) ||
caller->m_parent->m_routine_declarations.find(name->m_name, type()) ||
is_package_public_routine_quick(thd, caller->m_db,
pkgstr, name->m_name, type()))
{
DBUG_ASSERT(ret == SP_OK);
pkgname->copy(thd->mem_root, caller->m_db, pkgstr);
*pkg_routine_handler= package_routine_handler();
if (name->make_package_routine_name(thd->mem_root, pkgstr, name->m_name))
return true;
}
return ret != SP_OK;
}
if ((pkg= caller->get_package()) &&
pkg->m_routine_implementations.find(name->m_name, type()))
{
pkgname->m_db= caller->m_db;
pkgname->m_name= caller->m_name;
// Package initialization section is calling a non-qualified routine
*pkg_routine_handler= package_routine_handler();
return name->make_package_routine_name(thd->mem_root,
caller->m_name, name->m_name);
}
return false; // A standalone routine is called
}
/**
Detect cases when a package routine (rather than a standalone routine)
is called, and rewrite sp_name accordingly.
@param thd Current thd
@param caller The caller routine (or NULL if outside of a routine)
@param [IN/OUT] name The called routine name
@param [OUT] pkgname If the routine is found to be a package routine,
pkgname is populated with the package name.
Otherwise, it's not touched.
@retval false on success
@retval true on error (e.g. EOM, could not read CREATE PACKAGE)
*/
bool
Sp_handler::sp_resolve_package_routine(THD *thd,
sp_head *caller,
sp_name *name,
const Sp_handler **pkg_routine_handler,
Database_qualified_name *pkgname) const
{
if (!thd->db || !(thd->variables.sql_mode & MODE_ORACLE))
return false;
return name->m_explicit_name ?
sp_resolve_package_routine_explicit(thd, caller, name,
pkg_routine_handler, pkgname) :
sp_resolve_package_routine_implicit(thd, caller, name,
pkg_routine_handler, pkgname);
}
/** /**
Add routine which is explicitly used by statement to the set of stored Add routine which is explicitly used by statement to the set of stored
routines used by this statement. routines used by this statement.
@@ -1993,7 +2544,7 @@ void Sp_handler::add_used_routine(Query_tables_list *prelocking_ctx,
const Database_qualified_name *rt) const const Database_qualified_name *rt) const
{ {
MDL_key key(get_mdl_type(), rt->m_db.str, rt->m_name.str); MDL_key key(get_mdl_type(), rt->m_db.str, rt->m_name.str);
(void) sp_add_used_routine(prelocking_ctx, arena, &key, 0); (void) sp_add_used_routine(prelocking_ctx, arena, &key, this, 0);
prelocking_ctx->sroutines_list_own_last= prelocking_ctx->sroutines_list.next; prelocking_ctx->sroutines_list_own_last= prelocking_ctx->sroutines_list.next;
prelocking_ctx->sroutines_list_own_elements= prelocking_ctx->sroutines_list_own_elements=
prelocking_ctx->sroutines_list.elements; prelocking_ctx->sroutines_list.elements;
@@ -2086,7 +2637,8 @@ sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
{ {
Sroutine_hash_entry *rt= (Sroutine_hash_entry *)my_hash_element(src, i); Sroutine_hash_entry *rt= (Sroutine_hash_entry *)my_hash_element(src, i);
(void)sp_add_used_routine(prelocking_ctx, thd->stmt_arena, (void)sp_add_used_routine(prelocking_ctx, thd->stmt_arena,
&rt->mdl_request.key, belong_to_view); &rt->mdl_request.key, rt->m_handler,
belong_to_view);
} }
} }
@@ -2111,7 +2663,8 @@ void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
{ {
for (Sroutine_hash_entry *rt= src->first; rt; rt= rt->next) for (Sroutine_hash_entry *rt= src->first; rt; rt= rt->next)
(void)sp_add_used_routine(prelocking_ctx, thd->stmt_arena, (void)sp_add_used_routine(prelocking_ctx, thd->stmt_arena,
&rt->mdl_request.key, belong_to_view); &rt->mdl_request.key, rt->m_handler,
belong_to_view);
} }
@@ -2126,9 +2679,6 @@ int Sroutine_hash_entry::sp_cache_routine(THD *thd,
{ {
char qname_buff[NAME_LEN*2+1+1]; char qname_buff[NAME_LEN*2+1+1];
sp_name name(&mdl_request.key, qname_buff); sp_name name(&mdl_request.key, qname_buff);
MDL_key::enum_mdl_namespace mdl_type= mdl_request.key.mdl_namespace();
const Sp_handler *sph= Sp_handler::handler(mdl_type);
DBUG_ASSERT(sph);
/* /*
Check that we have an MDL lock on this routine, unless it's a top-level Check that we have an MDL lock on this routine, unless it's a top-level
CALL. The assert below should be unambiguous: the first element CALL. The assert below should be unambiguous: the first element
@@ -2137,7 +2687,7 @@ int Sroutine_hash_entry::sp_cache_routine(THD *thd,
*/ */
DBUG_ASSERT(mdl_request.ticket || this == thd->lex->sroutines_list.first); DBUG_ASSERT(mdl_request.ticket || this == thd->lex->sroutines_list.first);
return sph->sp_cache_routine(thd, &name, lookup_only, sp); return m_handler->sp_cache_routine(thd, &name, lookup_only, sp);
} }
@@ -2168,7 +2718,7 @@ int Sp_handler::sp_cache_routine(THD *thd,
int ret= 0; int ret= 0;
sp_cache **spc= get_cache(thd); sp_cache **spc= get_cache(thd);
DBUG_ENTER("sp_cache_routine"); DBUG_ENTER("Sp_handler::sp_cache_routine");
DBUG_ASSERT(spc); DBUG_ASSERT(spc);
@@ -2218,6 +2768,75 @@ int Sp_handler::sp_cache_routine(THD *thd,
} }
/**
Cache a package routine using its package name and a qualified name.
See sp_cache_routine() for more information on parameters and return values.
@param thd - current THD
@param pkgname_str - package name, e.g. "pkgname"
@param name - name with the following format:
* name->m_db is a database name, e.g. "dbname"
* name->m_name is a package-qualified name,
e.g. "pkgname.spname"
@param lookup_only - don't load mysql.proc if not cached
@param [OUT] sp - the result is returned here.
@retval false - loaded or does not exists
@retval true - error while loading mysql.proc
*/
int
Sp_handler::sp_cache_package_routine(THD *thd,
const LEX_CSTRING &pkgname_cstr,
const Database_qualified_name *name,
bool lookup_only, sp_head **sp) const
{
DBUG_ENTER("sp_cache_package_routine");
DBUG_ASSERT(type() == TYPE_ENUM_FUNCTION || type() == TYPE_ENUM_PROCEDURE);
sp_name pkgname(&name->m_db, &pkgname_cstr, false);
sp_head *ph= NULL;
int ret= sp_handler_package_body.sp_cache_routine(thd, &pkgname,
lookup_only,
&ph);
if (!ret)
{
sp_package *pkg= ph ? ph->get_package() : NULL;
LEX_CSTRING tmp= name->m_name;
const char *dot= strrchr(tmp.str, '.');
size_t prefix_length= dot ? dot - tmp.str + 1 : NULL;
tmp.str+= prefix_length;
tmp.length-= prefix_length;
LEX *rlex= pkg ? pkg->m_routine_implementations.find(tmp, type()) : NULL;
*sp= rlex ? rlex->sphead : NULL;
}
DBUG_RETURN(ret);
}
/**
Cache a package routine by its fully qualified name.
See sp_cache_routine() for more information on parameters and return values.
@param thd - current THD
@param name - name with the following format:
* name->m_db is a database name, e.g. "dbname"
* name->m_name is a package-qualified name,
e.g. "pkgname.spname"
@param lookup_only - don't load mysql.proc if not cached
@param [OUT] sp - the result is returned here
@retval false - loaded or does not exists
@retval true - error while loading mysql.proc
*/
int Sp_handler::sp_cache_package_routine(THD *thd,
const Database_qualified_name *name,
bool lookup_only, sp_head **sp) const
{
DBUG_ENTER("Sp_handler::sp_cache_package_routine");
Prefix_name_buf pkgname(thd, name->m_name);
DBUG_ASSERT(pkgname.length);
DBUG_RETURN(sp_cache_package_routine(thd, pkgname, name, lookup_only, sp));
}
/** /**
Generates the CREATE... string from the table information. Generates the CREATE... string from the table information.
@@ -2349,7 +2968,7 @@ Sp_handler::sp_load_for_information_schema(THD *thd, TABLE *proc_table,
thd->lex= &newlex; thd->lex= &newlex;
newlex.current_select= NULL; newlex.current_select= NULL;
sp= sp_compile(thd, &defstr, sql_mode, creation_ctx); sp= sp_compile(thd, &defstr, sql_mode, NULL, creation_ctx);
*free_sp_head= 1; *free_sp_head= 1;
thd->lex->sphead= NULL; thd->lex->sphead= NULL;
lex_end(thd->lex); lex_end(thd->lex);

242
sql/sp.h
View File

@@ -31,7 +31,9 @@ class Sroutine_hash_entry;
class THD; class THD;
class sp_cache; class sp_cache;
class sp_head; class sp_head;
class sp_package;
class sp_pcontext; class sp_pcontext;
class sp_name;
class Database_qualified_name; class Database_qualified_name;
struct st_sp_chistics; struct st_sp_chistics;
class Stored_program_creation_ctx; class Stored_program_creation_ctx;
@@ -49,13 +51,28 @@ enum stored_procedure_type
{ {
TYPE_ENUM_FUNCTION=1, TYPE_ENUM_FUNCTION=1,
TYPE_ENUM_PROCEDURE=2, TYPE_ENUM_PROCEDURE=2,
TYPE_ENUM_TRIGGER=3, TYPE_ENUM_PACKAGE=3,
TYPE_ENUM_PROXY=4 TYPE_ENUM_PACKAGE_BODY=4,
TYPE_ENUM_TRIGGER=5,
TYPE_ENUM_PROXY=6
}; };
class Sp_handler class Sp_handler
{ {
bool sp_resolve_package_routine_explicit(THD *thd,
sp_head *caller,
sp_name *name,
const Sp_handler **pkg_routine_hndlr,
Database_qualified_name *pkgname)
const;
bool sp_resolve_package_routine_implicit(THD *thd,
sp_head *caller,
sp_name *name,
const Sp_handler **pkg_routine_hndlr,
Database_qualified_name *pkgname)
const;
protected:
int db_find_routine_aux(THD *thd, const Database_qualified_name *name, int db_find_routine_aux(THD *thd, const Database_qualified_name *name,
TABLE *table) const; TABLE *table) const;
int db_find_routine(THD *thd, const Database_qualified_name *name, int db_find_routine(THD *thd, const Database_qualified_name *name,
@@ -72,6 +89,7 @@ class Sp_handler
const st_sp_chistics &chistics, const st_sp_chistics &chistics,
const AUTHID &definer, const AUTHID &definer,
longlong created, longlong modified, longlong created, longlong modified,
sp_package *parent,
Stored_program_creation_ctx *creation_ctx) const; Stored_program_creation_ctx *creation_ctx) const;
int sp_drop_routine_internal(THD *thd, int sp_drop_routine_internal(THD *thd,
const Database_qualified_name *name, const Database_qualified_name *name,
@@ -80,11 +98,37 @@ class Sp_handler
sp_head *sp_clone_and_link_routine(THD *thd, sp_head *sp_clone_and_link_routine(THD *thd,
const Database_qualified_name *name, const Database_qualified_name *name,
sp_head *sp) const; sp_head *sp) const;
int sp_cache_package_routine(THD *thd,
const LEX_CSTRING &pkgname_cstr,
const Database_qualified_name *name,
bool lookup_only, sp_head **sp) const;
int sp_cache_package_routine(THD *thd,
const Database_qualified_name *name,
bool lookup_only, sp_head **sp) const;
sp_head *sp_find_package_routine(THD *thd,
const LEX_CSTRING pkgname_str,
const Database_qualified_name *name,
bool cache_only) const;
sp_head *sp_find_package_routine(THD *thd,
const Database_qualified_name *name,
bool cache_only) const;
public: // TODO: make it private or protected
virtual int sp_find_and_drop_routine(THD *thd, TABLE *table,
const Database_qualified_name *name)
const;
public: public:
virtual ~Sp_handler() {} virtual ~Sp_handler() {}
static const Sp_handler *handler(enum enum_sql_command cmd); static const Sp_handler *handler(enum enum_sql_command cmd);
static const Sp_handler *handler(stored_procedure_type type); static const Sp_handler *handler(stored_procedure_type type);
static const Sp_handler *handler(MDL_key::enum_mdl_namespace ns); static const Sp_handler *handler(MDL_key::enum_mdl_namespace ns);
static bool eq_routine_name(const LEX_CSTRING &name1,
const LEX_CSTRING &name2)
{
return my_strnncoll(system_charset_info,
(const uchar *) name1.str, name1.length,
(const uchar *) name2.str, name2.length) == 0;
}
const char *type_str() const { return type_lex_cstring().str; } const char *type_str() const { return type_lex_cstring().str; }
virtual const char *show_create_routine_col1_caption() const virtual const char *show_create_routine_col1_caption() const
{ {
@@ -96,6 +140,10 @@ public:
DBUG_ASSERT(0); DBUG_ASSERT(0);
return ""; return "";
} }
virtual const Sp_handler *package_routine_handler() const
{
return this;
}
virtual stored_procedure_type type() const= 0; virtual stored_procedure_type type() const= 0;
virtual LEX_CSTRING type_lex_cstring() const= 0; virtual LEX_CSTRING type_lex_cstring() const= 0;
virtual LEX_CSTRING empty_body_lex_cstring() const virtual LEX_CSTRING empty_body_lex_cstring() const
@@ -132,12 +180,22 @@ public:
void add_used_routine(Query_tables_list *prelocking_ctx, void add_used_routine(Query_tables_list *prelocking_ctx,
Query_arena *arena, Query_arena *arena,
const Database_qualified_name *rt) const; const Database_qualified_name *name) const;
sp_head *sp_find_routine(THD *thd, const Database_qualified_name *name, bool sp_resolve_package_routine(THD *thd,
bool cache_only) const; sp_head *caller,
int sp_cache_routine(THD *thd, const Database_qualified_name *name, sp_name *name,
bool lookup_only, sp_head **sp) const; const Sp_handler **pkg_routine_handler,
Database_qualified_name *pkgname) const;
virtual sp_head *sp_find_routine(THD *thd,
const Database_qualified_name *name,
bool cache_only) const;
virtual int sp_cache_routine(THD *thd, const Database_qualified_name *name,
bool lookup_only, sp_head **sp) const;
int sp_cache_routine_reentrant(THD *thd,
const Database_qualified_name *nm,
sp_head **sp) const;
bool sp_exist_routines(THD *thd, TABLE_LIST *procs) const; bool sp_exist_routines(THD *thd, TABLE_LIST *procs) const;
bool sp_show_create_routine(THD *thd, bool sp_show_create_routine(THD *thd,
@@ -163,16 +221,17 @@ public:
@retval true on error @retval true on error
@retval false on success @retval false on success
*/ */
bool show_create_sp(THD *thd, String *buf, virtual bool show_create_sp(THD *thd, String *buf,
const LEX_CSTRING &db, const LEX_CSTRING &db,
const LEX_CSTRING &name, const LEX_CSTRING &name,
const LEX_CSTRING &params, const LEX_CSTRING &params,
const LEX_CSTRING &returns, const LEX_CSTRING &returns,
const LEX_CSTRING &body, const LEX_CSTRING &body,
const st_sp_chistics &chistics, const st_sp_chistics &chistics,
const AUTHID &definer, const AUTHID &definer,
const DDL_options_st ddl_options, const DDL_options_st ddl_options,
sql_mode_t sql_mode) const; sql_mode_t sql_mode) const;
}; };
@@ -202,6 +261,7 @@ public:
{ {
return MDL_key::PROCEDURE; return MDL_key::PROCEDURE;
} }
const Sp_handler *package_routine_handler() const;
sp_cache **get_cache(THD *) const; sp_cache **get_cache(THD *) const;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
HASH *get_priv_hash() const; HASH *get_priv_hash() const;
@@ -212,6 +272,23 @@ public:
}; };
class Sp_handler_package_procedure: public Sp_handler_procedure
{
public:
int sp_cache_routine(THD *thd, const Database_qualified_name *name,
bool lookup_only, sp_head **sp) const
{
return sp_cache_package_routine(thd, name, lookup_only, sp);
}
sp_head *sp_find_routine(THD *thd,
const Database_qualified_name *name,
bool cache_only) const
{
return sp_find_package_routine(thd, name, cache_only);
}
};
class Sp_handler_function: public Sp_handler class Sp_handler_function: public Sp_handler
{ {
public: public:
@@ -238,6 +315,7 @@ public:
{ {
return MDL_key::FUNCTION; return MDL_key::FUNCTION;
} }
const Sp_handler *package_routine_handler() const;
sp_cache **get_cache(THD *) const; sp_cache **get_cache(THD *) const;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
HASH *get_priv_hash() const; HASH *get_priv_hash() const;
@@ -247,6 +325,109 @@ public:
}; };
class Sp_handler_package_function: public Sp_handler_function
{
public:
int sp_cache_routine(THD *thd, const Database_qualified_name *name,
bool lookup_only, sp_head **sp) const
{
return sp_cache_package_routine(thd, name, lookup_only, sp);
}
sp_head *sp_find_routine(THD *thd,
const Database_qualified_name *name,
bool cache_only) const
{
return sp_find_package_routine(thd, name, cache_only);
}
};
class Sp_handler_package: public Sp_handler
{
public:
bool show_create_sp(THD *thd, String *buf,
const LEX_CSTRING &db,
const LEX_CSTRING &name,
const LEX_CSTRING &params,
const LEX_CSTRING &returns,
const LEX_CSTRING &body,
const st_sp_chistics &chistics,
const AUTHID &definer,
const DDL_options_st ddl_options,
sql_mode_t sql_mode) const;
};
class Sp_handler_package_spec: public Sp_handler_package
{
public: // TODO: make it private or protected
int sp_find_and_drop_routine(THD *thd, TABLE *table,
const Database_qualified_name *name)
const;
public:
stored_procedure_type type() const { return TYPE_ENUM_PACKAGE; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("PACKAGE")};
return m_type_str;
}
LEX_CSTRING empty_body_lex_cstring() const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("BEGIN END")};
return m_empty_body;
}
const char *show_create_routine_col1_caption() const
{
return "Package";
}
const char *show_create_routine_col3_caption() const
{
return "Create Package";
}
MDL_key::enum_mdl_namespace get_mdl_type() const
{
return MDL_key::PACKAGE_BODY;
}
sp_cache **get_cache(THD *) const;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
HASH *get_priv_hash() const;
#endif
};
class Sp_handler_package_body: public Sp_handler_package
{
public:
stored_procedure_type type() const { return TYPE_ENUM_PACKAGE_BODY; }
LEX_CSTRING type_lex_cstring() const
{
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("PACKAGE BODY")};
return m_type_str;
}
LEX_CSTRING empty_body_lex_cstring() const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("BEGIN END")};
return m_empty_body;
}
const char *show_create_routine_col1_caption() const
{
return "Package body";
}
const char *show_create_routine_col3_caption() const
{
return "Create Package Body";
}
MDL_key::enum_mdl_namespace get_mdl_type() const
{
return MDL_key::PACKAGE_BODY;
}
sp_cache **get_cache(THD *) const;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
HASH *get_priv_hash() const;
#endif
};
class Sp_handler_trigger: public Sp_handler class Sp_handler_trigger: public Sp_handler
{ {
public: public:
@@ -266,6 +447,10 @@ public:
extern MYSQL_PLUGIN_IMPORT Sp_handler_function sp_handler_function; extern MYSQL_PLUGIN_IMPORT Sp_handler_function sp_handler_function;
extern MYSQL_PLUGIN_IMPORT Sp_handler_procedure sp_handler_procedure; extern MYSQL_PLUGIN_IMPORT Sp_handler_procedure sp_handler_procedure;
extern MYSQL_PLUGIN_IMPORT Sp_handler_package_spec sp_handler_package_spec;
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_trigger sp_handler_trigger;
@@ -286,6 +471,17 @@ inline const Sp_handler *Sp_handler::handler(enum_sql_command cmd)
case SQLCOM_SHOW_CREATE_FUNC: case SQLCOM_SHOW_CREATE_FUNC:
case SQLCOM_SHOW_STATUS_FUNC: case SQLCOM_SHOW_STATUS_FUNC:
return &sp_handler_function; return &sp_handler_function;
case SQLCOM_CREATE_PACKAGE:
case SQLCOM_DROP_PACKAGE:
case SQLCOM_SHOW_CREATE_PACKAGE:
case SQLCOM_SHOW_STATUS_PACKAGE:
return &sp_handler_package_spec;
case SQLCOM_CREATE_PACKAGE_BODY:
case SQLCOM_DROP_PACKAGE_BODY:
case SQLCOM_SHOW_CREATE_PACKAGE_BODY:
case SQLCOM_SHOW_STATUS_PACKAGE_BODY:
case SQLCOM_SHOW_PACKAGE_BODY_CODE:
return &sp_handler_package_body;
default: default:
break; break;
} }
@@ -300,6 +496,10 @@ inline const Sp_handler *Sp_handler::handler(stored_procedure_type type)
return &sp_handler_procedure; return &sp_handler_procedure;
case TYPE_ENUM_FUNCTION: case TYPE_ENUM_FUNCTION:
return &sp_handler_function; return &sp_handler_function;
case TYPE_ENUM_PACKAGE:
return &sp_handler_package_spec;
case TYPE_ENUM_PACKAGE_BODY:
return &sp_handler_package_body;
case TYPE_ENUM_TRIGGER: case TYPE_ENUM_TRIGGER:
return &sp_handler_trigger; return &sp_handler_trigger;
case TYPE_ENUM_PROXY: case TYPE_ENUM_PROXY:
@@ -316,6 +516,8 @@ inline const Sp_handler *Sp_handler::handler(MDL_key::enum_mdl_namespace type)
return &sp_handler_function; return &sp_handler_function;
case MDL_key::PROCEDURE: case MDL_key::PROCEDURE:
return &sp_handler_procedure; return &sp_handler_procedure;
case MDL_key::PACKAGE_BODY:
return &sp_handler_package_body;
case MDL_key::GLOBAL: case MDL_key::GLOBAL:
case MDL_key::SCHEMA: case MDL_key::SCHEMA:
case MDL_key::TABLE: case MDL_key::TABLE:
@@ -424,12 +626,16 @@ public:
*/ */
ulong m_sp_cache_version; ulong m_sp_cache_version;
const Sp_handler *m_handler;
int sp_cache_routine(THD *thd, bool lookup_only, sp_head **sp) const; int sp_cache_routine(THD *thd, bool lookup_only, sp_head **sp) const;
}; };
bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena, bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
const MDL_key *key, TABLE_LIST *belong_to_view); const MDL_key *key,
const Sp_handler *handler,
TABLE_LIST *belong_to_view);
void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx); void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx);
bool sp_update_sp_used_routines(HASH *dst, HASH *src); bool sp_update_sp_used_routines(HASH *dst, HASH *src);
void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx, void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,

View File

@@ -192,6 +192,8 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_SHOW_CREATE_DB: case SQLCOM_SHOW_CREATE_DB:
case SQLCOM_SHOW_CREATE_FUNC: case SQLCOM_SHOW_CREATE_FUNC:
case SQLCOM_SHOW_CREATE_PROC: case SQLCOM_SHOW_CREATE_PROC:
case SQLCOM_SHOW_CREATE_PACKAGE:
case SQLCOM_SHOW_CREATE_PACKAGE_BODY:
case SQLCOM_SHOW_CREATE_EVENT: case SQLCOM_SHOW_CREATE_EVENT:
case SQLCOM_SHOW_CREATE_TRIGGER: case SQLCOM_SHOW_CREATE_TRIGGER:
case SQLCOM_SHOW_CREATE_USER: case SQLCOM_SHOW_CREATE_USER:
@@ -211,11 +213,14 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_SHOW_PRIVILEGES: case SQLCOM_SHOW_PRIVILEGES:
case SQLCOM_SHOW_PROCESSLIST: case SQLCOM_SHOW_PROCESSLIST:
case SQLCOM_SHOW_PROC_CODE: case SQLCOM_SHOW_PROC_CODE:
case SQLCOM_SHOW_PACKAGE_BODY_CODE:
case SQLCOM_SHOW_SLAVE_HOSTS: case SQLCOM_SHOW_SLAVE_HOSTS:
case SQLCOM_SHOW_SLAVE_STAT: case SQLCOM_SHOW_SLAVE_STAT:
case SQLCOM_SHOW_STATUS: case SQLCOM_SHOW_STATUS:
case SQLCOM_SHOW_STATUS_FUNC: case SQLCOM_SHOW_STATUS_FUNC:
case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_PROC:
case SQLCOM_SHOW_STATUS_PACKAGE:
case SQLCOM_SHOW_STATUS_PACKAGE_BODY:
case SQLCOM_SHOW_STORAGE_ENGINES: case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_TABLE_STATUS: case SQLCOM_SHOW_TABLE_STATUS:
@@ -260,6 +265,8 @@ sp_get_flags_for_command(LEX *lex)
break; break;
case SQLCOM_CREATE_INDEX: case SQLCOM_CREATE_INDEX:
case SQLCOM_CREATE_DB: case SQLCOM_CREATE_DB:
case SQLCOM_CREATE_PACKAGE:
case SQLCOM_CREATE_PACKAGE_BODY:
case SQLCOM_CREATE_VIEW: case SQLCOM_CREATE_VIEW:
case SQLCOM_CREATE_TRIGGER: case SQLCOM_CREATE_TRIGGER:
case SQLCOM_CREATE_USER: case SQLCOM_CREATE_USER:
@@ -276,6 +283,8 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_RENAME_USER: case SQLCOM_RENAME_USER:
case SQLCOM_DROP_INDEX: case SQLCOM_DROP_INDEX:
case SQLCOM_DROP_DB: case SQLCOM_DROP_DB:
case SQLCOM_DROP_PACKAGE:
case SQLCOM_DROP_PACKAGE_BODY:
case SQLCOM_REVOKE_ALL: case SQLCOM_REVOKE_ALL:
case SQLCOM_DROP_USER: case SQLCOM_DROP_USER:
case SQLCOM_DROP_ROLE: case SQLCOM_DROP_ROLE:
@@ -502,9 +511,10 @@ sp_head::operator delete(void *ptr, size_t size) throw()
} }
sp_head::sp_head(const Sp_handler *sph) sp_head::sp_head(sp_package *parent, const Sp_handler *sph)
:Query_arena(&main_mem_root, STMT_INITIALIZED_FOR_SP), :Query_arena(&main_mem_root, STMT_INITIALIZED_FOR_SP),
Database_qualified_name(&null_clex_str, &null_clex_str), Database_qualified_name(&null_clex_str, &null_clex_str),
m_parent(parent),
m_handler(sph), m_handler(sph),
m_flags(0), m_flags(0),
m_tmp_query(NULL), m_tmp_query(NULL),
@@ -529,6 +539,9 @@ sp_head::sp_head(const Sp_handler *sph)
m_param_begin(NULL), m_param_begin(NULL),
m_param_end(NULL), m_param_end(NULL),
m_body_begin(NULL), m_body_begin(NULL),
m_thd_root(NULL),
m_thd(NULL),
m_pcont(new (&main_mem_root) sp_pcontext()),
m_cont_level(0) m_cont_level(0)
{ {
m_first_instance= this; m_first_instance= this;
@@ -543,6 +556,7 @@ sp_head::sp_head(const Sp_handler *sph)
m_backpatch_goto.empty(); m_backpatch_goto.empty();
m_cont_backpatch.empty(); m_cont_backpatch.empty();
m_lex.empty(); m_lex.empty();
my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8, MYF(0));
my_hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); my_hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
my_hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, my_hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key,
0, 0); 0, 0);
@@ -551,12 +565,169 @@ sp_head::sp_head(const Sp_handler *sph)
} }
sp_package::sp_package(LEX *top_level_lex,
const sp_name *name,
const Sp_handler *sph)
:sp_head(NULL, sph),
m_current_routine(NULL),
m_top_level_lex(top_level_lex),
m_rcontext(NULL),
m_invoked_subroutine_count(0),
m_is_instantiated(false),
m_is_cloning_routine(false)
{
init_sp_name(name);
}
sp_package::~sp_package()
{
m_routine_implementations.cleanup();
m_routine_declarations.cleanup();
m_body= null_clex_str;
if (m_current_routine)
delete m_current_routine->sphead;
delete m_rcontext;
}
/*
Test if two routines have equal specifications
*/
bool sp_head::eq_routine_spec(const sp_head *sp) const
{
// TODO: Add tests for equal return data types (in case of FUNCTION)
// TODO: Add tests for equal argument data types
return
m_handler->type() == sp->m_handler->type() &&
m_pcont->context_var_count() == sp->m_pcont->context_var_count();
}
bool sp_package::validate_after_parser(THD *thd)
{
if (m_handler->type() != TYPE_ENUM_PACKAGE_BODY)
return false;
sp_head *sp= sp_cache_lookup(&thd->sp_package_spec_cache, this);
sp_package *spec= sp ? sp->get_package() : NULL;
DBUG_ASSERT(spec); // CREATE PACKAGE must already be cached
return validate_public_routines(thd, spec) ||
validate_private_routines(thd);
}
bool sp_package::validate_public_routines(THD *thd, sp_package *spec)
{
/*
Check that all routines declared in CREATE PACKAGE
have implementations in CREATE PACKAGE BODY.
*/
List_iterator<LEX> it(spec->m_routine_declarations);
for (LEX *lex; (lex= it++); )
{
bool found= false;
DBUG_ASSERT(lex->sphead);
List_iterator<LEX> it2(m_routine_implementations);
for (LEX *lex2; (lex2= it2++); )
{
DBUG_ASSERT(lex2->sphead);
if (Sp_handler::eq_routine_name(lex2->sphead->m_name,
lex->sphead->m_name) &&
lex2->sphead->eq_routine_spec(lex->sphead))
{
found= true;
break;
}
}
if (!found)
{
my_error(ER_PACKAGE_ROUTINE_IN_SPEC_NOT_DEFINED_IN_BODY, MYF(0),
ErrConvDQName(lex->sphead).ptr());
return true;
}
}
return false;
}
bool sp_package::validate_private_routines(THD *thd)
{
/*
Check that all forwad declarations in
CREATE PACKAGE BODY have implementations.
*/
List_iterator<LEX> it(m_routine_declarations);
for (LEX *lex; (lex= it++); )
{
bool found= false;
DBUG_ASSERT(lex->sphead);
List_iterator<LEX> it2(m_routine_implementations);
for (LEX *lex2; (lex2= it2++); )
{
DBUG_ASSERT(lex2->sphead);
if (Sp_handler::eq_routine_name(lex2->sphead->m_name,
lex->sphead->m_name) &&
lex2->sphead->eq_routine_spec(lex->sphead))
{
found= true;
break;
}
}
if (!found)
{
my_error(ER_PACKAGE_ROUTINE_FORWARD_DECLARATION_NOT_DEFINED, MYF(0),
ErrConvDQName(lex->sphead).ptr());
return true;
}
}
return false;
}
LEX *sp_package::LexList::find(const LEX_CSTRING &name,
stored_procedure_type type)
{
List_iterator<LEX> it(*this);
for (LEX *lex; (lex= it++); )
{
DBUG_ASSERT(lex->sphead);
const char *dot;
if (lex->sphead->m_handler->type() == type &&
(dot= strrchr(lex->sphead->m_name.str, '.')))
{
size_t ofs= dot + 1 - lex->sphead->m_name.str;
LEX_CSTRING non_qualified_sphead_name= lex->sphead->m_name;
non_qualified_sphead_name.str+= ofs;
non_qualified_sphead_name.length-= ofs;
if (Sp_handler::eq_routine_name(non_qualified_sphead_name, name))
return lex;
}
}
return NULL;
}
LEX *sp_package::LexList::find_qualified(const LEX_CSTRING &name,
stored_procedure_type type)
{
List_iterator<LEX> it(*this);
for (LEX *lex; (lex= it++); )
{
DBUG_ASSERT(lex->sphead);
if (lex->sphead->m_handler->type() == type &&
Sp_handler::eq_routine_name(lex->sphead->m_name, name))
return lex;
}
return NULL;
}
void void
sp_head::init(LEX *lex) sp_head::init(LEX *lex)
{ {
DBUG_ENTER("sp_head::init"); DBUG_ENTER("sp_head::init");
lex->spcont= m_pcont= new sp_pcontext(); lex->spcont= m_pcont;
if (!lex->spcont) if (!lex->spcont)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
@@ -566,7 +737,6 @@ sp_head::init(LEX *lex)
types of stored procedures to simplify reset_lex()/restore_lex() code. types of stored procedures to simplify reset_lex()/restore_lex() code.
*/ */
lex->trg_table_fields.empty(); lex->trg_table_fields.empty();
my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8, MYF(0));
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@@ -584,9 +754,6 @@ sp_head::init_sp_name(const sp_name *spname)
/* We have to copy strings to get them into the right memroot. */ /* We have to copy strings to get them into the right memroot. */
Database_qualified_name::copy(&main_mem_root, spname->m_db, spname->m_name); Database_qualified_name::copy(&main_mem_root, spname->m_db, spname->m_name);
m_explicit_name= spname->m_explicit_name; m_explicit_name= spname->m_explicit_name;
spname->make_qname(&main_mem_root, &m_qname);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@@ -682,6 +849,17 @@ sp_head::~sp_head()
} }
void sp_package::LexList::cleanup()
{
List_iterator<LEX> it(*this);
for (LEX *lex; (lex= it++); )
{
lex_end(lex);
delete lex;
}
}
/** /**
This is only used for result fields from functions (both during This is only used for result fields from functions (both during
fix_length_and_dec() and evaluation). fix_length_and_dec() and evaluation).
@@ -987,6 +1165,8 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
DBUG_ASSERT(!(m_flags & IS_INVOKED)); DBUG_ASSERT(!(m_flags & IS_INVOKED));
m_flags|= IS_INVOKED; m_flags|= IS_INVOKED;
if (m_parent)
m_parent->m_invoked_subroutine_count++;
m_first_instance->m_first_free_instance= m_next_cached_sp; m_first_instance->m_first_free_instance= m_next_cached_sp;
if (m_next_cached_sp) if (m_next_cached_sp)
{ {
@@ -1300,6 +1480,8 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
err_status|= mysql_change_db(thd, (LEX_CSTRING*) &saved_cur_db_name, TRUE); err_status|= mysql_change_db(thd, (LEX_CSTRING*) &saved_cur_db_name, TRUE);
} }
m_flags&= ~IS_INVOKED; m_flags&= ~IS_INVOKED;
if (m_parent)
m_parent->m_invoked_subroutine_count--;
DBUG_PRINT("info", DBUG_PRINT("info",
("first free for %p --: %p->%p, level: %lu, flags %x", ("first free for %p --: %p->%p, level: %lu, flags %x",
m_first_instance, m_first_instance,
@@ -1373,8 +1555,7 @@ set_routine_security_ctx(THD *thd, sp_head *sp, Security_context **save_ctx)
statement that 'may' affect this. statement that 'may' affect this.
*/ */
if (*save_ctx && if (*save_ctx &&
check_routine_access(thd, EXECUTE_ACL, sp->check_execute_access(thd))
sp->m_db.str, sp->m_name.str, sp->m_handler, false))
{ {
sp->m_security_ctx.restore_security_context(thd, *save_ctx); sp->m_security_ctx.restore_security_context(thd, *save_ctx);
*save_ctx= 0; *save_ctx= 0;
@@ -1388,9 +1569,10 @@ set_routine_security_ctx(THD *thd, sp_head *sp, Security_context **save_ctx)
bool sp_head::check_execute_access(THD *thd) const bool sp_head::check_execute_access(THD *thd) const
{ {
return check_routine_access(thd, EXECUTE_ACL, return m_parent ? m_parent->check_execute_access(thd) :
m_db.str, m_name.str, check_routine_access(thd, EXECUTE_ACL,
m_handler, false); m_db.str, m_name.str,
m_handler, false);
} }
@@ -1581,6 +1763,42 @@ err_with_cleanup:
} }
/*
Execute the package initialization section.
*/
bool sp_package::instantiate_if_needed(THD *thd)
{
List<Item> args;
if (m_is_instantiated)
return false;
/*
Set m_is_instantiated to true early, to avoid recursion in case if
the package initialization section calls routines from the same package.
*/
m_is_instantiated= true;
/*
Check that the initialization section doesn't contain Dynamic SQL
and doesn't return result sets: such stored procedures can't
be called from a function or trigger.
*/
if (thd->in_sub_stmt)
{
const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ?
"trigger" : "function");
if (is_not_allowed_in_function(where))
goto err;
}
args.elements= 0;
if (execute_procedure(thd, &args))
goto err;
return false;
err:
m_is_instantiated= false;
return true;
}
/** /**
Execute a function. Execute a function.
@@ -1632,6 +1850,9 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
DBUG_ENTER("sp_head::execute_function"); DBUG_ENTER("sp_head::execute_function");
DBUG_PRINT("info", ("function %s", m_name.str)); DBUG_PRINT("info", ("function %s", m_name.str));
if (m_parent && m_parent->instantiate_if_needed(thd))
DBUG_RETURN(true);
/* /*
Check that the function is called with all specified arguments. Check that the function is called with all specified arguments.
@@ -1861,9 +2082,13 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
sp_rcontext *nctx = NULL; sp_rcontext *nctx = NULL;
bool save_enable_slow_log; bool save_enable_slow_log;
bool save_log_general= false; bool save_log_general= false;
sp_package *pkg= get_package();
DBUG_ENTER("sp_head::execute_procedure"); DBUG_ENTER("sp_head::execute_procedure");
DBUG_PRINT("info", ("procedure %s", m_name.str)); DBUG_PRINT("info", ("procedure %s", m_name.str));
if (m_parent && m_parent->instantiate_if_needed(thd))
DBUG_RETURN(true);
if (args->elements != params) if (args->elements != params)
{ {
my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "PROCEDURE", my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "PROCEDURE",
@@ -1887,11 +2112,32 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
thd->spcont->callers_arena= thd; thd->spcont->callers_arena= thd;
} }
if (!(nctx= rcontext_create(thd, NULL, args))) if (!pkg)
{ {
delete nctx; /* Delete nctx if it was init() that failed. */ if (!(nctx= rcontext_create(thd, NULL, args)))
thd->spcont= save_spcont; {
DBUG_RETURN(TRUE); delete nctx; /* Delete nctx if it was init() that failed. */
thd->spcont= save_spcont;
DBUG_RETURN(TRUE);
}
}
else
{
if (!pkg->m_rcontext)
{
Query_arena backup_arena;
thd->set_n_backup_active_arena(this, &backup_arena);
nctx= pkg->rcontext_create(thd, NULL, args);
thd->restore_active_arena(this, &backup_arena);
if (!nctx)
{
thd->spcont= save_spcont;
DBUG_RETURN(TRUE);
}
pkg->m_rcontext= nctx;
}
else
nctx= pkg->m_rcontext;
} }
if (params > 0) if (params > 0)
@@ -2077,7 +2323,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (!save_spcont) if (!save_spcont)
delete octx; delete octx;
delete nctx; if (!pkg)
delete nctx;
thd->spcont= save_spcont; thd->spcont= save_spcont;
thd->utime_after_lock= utime_before_sp_exec; thd->utime_after_lock= utime_before_sp_exec;
@@ -3309,10 +3556,16 @@ sp_instr_set::execute(THD *thd, uint *nextp)
} }
sp_rcontext *sp_instr_set::get_rcontext(THD *thd) const
{
return m_rcontext_handler->get_rcontext(thd->spcont);
}
int int
sp_instr_set::exec_core(THD *thd, uint *nextp) sp_instr_set::exec_core(THD *thd, uint *nextp)
{ {
int res= thd->spcont->set_variable(thd, m_offset, &m_value); int res= get_rcontext(thd)->set_variable(thd, m_offset, &m_value);
delete_explain_query(thd->lex); delete_explain_query(thd->lex);
*nextp = m_ip+1; *nextp = m_ip+1;
return res; return res;
@@ -3324,13 +3577,15 @@ sp_instr_set::print(String *str)
/* set name@offset ... */ /* set name@offset ... */
int rsrv = SP_INSTR_UINT_MAXLEN+6; int rsrv = SP_INSTR_UINT_MAXLEN+6;
sp_variable *var = m_ctx->find_variable(m_offset); sp_variable *var = m_ctx->find_variable(m_offset);
const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
/* 'var' should always be non-null, but just in case... */ /* 'var' should always be non-null, but just in case... */
if (var) if (var)
rsrv+= var->name.length; rsrv+= var->name.length + prefix->length;
if (str->reserve(rsrv)) if (str->reserve(rsrv))
return; return;
str->qs_append(STRING_WITH_LEN("set ")); str->qs_append(STRING_WITH_LEN("set "));
str->qs_append(prefix->str, prefix->length);
if (var) if (var)
{ {
str->qs_append(var->name.str, var->name.length); str->qs_append(var->name.str, var->name.length);
@@ -3350,8 +3605,9 @@ sp_instr_set::print(String *str)
int int
sp_instr_set_row_field::exec_core(THD *thd, uint *nextp) sp_instr_set_row_field::exec_core(THD *thd, uint *nextp)
{ {
int res= thd->spcont->set_variable_row_field(thd, m_offset, m_field_offset, int res= get_rcontext(thd)->set_variable_row_field(thd, m_offset,
&m_value); m_field_offset,
&m_value);
delete_explain_query(thd->lex); delete_explain_query(thd->lex);
*nextp= m_ip + 1; *nextp= m_ip + 1;
return res; return res;
@@ -3364,17 +3620,19 @@ sp_instr_set_row_field::print(String *str)
/* set name@offset[field_offset] ... */ /* set name@offset[field_offset] ... */
int rsrv= SP_INSTR_UINT_MAXLEN + 6 + 6 + 3; int rsrv= SP_INSTR_UINT_MAXLEN + 6 + 6 + 3;
sp_variable *var= m_ctx->find_variable(m_offset); sp_variable *var= m_ctx->find_variable(m_offset);
const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
DBUG_ASSERT(var); DBUG_ASSERT(var);
DBUG_ASSERT(var->field_def.is_row()); DBUG_ASSERT(var->field_def.is_row());
const Column_definition *def= const Column_definition *def=
var->field_def.row_field_definitions()->elem(m_field_offset); var->field_def.row_field_definitions()->elem(m_field_offset);
DBUG_ASSERT(def); DBUG_ASSERT(def);
rsrv+= var->name.length + def->field_name.length; rsrv+= var->name.length + def->field_name.length + prefix->length;
if (str->reserve(rsrv)) if (str->reserve(rsrv))
return; return;
str->qs_append(STRING_WITH_LEN("set ")); str->qs_append(STRING_WITH_LEN("set "));
str->qs_append(var->name.str, var->name.length); str->qs_append(prefix->str, prefix->length);
str->qs_append(var->name.str, var->name.length);
str->qs_append('.'); str->qs_append('.');
str->qs_append(def->field_name.str, def->field_name.length); str->qs_append(def->field_name.str, def->field_name.length);
str->qs_append('@'); str->qs_append('@');
@@ -3395,9 +3653,9 @@ sp_instr_set_row_field::print(String *str)
int int
sp_instr_set_row_field_by_name::exec_core(THD *thd, uint *nextp) sp_instr_set_row_field_by_name::exec_core(THD *thd, uint *nextp)
{ {
int res= thd->spcont->set_variable_row_field_by_name(thd, m_offset, int res= get_rcontext(thd)->set_variable_row_field_by_name(thd, m_offset,
m_field_name, m_field_name,
&m_value); &m_value);
delete_explain_query(thd->lex); delete_explain_query(thd->lex);
*nextp= m_ip + 1; *nextp= m_ip + 1;
return res; return res;
@@ -3410,15 +3668,17 @@ sp_instr_set_row_field_by_name::print(String *str)
/* set name.field@offset["field"] ... */ /* set name.field@offset["field"] ... */
int rsrv= SP_INSTR_UINT_MAXLEN + 6 + 6 + 3 + 2; int rsrv= SP_INSTR_UINT_MAXLEN + 6 + 6 + 3 + 2;
sp_variable *var= m_ctx->find_variable(m_offset); sp_variable *var= m_ctx->find_variable(m_offset);
const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
DBUG_ASSERT(var); DBUG_ASSERT(var);
DBUG_ASSERT(var->field_def.is_table_rowtype_ref() || DBUG_ASSERT(var->field_def.is_table_rowtype_ref() ||
var->field_def.is_cursor_rowtype_ref()); var->field_def.is_cursor_rowtype_ref());
rsrv+= var->name.length + 2 * m_field_name.length; rsrv+= var->name.length + 2 * m_field_name.length + prefix->length;
if (str->reserve(rsrv)) if (str->reserve(rsrv))
return; return;
str->qs_append(STRING_WITH_LEN("set ")); str->qs_append(STRING_WITH_LEN("set "));
str->qs_append(var->name.str, var->name.length); str->qs_append(prefix->str, prefix->length);
str->qs_append(var->name.str, var->name.length);
str->qs_append('.'); str->qs_append('.');
str->qs_append(m_field_name.str, m_field_name.length); str->qs_append(m_field_name.str, m_field_name.length);
str->qs_append('@'); str->qs_append('@');
@@ -4542,6 +4802,7 @@ Item *sp_head::adjust_assignment_source(THD *thd, Item *val, Item *val2)
bool bool
sp_head::set_local_variable(THD *thd, sp_pcontext *spcont, sp_head::set_local_variable(THD *thd, sp_pcontext *spcont,
const Sp_rcontext_handler *rh,
sp_variable *spv, Item *val, LEX *lex, sp_variable *spv, Item *val, LEX *lex,
bool responsible_to_free_lex) bool responsible_to_free_lex)
{ {
@@ -4549,7 +4810,7 @@ sp_head::set_local_variable(THD *thd, sp_pcontext *spcont,
return true; return true;
sp_instr_set *sp_set= new (thd->mem_root) sp_instr_set *sp_set= new (thd->mem_root)
sp_instr_set(instructions(), spcont, sp_instr_set(instructions(), spcont, rh,
spv->offset, val, lex, spv->offset, val, lex,
responsible_to_free_lex); responsible_to_free_lex);
@@ -4562,6 +4823,7 @@ sp_head::set_local_variable(THD *thd, sp_pcontext *spcont,
*/ */
bool bool
sp_head::set_local_variable_row_field(THD *thd, sp_pcontext *spcont, sp_head::set_local_variable_row_field(THD *thd, sp_pcontext *spcont,
const Sp_rcontext_handler *rh,
sp_variable *spv, uint field_idx, sp_variable *spv, uint field_idx,
Item *val, LEX *lex) Item *val, LEX *lex)
{ {
@@ -4570,7 +4832,7 @@ sp_head::set_local_variable_row_field(THD *thd, sp_pcontext *spcont,
sp_instr_set_row_field *sp_set= new (thd->mem_root) sp_instr_set_row_field *sp_set= new (thd->mem_root)
sp_instr_set_row_field(instructions(), sp_instr_set_row_field(instructions(),
spcont, spcont, rh,
spv->offset, spv->offset,
field_idx, val, field_idx, val,
lex, true); lex, true);
@@ -4580,6 +4842,7 @@ sp_head::set_local_variable_row_field(THD *thd, sp_pcontext *spcont,
bool bool
sp_head::set_local_variable_row_field_by_name(THD *thd, sp_pcontext *spcont, sp_head::set_local_variable_row_field_by_name(THD *thd, sp_pcontext *spcont,
const Sp_rcontext_handler *rh,
sp_variable *spv, sp_variable *spv,
const LEX_CSTRING *field_name, const LEX_CSTRING *field_name,
Item *val, LEX *lex) Item *val, LEX *lex)
@@ -4589,7 +4852,7 @@ sp_head::set_local_variable_row_field_by_name(THD *thd, sp_pcontext *spcont,
sp_instr_set_row_field_by_name *sp_set= sp_instr_set_row_field_by_name *sp_set=
new (thd->mem_root) sp_instr_set_row_field_by_name(instructions(), new (thd->mem_root) sp_instr_set_row_field_by_name(instructions(),
spcont, spcont, rh,
spv->offset, spv->offset,
*field_name, *field_name,
val, val,
@@ -4669,6 +4932,7 @@ sp_head::add_set_for_loop_cursor_param_variables(THD *thd,
bool last= idx + 1 == parameters->argument_count(); bool last= idx + 1 == parameters->argument_count();
sp_variable *spvar= param_spcont->get_context_variable(idx); sp_variable *spvar= param_spcont->get_context_variable(idx);
if (set_local_variable(thd, param_spcont, if (set_local_variable(thd, param_spcont,
&sp_rcontext_handler_local,
spvar, parameters->arguments()[idx], spvar, parameters->arguments()[idx],
param_lex, last)) param_lex, last))
return true; return true;
@@ -4740,3 +5004,44 @@ bool sp_head::spvar_fill_table_rowtype_reference(THD *thd,
fill_spvar_using_table_rowtype_reference(thd, spvar, ref); fill_spvar_using_table_rowtype_reference(thd, spvar, ref);
return false; return false;
} }
/*
In Oracle mode stored routines have an optional name
at the end of a declaration:
PROCEDURE p1 AS
BEGIN
NULL
END p1;
Check that the first p1 and the last p1 match.
*/
bool sp_head::check_package_routine_end_name(const LEX_CSTRING &end_name) const
{
LEX_CSTRING non_qualified_name= m_name;
const char *errpos;
size_t ofs;
if (!end_name.length)
return false; // No end name
if (!(errpos= strrchr(m_name.str, '.')))
{
errpos= m_name.str;
goto err;
}
errpos++;
ofs= errpos - m_name.str;
non_qualified_name.str+= ofs;
non_qualified_name.length-= ofs;
if (Sp_handler::eq_routine_name(end_name, non_qualified_name))
return false;
err:
my_error(ER_END_IDENTIFIER_DOES_NOT_MATCH, MYF(0), end_name.str, errpos);
return true;
}
ulong sp_head::sp_cache_version() const
{
return m_parent ? m_parent->sp_cache_version() :
m_sp_cache_version;
}

View File

@@ -133,6 +133,7 @@ class sp_head :private Query_arena,
sp_head(const sp_head &); /**< Prevent use of these */ sp_head(const sp_head &); /**< Prevent use of these */
void operator=(sp_head &); void operator=(sp_head &);
protected:
MEM_ROOT main_mem_root; MEM_ROOT main_mem_root;
public: public:
/** Possible values of m_flags */ /** Possible values of m_flags */
@@ -168,6 +169,7 @@ public:
HAS_COLUMN_TYPE_REFS= 8192 HAS_COLUMN_TYPE_REFS= 8192
}; };
sp_package *m_parent;
const Sp_handler *m_handler; const Sp_handler *m_handler;
uint m_flags; // Boolean attributes of a stored routine uint m_flags; // Boolean attributes of a stored routine
@@ -201,13 +203,13 @@ public:
/** /**
Is this routine being executed? Is this routine being executed?
*/ */
bool is_invoked() const { return m_flags & IS_INVOKED; } virtual bool is_invoked() const { return m_flags & IS_INVOKED; }
/** /**
Get the value of the SP cache version, as remembered Get the value of the SP cache version, as remembered
when the routine was inserted into the cache. when the routine was inserted into the cache.
*/ */
ulong sp_cache_version() const { return m_sp_cache_version; } ulong sp_cache_version() const;
/** Set the value of the SP cache version. */ /** Set the value of the SP cache version. */
void set_sp_cache_version(ulong version_arg) void set_sp_cache_version(ulong version_arg)
@@ -221,6 +223,7 @@ public:
sp_rcontext *rcontext_create(THD *thd, Field *retval, sp_rcontext *rcontext_create(THD *thd, Field *retval,
Row_definition_list *list, Row_definition_list *list,
bool switch_security_ctx); bool switch_security_ctx);
bool eq_routine_spec(const sp_head *) const;
private: private:
/** /**
Version of the stored routine cache at the moment when the Version of the stored routine cache at the moment when the
@@ -316,7 +319,7 @@ public:
static void static void
operator delete(void *ptr, size_t size) throw (); operator delete(void *ptr, size_t size) throw ();
sp_head(const Sp_handler *handler); sp_head(sp_package *parent, const Sp_handler *handler);
/// Initialize after we have reset mem_root /// Initialize after we have reset mem_root
void void
@@ -395,15 +398,19 @@ public:
@retval false - on success @retval false - on success
*/ */
bool set_local_variable(THD *thd, sp_pcontext *spcont, bool set_local_variable(THD *thd, sp_pcontext *spcont,
const Sp_rcontext_handler *rh,
sp_variable *spv, Item *val, LEX *lex, sp_variable *spv, Item *val, LEX *lex,
bool responsible_to_free_lex); bool responsible_to_free_lex);
bool set_local_variable_row_field(THD *thd, sp_pcontext *spcont, bool set_local_variable_row_field(THD *thd, sp_pcontext *spcont,
const Sp_rcontext_handler *rh,
sp_variable *spv, uint field_idx, sp_variable *spv, uint field_idx,
Item *val, LEX *lex); Item *val, LEX *lex);
bool set_local_variable_row_field_by_name(THD *thd, sp_pcontext *spcont, bool set_local_variable_row_field_by_name(THD *thd, sp_pcontext *spcont,
const Sp_rcontext_handler *rh,
sp_variable *spv, sp_variable *spv,
const LEX_CSTRING *field_name, const LEX_CSTRING *field_name,
Item *val, LEX *lex); Item *val, LEX *lex);
bool check_package_routine_end_name(const LEX_CSTRING &end_name) const;
private: private:
/** /**
Generate a code to set a single cursor parameter variable. Generate a code to set a single cursor parameter variable.
@@ -426,7 +433,9 @@ private:
*/ */
DBUG_ASSERT(m_thd->free_list == NULL); DBUG_ASSERT(m_thd->free_list == NULL);
m_thd->free_list= prm->get_free_list(); m_thd->free_list= prm->get_free_list();
if (set_local_variable(thd, param_spcont, spvar, prm->get_item(), prm, true)) if (set_local_variable(thd, param_spcont,
&sp_rcontext_handler_local,
spvar, prm->get_item(), prm, true))
return true; return true;
/* /*
Safety: Safety:
@@ -822,9 +831,19 @@ public:
sp_pcontext *get_parse_context() { return m_pcont; } sp_pcontext *get_parse_context() { return m_pcont; }
/*
Check EXECUTE access:
- in case of a standalone rotuine, for the routine itself
- in case of a package routine, for the owner package body
*/
bool check_execute_access(THD *thd) const; bool check_execute_access(THD *thd) const;
private: virtual sp_package *get_package()
{
return NULL;
}
protected:
MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root
THD *m_thd; ///< Set if we have reset mem_root THD *m_thd; ///< Set if we have reset mem_root
@@ -889,6 +908,92 @@ private:
}; // class sp_head : public Sql_alloc }; // class sp_head : public Sql_alloc
class sp_package: public sp_head
{
bool validate_public_routines(THD *thd, sp_package *spec);
bool validate_private_routines(THD *thd);
public:
class LexList: public List<LEX>
{
public:
LexList() { elements= 0; }
// Find a package routine by a non qualified name
LEX *find(const LEX_CSTRING &name, stored_procedure_type type);
// Find a package routine by a package-qualified name, e.g. 'pkg.proc'
LEX *find_qualified(const LEX_CSTRING &name, stored_procedure_type type);
// Check if a routine with the given qualified name already exists
bool check_dup_qualified(const LEX_CSTRING &name, const Sp_handler *sph)
{
if (!find_qualified(name, sph->type()))
return false;
my_error(ER_SP_ALREADY_EXISTS, MYF(0), sph->type_str(), name.str);
return true;
}
bool check_dup_qualified(const sp_head *sp)
{
return check_dup_qualified(sp->m_name, sp->m_handler);
}
void cleanup();
};
/*
The LEX for a new package subroutine is initially assigned to
m_current_routine. After scanning parameters, return type and chistics,
the parser detects if we have a declaration or a definition, e.g.:
PROCEDURE p1(a INT);
vs
PROCEDURE p1(a INT) AS BEGIN NULL; END;
(i.e. either semicolon or the "AS" keyword)
m_current_routine is then added either to m_routine_implementations,
or m_routine_declarations, and then m_current_routine is set to NULL.
*/
LEX *m_current_routine;
LexList m_routine_implementations;
LexList m_routine_declarations;
LEX *m_top_level_lex;
sp_rcontext *m_rcontext;
uint m_invoked_subroutine_count;
bool m_is_instantiated;
bool m_is_cloning_routine;
sp_package(LEX *top_level_lex,
const sp_name *name,
const Sp_handler *sph);
~sp_package();
bool add_routine_declaration(LEX *lex)
{
return m_routine_declarations.check_dup_qualified(lex->sphead) ||
m_routine_declarations.push_back(lex, &main_mem_root);
}
bool add_routine_implementation(LEX *lex)
{
return m_routine_implementations.check_dup_qualified(lex->sphead) ||
m_routine_implementations.push_back(lex, &main_mem_root);
}
sp_package *get_package() { return this; }
bool is_invoked() const
{
/*
Cannot flush a package out of the SP cache when:
- its initialization block is running
- one of its subroutine is running
*/
return sp_head::is_invoked() || m_invoked_subroutine_count > 0;
}
sp_variable *find_package_variable(const LEX_CSTRING *name) const
{
/*
sp_head::m_pcont is a special level for routine parameters.
Variables declared inside CREATE PACKAGE BODY reside in m_children.at(0).
*/
sp_pcontext *ctx= m_pcont->child_context(0);
return ctx ? ctx->find_variable(name, true) : NULL;
}
bool validate_after_parser(THD *thd);
bool instantiate_if_needed(THD *thd);
};
class sp_lex_cursor: public sp_lex_local, public Query_arena class sp_lex_cursor: public sp_lex_local, public Query_arena
{ {
LEX_CSTRING m_cursor_name; LEX_CSTRING m_cursor_name;
@@ -1177,9 +1282,11 @@ class sp_instr_set : public sp_instr
public: public:
sp_instr_set(uint ip, sp_pcontext *ctx, sp_instr_set(uint ip, sp_pcontext *ctx,
const Sp_rcontext_handler *rh,
uint offset, Item *val, uint offset, Item *val,
LEX *lex, bool lex_resp) LEX *lex, bool lex_resp)
: sp_instr(ip, ctx), m_offset(offset), m_value(val), : sp_instr(ip, ctx),
m_rcontext_handler(rh), m_offset(offset), m_value(val),
m_lex_keeper(lex, lex_resp) m_lex_keeper(lex, lex_resp)
{} {}
@@ -1193,11 +1300,11 @@ public:
virtual void print(String *str); virtual void print(String *str);
protected: protected:
sp_rcontext *get_rcontext(THD *thd) const;
const Sp_rcontext_handler *m_rcontext_handler;
uint m_offset; ///< Frame offset uint m_offset; ///< Frame offset
Item *m_value; Item *m_value;
sp_lex_keeper m_lex_keeper; sp_lex_keeper m_lex_keeper;
}; // class sp_instr_set : public sp_instr }; // class sp_instr_set : public sp_instr
@@ -1215,10 +1322,11 @@ class sp_instr_set_row_field : public sp_instr_set
public: public:
sp_instr_set_row_field(uint ip, sp_pcontext *ctx, sp_instr_set_row_field(uint ip, sp_pcontext *ctx,
const Sp_rcontext_handler *rh,
uint offset, uint field_offset, uint offset, uint field_offset,
Item *val, Item *val,
LEX *lex, bool lex_resp) LEX *lex, bool lex_resp)
: sp_instr_set(ip, ctx, offset, val, lex, lex_resp), : sp_instr_set(ip, ctx, rh, offset, val, lex, lex_resp),
m_field_offset(field_offset) m_field_offset(field_offset)
{} {}
@@ -1257,10 +1365,11 @@ class sp_instr_set_row_field_by_name : public sp_instr_set
public: public:
sp_instr_set_row_field_by_name(uint ip, sp_pcontext *ctx, sp_instr_set_row_field_by_name(uint ip, sp_pcontext *ctx,
const Sp_rcontext_handler *rh,
uint offset, const LEX_CSTRING &field_name, uint offset, const LEX_CSTRING &field_name,
Item *val, Item *val,
LEX *lex, bool lex_resp) LEX *lex, bool lex_resp)
: sp_instr_set(ip, ctx, offset, val, lex, lex_resp), : sp_instr_set(ip, ctx, rh, offset, val, lex, lex_resp),
m_field_name(field_name) m_field_name(field_name)
{} {}

View File

@@ -394,6 +394,9 @@ public:
sp_pcontext *parent_context() const sp_pcontext *parent_context() const
{ return m_parent; } { return m_parent; }
sp_pcontext *child_context(uint i) const
{ return i < m_children.elements() ? m_children.at(i) : NULL; }
/// Calculate and return the number of handlers to pop between the given /// Calculate and return the number of handlers to pop between the given
/// context and this one. /// context and this one.
/// ///

View File

@@ -30,6 +30,33 @@
#include "sql_acl.h" // SELECT_ACL #include "sql_acl.h" // SELECT_ACL
#include "sql_parse.h" // check_table_access #include "sql_parse.h" // check_table_access
Sp_rcontext_handler_local sp_rcontext_handler_local;
Sp_rcontext_handler_package_body sp_rcontext_handler_package_body;
sp_rcontext *Sp_rcontext_handler_local::get_rcontext(sp_rcontext *ctx) const
{
return ctx;
}
sp_rcontext *Sp_rcontext_handler_package_body::get_rcontext(sp_rcontext *ctx) const
{
return ctx->m_sp->m_parent->m_rcontext;
}
const LEX_CSTRING *Sp_rcontext_handler_local::get_name_prefix() const
{
return &empty_clex_str;
}
const LEX_CSTRING *Sp_rcontext_handler_package_body::get_name_prefix() const
{
static const LEX_CSTRING sp_package_body_variable_prefix_clex_str=
{C_STRING_WITH_LEN("PACKAGE_BODY.")};
return &sp_package_body_variable_prefix_clex_str;
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// sp_rcontext implementation. // sp_rcontext implementation.
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@@ -40,9 +67,7 @@ sp_rcontext::sp_rcontext(const sp_head *owner,
Field *return_value_fld, Field *return_value_fld,
bool in_sub_stmt) bool in_sub_stmt)
:end_partial_result_set(false), :end_partial_result_set(false),
#ifndef DBUG_OFF
m_sp(owner), m_sp(owner),
#endif
m_root_parsing_ctx(root_parsing_ctx), m_root_parsing_ctx(root_parsing_ctx),
m_var_table(NULL), m_var_table(NULL),
m_return_value_fld(return_value_fld), m_return_value_fld(return_value_fld),

View File

@@ -179,11 +179,10 @@ public:
/// of the client/server protocol. /// of the client/server protocol.
bool end_partial_result_set; bool end_partial_result_set;
#ifndef DBUG_OFF
/// The stored program for which this runtime context is created. Used for /// The stored program for which this runtime context is created. Used for
/// checking if correct runtime context is used for variable handling. /// checking if correct runtime context is used for variable handling,
/// and to access the package run-time context
const sp_head *m_sp; const sp_head *m_sp;
#endif
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// SP-variables. // SP-variables.

View File

@@ -724,6 +724,7 @@ static MEM_ROOT acl_memroot, grant_memroot;
static bool initialized=0; static bool initialized=0;
static bool allow_all_hosts=1; static bool allow_all_hosts=1;
static HASH acl_check_hosts, column_priv_hash, proc_priv_hash, func_priv_hash; static HASH acl_check_hosts, column_priv_hash, proc_priv_hash, func_priv_hash;
static HASH package_spec_priv_hash, package_body_priv_hash;
static DYNAMIC_ARRAY acl_wild_hosts; static DYNAMIC_ARRAY acl_wild_hosts;
static Hash_filo<acl_entry> *acl_cache; static Hash_filo<acl_entry> *acl_cache;
static uint grant_version=0; /* Version of priv tables. incremented by acl_load */ static uint grant_version=0; /* Version of priv tables. incremented by acl_load */
@@ -767,6 +768,18 @@ HASH *Sp_handler_function::get_priv_hash() const
} }
HASH *Sp_handler_package_spec::get_priv_hash() const
{
return &package_spec_priv_hash;
}
HASH *Sp_handler_package_body::get_priv_hash() const
{
return &package_body_priv_hash;
}
/* /*
Enumeration of ACL/GRANT tables in the mysql database Enumeration of ACL/GRANT tables in the mysql database
*/ */
@@ -1439,6 +1452,8 @@ enum enum_acl_lists
COLUMN_PRIVILEGES_HASH, COLUMN_PRIVILEGES_HASH,
PROC_PRIVILEGES_HASH, PROC_PRIVILEGES_HASH,
FUNC_PRIVILEGES_HASH, FUNC_PRIVILEGES_HASH,
PACKAGE_SPEC_PRIVILEGES_HASH,
PACKAGE_BODY_PRIVILEGES_HASH,
PROXY_USERS_ACL, PROXY_USERS_ACL,
ROLES_MAPPINGS_HASH ROLES_MAPPINGS_HASH
}; };
@@ -5530,7 +5545,10 @@ table_error:
******************************************************************/ ******************************************************************/
struct PRIVS_TO_MERGE struct PRIVS_TO_MERGE
{ {
enum what { ALL, GLOBAL, DB, TABLE_COLUMN, PROC, FUNC } what; enum what
{
ALL, GLOBAL, DB, TABLE_COLUMN, PROC, FUNC, PACKAGE_SPEC, PACKAGE_BODY
} what;
const char *db, *name; const char *db, *name;
}; };
@@ -5542,6 +5560,10 @@ static enum PRIVS_TO_MERGE::what sp_privs_to_merge(stored_procedure_type type)
return PRIVS_TO_MERGE::FUNC; return PRIVS_TO_MERGE::FUNC;
case TYPE_ENUM_PROCEDURE: case TYPE_ENUM_PROCEDURE:
return PRIVS_TO_MERGE::PROC; return PRIVS_TO_MERGE::PROC;
case TYPE_ENUM_PACKAGE:
return PRIVS_TO_MERGE::PACKAGE_SPEC;
case TYPE_ENUM_PACKAGE_BODY:
return PRIVS_TO_MERGE::PACKAGE_BODY;
case TYPE_ENUM_TRIGGER: case TYPE_ENUM_TRIGGER:
case TYPE_ENUM_PROXY: case TYPE_ENUM_PROXY:
break; break;
@@ -6360,7 +6382,14 @@ static int merge_role_privileges(ACL_ROLE *role __attribute__((unused)),
if (all || data->what == PRIVS_TO_MERGE::FUNC) if (all || data->what == PRIVS_TO_MERGE::FUNC)
changed|= merge_role_routine_grant_privileges(grantee, changed|= merge_role_routine_grant_privileges(grantee,
data->db, data->name, &role_hash, &func_priv_hash); data->db, data->name, &role_hash, &func_priv_hash);
if (all || data->what == PRIVS_TO_MERGE::PACKAGE_SPEC)
changed|= merge_role_routine_grant_privileges(grantee,
data->db, data->name, &role_hash,
&package_spec_priv_hash);
if (all || data->what == PRIVS_TO_MERGE::PACKAGE_BODY)
changed|= merge_role_routine_grant_privileges(grantee,
data->db, data->name, &role_hash,
&package_body_priv_hash);
return !changed; // don't recurse into the subgraph if privs didn't change return !changed; // don't recurse into the subgraph if privs didn't change
} }
@@ -7244,6 +7273,8 @@ void grant_free(void)
my_hash_free(&column_priv_hash); my_hash_free(&column_priv_hash);
my_hash_free(&proc_priv_hash); my_hash_free(&proc_priv_hash);
my_hash_free(&func_priv_hash); my_hash_free(&func_priv_hash);
my_hash_free(&package_spec_priv_hash);
my_hash_free(&package_body_priv_hash);
free_root(&grant_memroot,MYF(0)); free_root(&grant_memroot,MYF(0));
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@@ -7310,6 +7341,10 @@ static bool grant_load(THD *thd,
0,0,0, (my_hash_get_key) get_grant_table, 0,0); 0,0,0, (my_hash_get_key) get_grant_table, 0,0);
(void) my_hash_init(&func_priv_hash, &my_charset_utf8_bin, (void) my_hash_init(&func_priv_hash, &my_charset_utf8_bin,
0,0,0, (my_hash_get_key) get_grant_table, 0,0); 0,0,0, (my_hash_get_key) get_grant_table, 0,0);
(void) my_hash_init(&package_spec_priv_hash, &my_charset_utf8_bin,
0,0,0, (my_hash_get_key) get_grant_table, 0,0);
(void) my_hash_init(&package_body_priv_hash, &my_charset_utf8_bin,
0,0,0, (my_hash_get_key) get_grant_table, 0,0);
init_sql_alloc(&grant_memroot, "GRANT", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); init_sql_alloc(&grant_memroot, "GRANT", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
t_table= tables_priv.table(); t_table= tables_priv.table();
@@ -7459,6 +7494,7 @@ static my_bool propagate_role_grants_action(void *role_ptr,
bool grant_reload(THD *thd) bool grant_reload(THD *thd)
{ {
HASH old_column_priv_hash, old_proc_priv_hash, old_func_priv_hash; HASH old_column_priv_hash, old_proc_priv_hash, old_func_priv_hash;
HASH old_package_spec_priv_hash, old_package_body_priv_hash;
MEM_ROOT old_mem; MEM_ROOT old_mem;
int result; int result;
DBUG_ENTER("grant_reload"); DBUG_ENTER("grant_reload");
@@ -7478,6 +7514,8 @@ bool grant_reload(THD *thd)
old_column_priv_hash= column_priv_hash; old_column_priv_hash= column_priv_hash;
old_proc_priv_hash= proc_priv_hash; old_proc_priv_hash= proc_priv_hash;
old_func_priv_hash= func_priv_hash; old_func_priv_hash= func_priv_hash;
old_package_spec_priv_hash= package_spec_priv_hash;
old_package_body_priv_hash= package_body_priv_hash;
/* /*
Create a new memory pool but save the current memory pool to make an undo Create a new memory pool but save the current memory pool to make an undo
@@ -7495,6 +7533,8 @@ bool grant_reload(THD *thd)
column_priv_hash= old_column_priv_hash; /* purecov: deadcode */ column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
proc_priv_hash= old_proc_priv_hash; proc_priv_hash= old_proc_priv_hash;
func_priv_hash= old_func_priv_hash; func_priv_hash= old_func_priv_hash;
package_spec_priv_hash= old_package_spec_priv_hash;
package_body_priv_hash= old_package_body_priv_hash;
grant_memroot= old_mem; /* purecov: deadcode */ grant_memroot= old_mem; /* purecov: deadcode */
} }
else else
@@ -7502,6 +7542,8 @@ bool grant_reload(THD *thd)
my_hash_free(&old_column_priv_hash); my_hash_free(&old_column_priv_hash);
my_hash_free(&old_proc_priv_hash); my_hash_free(&old_proc_priv_hash);
my_hash_free(&old_func_priv_hash); my_hash_free(&old_func_priv_hash);
my_hash_free(&old_package_spec_priv_hash);
my_hash_free(&old_package_body_priv_hash);
free_root(&old_mem,MYF(0)); free_root(&old_mem,MYF(0));
} }
@@ -8123,7 +8165,9 @@ bool check_grant_db(THD *thd, const char *db)
if (error) if (error)
error= check_grant_db_routine(thd, db, &proc_priv_hash) && error= check_grant_db_routine(thd, db, &proc_priv_hash) &&
check_grant_db_routine(thd, db, &func_priv_hash); check_grant_db_routine(thd, db, &func_priv_hash) &&
check_grant_db_routine(thd, db, &package_spec_priv_hash) &&
check_grant_db_routine(thd, db, &package_body_priv_hash);
mysql_rwlock_unlock(&LOCK_grant); mysql_rwlock_unlock(&LOCK_grant);
@@ -8519,6 +8563,14 @@ static bool print_grants_for_role(THD *thd, ACL_ROLE * role)
buff, sizeof(buff))) buff, sizeof(buff)))
return TRUE; return TRUE;
if (show_routine_grants(thd, role->user.str, "", &sp_handler_package_spec,
buff, sizeof(buff)))
return TRUE;
if (show_routine_grants(thd, role->user.str, "", &sp_handler_package_body,
buff, sizeof(buff)))
return TRUE;
return FALSE; return FALSE;
} }
@@ -8744,6 +8796,14 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user)
buff, sizeof(buff))) buff, sizeof(buff)))
goto end; goto end;
if (show_routine_grants(thd, username, hostname, &sp_handler_package_spec,
buff, sizeof(buff)))
goto end;
if (show_routine_grants(thd, username, hostname, &sp_handler_package_body,
buff, sizeof(buff)))
goto end;
if (show_proxy_grants(thd, username, hostname, buff, sizeof(buff))) if (show_proxy_grants(thd, username, hostname, buff, sizeof(buff)))
goto end; goto end;
} }
@@ -9678,6 +9738,14 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
grant_name_hash= &func_priv_hash; grant_name_hash= &func_priv_hash;
elements= grant_name_hash->records; elements= grant_name_hash->records;
break; break;
case PACKAGE_SPEC_PRIVILEGES_HASH:
grant_name_hash= &package_spec_priv_hash;
elements= grant_name_hash->records;
break;
case PACKAGE_BODY_PRIVILEGES_HASH:
grant_name_hash= &package_body_priv_hash;
elements= grant_name_hash->records;
break;
case PROXY_USERS_ACL: case PROXY_USERS_ACL:
elements= acl_proxy_users.elements; elements= acl_proxy_users.elements;
break; break;
@@ -9716,6 +9784,8 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
case COLUMN_PRIVILEGES_HASH: case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH: case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH: case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
grant_name= (GRANT_NAME*) my_hash_element(grant_name_hash, idx); grant_name= (GRANT_NAME*) my_hash_element(grant_name_hash, idx);
user= grant_name->user; user= grant_name->user;
host= grant_name->host.hostname; host= grant_name->host.hostname;
@@ -9798,6 +9868,8 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
case COLUMN_PRIVILEGES_HASH: case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH: case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH: case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
my_hash_delete(grant_name_hash, (uchar*) grant_name); my_hash_delete(grant_name_hash, (uchar*) grant_name);
/* /*
In our HASH implementation on deletion one elements In our HASH implementation on deletion one elements
@@ -9843,6 +9915,8 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
case COLUMN_PRIVILEGES_HASH: case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH: case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH: case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
{ {
/* /*
Save old hash key and its length to be able to properly update Save old hash key and its length to be able to properly update
@@ -10025,6 +10099,26 @@ static int handle_grant_data(THD *thd, Grant_tables& tables, bool drop,
if (search_only) if (search_only)
goto end; goto end;
} }
/* Handle package spec array. */
if ((handle_grant_struct(PACKAGE_SPEC_PRIVILEGES_HASH,
drop, user_from, user_to) || found)
&& ! result)
{
result= 1; /* At least one record/element found. */
/* If search is requested, we do not need to search further. */
if (search_only)
goto end;
}
/* Handle package body array. */
if ((handle_grant_struct(PACKAGE_BODY_PRIVILEGES_HASH,
drop, user_from, user_to) || found)
&& ! result)
{
result= 1; /* At least one record/element found. */
/* If search is requested, we do not need to search further. */
if (search_only)
goto end;
}
} }
/* Handle tables table. */ /* Handle tables table. */
@@ -10751,7 +10845,9 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
/* Remove procedure access */ /* Remove procedure access */
if (mysql_revoke_sp_privs(thd, &tables, &sp_handler_function, lex_user) || if (mysql_revoke_sp_privs(thd, &tables, &sp_handler_function, lex_user) ||
mysql_revoke_sp_privs(thd, &tables, &sp_handler_procedure, lex_user)) mysql_revoke_sp_privs(thd, &tables, &sp_handler_procedure, lex_user) ||
mysql_revoke_sp_privs(thd, &tables, &sp_handler_package_spec, lex_user) ||
mysql_revoke_sp_privs(thd, &tables, &sp_handler_package_body, lex_user))
result= -1; result= -1;
ACL_USER_BASE *user_or_role; ACL_USER_BASE *user_or_role;
@@ -11294,6 +11390,8 @@ SHOW_VAR acl_statistics[] = {
{"database_grants", (char*)&acl_dbs.elements, SHOW_UINT}, {"database_grants", (char*)&acl_dbs.elements, SHOW_UINT},
{"function_grants", (char*)&func_priv_hash.records, SHOW_ULONG}, {"function_grants", (char*)&func_priv_hash.records, SHOW_ULONG},
{"procedure_grants", (char*)&proc_priv_hash.records, SHOW_ULONG}, {"procedure_grants", (char*)&proc_priv_hash.records, SHOW_ULONG},
{"package_spec_grants", (char*)&package_spec_priv_hash.records, SHOW_ULONG},
{"package_body_grants", (char*)&package_body_priv_hash.records, SHOW_ULONG},
{"proxy_users", (char*)&acl_proxy_users.elements, SHOW_UINT}, {"proxy_users", (char*)&acl_proxy_users.elements, SHOW_UINT},
{"role_grants", (char*)&acl_roles_mappings.records, SHOW_ULONG}, {"role_grants", (char*)&acl_roles_mappings.records, SHOW_ULONG},
{"roles", (char*)&acl_roles.records, SHOW_ULONG}, {"roles", (char*)&acl_roles.records, SHOW_ULONG},

View File

@@ -3125,6 +3125,17 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
switch (mdl_type) switch (mdl_type)
{ {
case MDL_key::PACKAGE_BODY:
DBUG_ASSERT(rt != (Sroutine_hash_entry*)prelocking_ctx->sroutines_list.first);
/*
No need to cache the package body itself.
It gets cached during open_and_process_routine()
for the first used package routine. See the package related code
in the "case" below.
*/
if (sp_acquire_mdl(thd, rt, ot_ctx))
DBUG_RETURN(TRUE);
break;
case MDL_key::FUNCTION: case MDL_key::FUNCTION:
case MDL_key::PROCEDURE: case MDL_key::PROCEDURE:
{ {
@@ -3139,11 +3150,13 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
if (rt != (Sroutine_hash_entry*)prelocking_ctx->sroutines_list.first || if (rt != (Sroutine_hash_entry*)prelocking_ctx->sroutines_list.first ||
mdl_type != MDL_key::PROCEDURE) mdl_type != MDL_key::PROCEDURE)
{ {
/*
TODO: If this is a package routine, we should not put MDL
TODO: on the routine itself. We should put only the package MDL.
*/
if (sp_acquire_mdl(thd, rt, ot_ctx)) if (sp_acquire_mdl(thd, rt, ot_ctx))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
DEBUG_SYNC(thd, "after_shared_lock_pname");
/* Ensures the routine is up-to-date and cached, if exists. */ /* Ensures the routine is up-to-date and cached, if exists. */
if (rt->sp_cache_routine(thd, has_prelocking_list, &sp)) if (rt->sp_cache_routine(thd, has_prelocking_list, &sp))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
@@ -3158,8 +3171,24 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
*routine_modifies_data= sp->modifies_data(); *routine_modifies_data= sp->modifies_data();
if (!has_prelocking_list) if (!has_prelocking_list)
{
prelocking_strategy->handle_routine(thd, prelocking_ctx, rt, sp, prelocking_strategy->handle_routine(thd, prelocking_ctx, rt, sp,
need_prelocking); need_prelocking);
if (sp->m_parent)
{
/*
If it's a package routine, we need also to handle the
package body, as its initialization section can use
some tables and routine calls.
TODO: Only package public routines actually need this.
TODO: Skip package body handling for private routines.
*/
*routine_modifies_data|= sp->m_parent->modifies_data();
prelocking_strategy->handle_routine(thd, prelocking_ctx, rt,
sp->m_parent,
need_prelocking);
}
}
} }
} }
else else

View File

@@ -913,6 +913,8 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
sp_proc_cache= NULL; sp_proc_cache= NULL;
sp_func_cache= NULL; sp_func_cache= NULL;
sp_package_spec_cache= NULL;
sp_package_body_cache= NULL;
/* For user vars replication*/ /* For user vars replication*/
if (opt_bin_log) if (opt_bin_log)
@@ -1477,6 +1479,8 @@ void THD::change_user(void)
(my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC); (my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC);
sp_cache_clear(&sp_proc_cache); sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache); sp_cache_clear(&sp_func_cache);
sp_cache_clear(&sp_package_spec_cache);
sp_cache_clear(&sp_package_body_cache);
} }
@@ -1534,6 +1538,8 @@ void THD::cleanup(void)
my_hash_free(&sequences); my_hash_free(&sequences);
sp_cache_clear(&sp_proc_cache); sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache); sp_cache_clear(&sp_func_cache);
sp_cache_clear(&sp_package_spec_cache);
sp_cache_clear(&sp_package_body_cache);
auto_inc_intervals_forced.empty(); auto_inc_intervals_forced.empty();
auto_inc_intervals_in_cur_stmt_for_binlog.empty(); auto_inc_intervals_in_cur_stmt_for_binlog.empty();
@@ -3637,7 +3643,8 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
mvsp->type_handler() == &type_handler_row) mvsp->type_handler() == &type_handler_row)
{ {
// SELECT INTO row_type_sp_variable // SELECT INTO row_type_sp_variable
if (thd->spcont->get_variable(mvsp->offset)->cols() != list.elements) if (mvsp->get_rcontext(thd->spcont)->get_variable(mvsp->offset)->cols() !=
list.elements)
goto error; goto error;
m_var_sp_row= mvsp; m_var_sp_row= mvsp;
return 0; return 0;
@@ -3981,14 +3988,22 @@ bool my_var_user::set(THD *thd, Item *item)
return suv->fix_fields(thd, 0) || suv->update(); return suv->fix_fields(thd, 0) || suv->update();
} }
sp_rcontext *my_var_sp::get_rcontext(sp_rcontext *local_ctx) const
{
return m_rcontext_handler->get_rcontext(local_ctx);
}
bool my_var_sp::set(THD *thd, Item *item) bool my_var_sp::set(THD *thd, Item *item)
{ {
return thd->spcont->set_variable(thd, offset, &item); return get_rcontext(thd->spcont)->set_variable(thd, offset, &item);
} }
bool my_var_sp_row_field::set(THD *thd, Item *item) bool my_var_sp_row_field::set(THD *thd, Item *item)
{ {
return thd->spcont->set_variable_row_field(thd, offset, m_field_offset, &item); return get_rcontext(thd->spcont)->
set_variable_row_field(thd, offset, m_field_offset, &item);
} }
@@ -4023,7 +4038,8 @@ int select_dumpvar::send_data(List<Item> &items)
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (m_var_sp_row ? if (m_var_sp_row ?
thd->spcont->set_variable_row(thd, m_var_sp_row->offset, items) : m_var_sp_row->get_rcontext(thd->spcont)->
set_variable_row(thd, m_var_sp_row->offset, items) :
send_data_to_var_list(items)) send_data_to_var_list(items))
DBUG_RETURN(1); DBUG_RETURN(1);

View File

@@ -1119,6 +1119,16 @@ public:
char *db; char *db;
size_t db_length; size_t db_length;
/*
We should eventually replace "db" and "db_length" to LEX_STRING.
This helper method can be removed after that.
*/
LEX_CSTRING db_lex_cstring() const
{
LEX_CSTRING tmp= {db, db_length };
return tmp;
}
/* This is set to 1 of last call to send_result_to_client() was ok */ /* This is set to 1 of last call to send_result_to_client() was ok */
my_bool query_cache_is_applicable; my_bool query_cache_is_applicable;
@@ -3072,6 +3082,8 @@ public:
sp_rcontext *spcont; // SP runtime context sp_rcontext *spcont; // SP runtime context
sp_cache *sp_proc_cache; sp_cache *sp_proc_cache;
sp_cache *sp_func_cache; sp_cache *sp_func_cache;
sp_cache *sp_package_spec_cache;
sp_cache *sp_package_body_cache;
/** number of name_const() substitutions, see sp_head.cc:subst_spvars() */ /** number of name_const() substitutions, see sp_head.cc:subst_spvars() */
uint query_name_consts; uint query_name_consts;
@@ -5740,6 +5752,7 @@ public:
}; };
class my_var_sp: public my_var { class my_var_sp: public my_var {
const Sp_rcontext_handler *m_rcontext_handler;
const Type_handler *m_type_handler; const Type_handler *m_type_handler;
public: public:
uint offset; uint offset;
@@ -5748,13 +5761,17 @@ public:
runtime context is used for variable handling. runtime context is used for variable handling.
*/ */
sp_head *sp; sp_head *sp;
my_var_sp(const LEX_CSTRING *j, uint o, const Type_handler *type_handler, my_var_sp(const Sp_rcontext_handler *rcontext_handler,
const LEX_CSTRING *j, uint o, const Type_handler *type_handler,
sp_head *s) sp_head *s)
: my_var(j, LOCAL_VAR), m_type_handler(type_handler), offset(o), sp(s) { } : my_var(j, LOCAL_VAR),
m_rcontext_handler(rcontext_handler),
m_type_handler(type_handler), offset(o), sp(s) { }
~my_var_sp() { } ~my_var_sp() { }
bool set(THD *thd, Item *val); bool set(THD *thd, Item *val);
my_var_sp *get_my_var_sp() { return this; } my_var_sp *get_my_var_sp() { return this; }
const Type_handler *type_handler() const { return m_type_handler; } const Type_handler *type_handler() const { return m_type_handler; }
sp_rcontext *get_rcontext(sp_rcontext *local_ctx) const;
}; };
/* /*
@@ -5765,9 +5782,11 @@ class my_var_sp_row_field: public my_var_sp
{ {
uint m_field_offset; uint m_field_offset;
public: public:
my_var_sp_row_field(const LEX_CSTRING *varname, const LEX_CSTRING *fieldname, my_var_sp_row_field(const Sp_rcontext_handler *rcontext_handler,
const LEX_CSTRING *varname, const LEX_CSTRING *fieldname,
uint var_idx, uint field_idx, sp_head *s) uint var_idx, uint field_idx, sp_head *s)
:my_var_sp(varname, var_idx, &type_handler_double/*Not really used*/, s), :my_var_sp(rcontext_handler, varname, var_idx,
&type_handler_double/*Not really used*/, s),
m_field_offset(field_idx) m_field_offset(field_idx)
{ } { }
bool set(THD *thd, Item *val); bool set(THD *thd, Item *val);
@@ -6142,6 +6161,9 @@ public:
Database_qualified_name(const LEX_CSTRING *db, const LEX_CSTRING *name) Database_qualified_name(const LEX_CSTRING *db, const LEX_CSTRING *name)
:m_db(*db), m_name(*name) :m_db(*db), m_name(*name)
{ } { }
Database_qualified_name(const LEX_CSTRING &db, const LEX_CSTRING &name)
:m_db(db), m_name(name)
{ }
Database_qualified_name(const char *db, size_t db_length, Database_qualified_name(const char *db, size_t db_length,
const char *name, size_t name_length) const char *name, size_t name_length)
{ {
@@ -6191,6 +6213,34 @@ public:
DBUG_ASSERT(ok_for_lower_case_names(m_db.str)); DBUG_ASSERT(ok_for_lower_case_names(m_db.str));
return false; return false;
} }
bool make_package_routine_name(MEM_ROOT *mem_root,
const LEX_CSTRING &package,
const LEX_CSTRING &routine)
{
char *tmp;
size_t length= package.length + 1 + routine.length + 1;
if (!(tmp= (char *) alloc_root(mem_root, length)))
return true;
m_name.length= my_snprintf(tmp, length, "%.*s.%.*s",
(int) package.length, package.str,
(int) routine.length, routine.str);
m_name.str= tmp;
return false;
}
bool make_package_routine_name(MEM_ROOT *mem_root,
const LEX_CSTRING &db,
const LEX_CSTRING &package,
const LEX_CSTRING &routine)
{
if (make_package_routine_name(mem_root, package, routine))
return true;
if (!(m_db.str= strmake_root(mem_root, db.str, db.length)))
return true;
m_db.length= db.length;
return false;
}
}; };

View File

@@ -99,6 +99,15 @@ enum enum_sql_command {
SQLCOM_CREATE_SEQUENCE, SQLCOM_CREATE_SEQUENCE,
SQLCOM_DROP_SEQUENCE, SQLCOM_DROP_SEQUENCE,
SQLCOM_ALTER_SEQUENCE, SQLCOM_ALTER_SEQUENCE,
SQLCOM_CREATE_PACKAGE,
SQLCOM_DROP_PACKAGE,
SQLCOM_CREATE_PACKAGE_BODY,
SQLCOM_DROP_PACKAGE_BODY,
SQLCOM_SHOW_CREATE_PACKAGE,
SQLCOM_SHOW_CREATE_PACKAGE_BODY,
SQLCOM_SHOW_STATUS_PACKAGE,
SQLCOM_SHOW_STATUS_PACKAGE_BODY,
SQLCOM_SHOW_PACKAGE_BODY_CODE,
/* /*
When a command is added here, be sure it's also added in mysqld.cc When a command is added here, be sure it's also added in mysqld.cc
@@ -175,8 +184,10 @@ class Sql_cmd_call : public Sql_cmd
{ {
public: public:
class sp_name *m_name; class sp_name *m_name;
Sql_cmd_call(class sp_name *name) const class Sp_handler *m_handler;
:m_name(name) Sql_cmd_call(class sp_name *name, const class Sp_handler *handler)
:m_name(name),
m_handler(handler)
{} {}
virtual ~Sql_cmd_call() virtual ~Sql_cmd_call()

View File

@@ -2935,9 +2935,28 @@ void LEX::cleanup_lex_after_parse_error(THD *thd)
*/ */
if (thd->lex->sphead) if (thd->lex->sphead)
{ {
sp_package *pkg;
thd->lex->sphead->restore_thd_mem_root(thd); thd->lex->sphead->restore_thd_mem_root(thd);
delete thd->lex->sphead; if ((pkg= thd->lex->sphead->m_parent))
thd->lex->sphead= NULL; {
/*
If a syntax error happened inside a package routine definition,
then thd->lex points to the routine sublex. We need to restore to
the top level LEX.
*/
DBUG_ASSERT(pkg->m_top_level_lex);
DBUG_ASSERT(pkg == pkg->m_top_level_lex->sphead);
pkg->restore_thd_mem_root(thd);
LEX *top= pkg->m_top_level_lex;
delete pkg;
thd->lex= top;
thd->lex->sphead= NULL;
}
else
{
delete thd->lex->sphead;
thd->lex->sphead= NULL;
}
} }
} }
@@ -5156,13 +5175,50 @@ void LEX::set_stmt_init()
}; };
/**
Find a local or a package body variable by name.
@param IN name - the variable name
@param OUT ctx - NULL, if the variable was not found,
or LEX::spcont (if a local variable was found)
or the package top level context
(if a package variable was found)
@param OUT handler - NULL, if the variable was not found,
or a pointer to rcontext handler
@retval - the variable (if found), or NULL otherwise.
*/
sp_variable *
LEX::find_variable(const LEX_CSTRING *name,
sp_pcontext **ctx,
const Sp_rcontext_handler **rh) const
{
sp_variable *spv;
if (spcont && (spv= spcont->find_variable(name, false)))
{
*ctx= spcont;
*rh= &sp_rcontext_handler_local;
return spv;
}
sp_package *pkg= sphead ? sphead->m_parent : NULL;
if (pkg && (spv= pkg->find_package_variable(name)))
{
*ctx= pkg->get_parse_context()->child_context(0);
*rh= &sp_rcontext_handler_package_body;
return spv;
}
*ctx= NULL;
*rh= NULL;
return NULL;
}
bool LEX::init_internal_variable(struct sys_var_with_base *variable, bool LEX::init_internal_variable(struct sys_var_with_base *variable,
const LEX_CSTRING *name) const LEX_CSTRING *name)
{ {
sp_variable *spv; sp_variable *spv;
const Sp_rcontext_handler *rh;
/* Best effort lookup for system variable. */ /* Best effort lookup for system variable. */
if (!spcont || !(spv = spcont->find_variable(name, false))) if (!(spv= find_variable(name, &rh)))
{ {
struct sys_var_with_base tmp= {NULL, *name}; struct sys_var_with_base tmp= {NULL, *name};
@@ -5281,7 +5337,8 @@ bool LEX::sp_variable_declarations_set_default(THD *thd, int nvars,
/* The last instruction is responsible for freeing LEX. */ /* The last instruction is responsible for freeing LEX. */
sp_instr_set *is= new (this->thd->mem_root) sp_instr_set *is= new (this->thd->mem_root)
sp_instr_set(sphead->instructions(), sp_instr_set(sphead->instructions(),
spcont, spvar->offset, dflt_value_item, spcont, &sp_rcontext_handler_local,
spvar->offset, dflt_value_item,
this, last); this, last);
if (is == NULL || sphead->add_instr(is)) if (is == NULL || sphead->add_instr(is))
return true; return true;
@@ -5577,7 +5634,8 @@ sp_variable *LEX::sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name,
spvar->default_value= value; spvar->default_value= value;
sp_instr_set *is= new (this->thd->mem_root) sp_instr_set *is= new (this->thd->mem_root)
sp_instr_set(sphead->instructions(), sp_instr_set(sphead->instructions(),
spcont, spvar->offset, value, spcont, &sp_rcontext_handler_local,
spvar->offset, value,
this, true); this, true);
if (is == NULL || sphead->add_instr(is)) if (is == NULL || sphead->add_instr(is))
return NULL; return NULL;
@@ -5655,7 +5713,8 @@ bool LEX::sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop)
{ {
sp_variable *src= i == 0 ? loop.m_index : loop.m_upper_bound; sp_variable *src= i == 0 ? loop.m_index : loop.m_upper_bound;
args[i]= new (thd->mem_root) args[i]= new (thd->mem_root)
Item_splocal(thd, &src->name, src->offset, src->type_handler()); Item_splocal(thd, &sp_rcontext_handler_local,
&src->name, src->offset, src->type_handler());
if (args[i] == NULL) if (args[i] == NULL)
return true; return true;
#ifndef DBUG_OFF #ifndef DBUG_OFF
@@ -5788,7 +5847,8 @@ bool LEX::sp_for_loop_cursor_declarations(THD *thd,
bool LEX::sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop) bool LEX::sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop)
{ {
Item_splocal *splocal= new (thd->mem_root) Item_splocal *splocal= new (thd->mem_root)
Item_splocal(thd, &loop.m_index->name, loop.m_index->offset, Item_splocal(thd, &sp_rcontext_handler_local,
&loop.m_index->name, loop.m_index->offset,
loop.m_index->type_handler()); loop.m_index->type_handler());
if (splocal == NULL) if (splocal == NULL)
return true; return true;
@@ -5800,7 +5860,8 @@ bool LEX::sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop)
return true; return true;
Item *expr= new (thd->mem_root) Item_func_plus(thd, splocal, inc); Item *expr= new (thd->mem_root) Item_func_plus(thd, splocal, inc);
if (!expr || if (!expr ||
sphead->set_local_variable(thd, spcont, loop.m_index, expr, this, true)) sphead->set_local_variable(thd, spcont, &sp_rcontext_handler_local,
loop.m_index, expr, this, true))
return true; return true;
return false; return false;
} }
@@ -6000,6 +6061,31 @@ sp_name *LEX::make_sp_name(THD *thd, const LEX_CSTRING *name)
} }
/**
When a package routine name is stored in memory in Database_qualified_name,
the dot character is used to delimit package name from the routine name,
e.g.:
m_db= 'test'; -- database 'test'
m_name= 'p1.p1'; -- package 'p1', routine 'p1'
See database_qualified_name::make_package_routine_name() for details.
Disallow package routine names with dots,
to avoid ambiguity when interpreting m_name='p1.p1.p1', between:
a. package 'p1.p1' + routine 'p1'
b. package 'p1' + routine 'p1.p1'
m_name='p1.p1.p1' will always mean (a).
*/
sp_name *LEX::make_sp_name_package_routine(THD *thd, const LEX_CSTRING *name)
{
sp_name *res= make_sp_name(thd, name);
if (res && strchr(res->m_name.str, '.'))
{
my_error(ER_SP_WRONG_NAME, MYF(0), res->m_name.str);
res= NULL;
}
return res;
}
sp_name *LEX::make_sp_name(THD *thd, const LEX_CSTRING *name1, sp_name *LEX::make_sp_name(THD *thd, const LEX_CSTRING *name1,
const LEX_CSTRING *name2) const LEX_CSTRING *name2)
{ {
@@ -6022,15 +6108,25 @@ sp_name *LEX::make_sp_name(THD *thd, const LEX_CSTRING *name1,
sp_head *LEX::make_sp_head(THD *thd, const sp_name *name, sp_head *LEX::make_sp_head(THD *thd, const sp_name *name,
const Sp_handler *sph) const Sp_handler *sph)
{ {
sp_package *package= get_sp_package();
sp_head *sp; sp_head *sp;
/* Order is important here: new - reset - init */ /* Order is important here: new - reset - init */
if ((sp= new sp_head(sph))) if ((sp= new sp_head(package, sph)))
{ {
sp->reset_thd_mem_root(thd); sp->reset_thd_mem_root(thd);
sp->init(this); sp->init(this);
if (name) if (name)
sp->init_sp_name(name); {
if (package)
sp->make_package_routine_name(sp->get_main_mem_root(),
package->m_db,
package->m_name,
name->m_name);
else
sp->init_sp_name(name);
sp->make_qname(sp->get_main_mem_root(), &sp->m_qname);
}
sphead= sp; sphead= sp;
} }
sp_chistics.init(); sp_chistics.init();
@@ -6038,6 +6134,31 @@ 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 Sp_handler *sph)
{
sp_package *package= thd->lex->get_sp_package();
/*
Sp_handler::sp_clone_and_link_routine() generates a standalone-alike
statement to clone package routines for recursion, e.g.:
CREATE PROCEDURE p1 AS BEGIN NULL; END;
Translate a standalone routine handler to the corresponding
package routine handler if we're cloning a package routine, e.g.:
sp_handler_procedure -> sp_handler_package_procedure
sp_handler_function -> sp_handler_package_function
*/
if (package && package->m_is_cloning_routine)
sph= sph->package_routine_handler();
if (!sphead ||
(package &&
(sph == &sp_handler_package_procedure ||
sph == &sp_handler_package_function)))
return make_sp_head(thd, name, sph);
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), sph->type_str());
return NULL;
}
bool LEX::sp_body_finalize_procedure(THD *thd) bool LEX::sp_body_finalize_procedure(THD *thd)
{ {
if (sphead->check_unresolved_goto()) if (sphead->check_unresolved_goto())
@@ -6128,6 +6249,14 @@ LEX::sp_block_with_exceptions_finalize_exceptions(THD *thd,
} }
bool LEX::sp_block_with_exceptions_add_empty(THD *thd)
{
uint ip= sphead->instructions();
return sp_block_with_exceptions_finalize_executable_section(thd, ip) ||
sp_block_with_exceptions_finalize_exceptions(thd, ip, 0);
}
bool LEX::sp_change_context(THD *thd, const sp_pcontext *ctx, bool exclusive) bool LEX::sp_change_context(THD *thd, const sp_pcontext *ctx, bool exclusive)
{ {
uint n; uint n;
@@ -6546,6 +6675,7 @@ Item *LEX::create_item_ident_nospvar(THD *thd,
Item_splocal *LEX::create_item_spvar_row_field(THD *thd, Item_splocal *LEX::create_item_spvar_row_field(THD *thd,
const Sp_rcontext_handler *rh,
const LEX_CSTRING *a, const LEX_CSTRING *a,
const LEX_CSTRING *b, const LEX_CSTRING *b,
sp_variable *spv, sp_variable *spv,
@@ -6564,7 +6694,7 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd,
spv->field_def.is_cursor_rowtype_ref()) spv->field_def.is_cursor_rowtype_ref())
{ {
if (!(item= new (thd->mem_root) if (!(item= new (thd->mem_root)
Item_splocal_row_field_by_name(thd, a, b, spv->offset, Item_splocal_row_field_by_name(thd, rh, a, b, spv->offset,
&type_handler_null, &type_handler_null,
pos.pos(), pos.length()))) pos.pos(), pos.length())))
return NULL; return NULL;
@@ -6577,7 +6707,7 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd,
return NULL; return NULL;
if (!(item= new (thd->mem_root) if (!(item= new (thd->mem_root)
Item_splocal_row_field(thd, a, b, Item_splocal_row_field(thd, rh, a, b,
spv->offset, row_field_offset, spv->offset, row_field_offset,
def->type_handler(), def->type_handler(),
pos.pos(), pos.length()))) pos.pos(), pos.length())))
@@ -6591,12 +6721,27 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd,
} }
my_var *LEX::create_outvar(THD *thd, const LEX_CSTRING *name)
{
const Sp_rcontext_handler *rh;
sp_variable *spv;
if ((spv= find_variable(name, &rh)))
return result ? new (thd->mem_root)
my_var_sp(rh, name, spv->offset,
spv->type_handler(), sphead) :
NULL /* EXPLAIN */;
my_error(ER_SP_UNDECLARED_VAR, MYF(0), name->str);
return NULL;
}
my_var *LEX::create_outvar(THD *thd, my_var *LEX::create_outvar(THD *thd,
const LEX_CSTRING *a, const LEX_CSTRING *a,
const LEX_CSTRING *b) const LEX_CSTRING *b)
{ {
const Sp_rcontext_handler *rh;
sp_variable *t; sp_variable *t;
if (!spcont || !(t= spcont->find_variable(a, false))) if (!(t= find_variable(a, &rh)))
{ {
my_error(ER_SP_UNDECLARED_VAR, MYF(0), a->str); my_error(ER_SP_UNDECLARED_VAR, MYF(0), a->str);
return NULL; return NULL;
@@ -6605,9 +6750,9 @@ my_var *LEX::create_outvar(THD *thd,
if (!t->find_row_field(a, b, &row_field_offset)) if (!t->find_row_field(a, b, &row_field_offset))
return NULL; return NULL;
return result ? return result ?
new (thd->mem_root) my_var_sp_row_field(a, b, t->offset, new (thd->mem_root) my_var_sp_row_field(rh, a, b, t->offset,
row_field_offset, sphead) : row_field_offset, sphead) :
NULL; NULL /* EXPLAIN */;
} }
@@ -6677,12 +6822,13 @@ Item *LEX::create_item_ident(THD *thd,
const LEX_CSTRING *b, const LEX_CSTRING *b,
const char *start, const char *end) const char *start, const char *end)
{ {
const Sp_rcontext_handler *rh;
sp_variable *spv; sp_variable *spv;
if (spcont && (spv= spcont->find_variable(a, false)) && if ((spv= find_variable(a, &rh)) &&
(spv->field_def.is_row() || (spv->field_def.is_row() ||
spv->field_def.is_table_rowtype_ref() || spv->field_def.is_table_rowtype_ref() ||
spv->field_def.is_cursor_rowtype_ref())) spv->field_def.is_cursor_rowtype_ref()))
return create_item_spvar_row_field(thd, a, b, spv, start, end); return create_item_spvar_row_field(thd, rh, a, b, spv, start, end);
if ((thd->variables.sql_mode & MODE_ORACLE) && b->length == 7) if ((thd->variables.sql_mode & MODE_ORACLE) && b->length == 7)
{ {
@@ -6738,8 +6884,9 @@ Item *LEX::create_item_limit(THD *thd,
const LEX_CSTRING *a, const LEX_CSTRING *a,
const char *start, const char *end) const char *start, const char *end)
{ {
const Sp_rcontext_handler *rh;
sp_variable *spv; sp_variable *spv;
if (!spcont || !(spv= spcont->find_variable(a, false))) if (!(spv= find_variable(a, &rh)))
{ {
my_error(ER_SP_UNDECLARED_VAR, MYF(0), a->str); my_error(ER_SP_UNDECLARED_VAR, MYF(0), a->str);
return NULL; return NULL;
@@ -6747,7 +6894,7 @@ Item *LEX::create_item_limit(THD *thd,
Query_fragment pos(thd, sphead, start, end); Query_fragment pos(thd, sphead, start, end);
Item_splocal *item; Item_splocal *item;
if (!(item= new (thd->mem_root) Item_splocal(thd, a, if (!(item= new (thd->mem_root) Item_splocal(thd, rh, a,
spv->offset, spv->type_handler(), spv->offset, spv->type_handler(),
pos.pos(), pos.length()))) pos.pos(), pos.length())))
return NULL; return NULL;
@@ -6771,8 +6918,9 @@ Item *LEX::create_item_limit(THD *thd,
const LEX_CSTRING *b, const LEX_CSTRING *b,
const char *start, const char *end) const char *start, const char *end)
{ {
const Sp_rcontext_handler *rh;
sp_variable *spv; sp_variable *spv;
if (!spcont || !(spv= spcont->find_variable(a, false))) if (!(spv= find_variable(a, &rh)))
{ {
my_error(ER_SP_UNDECLARED_VAR, MYF(0), a->str); my_error(ER_SP_UNDECLARED_VAR, MYF(0), a->str);
return NULL; return NULL;
@@ -6780,7 +6928,7 @@ Item *LEX::create_item_limit(THD *thd,
// Qualified %TYPE variables are not possible // Qualified %TYPE variables are not possible
DBUG_ASSERT(!spv->field_def.column_type_ref()); DBUG_ASSERT(!spv->field_def.column_type_ref());
Item_splocal *item; Item_splocal *item;
if (!(item= create_item_spvar_row_field(thd, a, b, spv, start, end))) if (!(item= create_item_spvar_row_field(thd, rh, a, b, spv, start, end)))
return NULL; return NULL;
if (item->type() != Item::INT_ITEM) if (item->type() != Item::INT_ITEM)
{ {
@@ -6826,10 +6974,13 @@ bool LEX::set_variable(struct sys_var_with_base *variable, Item *item)
was previously checked by init_internal_variable(). was previously checked by init_internal_variable().
*/ */
DBUG_ASSERT(spcont); DBUG_ASSERT(spcont);
sp_variable *spv= spcont->find_variable(&variable->base_name, false); const Sp_rcontext_handler *rh;
sp_pcontext *ctx;
sp_variable *spv= find_variable(&variable->base_name, &ctx, &rh);
DBUG_ASSERT(spv); DBUG_ASSERT(spv);
/* It is a local variable. */ DBUG_ASSERT(ctx);
return sphead->set_local_variable(thd, spcont, spv, item, this, true); DBUG_ASSERT(rh);
return sphead->set_local_variable(thd, ctx, rh, spv, item, this, true);
} }
@@ -6849,10 +7000,11 @@ Item *LEX::create_item_ident_sp(THD *thd, LEX_CSTRING *name,
const char *start, const char *start,
const char *end) const char *end)
{ {
const Sp_rcontext_handler *rh;
sp_variable *spv; sp_variable *spv;
DBUG_ASSERT(spcont); DBUG_ASSERT(spcont);
DBUG_ASSERT(sphead); DBUG_ASSERT(sphead);
if ((spv= spcont->find_variable(name, false))) if ((spv= find_variable(name, &rh)))
{ {
/* We're compiling a stored procedure and found a variable */ /* We're compiling a stored procedure and found a variable */
if (!parsing_options.allows_variable) if (!parsing_options.allows_variable)
@@ -6863,11 +7015,11 @@ Item *LEX::create_item_ident_sp(THD *thd, LEX_CSTRING *name,
Query_fragment pos(thd, sphead, start, end); Query_fragment pos(thd, sphead, start, end);
Item_splocal *splocal= spv->field_def.is_column_type_ref() ? Item_splocal *splocal= spv->field_def.is_column_type_ref() ?
new (thd->mem_root) Item_splocal_with_delayed_data_type(thd, name, new (thd->mem_root) Item_splocal_with_delayed_data_type(thd, rh, name,
spv->offset, spv->offset,
pos.pos(), pos.pos(),
pos.length()) : pos.length()) :
new (thd->mem_root) Item_splocal(thd, name, new (thd->mem_root) Item_splocal(thd, rh, name,
spv->offset, spv->type_handler(), spv->offset, spv->type_handler(),
pos.pos(), pos.length()); pos.pos(), pos.length());
if (splocal == NULL) if (splocal == NULL)
@@ -6898,18 +7050,21 @@ bool LEX::set_variable(const LEX_CSTRING *name1,
const LEX_CSTRING *name2, const LEX_CSTRING *name2,
Item *item) Item *item)
{ {
const Sp_rcontext_handler *rh;
sp_pcontext *ctx;
sp_variable *spv; sp_variable *spv;
if (spcont && (spv= spcont->find_variable(name1, false))) if (spcont && (spv= find_variable(name1, &ctx, &rh)))
{ {
if (spv->field_def.is_table_rowtype_ref() || if (spv->field_def.is_table_rowtype_ref() ||
spv->field_def.is_cursor_rowtype_ref()) spv->field_def.is_cursor_rowtype_ref())
return sphead->set_local_variable_row_field_by_name(thd, spcont, return sphead->set_local_variable_row_field_by_name(thd, ctx,
rh,
spv, name2, spv, name2,
item, this); item, this);
// A field of a ROW variable // A field of a ROW variable
uint row_field_offset; uint row_field_offset;
return !spv->find_row_field(name1, name2, &row_field_offset) || return !spv->find_row_field(name1, name2, &row_field_offset) ||
sphead->set_local_variable_row_field(thd, spcont, sphead->set_local_variable_row_field(thd, ctx, rh,
spv, row_field_offset, spv, row_field_offset,
item, this); item, this);
} }
@@ -7330,12 +7485,18 @@ bool LEX::add_create_view(THD *thd, DDL_options_st ddl,
bool LEX::call_statement_start(THD *thd, sp_name *name) bool LEX::call_statement_start(THD *thd, sp_name *name)
{ {
Database_qualified_name pkgname(&null_clex_str, &null_clex_str);
const Sp_handler *sph= &sp_handler_procedure;
sql_command= SQLCOM_CALL; sql_command= SQLCOM_CALL;
spname= name;
value_list.empty(); value_list.empty();
if (!(m_sql_cmd= new (thd->mem_root) Sql_cmd_call(name))) if (sph->sp_resolve_package_routine(thd, thd->lex->sphead,
name, &sph, &pkgname))
return true; return true;
sp_handler_procedure.add_used_routine(this, thd, name); if (!(m_sql_cmd= new (thd->mem_root) Sql_cmd_call(name, sph)))
return true;
sph->add_used_routine(this, thd, name);
if (pkgname.m_name.length)
sp_handler_package_body.add_used_routine(this, thd, &pkgname);
return false; return false;
} }
@@ -7355,6 +7516,98 @@ bool LEX::call_statement_start(THD *thd, const LEX_CSTRING *name1,
} }
sp_package *LEX::get_sp_package() const
{
return sphead ? sphead->get_package() : NULL;
}
sp_package *LEX::create_package_start(THD *thd,
enum_sql_command command,
const Sp_handler *sph,
const sp_name *name_arg,
DDL_options_st options)
{
sp_package *pkg;
if (sphead)
{
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), sph->type_str());
return NULL;
}
if (set_command_with_check(command, options))
return NULL;
if (sph->type() == TYPE_ENUM_PACKAGE_BODY)
{
/*
If we start parsing a "CREATE PACKAGE BODY", we need to load
the corresponding "CREATE PACKAGE", for the following reasons:
1. "CREATE PACKAGE BODY" is allowed only if "CREATE PACKAGE"
was done earlier for the same package name.
So if "CREATE PACKAGE" does not exist, we throw an error here.
2. When parsing "CREATE PACKAGE BODY", we need to know all package
public and private routine names, to translate procedure and
function calls correctly.
For example, this statement inside a package routine:
CALL p;
can be translated to:
CALL db.pkg.p; -- p is a known (public or private) package routine
CALL db.p; -- p is not a known package routine
*/
sp_head *spec;
int ret= sp_handler_package_spec.
sp_cache_routine_reentrant(thd, name_arg, &spec);
if (!spec)
{
if (!ret)
my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
"PACKAGE", ErrConvDQName(name_arg).ptr());
return 0;
}
}
if (!(pkg= new sp_package(this, name_arg, sph)))
return NULL;
pkg->reset_thd_mem_root(thd);
pkg->init(this);
pkg->make_qname(pkg->get_main_mem_root(), &pkg->m_qname);
sphead= pkg;
return pkg;
}
bool LEX::create_package_finalize(THD *thd,
const sp_name *name,
const sp_name *name2,
const char *body_start,
const char *body_end)
{
if (name2 &&
(name2->m_explicit_name != name->m_explicit_name ||
strcmp(name2->m_db.str, name->m_db.str) ||
!Sp_handler::eq_routine_name(name2->m_name, name->m_name)))
{
bool exp= name2->m_explicit_name || name->m_explicit_name;
my_error(ER_END_IDENTIFIER_DOES_NOT_MATCH, MYF(0),
exp ? ErrConvDQName(name2).ptr() : name2->m_name.str,
exp ? ErrConvDQName(name).ptr() : name->m_name.str);
return true;
}
sphead->m_body.length= body_end - body_start;
if (!(sphead->m_body.str= thd->strmake(body_start, sphead->m_body.length)))
return true;
uint not_used;
Lex_input_stream *lip= & thd->m_parser_state->m_lip;
sphead->m_defstr.length= lip->get_cpp_ptr() - lip->get_cpp_buf();
sphead->m_defstr.str= thd->strmake(lip->get_cpp_buf(), sphead->m_defstr.length);
trim_whitespace(thd->charset(), &sphead->m_defstr, &not_used);
sphead->restore_thd_mem_root(thd);
sp_package *pkg= sphead->get_package();
DBUG_ASSERT(pkg);
return pkg->validate_after_parser(thd);
}
bool LEX::add_grant_command(THD *thd, enum_sql_command sql_command_arg, bool LEX::add_grant_command(THD *thd, enum_sql_command sql_command_arg,
stored_procedure_type type_arg) stored_procedure_type type_arg)
{ {

View File

@@ -2311,6 +2311,19 @@ public:
return m_cpp_ptr; return m_cpp_ptr;
} }
/**
Get the current stream pointer, in the pre-processed buffer,
with traling spaces removed.
*/
const char *get_cpp_ptr_rtrim()
{
const char *p;
for (p= m_cpp_ptr;
p > m_cpp_buf && my_isspace(system_charset_info, p[-1]);
p--)
{ }
return p;
}
/** Get the utf8-body string. */ /** Get the utf8-body string. */
const char *get_body_utf8_str() const char *get_body_utf8_str()
{ {
@@ -3176,15 +3189,10 @@ public:
sp_name *make_sp_name(THD *thd, const LEX_CSTRING *name); sp_name *make_sp_name(THD *thd, const LEX_CSTRING *name);
sp_name *make_sp_name(THD *thd, const LEX_CSTRING *name1, sp_name *make_sp_name(THD *thd, const LEX_CSTRING *name1,
const LEX_CSTRING *name2); const LEX_CSTRING *name2);
sp_name *make_sp_name_package_routine(THD *thd, const LEX_CSTRING *name);
sp_head *make_sp_head(THD *thd, const sp_name *name, const Sp_handler *sph); sp_head *make_sp_head(THD *thd, const sp_name *name, const Sp_handler *sph);
sp_head *make_sp_head_no_recursive(THD *thd, const sp_name *name, sp_head *make_sp_head_no_recursive(THD *thd, const sp_name *name,
const Sp_handler *sph) const Sp_handler *sph);
{
if (!sphead)
return make_sp_head(thd, name, sph);
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), sph->type_str());
return NULL;
}
sp_head *make_sp_head_no_recursive(THD *thd, sp_head *make_sp_head_no_recursive(THD *thd,
DDL_options_st options, sp_name *name, DDL_options_st options, sp_name *name,
const Sp_handler *sph) const Sp_handler *sph)
@@ -3195,10 +3203,29 @@ public:
} }
bool sp_body_finalize_function(THD *); bool sp_body_finalize_function(THD *);
bool sp_body_finalize_procedure(THD *); bool sp_body_finalize_procedure(THD *);
sp_package *create_package_start(THD *thd,
enum_sql_command command,
const Sp_handler *sph,
const sp_name *name,
DDL_options_st options);
bool create_package_finalize(THD *thd,
const sp_name *name,
const sp_name *name2,
const char *body_start,
const char *body_end);
bool call_statement_start(THD *thd, sp_name *name); bool call_statement_start(THD *thd, sp_name *name);
bool call_statement_start(THD *thd, const LEX_CSTRING *name); bool call_statement_start(THD *thd, const LEX_CSTRING *name);
bool call_statement_start(THD *thd, const LEX_CSTRING *name1, bool call_statement_start(THD *thd, const LEX_CSTRING *name1,
const LEX_CSTRING *name2); const LEX_CSTRING *name2);
sp_variable *find_variable(const LEX_CSTRING *name,
sp_pcontext **ctx,
const Sp_rcontext_handler **rh) const;
sp_variable *find_variable(const LEX_CSTRING *name,
const Sp_rcontext_handler **rh) const
{
sp_pcontext *not_used_ctx;
return find_variable(name, &not_used_ctx, rh);
}
bool init_internal_variable(struct sys_var_with_base *variable, bool init_internal_variable(struct sys_var_with_base *variable,
const LEX_CSTRING *name); const LEX_CSTRING *name);
bool init_internal_variable(struct sys_var_with_base *variable, bool init_internal_variable(struct sys_var_with_base *variable,
@@ -3282,6 +3309,7 @@ public:
/* /*
Create an Item corresponding to a ROW field valiable: var.field Create an Item corresponding to a ROW field valiable: var.field
@param THD - THD, for mem_root @param THD - THD, for mem_root
@param rh [OUT] - the rcontext handler (local vs package variables)
@param var - the ROW variable name @param var - the ROW variable name
@param field - the ROW variable field name @param field - the ROW variable field name
@param spvar - the variable that was previously found by name @param spvar - the variable that was previously found by name
@@ -3290,6 +3318,7 @@ public:
@param end - end in the query (for binary log) @param end - end in the query (for binary log)
*/ */
Item_splocal *create_item_spvar_row_field(THD *thd, Item_splocal *create_item_spvar_row_field(THD *thd,
const Sp_rcontext_handler *rh,
const LEX_CSTRING *var, const LEX_CSTRING *var,
const LEX_CSTRING *field, const LEX_CSTRING *field,
sp_variable *spvar, sp_variable *spvar,
@@ -3383,6 +3412,8 @@ public:
Item *make_item_func_replace(THD *thd, Item *org, Item *find, Item *replace); Item *make_item_func_replace(THD *thd, Item *org, Item *find, Item *replace);
Item *make_item_func_substr(THD *thd, Item *a, Item *b, Item *c); Item *make_item_func_substr(THD *thd, Item *a, Item *b, Item *c);
Item *make_item_func_substr(THD *thd, Item *a, Item *b); Item *make_item_func_substr(THD *thd, Item *a, Item *b);
my_var *create_outvar(THD *thd, const LEX_CSTRING *name);
/* /*
Create a my_var instance for a ROW field variable that was used Create a my_var instance for a ROW field variable that was used
as an OUT SP parameter: CALL p1(var.field); as an OUT SP parameter: CALL p1(var.field);
@@ -3443,6 +3474,7 @@ public:
bool sp_block_with_exceptions_finalize_exceptions(THD *thd, bool sp_block_with_exceptions_finalize_exceptions(THD *thd,
uint executable_section_ip, uint executable_section_ip,
uint exception_count); uint exception_count);
bool sp_block_with_exceptions_add_empty(THD *thd);
bool sp_exit_statement(THD *thd, Item *when); bool sp_exit_statement(THD *thd, Item *when);
bool sp_exit_statement(THD *thd, const LEX_CSTRING *label_name, Item *item); bool sp_exit_statement(THD *thd, const LEX_CSTRING *label_name, Item *item);
bool sp_leave_statement(THD *thd, const LEX_CSTRING *label_name); bool sp_leave_statement(THD *thd, const LEX_CSTRING *label_name);
@@ -3685,6 +3717,7 @@ public:
bool add_grant_command(THD *thd, enum_sql_command sql_command_arg, bool add_grant_command(THD *thd, enum_sql_command sql_command_arg,
stored_procedure_type type_arg); stored_procedure_type type_arg);
sp_package *get_sp_package() const;
}; };

View File

@@ -559,6 +559,10 @@ void init_update_queries(void)
CF_INSERTS_DATA; CF_INSERTS_DATA;
sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE; sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE;
sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE; sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE;
sql_command_flags[SQLCOM_CREATE_PACKAGE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_PACKAGE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_CREATE_PACKAGE_BODY]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_PACKAGE_BODY]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
@@ -632,6 +636,8 @@ void init_update_queries(void)
CF_OPTIMIZER_TRACE; // (1) CF_OPTIMIZER_TRACE; // (1)
sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_STATUS_PACKAGE]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_STATUS_PACKAGE_BODY]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
@@ -666,10 +672,13 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_PACKAGE]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_PACKAGE_BODY]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_PROC_CODE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_PROC_CODE]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_FUNC_CODE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_FUNC_CODE]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_PACKAGE_BODY_CODE]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_PROFILES]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_PROFILES]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND;
@@ -830,6 +839,10 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_DROP_INDEX]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_INDEX]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_DB]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_DB]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_DB]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_DB]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_PACKAGE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_PACKAGE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_PACKAGE_BODY]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_PACKAGE_BODY]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_DB]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_ALTER_DB]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_VIEW]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_VIEW]|= CF_DISALLOW_IN_RO_TRANS;
@@ -3115,7 +3128,7 @@ bool Sql_cmd_call::execute(THD *thd)
By this moment all needed SPs should be in cache so no need to look By this moment all needed SPs should be in cache so no need to look
into DB. into DB.
*/ */
if (!(sp= sp_handler_procedure.sp_find_routine(thd, m_name, true))) if (!(sp= m_handler->sp_find_routine(thd, m_name, true)))
{ {
/* /*
If the routine is not found, let's still check EXECUTE_ACL to decide If the routine is not found, let's still check EXECUTE_ACL to decide
@@ -3678,6 +3691,8 @@ mysql_execute_command(THD *thd)
/* fall through */ /* fall through */
case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_PROC:
case SQLCOM_SHOW_STATUS_FUNC: case SQLCOM_SHOW_STATUS_FUNC:
case SQLCOM_SHOW_STATUS_PACKAGE:
case SQLCOM_SHOW_STATUS_PACKAGE_BODY:
case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_DATABASES:
case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_TRIGGERS: case SQLCOM_SHOW_TRIGGERS:
@@ -5831,6 +5846,8 @@ end_with_restore_list:
break; break;
case SQLCOM_CREATE_PROCEDURE: case SQLCOM_CREATE_PROCEDURE:
case SQLCOM_CREATE_SPFUNCTION: case SQLCOM_CREATE_SPFUNCTION:
case SQLCOM_CREATE_PACKAGE:
case SQLCOM_CREATE_PACKAGE_BODY:
{ {
if (mysql_create_routine(thd, lex)) if (mysql_create_routine(thd, lex))
goto error; goto error;
@@ -5880,6 +5897,8 @@ end_with_restore_list:
} }
case SQLCOM_DROP_PROCEDURE: case SQLCOM_DROP_PROCEDURE:
case SQLCOM_DROP_FUNCTION: case SQLCOM_DROP_FUNCTION:
case SQLCOM_DROP_PACKAGE:
case SQLCOM_DROP_PACKAGE_BODY:
{ {
#ifdef HAVE_DLOPEN #ifdef HAVE_DLOPEN
if (lex->sql_command == SQLCOM_DROP_FUNCTION && if (lex->sql_command == SQLCOM_DROP_FUNCTION &&
@@ -5996,6 +6015,8 @@ end_with_restore_list:
} }
case SQLCOM_SHOW_CREATE_PROC: case SQLCOM_SHOW_CREATE_PROC:
case SQLCOM_SHOW_CREATE_FUNC: case SQLCOM_SHOW_CREATE_FUNC:
case SQLCOM_SHOW_CREATE_PACKAGE:
case SQLCOM_SHOW_CREATE_PACKAGE_BODY:
{ {
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
const Sp_handler *sph= Sp_handler::handler(lex->sql_command); const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
@@ -6005,11 +6026,19 @@ end_with_restore_list:
} }
case SQLCOM_SHOW_PROC_CODE: case SQLCOM_SHOW_PROC_CODE:
case SQLCOM_SHOW_FUNC_CODE: case SQLCOM_SHOW_FUNC_CODE:
case SQLCOM_SHOW_PACKAGE_BODY_CODE:
{ {
#ifndef DBUG_OFF #ifndef DBUG_OFF
Database_qualified_name pkgname(&null_clex_str, &null_clex_str);
sp_head *sp; sp_head *sp;
const Sp_handler *sph= Sp_handler::handler(lex->sql_command); const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
#ifdef WITH_WSREP
if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
#endif /* WITH_WSREP */
if (sph->sp_resolve_package_routine(thd, thd->lex->sphead,
lex->spname, &sph, &pkgname))
return true;
if (sph->sp_cache_routine(thd, lex->spname, false, &sp)) if (sph->sp_cache_routine(thd, lex->spname, false, &sp))
goto error; goto error;
if (!sp || sp->show_routine_code(thd)) if (!sp || sp->show_routine_code(thd))
@@ -7966,6 +7995,8 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
THD_STAGE_INFO(thd, stage_freeing_items); THD_STAGE_INFO(thd, stage_freeing_items);
sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size); sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size); sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_package_spec_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_package_body_cache, stored_program_cache_size);
thd->end_statement(); thd->end_statement();
thd->cleanup_after_query(); thd->cleanup_after_query();
DBUG_ASSERT(thd->Item_change_list::is_empty()); DBUG_ASSERT(thd->Item_change_list::is_empty());

View File

@@ -2313,6 +2313,8 @@ static bool check_prepared_statement(Prepared_statement *stmt)
case SQLCOM_SHOW_TABLE_STATUS: case SQLCOM_SHOW_TABLE_STATUS:
case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_PROC:
case SQLCOM_SHOW_STATUS_FUNC: case SQLCOM_SHOW_STATUS_FUNC:
case SQLCOM_SHOW_STATUS_PACKAGE:
case SQLCOM_SHOW_STATUS_PACKAGE_BODY:
case SQLCOM_SELECT: case SQLCOM_SELECT:
res= mysql_test_select(stmt, tables); res= mysql_test_select(stmt, tables);
if (res == 2) if (res == 2)
@@ -2385,6 +2387,21 @@ static bool check_prepared_statement(Prepared_statement *stmt)
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
break; break;
case SQLCOM_SHOW_CREATE_PACKAGE:
if ((res= mysql_test_show_create_routine(stmt, &sp_handler_package_spec)) == 2)
{
/* Statement and field info has already been sent */
DBUG_RETURN(FALSE);
}
break;
case SQLCOM_SHOW_CREATE_PACKAGE_BODY:
if ((res= mysql_test_show_create_routine(stmt,
&sp_handler_package_body)) == 2)
{
/* Statement and field info has already been sent */
DBUG_RETURN(FALSE);
}
break;
case SQLCOM_CREATE_VIEW: case SQLCOM_CREATE_VIEW:
if (lex->create_view->mode == VIEW_ALTER) if (lex->create_view->mode == VIEW_ALTER)
{ {
@@ -2589,6 +2606,8 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length)
sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size); sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size); sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_package_spec_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_package_body_cache, stored_program_cache_size);
/* check_prepared_statemnt sends the metadata packet in case of success */ /* check_prepared_statemnt sends the metadata packet in case of success */
end: end:
@@ -3155,6 +3174,8 @@ static void mysql_stmt_execute_common(THD *thd,
sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size); sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size); sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_package_spec_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_package_body_cache, stored_program_cache_size);
/* Close connection socket; for use with client testing (Bug#43560). */ /* Close connection socket; for use with client testing (Bug#43560). */
DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio);); DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio););

View File

@@ -2459,6 +2459,17 @@ static const LEX_CSTRING *view_algorithm(TABLE_LIST *table)
} }
} }
static bool append_at_host(THD *thd, String *buffer, const LEX_CSTRING *host)
{
if (!host->str || !host->str[0])
return false;
return
buffer->append('@') ||
append_identifier(thd, buffer, host->str, host->length);
}
/* /*
Append DEFINER clause to the given buffer. Append DEFINER clause to the given buffer.
@@ -2470,17 +2481,14 @@ static const LEX_CSTRING *view_algorithm(TABLE_LIST *table)
definer_host [in] host name part of definer definer_host [in] host name part of definer
*/ */
void append_definer(THD *thd, String *buffer, const LEX_CSTRING *definer_user, bool append_definer(THD *thd, String *buffer, const LEX_CSTRING *definer_user,
const LEX_CSTRING *definer_host) const LEX_CSTRING *definer_host)
{ {
buffer->append(STRING_WITH_LEN("DEFINER=")); return
append_identifier(thd, buffer, definer_user->str, definer_user->length); buffer->append(STRING_WITH_LEN("DEFINER=")) ||
if (definer_host->str && definer_host->str[0]) append_identifier(thd, buffer, definer_user->str, definer_user->length) ||
{ append_at_host(thd, buffer, definer_host) ||
buffer->append('@'); buffer->append(' ');
append_identifier(thd, buffer, definer_host->str, definer_host->length);
}
buffer->append(' ');
} }
@@ -8857,7 +8865,7 @@ ST_FIELD_INFO proc_fields_info[]=
SKIP_OPEN_TABLE}, SKIP_OPEN_TABLE},
{"ROUTINE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name", {"ROUTINE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
SKIP_OPEN_TABLE}, SKIP_OPEN_TABLE},
{"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE}, {"ROUTINE_TYPE", 13, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
{"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE}, {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
{"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE}, {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},

View File

@@ -103,7 +103,7 @@ bool mysqld_show_contributors(THD *thd);
bool mysqld_show_privileges(THD *thd); bool mysqld_show_privileges(THD *thd);
char *make_backup_log_name(char *buff, const char *name, const char* log_ext); char *make_backup_log_name(char *buff, const char *name, const char* log_ext);
uint calc_sum_of_all_status(STATUS_VAR *to); uint calc_sum_of_all_status(STATUS_VAR *to);
void append_definer(THD *thd, String *buffer, const LEX_CSTRING *definer_user, bool append_definer(THD *thd, String *buffer, const LEX_CSTRING *definer_user,
const LEX_CSTRING *definer_host); const LEX_CSTRING *definer_host);
int add_status_vars(SHOW_VAR *list); int add_status_vars(SHOW_VAR *list);
void remove_status_vars(SHOW_VAR *list); void remove_status_vars(SHOW_VAR *list);

View File

@@ -2249,7 +2249,8 @@ add_tables_and_routines_for_triggers(THD *thd,
MDL_key key(MDL_key::TRIGGER, trigger->m_db.str, trigger->m_name.str); MDL_key key(MDL_key::TRIGGER, trigger->m_db.str, trigger->m_name.str);
if (sp_add_used_routine(prelocking_ctx, thd->stmt_arena, if (sp_add_used_routine(prelocking_ctx, thd->stmt_arena,
&key, table_list->belong_to_view)) &key, &sp_handler_trigger,
table_list->belong_to_view))
{ {
trigger->add_used_tables_to_table_list(thd, trigger->add_used_tables_to_table_list(thd,
&prelocking_ctx->query_tables_last, &prelocking_ctx->query_tables_last,

View File

@@ -376,12 +376,13 @@ Item_splocal*
LEX::create_item_for_sp_var(LEX_CSTRING *name, sp_variable *spvar, LEX::create_item_for_sp_var(LEX_CSTRING *name, sp_variable *spvar,
const char *start_in_q, const char *end_in_q) const char *start_in_q, const char *end_in_q)
{ {
const Sp_rcontext_handler *rh;
Item_splocal *item; Item_splocal *item;
uint pos_in_q, len_in_q; uint pos_in_q, len_in_q;
/* If necessary, look for the variable. */ /* If necessary, look for the variable. */
if (spcont && !spvar) if (spcont && !spvar)
spvar= spcont->find_variable(name, false); spvar= find_variable(name, &rh);
if (!spvar) if (!spvar)
{ {
@@ -396,7 +397,7 @@ LEX::create_item_for_sp_var(LEX_CSTRING *name, sp_variable *spvar,
len_in_q= (uint)(end_in_q - start_in_q); len_in_q= (uint)(end_in_q - start_in_q);
item= new (thd->mem_root) item= new (thd->mem_root)
Item_splocal(thd, name, spvar->offset, spvar->type_handler(), Item_splocal(thd, rh, name, spvar->offset, spvar->type_handler(),
pos_in_q, len_in_q); pos_in_q, len_in_q);
#ifndef DBUG_OFF #ifndef DBUG_OFF
@@ -932,6 +933,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token BIT_XOR /* MYSQL-FUNC */ %token BIT_XOR /* MYSQL-FUNC */
%token BLOB_SYM /* SQL-2003-R */ %token BLOB_SYM /* SQL-2003-R */
%token BLOCK_SYM %token BLOCK_SYM
%token BODY_SYM /* Oracle-R */
%token BOOLEAN_SYM /* SQL-2003-R */ %token BOOLEAN_SYM /* SQL-2003-R */
%token BOOL_SYM %token BOOL_SYM
%token BOTH /* SQL-2003-R */ %token BOTH /* SQL-2003-R */
@@ -1316,6 +1318,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token OUT_SYM /* SQL-2003-R */ %token OUT_SYM /* SQL-2003-R */
%token OVER_SYM %token OVER_SYM
%token OWNER_SYM %token OWNER_SYM
%token PACKAGE_SYM /* Oracle-R */
%token PACK_KEYS_SYM %token PACK_KEYS_SYM
%token PAGE_SYM %token PAGE_SYM
%token PAGE_CHECKSUM_SYM %token PAGE_CHECKSUM_SYM
@@ -12284,14 +12287,8 @@ select_outvar:
} }
| ident_or_text | ident_or_text
{ {
sp_variable *t; if (!($$= Lex->create_outvar(thd, &$1)) && Lex->result)
MYSQL_YYABORT;
if (!Lex->spcont || !(t= Lex->spcont->find_variable(&$1, false)))
my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str));
$$ = Lex->result ? (new (thd->mem_root)
my_var_sp(&$1, t->offset, t->type_handler(),
Lex->sphead)) :
NULL;
} }
| ident '.' ident | ident '.' ident
{ {
@@ -13301,6 +13298,18 @@ show_param:
lex->sql_command = SQLCOM_SHOW_CREATE_FUNC; lex->sql_command = SQLCOM_SHOW_CREATE_FUNC;
lex->spname= $3; lex->spname= $3;
} }
| CREATE PACKAGE_SYM sp_name
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE;
lex->spname= $3;
}
| CREATE PACKAGE_SYM BODY_SYM sp_name
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE_BODY;
lex->spname= $4;
}
| CREATE TRIGGER_SYM sp_name | CREATE TRIGGER_SYM sp_name
{ {
LEX *lex= Lex; LEX *lex= Lex;
@@ -13333,6 +13342,20 @@ show_param:
if (prepare_schema_table(thd, lex, 0, SCH_PROCEDURES)) if (prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| PACKAGE_SYM STATUS_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE;
if (prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))
MYSQL_YYABORT;
}
| PACKAGE_SYM BODY_SYM STATUS_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE_BODY;
if (prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))
MYSQL_YYABORT;
}
| PROCEDURE_SYM CODE_SYM sp_name | PROCEDURE_SYM CODE_SYM sp_name
{ {
Lex->sql_command= SQLCOM_SHOW_PROC_CODE; Lex->sql_command= SQLCOM_SHOW_PROC_CODE;
@@ -13343,6 +13366,11 @@ show_param:
Lex->sql_command= SQLCOM_SHOW_FUNC_CODE; Lex->sql_command= SQLCOM_SHOW_FUNC_CODE;
Lex->spname= $3; Lex->spname= $3;
} }
| PACKAGE_SYM BODY_SYM CODE_SYM sp_name
{
Lex->sql_command= SQLCOM_SHOW_PACKAGE_BODY_CODE;
Lex->spname= $4;
}
| CREATE EVENT_SYM sp_name | CREATE EVENT_SYM sp_name
{ {
Lex->spname= $3; Lex->spname= $3;
@@ -14836,6 +14864,7 @@ keyword_sp_not_data_type:
| AVG_ROW_LENGTH {} | AVG_ROW_LENGTH {}
| AVG_SYM {} | AVG_SYM {}
| BLOCK_SYM {} | BLOCK_SYM {}
| BODY_SYM {}
| BTREE_SYM {} | BTREE_SYM {}
| CASCADED {} | CASCADED {}
| CATALOG_NAME_SYM {} | CATALOG_NAME_SYM {}
@@ -15008,6 +15037,7 @@ keyword_sp_not_data_type:
| ONE_SYM {} | ONE_SYM {}
| ONLINE_SYM {} | ONLINE_SYM {}
| ONLY_SYM {} | ONLY_SYM {}
| PACKAGE_SYM {}
| PACK_KEYS_SYM {} | PACK_KEYS_SYM {}
| PAGE_SYM {} | PAGE_SYM {}
| PARTIAL {} | PARTIAL {}

View File

@@ -237,6 +237,7 @@ void ORAerror(THD *thd, const char *s)
st_trg_execution_order trg_execution_order; st_trg_execution_order trg_execution_order;
/* enums */ /* enums */
enum enum_sp_suid_behaviour sp_suid;
enum enum_view_suid view_suid; enum enum_view_suid view_suid;
enum sub_select_type unit_type; enum sub_select_type unit_type;
enum Condition_information_item::Name cond_info_item_name; enum Condition_information_item::Name cond_info_item_name;
@@ -341,6 +342,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token BIT_XOR /* MYSQL-FUNC */ %token BIT_XOR /* MYSQL-FUNC */
%token BLOB_SYM /* SQL-2003-R */ %token BLOB_SYM /* SQL-2003-R */
%token BLOCK_SYM %token BLOCK_SYM
%token BODY_SYM /* Oracle-R */
%token BOOLEAN_SYM /* SQL-2003-R */ %token BOOLEAN_SYM /* SQL-2003-R */
%token BOOL_SYM %token BOOL_SYM
%token BOTH /* SQL-2003-R */ %token BOTH /* SQL-2003-R */
@@ -725,6 +727,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token OUT_SYM /* SQL-2003-R */ %token OUT_SYM /* SQL-2003-R */
%token OVER_SYM %token OVER_SYM
%token OWNER_SYM %token OWNER_SYM
%token PACKAGE_SYM /* Oracle-R */
%token PACK_KEYS_SYM %token PACK_KEYS_SYM
%token PAGE_SYM %token PAGE_SYM
%token PAGE_CHECKSUM_SYM %token PAGE_CHECKSUM_SYM
@@ -1027,6 +1030,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
sp_opt_label BIN_NUM TEXT_STRING_filesystem ident_or_empty sp_opt_label BIN_NUM TEXT_STRING_filesystem ident_or_empty
opt_constraint constraint opt_ident opt_constraint constraint opt_ident
ident_directly_assignable ident_directly_assignable
opt_package_routine_end_name
sp_decl_ident sp_decl_ident
sp_block_label opt_place opt_db sp_block_label opt_place opt_db
@@ -1053,7 +1057,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
optionally_qualified_column_ident optionally_qualified_column_ident
%type <simple_string> %type <simple_string>
remember_name remember_end remember_tok_start remember_name remember_end remember_end_opt remember_tok_start
wild_and_where wild_and_where
colon_with_pos colon_with_pos
@@ -1314,7 +1318,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_extended_describe shutdown opt_extended_describe shutdown
opt_format_json opt_format_json
prepare prepare_src execute deallocate prepare prepare_src execute deallocate
statement sp_suid statement
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
opt_field_or_var_spec fields_or_vars opt_load_data_set_spec opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
view_list_opt view_list view_select view_list_opt view_list view_select
@@ -1356,17 +1360,28 @@ END_OF_INPUT
%type <num> view_algorithm view_check_option %type <num> view_algorithm view_check_option
%type <view_suid> view_suid opt_view_suid %type <view_suid> view_suid opt_view_suid
%type <sp_suid> sp_suid
%type <num> sp_decl_idents sp_decl_idents_init_vars %type <num> sp_decl_idents sp_decl_idents_init_vars
%type <num> sp_handler_type sp_hcond_list %type <num> sp_handler_type sp_hcond_list
%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value %type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value
%type <spblock> sp_decl_body_list opt_sp_decl_body_list %type <spblock> sp_decl_body_list opt_sp_decl_body_list
%type <spblock> sp_decl_vars
%type <spblock> sp_decl_non_handler sp_decl_non_handler_list %type <spblock> sp_decl_non_handler sp_decl_non_handler_list
%type <spblock> sp_decl_handler sp_decl_handler_list opt_sp_decl_handler_list %type <spblock> sp_decl_handler sp_decl_handler_list opt_sp_decl_handler_list
%type <spblock> package_implementation_routine_definition
%type <spblock> package_implementation_item_declaration
%type <spblock> package_implementation_declare_section
%type <spblock> package_implementation_declare_section_list1
%type <spblock> package_implementation_declare_section_list2
%type <spblock_handlers> sp_block_statements_and_exceptions %type <spblock_handlers> sp_block_statements_and_exceptions
%type <spblock_handlers> package_implementation_executable_section
%type <sp_instr_addr> sp_instr_addr %type <sp_instr_addr> sp_instr_addr
%type <sp_cursor_name_and_offset> sp_cursor_name_and_offset %type <sp_cursor_name_and_offset> sp_cursor_name_and_offset
%type <num> opt_exception_clause exception_handlers %type <num> opt_exception_clause exception_handlers
%type <lex> remember_lex package_routine_lex
package_specification_function
package_specification_procedure
%type <spname> sp_name opt_sp_name %type <spname> sp_name opt_sp_name
%type <spvar> sp_param_name sp_param_name_and_type %type <spvar> sp_param_name sp_param_name_and_type
%type <for_loop> sp_for_loop_index_and_bounds %type <for_loop> sp_for_loop_index_and_bounds
@@ -2095,6 +2110,243 @@ create:
| create_or_replace { Lex->set_command(SQLCOM_CREATE_SERVER, $1); } | create_or_replace { Lex->set_command(SQLCOM_CREATE_SERVER, $1); }
server_def server_def
{ } { }
| create_or_replace definer_opt PACKAGE_SYM
opt_if_not_exists sp_name opt_create_package_chistics_init
sp_tail_is
remember_name
{
sp_package *pkg;
if (!(pkg= Lex->create_package_start(thd,
SQLCOM_CREATE_PACKAGE,
&sp_handler_package_spec,
$5, $1 | $4)))
MYSQL_YYABORT;
pkg->set_chistics(Lex->sp_chistics);
}
opt_package_specification_element_list END
remember_end_opt opt_sp_name
{
if (Lex->create_package_finalize(thd, $5, $13, $8, $12))
MYSQL_YYABORT;
}
| create_or_replace definer_opt PACKAGE_SYM BODY_SYM
opt_if_not_exists sp_name opt_create_package_chistics_init
sp_tail_is
remember_name
{
sp_package *pkg;
if (!(pkg= Lex->create_package_start(thd,
SQLCOM_CREATE_PACKAGE_BODY,
&sp_handler_package_body,
$6, $1 | $5)))
MYSQL_YYABORT;
pkg->set_chistics(Lex->sp_chistics);
Lex->sp_block_init(thd);
}
package_implementation_declare_section
{
if (Lex->sp_block_with_exceptions_finalize_declarations(thd))
MYSQL_YYABORT;
}
package_implementation_executable_section
{
$11.hndlrs+= $13.hndlrs;
if (Lex->sp_block_finalize(thd, $11))
MYSQL_YYABORT;
}
remember_end_opt opt_sp_name
{
if (Lex->create_package_finalize(thd, $6, $16, $9, $15))
MYSQL_YYABORT;
}
;
package_implementation_executable_section:
END
{
if (Lex->sp_block_with_exceptions_add_empty(thd))
MYSQL_YYABORT;
$$.init(0);
}
| BEGIN_SYM sp_block_statements_and_exceptions END { $$= $2; }
;
/*
Inside CREATE PACKATE BODY, package-wide items (e.g. variables)
must be declared before routine definitions.
*/
package_implementation_declare_section:
package_implementation_declare_section_list1
| package_implementation_declare_section_list2
| package_implementation_declare_section_list1
package_implementation_declare_section_list2
{ $$.join($1, $2); }
;
package_implementation_declare_section_list1:
package_implementation_item_declaration
| package_implementation_declare_section_list1
package_implementation_item_declaration
{ $$.join($1, $2); }
;
package_implementation_declare_section_list2:
package_implementation_routine_definition
| package_implementation_declare_section_list2
package_implementation_routine_definition
{ $$.join($1, $2); }
;
package_routine_lex:
{
if (!($$= new (thd->mem_root) sp_lex_local(thd, thd->lex)))
MYSQL_YYABORT;
thd->m_parser_state->m_yacc.reset_before_substatement();
}
;
package_specification_function:
remember_lex package_routine_lex ident
{
DBUG_ASSERT($1->sphead->get_package());
$2->sql_command= SQLCOM_CREATE_FUNCTION;
sp_name *spname= $1->make_sp_name_package_routine(thd, &$3);
if (!spname)
MYSQL_YYABORT;
thd->lex= $2;
if (!$2->make_sp_head_no_recursive(thd, spname,
&sp_handler_package_function))
MYSQL_YYABORT;
$1->sphead->get_package()->m_current_routine= $2;
(void) is_native_function_with_warn(thd, &$3);
}
opt_sp_parenthesized_fdparam_list
sf_return_type
sp_c_chistics
{
sp_head *sp= thd->lex->sphead;
sp->restore_thd_mem_root(thd);
thd->lex= $1;
$$= $2;
}
;
package_specification_procedure:
remember_lex package_routine_lex ident
{
DBUG_ASSERT($1->sphead->get_package());
$2->sql_command= SQLCOM_CREATE_PROCEDURE;
sp_name *spname= $1->make_sp_name_package_routine(thd, &$3);
if (!spname)
MYSQL_YYABORT;
thd->lex= $2;
if (!$2->make_sp_head_no_recursive(thd, spname,
&sp_handler_package_procedure))
MYSQL_YYABORT;
$1->sphead->get_package()->m_current_routine= $2;
}
opt_sp_parenthesized_pdparam_list
sp_c_chistics
{
sp_head *sp= thd->lex->sphead;
sp->restore_thd_mem_root(thd);
thd->lex= $1;
$$= $2;
}
;
package_implementation_routine_definition:
FUNCTION_SYM package_specification_function
package_implementation_function_body ';'
{
sp_package *pkg= Lex->get_sp_package();
if (pkg->add_routine_implementation($2))
MYSQL_YYABORT;
pkg->m_current_routine= NULL;
$$.init();
}
| PROCEDURE_SYM package_specification_procedure
package_implementation_procedure_body ';'
{
sp_package *pkg= Lex->get_sp_package();
if (pkg->add_routine_implementation($2))
MYSQL_YYABORT;
pkg->m_current_routine= NULL;
$$.init();
}
| package_specification_element { $$.init(); }
;
package_implementation_function_body:
sp_tail_is remember_lex
{
sp_package *pkg= Lex->get_sp_package();
sp_head *sp= pkg->m_current_routine->sphead;
thd->lex= pkg->m_current_routine;
sp->reset_thd_mem_root(thd);
sp->set_body_start(thd, YYLIP->get_cpp_tok_start());
}
sp_body opt_package_routine_end_name
{
if (thd->lex->sp_body_finalize_function(thd) ||
thd->lex->sphead->check_package_routine_end_name($5))
MYSQL_YYABORT;
thd->lex= $2;
}
;
package_implementation_procedure_body:
sp_tail_is remember_lex
{
sp_package *pkg= Lex->get_sp_package();
sp_head *sp= pkg->m_current_routine->sphead;
thd->lex= pkg->m_current_routine;
sp->reset_thd_mem_root(thd);
sp->set_body_start(thd, YYLIP->get_cpp_tok_start());
}
sp_body opt_package_routine_end_name
{
if (thd->lex->sp_body_finalize_procedure(thd) ||
thd->lex->sphead->check_package_routine_end_name($5))
MYSQL_YYABORT;
thd->lex= $2;
}
;
package_implementation_item_declaration:
sp_decl_vars ';'
;
opt_package_specification_element_list:
/* Empty */
| package_specification_element_list
;
package_specification_element_list:
package_specification_element
| package_specification_element_list package_specification_element
;
package_specification_element:
FUNCTION_SYM package_specification_function ';'
{
sp_package *pkg= Lex->get_sp_package();
if (pkg->add_routine_declaration($2))
MYSQL_YYABORT;
pkg->m_current_routine= NULL;
}
| PROCEDURE_SYM package_specification_procedure ';'
{
sp_package *pkg= Lex->get_sp_package();
if (pkg->add_routine_declaration($2))
MYSQL_YYABORT;
pkg->m_current_routine= NULL;
}
; ;
create_function_tail: create_function_tail:
@@ -2495,7 +2747,29 @@ sp_chistic:
| MODIFIES_SYM SQL_SYM DATA_SYM | MODIFIES_SYM SQL_SYM DATA_SYM
{ Lex->sp_chistics.daccess= SP_MODIFIES_SQL_DATA; } { Lex->sp_chistics.daccess= SP_MODIFIES_SQL_DATA; }
| sp_suid | sp_suid
{} { Lex->sp_chistics.suid= $1; }
;
create_package_chistic:
COMMENT_SYM TEXT_STRING_sys
{ Lex->sp_chistics.comment= $2; }
| sp_suid
{ Lex->sp_chistics.suid= $1; }
;
create_package_chistics:
create_package_chistic {}
| create_package_chistics create_package_chistic { }
;
opt_create_package_chistics:
/* Empty */
| create_package_chistics { }
;
opt_create_package_chistics_init:
{ Lex->sp_chistics.init(); }
opt_create_package_chistics
; ;
/* Create characteristics */ /* Create characteristics */
@@ -2505,14 +2779,8 @@ sp_c_chistic:
; ;
sp_suid: sp_suid:
SQL_SYM SECURITY_SYM DEFINER_SYM SQL_SYM SECURITY_SYM DEFINER_SYM { $$= SP_IS_SUID; }
{ | SQL_SYM SECURITY_SYM INVOKER_SYM { $$= SP_IS_NOT_SUID; }
Lex->sp_chistics.suid= SP_IS_SUID;
}
| SQL_SYM SECURITY_SYM INVOKER_SYM
{
Lex->sp_chistics.suid= SP_IS_NOT_SUID;
}
; ;
call: call:
@@ -2824,7 +3092,7 @@ sp_decl_idents_init_vars:
} }
; ;
sp_decl_non_handler: sp_decl_vars:
sp_decl_idents_init_vars sp_decl_idents_init_vars
type_with_opt_collate type_with_opt_collate
sp_opt_default sp_opt_default
@@ -2858,6 +3126,10 @@ sp_decl_non_handler:
MYSQL_YYABORT; MYSQL_YYABORT;
$$.init_using_vars($1); $$.init_using_vars($1);
} }
;
sp_decl_non_handler:
sp_decl_vars
| ident_directly_assignable CONDITION_SYM FOR_SYM sp_cond | ident_directly_assignable CONDITION_SYM FOR_SYM sp_cond
{ {
if (Lex->spcont->declare_condition(thd, &$1, $4)) if (Lex->spcont->declare_condition(thd, &$1, $4))
@@ -3584,6 +3856,12 @@ sp_proc_stmt_goto:
; ;
remember_lex:
{
$$= thd->lex;
}
;
assignment_source_lex: assignment_source_lex:
{ {
DBUG_ASSERT(Lex->sphead); DBUG_ASSERT(Lex->sphead);
@@ -8821,6 +9099,15 @@ remember_end:
} }
; ;
remember_end_opt:
{
if (yychar == YYEMPTY)
$$= (char*) YYLIP->get_cpp_ptr_rtrim();
else
$$= (char*) YYLIP->get_cpp_tok_end_rtrim();
}
;
select_alias: select_alias:
/* empty */ { $$=null_clex_str;} /* empty */ { $$=null_clex_str;}
| AS ident { $$=$2; } | AS ident { $$=$2; }
@@ -12219,14 +12506,8 @@ select_outvar:
} }
| ident_or_text | ident_or_text
{ {
sp_variable *t; if (!($$= Lex->create_outvar(thd, &$1)) && Lex->result)
MYSQL_YYABORT;
if (!Lex->spcont || !(t= Lex->spcont->find_variable(&$1, false)))
my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str));
$$ = Lex->result ? (new (thd->mem_root)
my_var_sp(&$1, t->offset, t->type_handler(),
Lex->sphead)) :
NULL;
} }
| ident '.' ident | ident '.' ident
{ {
@@ -12326,6 +12607,22 @@ drop:
lex->set_command(SQLCOM_DROP_DB, $3); lex->set_command(SQLCOM_DROP_DB, $3);
lex->name= $4; lex->name= $4;
} }
| DROP PACKAGE_SYM opt_if_exists sp_name
{
LEX *lex= Lex;
lex->set_command(SQLCOM_DROP_PACKAGE, $3);
if (lex->sphead)
my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PACKAGE"));
lex->spname= $4;
}
| DROP PACKAGE_SYM BODY_SYM opt_if_exists sp_name
{
LEX *lex= Lex;
lex->set_command(SQLCOM_DROP_PACKAGE_BODY, $4);
if (lex->sphead)
my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PACKAGE BODY"));
lex->spname= $5;
}
| DROP FUNCTION_SYM opt_if_exists ident '.' ident | DROP FUNCTION_SYM opt_if_exists ident '.' ident
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
@@ -13243,6 +13540,18 @@ show_param:
lex->sql_command = SQLCOM_SHOW_CREATE_FUNC; lex->sql_command = SQLCOM_SHOW_CREATE_FUNC;
lex->spname= $3; lex->spname= $3;
} }
| CREATE PACKAGE_SYM sp_name
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE;
lex->spname= $3;
}
| CREATE PACKAGE_SYM BODY_SYM sp_name
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE_BODY;
lex->spname= $4;
}
| CREATE TRIGGER_SYM sp_name | CREATE TRIGGER_SYM sp_name
{ {
LEX *lex= Lex; LEX *lex= Lex;
@@ -13275,6 +13584,20 @@ show_param:
if (prepare_schema_table(thd, lex, 0, SCH_PROCEDURES)) if (prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| PACKAGE_SYM STATUS_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE;
if (prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))
MYSQL_YYABORT;
}
| PACKAGE_SYM BODY_SYM STATUS_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE_BODY;
if (prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))
MYSQL_YYABORT;
}
| PROCEDURE_SYM CODE_SYM sp_name | PROCEDURE_SYM CODE_SYM sp_name
{ {
Lex->sql_command= SQLCOM_SHOW_PROC_CODE; Lex->sql_command= SQLCOM_SHOW_PROC_CODE;
@@ -13285,6 +13608,11 @@ show_param:
Lex->sql_command= SQLCOM_SHOW_FUNC_CODE; Lex->sql_command= SQLCOM_SHOW_FUNC_CODE;
Lex->spname= $3; Lex->spname= $3;
} }
| PACKAGE_SYM BODY_SYM CODE_SYM sp_name
{
Lex->sql_command= SQLCOM_SHOW_PACKAGE_BODY_CODE;
Lex->spname= $4;
}
| CREATE EVENT_SYM sp_name | CREATE EVENT_SYM sp_name
{ {
Lex->spname= $3; Lex->spname= $3;
@@ -14772,6 +15100,7 @@ keyword_directly_not_assignable:
keyword_sp: keyword_sp:
keyword_sp_data_type keyword_sp_data_type
| keyword_sp_not_data_type | keyword_sp_not_data_type
| FUNCTION_SYM { /* Oracle-PLSQL-R */}
; ;
@@ -15124,7 +15453,6 @@ keyword_sp_not_data_type:
| TYPES_SYM {} | TYPES_SYM {}
| TYPE_SYM {} | TYPE_SYM {}
| UDF_RETURNS_SYM {} | UDF_RETURNS_SYM {}
| FUNCTION_SYM {}
| UNCOMMITTED_SYM {} | UNCOMMITTED_SYM {}
| UNDEFINED_SYM {} | UNDEFINED_SYM {}
| UNDO_BUFFER_SIZE_SYM {} | UNDO_BUFFER_SIZE_SYM {}
@@ -15804,6 +16132,18 @@ revoke_command:
if (Lex->add_grant_command(thd, SQLCOM_REVOKE, TYPE_ENUM_PROCEDURE)) if (Lex->add_grant_command(thd, SQLCOM_REVOKE, TYPE_ENUM_PROCEDURE))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| grant_privileges ON PACKAGE_SYM grant_ident FROM user_and_role_list
{
if (Lex->add_grant_command(thd, SQLCOM_REVOKE,
TYPE_ENUM_PACKAGE))
MYSQL_YYABORT;
}
| grant_privileges ON PACKAGE_SYM BODY_SYM grant_ident FROM user_and_role_list
{
if (Lex->add_grant_command(thd, SQLCOM_REVOKE,
TYPE_ENUM_PACKAGE_BODY))
MYSQL_YYABORT;
}
| ALL opt_privileges ',' GRANT OPTION FROM user_and_role_list | ALL opt_privileges ',' GRANT OPTION FROM user_and_role_list
{ {
Lex->sql_command = SQLCOM_REVOKE_ALL; Lex->sql_command = SQLCOM_REVOKE_ALL;
@@ -15855,6 +16195,20 @@ grant_command:
if (Lex->add_grant_command(thd, SQLCOM_GRANT, TYPE_ENUM_PROCEDURE)) if (Lex->add_grant_command(thd, SQLCOM_GRANT, TYPE_ENUM_PROCEDURE))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| grant_privileges ON PACKAGE_SYM grant_ident TO_SYM grant_list
opt_require_clause opt_grant_options
{
if (Lex->add_grant_command(thd, SQLCOM_GRANT,
TYPE_ENUM_PACKAGE))
MYSQL_YYABORT;
}
| grant_privileges ON PACKAGE_SYM BODY_SYM grant_ident TO_SYM grant_list
opt_require_clause opt_grant_options
{
if (Lex->add_grant_command(thd, SQLCOM_GRANT,
TYPE_ENUM_PACKAGE_BODY))
MYSQL_YYABORT;
}
| PROXY_SYM ON user TO_SYM grant_list opt_grant_option | PROXY_SYM ON user TO_SYM grant_list opt_grant_option
{ {
LEX *lex= Lex; LEX *lex= Lex;
@@ -16896,6 +17250,11 @@ sp_tail_standalone:
} }
; ;
opt_package_routine_end_name:
/* Empty */ { $$= null_clex_str; }
| ident { $$= $1; }
;
sp_tail_is: sp_tail_is:
IS IS
| AS | AS