From 8eed08dcec148260415e0c3629ee35553de8b5af Mon Sep 17 00:00:00 2001 From: Sven Klemm Date: Fri, 5 Jun 2026 14:36:52 +0200 Subject: [PATCH] Detach public views during extension downgrade To allow user references on extension views detach our catalog views during extension downgrade similar to how we already do for extension update. --- .gitignore | 1 + cmake/GenerateScripts.cmake | 2 +- scripts/check_updates.py | 9 +++ scripts/test_updates.sh | 4 +- sql/updates/2.23.1--2.24.0.sql | 4 ++ sql/updates/2.24.0--2.25.0.sql | 6 ++ sql/updates/2.25.2--2.26.0.sql | 4 -- sql/updates/latest-dev.sql | 6 -- sql/updates/reverse-dev.sql | 5 -- sql/views_detached.sql | 100 ++++++++++++++++--------------- test/sql/updates/cleanup.v12.sql | 5 ++ test/sql/updates/post.v12.sql | 5 ++ test/sql/updates/setup.v11.sql | 1 + test/sql/updates/setup.v12.sql | 22 +++++++ 14 files changed, 109 insertions(+), 65 deletions(-) create mode 100644 test/sql/updates/cleanup.v12.sql create mode 100644 test/sql/updates/post.v12.sql create mode 100644 test/sql/updates/setup.v12.sql diff --git a/.gitignore b/.gitignore index ca0916610af..0715364d966 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ /sql/pre_install/*.gen /sql/updates/*.gen /sql/updates/header.sql +/sql/updates/views_detached.sql /data/ /src/*.o /src/*.so diff --git a/cmake/GenerateScripts.cmake b/cmake/GenerateScripts.cmake index 5f01ec82684..5e931ec8af9 100644 --- a/cmake/GenerateScripts.cmake +++ b/cmake/GenerateScripts.cmake @@ -59,7 +59,7 @@ function(generate_downgrade_script) include( ${CMAKE_BINARY_DIR}/v${_downgrade_TARGET_VERSION}/cmake/ScriptFiles.cmake) - set(_downgrade_PRE_FILES "header.sql;${PRE_DOWNGRADE_FILES}") + set(_downgrade_PRE_FILES "header.sql;views_detached.sql;${PRE_DOWNGRADE_FILES}") set(_downgrade_POST_FILES "${PRE_INSTALL_FUNCTION_FILES};${SOURCE_FILES}" ${POST_UPDATE_FILES}) # Fetch epilog from target version. diff --git a/scripts/check_updates.py b/scripts/check_updates.py index 69b360e54eb..d83a9778e4d 100644 --- a/scripts/check_updates.py +++ b/scripts/check_updates.py @@ -6,6 +6,7 @@ from pglast import parse_sql from pglast.ast import ColumnDef +from pglast.enums.parsenodes import ObjectType from pglast.visitors import Visitor from pglast import enums import sys @@ -178,6 +179,14 @@ def visit_CreateFunctionStmt( "_timescaledb_functions should be used as schema for internal functions", ) + def visit_DropStmt(self, _ancestors, node): + if node.removeType == ObjectType.OBJECT_VIEW: + if node.objects[0][0].sval == "timescaledb_information": + self.error( + f"Attempting to drop view {node.objects[0][0].sval}.{node.objects[0][1].sval}", + "Views in schema timescaledb_information must not be dropped in update scripts", + ) + # copied from pgspot def visit_sql(sql): diff --git a/scripts/test_updates.sh b/scripts/test_updates.sh index 5b0e75e63ce..d78439d49f8 100755 --- a/scripts/test_updates.sh +++ b/scripts/test_updates.sh @@ -91,7 +91,9 @@ if [ -n "${VERSIONS}" ]; then for version in ${VERSIONS}; do ts_minor_version=$(echo "${version}" | awk -F. '{print $2}') - if [ "${ts_minor_version}" -ge 22 ]; then + if [ "${ts_minor_version}" -ge 25 ]; then + TEST_VERSION=v12 + elif [ "${ts_minor_version}" -ge 22 ]; then TEST_VERSION=v11 elif [ "${ts_minor_version}" -ge 20 ]; then TEST_VERSION=v10 diff --git a/sql/updates/2.23.1--2.24.0.sql b/sql/updates/2.23.1--2.24.0.sql index 6a401e14bb7..7c625c637c7 100644 --- a/sql/updates/2.23.1--2.24.0.sql +++ b/sql/updates/2.23.1--2.24.0.sql @@ -1,5 +1,8 @@ DROP FUNCTION IF EXISTS _timescaledb_functions.policy_job_stat_history_retention; +DROP VIEW IF EXISTS timescaledb_information.hypertables; DROP VIEW IF EXISTS timescaledb_information.chunks; +DROP VIEW IF EXISTS timescaledb_information.chunk_columnstore_settings; +DROP VIEW IF EXISTS timescaledb_information.chunk_compression_settings; -- Add support for concurrent merge_chunks() CREATE TABLE _timescaledb_catalog.chunk_rewrite ( @@ -27,3 +30,4 @@ BEGIN END IF; END $$; + diff --git a/sql/updates/2.24.0--2.25.0.sql b/sql/updates/2.24.0--2.25.0.sql index f3789b4b4c2..b9fa4b50194 100644 --- a/sql/updates/2.24.0--2.25.0.sql +++ b/sql/updates/2.24.0--2.25.0.sql @@ -1,4 +1,9 @@ DROP VIEW IF EXISTS timescaledb_information.dimensions; +DROP VIEW IF EXISTS timescaledb_information.hypertables; +DROP VIEW IF EXISTS timescaledb_information.chunks; +DROP VIEW IF EXISTS timescaledb_information.chunk_columnstore_settings; +DROP VIEW IF EXISTS timescaledb_information.chunk_compression_settings; + -- Block update if CAggs in old format are found DO $$ @@ -252,3 +257,4 @@ DROP FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts DROP FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts TIMESTAMPTZ); DROP FUNCTION timescaledb_experimental.time_bucket_ng(bucket_width INTERVAL, ts TIMESTAMPTZ, origin TIMESTAMPTZ); + diff --git a/sql/updates/2.25.2--2.26.0.sql b/sql/updates/2.25.2--2.26.0.sql index 472c923f207..5e8835e91a8 100644 --- a/sql/updates/2.25.2--2.26.0.sql +++ b/sql/updates/2.25.2--2.26.0.sql @@ -14,12 +14,8 @@ ALTER TABLE _timescaledb_catalog.compression_chunk_size DROP CONSTRAINT compress ALTER TABLE _timescaledb_catalog.compression_chunk_size DROP CONSTRAINT compression_chunk_size_compressed_chunk_id_fkey; --drop dependent views -DROP VIEW IF EXISTS timescaledb_information.hypertables; -DROP VIEW IF EXISTS timescaledb_information.chunks; DROP VIEW IF EXISTS _timescaledb_internal.hypertable_chunk_local_size; DROP VIEW IF EXISTS _timescaledb_internal.compressed_chunk_stats; -DROP VIEW IF EXISTS timescaledb_information.chunk_columnstore_settings; -DROP VIEW IF EXISTS timescaledb_information.chunk_compression_settings; ALTER EXTENSION timescaledb DROP TABLE _timescaledb_catalog.chunk; ALTER EXTENSION timescaledb DROP SEQUENCE _timescaledb_catalog.chunk_id_seq; diff --git a/sql/updates/latest-dev.sql b/sql/updates/latest-dev.sql index d33d587f216..d81e8434401 100644 --- a/sql/updates/latest-dev.sql +++ b/sql/updates/latest-dev.sql @@ -72,8 +72,6 @@ CREATE TABLE _timescaledb_internal.tmp_dimension_slice_seq_value AS ALTER TABLE _timescaledb_catalog.chunk_constraint DROP CONSTRAINT IF EXISTS chunk_constraint_dimension_slice_id_fkey; -DROP VIEW IF EXISTS timescaledb_information.chunks; - ALTER EXTENSION timescaledb DROP TABLE _timescaledb_catalog.dimension_slice; ALTER EXTENSION timescaledb DROP SEQUENCE _timescaledb_catalog.dimension_slice_id_seq; @@ -163,7 +161,6 @@ DROP FUNCTION _timescaledb_functions.chunk_constraint_add_table_constraint( _timescaledb_catalog.chunk_constraint); DROP FUNCTION IF EXISTS _timescaledb_internal.chunk_constraint_add_table_constraint( _timescaledb_catalog.chunk_constraint); -DROP VIEW IF EXISTS timescaledb_information.chunks; ALTER EXTENSION timescaledb DROP TABLE _timescaledb_catalog.chunk_constraint; ALTER EXTENSION timescaledb DROP SEQUENCE _timescaledb_catalog.chunk_constraint_name; @@ -187,9 +184,6 @@ ALTER TABLE _timescaledb_catalog.hypertable -- Drop views and foreign keys that depend on the catalog table. DROP VIEW IF EXISTS timescaledb_experimental.policies; -DROP VIEW IF EXISTS timescaledb_information.hypertables; -DROP VIEW IF EXISTS timescaledb_information.continuous_aggregates; -DROP VIEW IF EXISTS timescaledb_information.jobs; ALTER TABLE _timescaledb_catalog.continuous_aggs_watermark DROP CONSTRAINT continuous_aggs_watermark_mat_hypertable_id_fkey; diff --git a/sql/updates/reverse-dev.sql b/sql/updates/reverse-dev.sql index 4d98a20ff64..5c257da5ff2 100644 --- a/sql/updates/reverse-dev.sql +++ b/sql/updates/reverse-dev.sql @@ -91,8 +91,6 @@ CREATE TABLE _timescaledb_internal.tmp_dimension_slice AS CREATE TABLE _timescaledb_internal.tmp_dimension_slice_seq_value AS SELECT last_value, is_called FROM _timescaledb_catalog.dimension_slice_id_seq; -DROP VIEW IF EXISTS timescaledb_information.chunks; - ALTER EXTENSION timescaledb DROP TABLE _timescaledb_catalog.dimension_slice; ALTER EXTENSION timescaledb DROP SEQUENCE _timescaledb_catalog.dimension_slice_id_seq; @@ -193,9 +191,6 @@ DROP FUNCTION IF EXISTS _timescaledb_functions.rebuild_sparse_index(REGCLASS, BO -- Rebuild the catalog table `_timescaledb_catalog.continuous_agg` to drop the -- `schema_change_timestamp` column. DROP VIEW IF EXISTS timescaledb_experimental.policies; -DROP VIEW IF EXISTS timescaledb_information.hypertables; -DROP VIEW IF EXISTS timescaledb_information.continuous_aggregates; -DROP VIEW IF EXISTS timescaledb_information.jobs; ALTER TABLE _timescaledb_catalog.continuous_aggs_watermark DROP CONSTRAINT continuous_aggs_watermark_mat_hypertable_id_fkey; diff --git a/sql/views_detached.sql b/sql/views_detached.sql index 18e15068c57..561be8e76f4 100644 --- a/sql/views_detached.sql +++ b/sql/views_detached.sql @@ -168,51 +168,55 @@ SELECT NULL::text AS orderby, NULL::jsonb AS index; -CREATE OR REPLACE VIEW timescaledb_information.stat_chunk_activity AS -SELECT - NULL::regclass AS chunk, - NULL::regclass AS compressed_chunk, - NULL::integer AS chunk_id, - NULL::integer AS hypertable_id, - NULL::name AS hypertable, - NULL::bigint AS compressed_batch_count, - NULL::bigint AS compressed_block_count, - NULL::bigint AS compressed_batch_rows_min, - NULL::bigint AS compressed_batch_rows_max, - NULL::bigint AS compressed_batch_rows_avg, - NULL::double precision AS compressed_batch_rows_stddev, - NULL::bigint AS compressed_batch_bytes_min, - NULL::bigint AS compressed_batch_bytes_max, - NULL::bigint AS compressed_batch_bytes_avg, - NULL::double precision AS compressed_batch_bytes_stddev, - NULL::bigint AS compressed_block_bytes_min, - NULL::bigint AS compressed_block_bytes_max, - NULL::bigint AS compressed_block_bytes_avg, - NULL::double precision AS compressed_block_bytes_stddev, - NULL::bigint AS total_batches_deleted, - NULL::bigint AS total_batches_decompressed, - NULL::bigint AS total_tuples_decompressed, - NULL::bigint AS total_batches_scanned, - NULL::bigint AS total_batches_checked_by_bloom, - NULL::bigint AS total_batches_pruned_by_bloom, - NULL::bigint AS total_batches_without_bloom, - NULL::bigint AS total_batches_bloom_false_positives, - NULL::bigint AS total_batches_filtered_compressed, - NULL::bigint AS total_batches_filtered_decompressed, - NULL::bigint AS last_op_batches_deleted, - NULL::bigint AS last_op_batches_decompressed, - NULL::bigint AS last_op_tuples_decompressed, - NULL::bigint AS last_op_batches_scanned, - NULL::bigint AS last_op_batches_checked_by_bloom, - NULL::bigint AS last_op_batches_pruned_by_bloom, - NULL::bigint AS last_op_batches_without_bloom, - NULL::bigint AS last_op_batches_bloom_false_positives, - NULL::bigint AS last_op_batches_filtered_compressed, - NULL::bigint AS last_op_batches_filtered_decompressed, - NULL::bigint AS n_selects, - NULL::bigint AS n_inserts, - NULL::bigint AS n_updates, - NULL::bigint AS n_deletes, - NULL::timestamptz AS first_update, - NULL::timestamptz AS last_update; - +DO $$ +BEGIN + IF EXISTS (SELECT FROM pg_class WHERE relname = 'stat_chunk_activity' AND relkind = 'v') THEN + CREATE OR REPLACE VIEW timescaledb_information.stat_chunk_activity AS + SELECT + NULL::regclass AS chunk, + NULL::regclass AS compressed_chunk, + NULL::integer AS chunk_id, + NULL::integer AS hypertable_id, + NULL::name AS hypertable, + NULL::bigint AS compressed_batch_count, + NULL::bigint AS compressed_block_count, + NULL::bigint AS compressed_batch_rows_min, + NULL::bigint AS compressed_batch_rows_max, + NULL::bigint AS compressed_batch_rows_avg, + NULL::double precision AS compressed_batch_rows_stddev, + NULL::bigint AS compressed_batch_bytes_min, + NULL::bigint AS compressed_batch_bytes_max, + NULL::bigint AS compressed_batch_bytes_avg, + NULL::double precision AS compressed_batch_bytes_stddev, + NULL::bigint AS compressed_block_bytes_min, + NULL::bigint AS compressed_block_bytes_max, + NULL::bigint AS compressed_block_bytes_avg, + NULL::double precision AS compressed_block_bytes_stddev, + NULL::bigint AS total_batches_deleted, + NULL::bigint AS total_batches_decompressed, + NULL::bigint AS total_tuples_decompressed, + NULL::bigint AS total_batches_scanned, + NULL::bigint AS total_batches_checked_by_bloom, + NULL::bigint AS total_batches_pruned_by_bloom, + NULL::bigint AS total_batches_without_bloom, + NULL::bigint AS total_batches_bloom_false_positives, + NULL::bigint AS total_batches_filtered_compressed, + NULL::bigint AS total_batches_filtered_decompressed, + NULL::bigint AS last_op_batches_deleted, + NULL::bigint AS last_op_batches_decompressed, + NULL::bigint AS last_op_tuples_decompressed, + NULL::bigint AS last_op_batches_scanned, + NULL::bigint AS last_op_batches_checked_by_bloom, + NULL::bigint AS last_op_batches_pruned_by_bloom, + NULL::bigint AS last_op_batches_without_bloom, + NULL::bigint AS last_op_batches_bloom_false_positives, + NULL::bigint AS last_op_batches_filtered_compressed, + NULL::bigint AS last_op_batches_filtered_decompressed, + NULL::bigint AS n_selects, + NULL::bigint AS n_inserts, + NULL::bigint AS n_updates, + NULL::bigint AS n_deletes, + NULL::timestamptz AS first_update, + NULL::timestamptz AS last_update; + END IF; +END $$; diff --git a/test/sql/updates/cleanup.v12.sql b/test/sql/updates/cleanup.v12.sql new file mode 100644 index 00000000000..705ec140c1b --- /dev/null +++ b/test/sql/updates/cleanup.v12.sql @@ -0,0 +1,5 @@ +-- 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. + +\ir cleanup.v11.sql diff --git a/test/sql/updates/post.v12.sql b/test/sql/updates/post.v12.sql new file mode 100644 index 00000000000..cda89b08d42 --- /dev/null +++ b/test/sql/updates/post.v12.sql @@ -0,0 +1,5 @@ +-- 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. + +\ir post.v11.sql diff --git a/test/sql/updates/setup.v11.sql b/test/sql/updates/setup.v11.sql index 9a838d5aab1..f4ac29db9eb 100644 --- a/test/sql/updates/setup.v11.sql +++ b/test/sql/updates/setup.v11.sql @@ -4,3 +4,4 @@ \ir setup.v10.sql \ir setup.fix_sparse_index_migration.sql + diff --git a/test/sql/updates/setup.v12.sql b/test/sql/updates/setup.v12.sql new file mode 100644 index 00000000000..69d8fc8bf1b --- /dev/null +++ b/test/sql/updates/setup.v12.sql @@ -0,0 +1,22 @@ +-- 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. + +\ir setup.v11.sql + +CREATE schema user_views; + +CREATE OR REPLACE VIEW user_views.hypertables AS SELECT * FROM timescaledb_information.hypertables; +CREATE OR REPLACE VIEW user_views.job_stats AS SELECT * FROM timescaledb_information.job_stats; +CREATE OR REPLACE VIEW user_views.jobs AS SELECT * FROM timescaledb_information.jobs; +CREATE OR REPLACE VIEW user_views.continuous_aggregates AS SELECT * FROM timescaledb_information.continuous_aggregates; +CREATE OR REPLACE VIEW user_views.chunks AS SELECT * FROM timescaledb_information.chunks; +CREATE OR REPLACE VIEW user_views.dimensions AS SELECT * FROM timescaledb_information.dimensions; +CREATE OR REPLACE VIEW user_views.compression_settings AS SELECT * FROM timescaledb_information.compression_settings; +CREATE OR REPLACE VIEW user_views.job_errors AS SELECT * FROM timescaledb_information.job_errors; +CREATE OR REPLACE VIEW user_views.job_history AS SELECT * FROM timescaledb_information.job_history; +CREATE OR REPLACE VIEW user_views.hypertable_compression_settings AS SELECT * FROM timescaledb_information.hypertable_compression_settings; +CREATE OR REPLACE VIEW user_views.chunk_compression_settings AS SELECT * FROM timescaledb_information.chunk_compression_settings; +CREATE OR REPLACE VIEW user_views.hypertable_columnstore_settings AS SELECT * FROM timescaledb_information.hypertable_columnstore_settings; +CREATE OR REPLACE VIEW user_views.chunk_columnstore_settings AS SELECT * FROM timescaledb_information.chunk_columnstore_settings; +