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

Package routines are recorded in performance schema as
PROCEDURE/FUNCTION "<package>.<routine>", but dropping a package body
removed only the PACKAGE BODY record, so routine statistics survived
DROP PACKAGE [BODY] and DROP DATABASE.

Drop the routine records of the package together with the package body
record. Also reset statistics of a newly allocated PFS_program (as in
089caf901f), so a reused slot does not inherit stale counters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Oleksandr Byelkin
2026-10-15 14:03:24 +02:00
committed by Raghunandan Bhat
parent fb641b0cd1
commit f57a2b97ad
3 changed files with 291 additions and 2 deletions

View File

@@ -187,3 +187,138 @@ SET default_storage_engine = performance_schema;
CREATE TEMPORARY TABLE t1 (t int);
ERROR HY000: Table storage engine 'PERFORMANCE_SCHEMA' does not support the create option 'TEMPORARY'
SET @@default_storage_engine = @default_storage_engine_old;
#
# MDEV-34817 Performance schema is not cleared of removed package routines
#
SET @save_sql_mode= @@sql_mode;
SET sql_mode=ORACLE;
CREATE DATABASE db1;
CREATE DATABASE db2;
CREATE PACKAGE db1.pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
CREATE PACKAGE BODY db1.pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
FUNCTION f1 RETURN INT AS BEGIN RETURN 1; END;
END;
$$
CREATE PACKAGE db2.pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY db2.pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
END;
$$
CREATE PROCEDURE db1.pkg1x AS BEGIN NULL; END;
$$
CALL db1.pkg1.p1;
SELECT db1.pkg1.f1();
db1.pkg1.f1()
1
CALL db2.pkg1.p1;
CALL db1.pkg1x;
# Routines executed in another connection must be removed as well
connect con1,localhost,root;
CALL db1.pkg1.p1;
disconnect con1;
connection default;
SELECT object_schema, object_name, count_star
FROM performance_schema.events_statements_summary_by_program
WHERE object_type IN ('PROCEDURE','FUNCTION') AND
object_schema IN ('db1','db2')
ORDER BY object_schema, object_name;
object_schema object_name count_star
db1 pkg1.f1 1
db1 pkg1.p1 2
db1 pkg1x 1
db2 pkg1.p1 1
DROP PACKAGE BODY db1.PKG1;
SELECT object_schema, object_name, count_star
FROM performance_schema.events_statements_summary_by_program
WHERE object_type IN ('PROCEDURE','FUNCTION') AND
object_schema IN ('db1','db2')
ORDER BY object_schema, object_name;
object_schema object_name count_star
db1 pkg1x 1
db2 pkg1.p1 1
# Statistics of the re-created routines start from zero
CREATE PACKAGE BODY db1.pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
FUNCTION f1 RETURN INT AS BEGIN RETURN 1; END;
END;
$$
CALL db1.pkg1.p1;
SELECT object_schema, object_name, count_star
FROM performance_schema.events_statements_summary_by_program
WHERE object_type IN ('PROCEDURE','FUNCTION') AND
object_schema IN ('db1','db2')
ORDER BY object_schema, object_name;
object_schema object_name count_star
db1 pkg1.f1 0
db1 pkg1.p1 1
db1 pkg1x 1
db2 pkg1.p1 1
# CREATE OR REPLACE PACKAGE BODY
CREATE OR REPLACE PACKAGE BODY db1.pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
FUNCTION f1 RETURN INT AS BEGIN RETURN 2; END;
END;
$$
SELECT object_schema, object_name, count_star
FROM performance_schema.events_statements_summary_by_program
WHERE object_type IN ('PROCEDURE','FUNCTION') AND
object_schema IN ('db1','db2')
ORDER BY object_schema, object_name;
object_schema object_name count_star
db1 pkg1x 1
db2 pkg1.p1 1
# DROP PACKAGE
CALL db1.pkg1.p1;
DROP PACKAGE db1.pkg1;
SELECT object_schema, object_name, count_star
FROM performance_schema.events_statements_summary_by_program
WHERE object_type IN ('PROCEDURE','FUNCTION') AND
object_schema IN ('db1','db2')
ORDER BY object_schema, object_name;
object_schema object_name count_star
db1 pkg1x 1
db2 pkg1.p1 1
# DROP DATABASE
CREATE PACKAGE db1.pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY db1.pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
END;
$$
CALL db1.pkg1.p1;
SELECT object_schema, object_name, count_star
FROM performance_schema.events_statements_summary_by_program
WHERE object_type IN ('PROCEDURE','FUNCTION') AND
object_schema IN ('db1','db2')
ORDER BY object_schema, object_name;
object_schema object_name count_star
db1 pkg1.p1 1
db1 pkg1x 1
db2 pkg1.p1 1
DROP DATABASE db1;
SELECT object_schema, object_name, count_star
FROM performance_schema.events_statements_summary_by_program
WHERE object_type IN ('PROCEDURE','FUNCTION') AND
object_schema IN ('db1','db2')
ORDER BY object_schema, object_name;
object_schema object_name count_star
db2 pkg1.p1 1
DROP DATABASE db2;
SELECT object_schema, object_name, count_star
FROM performance_schema.events_statements_summary_by_program
WHERE object_type IN ('PROCEDURE','FUNCTION') AND
object_schema IN ('db1','db2')
ORDER BY object_schema, object_name;
object_schema object_name count_star
SET sql_mode= @save_sql_mode;
# End of 10.11 tests

