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:
@@ -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)
|
||||||
|
@@ -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')
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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',
|
||||||
|
@@ -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',
|
||||||
|
@@ -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',
|
||||||
|
@@ -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',
|
||||||
|
268
mysql-test/suite/compat/oracle/r/binlog_stm_sp_package.result
Normal file
268
mysql-test/suite/compat/oracle/r/binlog_stm_sp_package.result
Normal 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 */
|
181
mysql-test/suite/compat/oracle/r/rpl_sp_package.result
Normal file
181
mysql-test/suite/compat/oracle/r/rpl_sp_package.result
Normal 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
|
@@ -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
|
245
mysql-test/suite/compat/oracle/r/sp-package-code.result
Normal file
245
mysql-test/suite/compat/oracle/r/sp-package-code.result
Normal 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;
|
@@ -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;
|
@@ -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
|
@@ -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;
|
@@ -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;
|
75
mysql-test/suite/compat/oracle/r/sp-package-innodb.result
Normal file
75
mysql-test/suite/compat/oracle/r/sp-package-innodb.result
Normal 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;
|
80
mysql-test/suite/compat/oracle/r/sp-package-mdl.result
Normal file
80
mysql-test/suite/compat/oracle/r/sp-package-mdl.result
Normal 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;
|
261
mysql-test/suite/compat/oracle/r/sp-package-mysqldump.result
Normal file
261
mysql-test/suite/compat/oracle/r/sp-package-mysqldump.result
Normal 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
|
322
mysql-test/suite/compat/oracle/r/sp-package-security.result
Normal file
322
mysql-test/suite/compat/oracle/r/sp-package-security.result
Normal 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;
|
2870
mysql-test/suite/compat/oracle/r/sp-package.result
Normal file
2870
mysql-test/suite/compat/oracle/r/sp-package.result
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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/
|
||||||
|
158
mysql-test/suite/compat/oracle/t/binlog_stm_sp_package.test
Normal file
158
mysql-test/suite/compat/oracle/t/binlog_stm_sp_package.test
Normal 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;
|
134
mysql-test/suite/compat/oracle/t/rpl_sp_package.test
Normal file
134
mysql-test/suite/compat/oracle/t/rpl_sp_package.test
Normal 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
|
@@ -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
|
11
mysql-test/suite/compat/oracle/t/sp-cache-invalidate.inc
Normal file
11
mysql-test/suite/compat/oracle/t/sp-cache-invalidate.inc
Normal 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
|
182
mysql-test/suite/compat/oracle/t/sp-package-code.test
Normal file
182
mysql-test/suite/compat/oracle/t/sp-package-code.test
Normal 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;
|
@@ -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
|
@@ -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
|
||||||
|
|
@@ -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
|
@@ -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
|
107
mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml.inc
Normal file
107
mysql-test/suite/compat/oracle/t/sp-package-concurrent-dml.inc
Normal 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
|
62
mysql-test/suite/compat/oracle/t/sp-package-innodb.test
Normal file
62
mysql-test/suite/compat/oracle/t/sp-package-innodb.test
Normal 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;
|
110
mysql-test/suite/compat/oracle/t/sp-package-mdl.test
Normal file
110
mysql-test/suite/compat/oracle/t/sp-package-mdl.test
Normal 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;
|
93
mysql-test/suite/compat/oracle/t/sp-package-mysqldump.test
Normal file
93
mysql-test/suite/compat/oracle/t/sp-package-mysqldump.test
Normal 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
|
331
mysql-test/suite/compat/oracle/t/sp-package-security.test
Normal file
331
mysql-test/suite/compat/oracle/t/sp-package-security.test
Normal 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;
|
2626
mysql-test/suite/compat/oracle/t/sp-package.test
Normal file
2626
mysql-test/suite/compat/oracle/t/sp-package.test
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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 /;
|
||||||
|
@@ -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)
|
||||||
|
@@ -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)
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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.
|
||||||
|
@@ -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.
|
||||||
|
@@ -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},
|
||||||
|
@@ -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.
|
||||||
|
@@ -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
|
||||||
|
59
sql/item.cc
59
sql/item.cc
@@ -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);
|
||||||
|
52
sql/item.h
52
sql/item.h
@@ -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)
|
||||||
{ }
|
{ }
|
||||||
|
@@ -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;
|
||||||
|
@@ -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
|
||||||
|
@@ -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()
|
||||||
{}
|
{}
|
||||||
|
@@ -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;
|
||||||
|
@@ -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)},
|
||||||
|
@@ -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";
|
||||||
|
@@ -299,6 +299,7 @@ public:
|
|||||||
TABLE,
|
TABLE,
|
||||||
FUNCTION,
|
FUNCTION,
|
||||||
PROCEDURE,
|
PROCEDURE,
|
||||||
|
PACKAGE_BODY,
|
||||||
TRIGGER,
|
TRIGGER,
|
||||||
EVENT,
|
EVENT,
|
||||||
COMMIT,
|
COMMIT,
|
||||||
|
@@ -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
|
||||||
|
@@ -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
667
sql/sp.cc
@@ -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,
|
||||||
¶ms);
|
¶ms);
|
||||||
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 ¶ms,
|
||||||
|
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
242
sql/sp.h
@@ -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 ¶ms,
|
const LEX_CSTRING ¶ms,
|
||||||
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 ¶ms,
|
||||||
|
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,
|
||||||
|
365
sql/sp_head.cc
365
sql/sp_head.cc
@@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
129
sql/sp_head.h
129
sql/sp_head.h
@@ -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)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@@ -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.
|
||||||
///
|
///
|
||||||
|
@@ -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),
|
||||||
|
@@ -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.
|
||||||
|
106
sql/sql_acl.cc
106
sql/sql_acl.cc
@@ -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},
|
||||||
|
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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()
|
||||||
|
319
sql/sql_lex.cc
319
sql/sql_lex.cc
@@ -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, ¬_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)
|
||||||
{
|
{
|
||||||
|
@@ -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, ¬_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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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());
|
||||||
|
@@ -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););
|
||||||
|
@@ -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},
|
||||||
|
@@ -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);
|
||||||
|
@@ -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,
|
||||||
|
@@ -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 {}
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user