1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00
Files
mariadb/scripts/sys_schema/procedures/ps_setup_save.sql
Oleksandr Byelkin 6c951fea5f MDEV-39993 Use CREATE OR REPLACE for sys schema routines
mariadb-upgrade silently dropped EXECUTE grants on sys schema stored
functions and procedures. The sys schema install scripts reinstalled
every routine with DROP FUNCTION/PROCEDURE IF EXISTS followed by
CREATE. DROP cascades to delete the routine's rows in
mysql.procs_priv, so any EXECUTE grant a DBA had issued on e.g.
sys.table_exists or sys.quote_identifier was lost every time
mariadb-upgrade reinstalled the sys schema, even though the routine
itself came back unchanged.

Fix: replace DROP ... IF EXISTS + CREATE with CREATE OR REPLACE in
all 53 sys_schema function/procedure files and in the two templates
(templates/function.sql, templates/procedure.sql) so future routines
follow the same pattern. CREATE OR REPLACE PROCEDURE/FUNCTION goes
through sp_drop_routine_internal(), which only deletes the
mysql.proc row and never reaches sp_revoke_privileges() (that is
only called from the explicit DROP PROCEDURE/FUNCTION statement),
so mysql.procs_priv is left untouched and existing grants survive.
This mirrors the pattern already used by sys schema views
(CREATE OR REPLACE ... VIEW, since MDEV-9077), which never had this
problem.

Four of the converted files (functions/format_path.sql,
functions/ps_is_account_enabled_57.sql,
procedures/ps_setup_reset_to_default.sql,
procedures/ps_trace_thread_57.sql) are not referenced by
scripts/sys_schema/CMakeLists.txt; they were converted anyway for
consistency and have no behavioural effect.

As a side effect, a pre-existing UDF whose name collides with a sys
routine name is no longer destroyed before the reinstall fails:
DROP FUNCTION IF EXISTS resolved the UDF namespace first, silently
dropping the UDF and then failing on ER_SP_ALREADY_EXISTS anyway;
CREATE OR REPLACE fails immediately on ER_UDF_EXISTS with the UDF
intact.

scripts/maria_add_gis_sp.sql.in and the sys_config triggers were
deliberately left untouched: the GIS procedures are only
re-installed at bootstrap time (mariadb-upgrade instead patches
their definer in place via UPDATE), and triggers carry no
procs_priv rows, so neither is on the code path this bug is about.

Added mysql-test/main/mysql_upgrade_sys_routine_grants.test, which
grants EXECUTE on sys.table_exists and sys.quote_identifier,
overwrites both routine bodies with a marker to prove the upgrade
actually reinstalls them (rather than the sys schema install being
skipped), runs mariadb-upgrade, and checks both that the grants
survived and that the real routine bodies came back.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 17:07:02 +02:00

96 lines
3.6 KiB
SQL

-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; version 2 of the License.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
DELIMITER $$
CREATE OR REPLACE DEFINER='mariadb.sys'@'localhost' PROCEDURE ps_setup_save (
IN in_timeout INT
)
COMMENT '
Description
-----------
Saves the current configuration of Performance Schema,
so that you can alter the setup for debugging purposes,
but restore it to a previous state.
Use the companion procedure - ps_setup_reload_saved(), to
restore the saved config.
The named lock "sys.ps_setup_save" is taken before the
current configuration is saved. If the attempt to get the named
lock times out, an error occurs.
The lock is released after the settings have been restored by
calling ps_setup_reload_saved().
Requires the SUPER privilege for "SET sql_log_bin = 0;".
Parameters
-----------
in_timeout INT
The timeout in seconds used when trying to obtain the lock.
A negative timeout means infinite timeout.
Example
-----------
mysql> CALL sys.ps_setup_save(-1);
Query OK, 0 rows affected (0.08 sec)
mysql> UPDATE performance_schema.setup_instruments
-> SET enabled = ''YES'', timed = ''YES'';
Query OK, 547 rows affected (0.40 sec)
Rows matched: 784 Changed: 547 Warnings: 0
/* Run some tests that need more detailed instrumentation here */
mysql> CALL sys.ps_setup_reload_saved();
Query OK, 0 rows affected (0.32 sec)
'
SQL SECURITY INVOKER
NOT DETERMINISTIC
MODIFIES SQL DATA
BEGIN
DECLARE v_lock_result INT;
SELECT GET_LOCK('sys.ps_setup_save', in_timeout) INTO v_lock_result;
IF v_lock_result THEN
SET @log_bin := @@sql_log_bin;
SET sql_log_bin = 0;
DROP TEMPORARY TABLE IF EXISTS tmp_setup_actors;
DROP TEMPORARY TABLE IF EXISTS tmp_setup_consumers;
DROP TEMPORARY TABLE IF EXISTS tmp_setup_instruments;
DROP TEMPORARY TABLE IF EXISTS tmp_threads;
CREATE TEMPORARY TABLE tmp_setup_actors AS SELECT * FROM performance_schema.setup_actors;
CREATE TEMPORARY TABLE tmp_setup_consumers AS SELECT * FROM performance_schema.setup_consumers;
CREATE TEMPORARY TABLE tmp_setup_instruments AS SELECT * FROM performance_schema.setup_instruments;
CREATE TEMPORARY TABLE tmp_threads (THREAD_ID bigint unsigned NOT NULL PRIMARY KEY, INSTRUMENTED enum('YES','NO') NOT NULL);
INSERT INTO tmp_threads SELECT THREAD_ID, INSTRUMENTED FROM performance_schema.threads;
SET sql_log_bin = @log_bin;
ELSE
SIGNAL SQLSTATE VALUE '90000'
SET MESSAGE_TEXT = 'Could not lock the sys.ps_setup_save user lock, another thread has a saved configuration';
END IF;
END$$
DELIMITER ;