diff --git a/mysql-test/suite/compat/oracle/r/sp-package-perfschema.result b/mysql-test/suite/compat/oracle/r/sp-package-perfschema.result new file mode 100644 index 00000000000..8b465fceba5 --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/sp-package-perfschema.result @@ -0,0 +1,198 @@ +# +# MDEV-34817: Performance schema is not cleared of removed package routines +# +SET @save_sql_mode= @@sql_mode; +CREATE DATABASE mdev34817; +USE mdev34817; +SET sql_mode=ORACLE; +CREATE PROCEDURE p1 AS BEGIN NULL; END; +$$ +CREATE PACKAGE pkg1 AS +PROCEDURE p1; +FUNCTION f1 RETURN INT; +END; +; +CREATE PACKAGE BODY pkg1 AS +PROCEDURE p1 AS BEGIN NULL; END; +FUNCTION f1 RETURN INT AS BEGIN RETURN 1; END; +END; +; +connect con1,localhost,root,,mdev34817; +SET sql_mode=ORACLE; +CALL pkg1.p1; +SELECT pkg1.f1(); +pkg1.f1() +1 +CALL p1; +connect con2,localhost,root,,mdev34817; +SET sql_mode=ORACLE; +CALL pkg1.p1; +SELECT pkg1.f1(); +pkg1.f1() +1 +connection default; +SELECT object_type, object_name, count_star +FROM performance_schema.events_statements_summary_by_program +WHERE object_schema='mdev34817' AND object_type IN ('PROCEDURE','FUNCTION') +ORDER BY object_type, object_name, count_star; +object_type object_name count_star +FUNCTION pkg1.f1 2 +PROCEDURE p1 1 +PROCEDURE pkg1.p1 2 +# DROP PACKAGE BODY: package routines are gone, p1 stays +DROP PACKAGE BODY pkg1; +SELECT object_type, object_name, count_star +FROM performance_schema.events_statements_summary_by_program +WHERE object_schema='mdev34817' AND object_type IN ('PROCEDURE','FUNCTION') +ORDER BY object_type, object_name, count_star; +object_type object_name count_star +PROCEDURE p1 1 +# DROP PACKAGE: re-create routines, then drop package +CREATE PACKAGE BODY pkg1 AS +PROCEDURE p1 AS BEGIN NULL; END; +FUNCTION f1 RETURN INT AS BEGIN RETURN 1; END; +END; +; +connection con1; +CALL pkg1.p1; +SELECT pkg1.f1(); +pkg1.f1() +1 +connection default; +SELECT object_type, object_name, count_star +FROM performance_schema.events_statements_summary_by_program +WHERE object_schema='mdev34817' AND object_type IN ('PROCEDURE','FUNCTION') +ORDER BY object_type, object_name, count_star; +object_type object_name count_star +FUNCTION pkg1.f1 1 +PROCEDURE p1 1 +PROCEDURE pkg1.p1 1 +DROP PACKAGE pkg1; +SELECT object_type, object_name, count_star +FROM performance_schema.events_statements_summary_by_program +WHERE object_schema='mdev34817' AND object_type IN ('PROCEDURE','FUNCTION') +ORDER BY object_type, object_name, count_star; +object_type object_name count_star +PROCEDURE p1 1 +# DROP DATABASE: drop everything +CREATE PACKAGE pkg1 AS +PROCEDURE p1; +FUNCTION f1 RETURN INT; +END; +; +CREATE PACKAGE BODY pkg1 AS +PROCEDURE p1 AS BEGIN NULL; END; +FUNCTION f1 RETURN INT AS BEGIN RETURN 1; END; +END; +; +connection con2; +CALL pkg1.p1; +SELECT pkg1.f1(); +pkg1.f1() +1 +disconnect con2; +disconnect con1; +connection default; +SELECT object_type, object_name, count_star +FROM performance_schema.events_statements_summary_by_program +WHERE object_schema='mdev34817' AND object_type IN ('PROCEDURE','FUNCTION') +ORDER BY object_type, object_name, count_star; +object_type object_name count_star +FUNCTION pkg1.f1 1 +PROCEDURE p1 1 +PROCEDURE pkg1.p1 1 +DROP DATABASE mdev34817; +SELECT object_type, object_name, count_star +FROM performance_schema.events_statements_summary_by_program +WHERE object_schema='mdev34817' AND object_type IN ('PROCEDURE','FUNCTION') +ORDER BY object_type, object_name, count_star; +object_type object_name count_star +# +# Differentiate between package routines and standalone routines +# (with a dot(.) in the name. ex: `pkg1.p1` +# +CREATE DATABASE mdev34817; +USE mdev34817; +CREATE PACKAGE pkg1 AS +PROCEDURE p1; +FUNCTION f1 RETURN INT; +END; +; +CREATE PACKAGE BODY pkg1 AS +PROCEDURE p1 AS BEGIN NULL; END; +FUNCTION f1 RETURN INT AS BEGIN RETURN 1; END; +END; +; +CREATE PROCEDURE `pkg1.p1` AS BEGIN NULL; END; +$$ +CREATE PROCEDURE `pkg1.p9` AS BEGIN NULL; END; +$$ +CALL pkg1.p1; +CALL `pkg1.p1`; +CALL `pkg1.p1`; +CALL `pkg1.p9`; +SELECT object_type, object_name, count_star +FROM performance_schema.events_statements_summary_by_program +WHERE object_schema='mdev34817' AND object_type IN ('PROCEDURE','FUNCTION') +ORDER BY object_type, object_name, count_star; +object_type object_name count_star +FUNCTION pkg1.f1 0 +PROCEDURE pkg1.p1 1 +PROCEDURE pkg1.p1 2 +PROCEDURE pkg1.p9 1 +# Only the package routines are gone +DROP PACKAGE BODY pkg1; +SELECT object_type, object_name, count_star +FROM performance_schema.events_statements_summary_by_program +WHERE object_schema='mdev34817' AND object_type IN ('PROCEDURE','FUNCTION') +ORDER BY object_type, object_name, count_star; +object_type object_name count_star +PROCEDURE pkg1.p1 2 +PROCEDURE pkg1.p9 1 +# +# Routines of packages with names truncated in performance schema +# +connect con1,localhost,root,,mdev34817; +SET NAMES utf8mb4; +SET sql_mode=ORACLE; +CREATE PACKAGE kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk AS PROCEDURE p1; PROCEDURE p2; END; +$$ +CREATE PACKAGE BODY kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk AS +PROCEDURE p1 AS BEGIN NULL; END; +PROCEDURE p2 AS BEGIN NULL; END; +END; +$$ +CREATE PACKAGE жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж AS PROCEDURE p1; END; +$$ +CREATE PACKAGE BODY жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж AS PROCEDURE p1 AS BEGIN NULL; END; END; +$$ +CALL kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk.p1; +CALL kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk.p2; +CALL жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж.p1; +SELECT object_type, CHAR_LENGTH(object_name), count_star +FROM performance_schema.events_statements_summary_by_program +WHERE object_schema='mdev34817' AND object_name NOT LIKE 'pkg%' + AND object_type IN ('PROCEDURE','FUNCTION') +ORDER BY object_type, object_name; +object_type CHAR_LENGTH(object_name) count_star +PROCEDURE 64 2 +PROCEDURE 32 1 +DROP PACKAGE BODY kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk; +DROP PACKAGE BODY жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж; +SELECT object_type, CHAR_LENGTH(object_name), count_star +FROM performance_schema.events_statements_summary_by_program +WHERE object_schema='mdev34817' AND object_name NOT LIKE 'pkg%' + AND object_type IN ('PROCEDURE','FUNCTION') +ORDER BY object_type, object_name; +object_type CHAR_LENGTH(object_name) count_star +disconnect con1; +connection default; +DROP DATABASE mdev34817; +SELECT object_type, object_name, count_star +FROM performance_schema.events_statements_summary_by_program +WHERE object_schema='mdev34817' AND object_type IN ('PROCEDURE','FUNCTION') +ORDER BY object_type, object_name, count_star; +object_type object_name count_star +USE test; +SET sql_mode= @save_sql_mode; +# End of 10.11 tests diff --git a/mysql-test/suite/compat/oracle/t/sp-package-perfschema.test b/mysql-test/suite/compat/oracle/t/sp-package-perfschema.test new file mode 100644 index 00000000000..7103bfccd02 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-package-perfschema.test @@ -0,0 +1,158 @@ +--source include/not_embedded.inc +--source include/have_perfschema.inc +--source include/no_protocol.inc + +--echo # +--echo # MDEV-34817: Performance schema is not cleared of removed package routines +--echo # + +# Package routines are recorded in performance schema as +# PROCEDURE/FUNCTION ".". They must disappear when +# the package is dropped, regardless of which connection executed them +# and which connection drops the package. +# Non-zero counts of package routines also show that SETUP_OBJECTS +# rules for PROCEDURE/FUNCTION apply to them. + +SET @save_sql_mode= @@sql_mode; +CREATE DATABASE mdev34817; +USE mdev34817; +SET sql_mode=ORACLE; + +DELIMITER $$; +let $create_pkg= +CREATE PACKAGE pkg1 AS + PROCEDURE p1; + FUNCTION f1 RETURN INT; +END; +$$ +let $create_pkg_body= +CREATE PACKAGE BODY pkg1 AS + PROCEDURE p1 AS BEGIN NULL; END; + FUNCTION f1 RETURN INT AS BEGIN RETURN 1; END; +END; +$$ +CREATE PROCEDURE p1 AS BEGIN NULL; END; +$$ +DELIMITER ;$$ +let $show= +SELECT object_type, object_name, count_star + FROM performance_schema.events_statements_summary_by_program + WHERE object_schema='mdev34817' AND object_type IN ('PROCEDURE','FUNCTION') + ORDER BY object_type, object_name, count_star; + +eval $create_pkg; +eval $create_pkg_body; + +# Execute the package routines from two other connections. +# The default connection, which drops the package, never executes them. +connect (con1,localhost,root,,mdev34817); +SET sql_mode=ORACLE; +CALL pkg1.p1; +SELECT pkg1.f1(); +CALL p1; +connect (con2,localhost,root,,mdev34817); +SET sql_mode=ORACLE; +CALL pkg1.p1; +SELECT pkg1.f1(); +connection default; +eval $show; + +--echo # DROP PACKAGE BODY: package routines are gone, p1 stays +DROP PACKAGE BODY pkg1; +eval $show; + +--echo # DROP PACKAGE: re-create routines, then drop package +eval $create_pkg_body; +connection con1; +CALL pkg1.p1; +SELECT pkg1.f1(); +connection default; +eval $show; +DROP PACKAGE pkg1; +eval $show; + +--echo # DROP DATABASE: drop everything +eval $create_pkg; +eval $create_pkg_body; +connection con2; +CALL pkg1.p1; +SELECT pkg1.f1(); +disconnect con2; +disconnect con1; +connection default; +eval $show; +DROP DATABASE mdev34817; +eval $show; + +--echo # +--echo # Differentiate between package routines and standalone routines +--echo # (with a dot(.) in the name. ex: `pkg1.p1` +--echo # + +CREATE DATABASE mdev34817; +USE mdev34817; +eval $create_pkg; +eval $create_pkg_body; +DELIMITER $$; +CREATE PROCEDURE `pkg1.p1` AS BEGIN NULL; END; +$$ +CREATE PROCEDURE `pkg1.p9` AS BEGIN NULL; END; +$$ +DELIMITER ;$$ +CALL pkg1.p1; +CALL `pkg1.p1`; +CALL `pkg1.p1`; +CALL `pkg1.p9`; +eval $show; +--echo # Only the package routines are gone +DROP PACKAGE BODY pkg1; +eval $show; + +--echo # +--echo # Routines of packages with names truncated in performance schema +--echo # + +connect (con1,localhost,root,,mdev34817); +SET NAMES utf8mb4; +SET sql_mode=ORACLE; +let $long= `SELECT REPEAT('k', 64)`; +# 32 characters, 64 bytes +let $cyrillic= `SELECT REPEAT('ж', 32)`; +DELIMITER $$; +eval CREATE PACKAGE $long AS PROCEDURE p1; PROCEDURE p2; END; +$$ +eval CREATE PACKAGE BODY $long AS + PROCEDURE p1 AS BEGIN NULL; END; + PROCEDURE p2 AS BEGIN NULL; END; +END; +$$ +eval CREATE PACKAGE $cyrillic AS PROCEDURE p1; END; +$$ +eval CREATE PACKAGE BODY $cyrillic AS PROCEDURE p1 AS BEGIN NULL; END; END; +$$ +DELIMITER ;$$ +eval CALL $long.p1; +eval CALL $long.p2; +eval CALL $cyrillic.p1; +SELECT object_type, CHAR_LENGTH(object_name), count_star + FROM performance_schema.events_statements_summary_by_program + WHERE object_schema='mdev34817' AND object_name NOT LIKE 'pkg%' + AND object_type IN ('PROCEDURE','FUNCTION') + ORDER BY object_type, object_name; +eval DROP PACKAGE BODY $long; +eval DROP PACKAGE BODY $cyrillic; +SELECT object_type, CHAR_LENGTH(object_name), count_star + FROM performance_schema.events_statements_summary_by_program + WHERE object_schema='mdev34817' AND object_name NOT LIKE 'pkg%' + AND object_type IN ('PROCEDURE','FUNCTION') + ORDER BY object_type, object_name; +disconnect con1; +connection default; + +DROP DATABASE mdev34817; +eval $show; + +USE test; +SET sql_mode= @save_sql_mode; + +--echo # End of 10.11 tests diff --git a/sql/sp.h b/sql/sp.h index 8665ebf86e1..1152c9c114f 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -59,6 +59,13 @@ enum enum_sp_type SP_TYPE_EVENT=6, }; +/* + Types of package routines, used only for performance schema + instrumentation, see sp_head::init_psi_share(). +*/ +#define SP_PSI_TYPE_PACKAGE_PROCEDURE 7 +#define SP_PSI_TYPE_PACKAGE_FUNCTION 8 + class Sp_handler { bool sp_resolve_package_routine_explicit(THD *thd, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 139f10dea92..0054838e0c1 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -842,7 +842,15 @@ sp_head::init_sp_name(const sp_name *spname) void sp_head::init_psi_share() { - m_sp_share= MYSQL_GET_SP_SHARE(m_handler->type(), m_db.str, static_cast(m_db.length), + /* + Package routines are instrumented with their own types, so that + "pkg.routine" is not confused with a standalone routine `pkg.routine`. + */ + m_sp_share= MYSQL_GET_SP_SHARE(!m_parent ? (uint) m_handler->type() : + m_handler->type() == SP_TYPE_FUNCTION ? + SP_PSI_TYPE_PACKAGE_FUNCTION : + SP_PSI_TYPE_PACKAGE_PROCEDURE, + m_db.str, static_cast(m_db.length), m_name.str, static_cast(m_name.length)); } diff --git a/storage/perfschema/pfs.cc b/storage/perfschema/pfs.cc index 1d867e44975..401ad3971d5 100644 --- a/storage/perfschema/pfs.cc +++ b/storage/perfschema/pfs.cc @@ -5776,14 +5776,16 @@ void pfs_end_statement_v1(PSI_statement_locker *locker, void *stmt_da) static inline enum_object_type sp_type_to_object_type(uint sp_type) { - enum enum_sp_type value= static_cast (sp_type); - - switch (value) + switch (sp_type) { case SP_TYPE_FUNCTION: return OBJECT_TYPE_FUNCTION; case SP_TYPE_PROCEDURE: return OBJECT_TYPE_PROCEDURE; + case SP_PSI_TYPE_PACKAGE_FUNCTION: + return OBJECT_TYPE_PACKAGE_FUNCTION; + case SP_PSI_TYPE_PACKAGE_PROCEDURE: + return OBJECT_TYPE_PACKAGE_PROCEDURE; case SP_TYPE_PACKAGE: return OBJECT_TYPE_PACKAGE; case SP_TYPE_PACKAGE_BODY: diff --git a/storage/perfschema/pfs_column_types.h b/storage/perfschema/pfs_column_types.h index 862916fa4fc..6bf20cae4ec 100644 --- a/storage/perfschema/pfs_column_types.h +++ b/storage/perfschema/pfs_column_types.h @@ -220,6 +220,14 @@ enum enum_object_type OBJECT_TYPE_PACKAGE= 9, OBJECT_TYPE_PACKAGE_BODY= 10, OBJECT_TYPE_USER_LEVEL_LOCK= 11, + + /* + Internal, outside of FIRST_OBJECT_TYPE..LAST_OBJECT_TYPE. + Used only in the hash key of package routines, see PFS_program. + */ + + OBJECT_TYPE_PACKAGE_PROCEDURE= 12, + OBJECT_TYPE_PACKAGE_FUNCTION= 13, }; /** Integer, first value of @sa enum_object_type. */ #define FIRST_OBJECT_TYPE (static_cast (OBJECT_TYPE_EVENT)) diff --git a/storage/perfschema/pfs_program.cc b/storage/perfschema/pfs_program.cc index 3ba11da0240..033d30f7020 100644 --- a/storage/perfschema/pfs_program.cc +++ b/storage/perfschema/pfs_program.cc @@ -178,6 +178,24 @@ static LF_PINS* get_program_hash_pins(PFS_thread *thread) return thread->m_program_hash_pins; } +/** + Package routines differ from standalone routines only by the object type + in PFS_program_key. Everywhere else, e.g. in SETUP_OBJECTS and in the + OBJECT_TYPE columns, they are FUNCTION and PROCEDURE. +*/ +static enum_object_type program_public_type(enum_object_type object_type) +{ + switch (object_type) + { + case OBJECT_TYPE_PACKAGE_FUNCTION: + return OBJECT_TYPE_FUNCTION; + case OBJECT_TYPE_PACKAGE_PROCEDURE: + return OBJECT_TYPE_PROCEDURE; + default: + return object_type; + } +} + PFS_program* find_or_create_program(PFS_thread *thread, enum_object_type object_type, @@ -187,6 +205,7 @@ find_or_create_program(PFS_thread *thread, uint schema_name_length) { bool is_enabled, is_timed; + enum_object_type public_type= program_public_type(object_type); LF_PINS *pins= get_program_hash_pins(thread); if (unlikely(pins == NULL)) @@ -226,7 +245,7 @@ search: First time while inserting this record to program array we need to find out if it is enabled and timed. */ - lookup_setup_object(thread, object_type, + lookup_setup_object(thread, public_type, schema_name, schema_name_length, object_name, object_name_length, &is_enabled, &is_timed); @@ -238,7 +257,7 @@ search: /* Do the assignments. */ memcpy(pfs->m_key.m_hash_key, key.m_hash_key, key.m_key_length); pfs->m_key.m_key_length= key.m_key_length; - pfs->m_type= object_type; + pfs->m_type= public_type; pfs->m_object_name= pfs->m_key.m_hash_key + 1; pfs->m_object_name_length= object_name_length; @@ -281,7 +300,9 @@ search: /** Drops records of the routines of a package body. - They are named "." in the package schema. + They have package routine types in the key and are named + "." in the package schema, or just "" + if the name is truncated to COL_OBJECT_NAME_SIZE. Names are compared in the lower-cased form of PFS_program_key. */ class Proc_drop_package_routines @@ -297,10 +318,13 @@ public: void operator()(PFS_program *pfs) override { - if ((pfs->m_type != OBJECT_TYPE_PROCEDURE && - pfs->m_type != OBJECT_TYPE_FUNCTION) || - uint(pfs->m_object_name_length) <= m_name_length || - pfs->m_object_name[m_name_length] != '.' || + uint type= (uchar) pfs->m_key.m_hash_key[0]; + uint length= pfs->m_object_name_length; + if ((type != OBJECT_TYPE_PACKAGE_PROCEDURE && + type != OBJECT_TYPE_PACKAGE_FUNCTION) || + length < m_name_length || + (length > m_name_length ? pfs->m_object_name[m_name_length] != '.' : + length != COL_OBJECT_NAME_SIZE) || memcmp(pfs->m_object_name, m_name, m_name_length) || uint(pfs->m_schema_name_length) != m_schema_length || memcmp(pfs->m_schema_name, m_schema, m_schema_length)) diff --git a/storage/perfschema/pfs_program.h b/storage/perfschema/pfs_program.h index a5a6245c1cc..b20df7accda 100644 --- a/storage/perfschema/pfs_program.h +++ b/storage/perfschema/pfs_program.h @@ -43,7 +43,9 @@ struct PFS_program_key /** Hash search key. This has to be a string for LF_HASH, - the format is "<0x00><0x00><0x00>" + the format is "<0x00><0x00>". + The object type of package routines is OBJECT_TYPE_PACKAGE_PROCEDURE + or OBJECT_TYPE_PACKAGE_FUNCTION. */ char m_hash_key[PROGRAM_HASH_KEY_LENGTH]; uint m_key_length; @@ -51,7 +53,7 @@ struct PFS_program_key struct PFS_ALIGNED PFS_program : public PFS_instr { - /** Object type. */ + /** Object type, PROCEDURE or FUNCTION for package routines too. */ enum_object_type m_type; /** Object name. */