From ce90fde5261d9fb87dfe957963b594f02ec9e96e Mon Sep 17 00:00:00 2001 From: Sven Klemm Date: Sat, 16 Dec 2023 13:13:06 +0100 Subject: [PATCH] Alter pre-update handling during downgrade script generation Before this change during downgrade script generation we would always fetch the pre-update script from the previous version and prepend it to the generated scripts. This limits what can be referenced in the pre-update script and also what is possible within the downgrade itself. This patch splits the pre-update script into a generic part that is used for update/downgrade and an update specific part. We could later also add a downgrade specific part but currently it is not needed. This change is necessary because we reference a timescaledb view in the pre-update script which prevents changes to that view. --- cmake/GenerateScripts.cmake | 18 ++++------ cmake/ScriptFiles.cmake | 3 +- sql/updates/pre-update.sql | 49 +------------------------- sql/updates/pre-version-change.sql | 56 ++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 60 deletions(-) create mode 100644 sql/updates/pre-version-change.sql diff --git a/cmake/GenerateScripts.cmake b/cmake/GenerateScripts.cmake index 91c8f602e95..b9da3f15609 100644 --- a/cmake/GenerateScripts.cmake +++ b/cmake/GenerateScripts.cmake @@ -158,19 +158,11 @@ function(generate_downgrade_script) include( ${CMAKE_BINARY_DIR}/v${_downgrade_TARGET_VERSION}/cmake/ScriptFiles.cmake) - set(_downgrade_PRE_FILES ${PRE_UPDATE_FILES}) + set(_downgrade_PRE_FILES ${PRE_DOWNGRADE_FILES}) set(_downgrade_POST_FILES "${PRE_INSTALL_FUNCTION_FILES};${SOURCE_FILES}" ${SET_POST_UPDATE_STAGE} ${POST_UPDATE_FILES} ${UNSET_UPDATE_STAGE}) - # Fetch prolog and epilog from target version. - git_versioned_get( - VERSION - ${_downgrade_TARGET_VERSION} - FILES - ${_downgrade_PRE_FILES} - RESULT_FILES - _prolog_files - IGNORE_ERRORS) + # Fetch epilog from target version. git_versioned_get( VERSION ${_downgrade_TARGET_VERSION} @@ -180,7 +172,11 @@ function(generate_downgrade_script) _epilog_files IGNORE_ERRORS) - set(_files ${_prolog_files}) + foreach(_downgrade_file ${_downgrade_PRE_FILES}) + get_filename_component(_downgrade_filename ${_downgrade_file} NAME) + configure_file(${_downgrade_file} ${_downgrade_INPUT_DIRECTORY}/${_downgrade_filename} COPYONLY) + list(APPEND _files ${_downgrade_INPUT_DIRECTORY}/${_downgrade_filename}) + endforeach() foreach(_downgrade_file ${_downgrade_FILES}) list(APPEND _files ${_downgrade_INPUT_DIRECTORY}/${_downgrade_file}) endforeach() diff --git a/cmake/ScriptFiles.cmake b/cmake/ScriptFiles.cmake index 6146d84f658..c388f783482 100644 --- a/cmake/ScriptFiles.cmake +++ b/cmake/ScriptFiles.cmake @@ -77,7 +77,8 @@ list(APPEND SOURCE_FILES # These files should be pre-pended to update scripts so that they are executed # before anything else during updates -set(PRE_UPDATE_FILES updates/pre-update.sql) +set(PRE_UPDATE_FILES updates/pre-version-change.sql updates/pre-update.sql) +set(PRE_DOWNGRADE_FILES updates/pre-version-change.sql) # The POST_UPDATE_FILES should be executed as the last part of the update # script. sets state for executing POST_UPDATE_FILES during ALTER EXTENSION diff --git a/sql/updates/pre-update.sql b/sql/updates/pre-update.sql index 899b2801aea..2de5baa84e9 100644 --- a/sql/updates/pre-update.sql +++ b/sql/updates/pre-update.sql @@ -2,54 +2,7 @@ -- Please see the included NOTICE for copyright information and -- LICENSE-APACHE for a copy of the license. --- This file is always prepended to all upgrade and downgrade scripts. -SET LOCAL search_path TO pg_catalog, pg_temp; - --- Disable parallel execution for the duration of the update process. --- This avoids version mismatch errors that would have beeen triggered by the --- parallel workers in ts_extension_check_version(). -SET LOCAL max_parallel_workers = 0; - --- Triggers should be disabled during upgrades to avoid having them --- invoke functions that might load an old version of the shared --- library before those functions have been updated. -DROP EVENT TRIGGER IF EXISTS timescaledb_ddl_command_end; -DROP EVENT TRIGGER IF EXISTS timescaledb_ddl_sql_drop; - --- Since we want to call the new version of restart_background_workers we --- create a function that points to that version. The proper restart_background_workers --- may either be in _timescaledb_internal or in _timescaledb_functions --- depending on the version we are upgrading from and we can't make --- the move in this location as the new schema might not have been set up. -CREATE FUNCTION _timescaledb_internal._tmp_restart_background_workers() -RETURNS BOOL -AS '@LOADER_PATHNAME@', 'ts_bgw_db_workers_restart' -LANGUAGE C VOLATILE; -SELECT _timescaledb_internal._tmp_restart_background_workers(); -DROP FUNCTION _timescaledb_internal._tmp_restart_background_workers(); - --- Table for ACL and initprivs of tables. -CREATE TABLE _timescaledb_internal.saved_privs( - tmpnsp name, - tmpname name, - tmpacl aclitem[], - tmpini aclitem[], - UNIQUE (tmpnsp, tmpname)); - --- We save away both the ACL and the initprivs for all tables and --- views in the extension (but not for chunks and internal objects) so --- that we can restore them to the proper state after the update. -INSERT INTO _timescaledb_internal.saved_privs -SELECT nspname, relname, relacl, initprivs - FROM pg_class cl JOIN pg_namespace ns ON ns.oid = relnamespace - JOIN pg_init_privs ip ON ip.objoid = cl.oid AND ip.objsubid = 0 AND ip.classoid = 'pg_class'::regclass -WHERE - nspname IN ('_timescaledb_catalog', '_timescaledb_config') - OR ( - relname IN ('hypertable_chunk_local_size', 'compressed_chunk_stats', 'bgw_job_stat', 'bgw_policy_chunk_stats') - AND nspname = '_timescaledb_internal' - ) -; +-- This file is always prepended to all upgrade scripts. -- ERROR if trying to update the extension on PG16 using Multi-Node DO $$ diff --git a/sql/updates/pre-version-change.sql b/sql/updates/pre-version-change.sql new file mode 100644 index 00000000000..0480819a018 --- /dev/null +++ b/sql/updates/pre-version-change.sql @@ -0,0 +1,56 @@ +-- This file and its contents are licensed under the Apache License 2.0. +-- Please see the included NOTICE for copyright information and +-- LICENSE-APACHE for a copy of the license. + +-- This file is always prepended to all upgrade and downgrade scripts. +-- This file must avoid referencing extension objects directly as that +-- would limit the things we can alter in extension update/downgrade +-- itself. +SET LOCAL search_path TO pg_catalog, pg_temp; + +-- Disable parallel execution for the duration of the update process. +-- This avoids version mismatch errors that would have beeen triggered by the +-- parallel workers in ts_extension_check_version(). +SET LOCAL max_parallel_workers = 0; + +-- Triggers should be disabled during upgrades to avoid having them +-- invoke functions that might load an old version of the shared +-- library before those functions have been updated. +DROP EVENT TRIGGER IF EXISTS timescaledb_ddl_command_end; +DROP EVENT TRIGGER IF EXISTS timescaledb_ddl_sql_drop; + +-- Since we want to call the new version of restart_background_workers we +-- create a function that points to that version. The proper restart_background_workers +-- may either be in _timescaledb_internal or in _timescaledb_functions +-- depending on the version we are upgrading from and we can't make +-- the move in this location as the new schema might not have been set up. +CREATE FUNCTION _timescaledb_internal._tmp_restart_background_workers() +RETURNS BOOL +AS '@LOADER_PATHNAME@', 'ts_bgw_db_workers_restart' +LANGUAGE C VOLATILE; +SELECT _timescaledb_internal._tmp_restart_background_workers(); +DROP FUNCTION _timescaledb_internal._tmp_restart_background_workers(); + +-- Table for ACL and initprivs of tables. +CREATE TABLE _timescaledb_internal.saved_privs( + tmpnsp name, + tmpname name, + tmpacl aclitem[], + tmpini aclitem[], + UNIQUE (tmpnsp, tmpname)); + +-- We save away both the ACL and the initprivs for all tables and +-- views in the extension (but not for chunks and internal objects) so +-- that we can restore them to the proper state after the update. +INSERT INTO _timescaledb_internal.saved_privs +SELECT nspname, relname, relacl, initprivs + FROM pg_class cl JOIN pg_namespace ns ON ns.oid = relnamespace + JOIN pg_init_privs ip ON ip.objoid = cl.oid AND ip.objsubid = 0 AND ip.classoid = 'pg_class'::regclass +WHERE + nspname IN ('_timescaledb_catalog', '_timescaledb_config') + OR ( + relname IN ('hypertable_chunk_local_size', 'compressed_chunk_stats', 'bgw_job_stat', 'bgw_policy_chunk_stats') + AND nspname = '_timescaledb_internal' + ) +; +