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

MDEV-34817: Performance schema is not cleared of removed package routines - part 2

Problem:
  1. A package routine and a standalone routine can have the same name,
  e.g. routine p1 of package pkg1 and procedure `pkg1.p1`. Performance
  schema stored both under one key, so their statistics were merged,
  and DROP PACKAGE BODY pkg1 also removed the statistics of standalone
  routines named `pkg1.<anything>`.

  2. Performance schema truncates names to COL_OBJECT_NAME_SIZE bytes.
  For a package name of that length or longer, "<package>.<routine>"
  became just "<package>", and these records were never dropped.

Solution:
  Give package routines their own object types,
  OBJECT_TYPE_PACKAGE_PROCEDURE and OBJECT_TYPE_PACKAGE_FUNCTION.
  They are used only in the hash key, so SETUP_OBJECTS and OBJECT_TYPE
  columns still see PROCEDURE and FUNCTION. When a package body is
  dropped, only records with these types are dropped, including names
  truncated to the package name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Raghunandan Bhat
2026-10-16 17:28:16 +05:30
parent f57a2b97ad
commit 3b532900ed
8 changed files with 420 additions and 13 deletions

View File

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

View File

@@ -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 "<package>.<routine>". 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

View File

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

View File

@@ -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<uint>(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<uint>(m_db.length),
m_name.str, static_cast<uint>(m_name.length));
}

View File

@@ -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<enum enum_sp_type> (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:

View File

@@ -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<int> (OBJECT_TYPE_EVENT))

View File

@@ -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 "<package>.<routine>" in the package schema.
They have package routine types in the key and are named
"<package>.<routine>" in the package schema, or just "<package>"
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))

View File

@@ -43,7 +43,9 @@ struct PFS_program_key
/**
Hash search key.
This has to be a string for LF_HASH,
the format is "<object_type><0x00><object_name><0x00><schema_name><0x00>"
the format is "<object_type><object_name><0x00><schema_name><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. */