View File

@@ -318,4 +318,103 @@ SET default_storage_engine = performance_schema;
--error ER_ILLEGAL_HA_CREATE_OPTION
CREATE TEMPORARY TABLE t1 (t int);
SET @@default_storage_engine = @default_storage_engine_old;
SET @@default_storage_engine = @default_storage_engine_old;
--echo #
--echo # MDEV-34817 Performance schema is not cleared of removed package routines
--echo #
let $q= SELECT object_schema, object_name, count_star
FROM performance_schema.events_statements_summary_by_program
WHERE object_type IN ('PROCEDURE','FUNCTION') AND
object_schema IN ('db1','db2')
ORDER BY object_schema, object_name;
SET @save_sql_mode= @@sql_mode;
SET sql_mode=ORACLE;
CREATE DATABASE db1;
CREATE DATABASE db2;
DELIMITER $$;
CREATE PACKAGE db1.pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
CREATE PACKAGE BODY db1.pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
FUNCTION f1 RETURN INT AS BEGIN RETURN 1; END;
END;
$$
CREATE PACKAGE db2.pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY db2.pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
END;
$$
CREATE PROCEDURE db1.pkg1x AS BEGIN NULL; END;
$$
DELIMITER ;$$
CALL db1.pkg1.p1;
SELECT db1.pkg1.f1();
CALL db2.pkg1.p1;
CALL db1.pkg1x;
--echo # Routines executed in another connection must be removed as well
connect con1,localhost,root;
CALL db1.pkg1.p1;
disconnect con1;
connection default;
eval $q;
DROP PACKAGE BODY db1.PKG1;
eval $q;
--echo # Statistics of the re-created routines start from zero
DELIMITER $$;
CREATE PACKAGE BODY db1.pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
FUNCTION f1 RETURN INT AS BEGIN RETURN 1; END;
END;
$$
DELIMITER ;$$
CALL db1.pkg1.p1;
eval $q;
--echo # CREATE OR REPLACE PACKAGE BODY
DELIMITER $$;
CREATE OR REPLACE PACKAGE BODY db1.pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
FUNCTION f1 RETURN INT AS BEGIN RETURN 2; END;
END;
$$
DELIMITER ;$$
eval $q;
--echo # DROP PACKAGE
CALL db1.pkg1.p1;
DROP PACKAGE db1.pkg1;
eval $q;
--echo # DROP DATABASE
DELIMITER $$;
CREATE PACKAGE db1.pkg1 AS
PROCEDURE p1;
END;
$$
CREATE PACKAGE BODY db1.pkg1 AS
PROCEDURE p1 AS BEGIN NULL; END;
END;
$$
DELIMITER ;$$
CALL db1.pkg1.p1;
eval $q;
DROP DATABASE db1;
eval $q;
DROP DATABASE db2;
eval $q;
SET sql_mode= @save_sql_mode;
--echo # End of 10.11 tests

View File

@@ -246,6 +246,8 @@ search:
pfs->m_schema_name_length= schema_name_length;
pfs->m_enabled= is_enabled;
pfs->m_timed= is_timed;
pfs->m_stmt_stat.reset();
pfs->m_sp_stat.reset();
/* Insert this record. */
pfs->m_lock.dirty_to_allocated(& dirty_state);
@@ -277,6 +279,51 @@ search:
return NULL;
}
/**
Drops records of the routines of a package body.
They are named "<package>.<routine>" in the package schema.
Names are compared in the lower-cased form of PFS_program_key.
*/
class Proc_drop_package_routines
: public PFS_buffer_processor<PFS_program>
{
public:
Proc_drop_package_routines(LF_PINS *pins,
const char *name, uint name_length,
const char *schema, uint schema_length)
: m_pins(pins), m_name(name), m_name_length(name_length),
m_schema(schema), m_schema_length(schema_length)
{}
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] != '.' ||
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))
return;
/*
Not in the hash yet means find_or_create_program() still owns it.
Concurrent creation of the same key is not possible: routines of
the package are loaded under MDL of the package body.
*/
if (!lf_hash_delete(&program_hash, m_pins,
pfs->m_key.m_hash_key, pfs->m_key.m_key_length))
global_program_container.deallocate(pfs);
}
private:
LF_PINS *m_pins;
const char *m_name;
uint m_name_length;
const char *m_schema;
uint m_schema_length;
};
void drop_program(PFS_thread *thread,
enum_object_type object_type,
const char *object_name,
@@ -310,7 +357,15 @@ void drop_program(PFS_thread *thread,
}
lf_hash_search_unpin(pins);
return;
if (object_type == OBJECT_TYPE_PACKAGE_BODY)
{
const char *name= key.m_hash_key + 1;
Proc_drop_package_routines proc(pins, name, object_name_length,
name + object_name_length + 1,
schema_name_length);
global_program_container.apply(proc);
}
}
void PFS_program::refresh_setup_object_flags(PFS_thread *thread)