From: Álvaro Herrera Date: Fri, 29 May 2026 09:54:00 +0000 (+0200) Subject: Cover additional errors and corner conditions in repack.c X-Git-Tag: REL_19_BETA1~22 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=2670cc298f42cd7b1c426bf7ccfb0652d8e0b347;p=thirdparty%2Fpostgresql.git Cover additional errors and corner conditions in repack.c The coverage report shows that some error cases were not being tested; add test cases for them. While at it, move some recently added ones to the test_decoding suite: the preventative check added in 43649b6a53e9 now causes servers with wal_level=minimal to error out earlier than before. Author: Álvaro Herrera Reviewed-by: Baji Shaik Discussion: https://postgr.es/m/ahiwD29RNfVT4tjQ@alvherre.pgsql --- diff --git a/contrib/test_decoding/expected/repack.out b/contrib/test_decoding/expected/repack.out index cf93c1f0d3d..6204e620b43 100644 --- a/contrib/test_decoding/expected/repack.out +++ b/contrib/test_decoding/expected/repack.out @@ -51,3 +51,53 @@ SELECT * FROM rpk_missing; (3 rows) DROP TABLE rpk_missing; +-- Error cases for concurrent mode +-- Doesn't like partitioned tables +CREATE TABLE clstrpart (a int) PARTITION BY RANGE (a); +REPACK (CONCURRENTLY) clstrpart; +ERROR: REPACK (CONCURRENTLY) is not supported for partitioned tables +HINT: Consider running the command on individual partitions. +-- Disallowed in catalogs +REPACK (CONCURRENTLY) pg_class; +ERROR: cannot execute REPACK (CONCURRENTLY) on relation "pg_class" +HINT: REPACK (CONCURRENTLY) is not supported for catalog relations. +-- Doesn't support TOAST tables directly +CREATE TABLE repack_conc_toast (t text); +SELECT reltoastrelid::regclass AS toast_rel +FROM pg_class WHERE oid = 'repack_conc_toast'::regclass \gset +\set VERBOSITY sqlstate +REPACK (CONCURRENTLY) :toast_rel; +ERROR: 0A000 +\set VERBOSITY default +DROP TABLE repack_conc_toast; +-- Only support permanent tables, temp and unlogged tables are not supported +CREATE TEMP TABLE repack_conc_temp (i int PRIMARY KEY); +REPACK (CONCURRENTLY) repack_conc_temp; +ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_temp" +HINT: REPACK (CONCURRENTLY) is only allowed for permanent relations. +DROP TABLE repack_conc_temp; +CREATE UNLOGGED TABLE repack_conc_unlogged (i int PRIMARY KEY); +REPACK (CONCURRENTLY) repack_conc_unlogged; +ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_unlogged" +HINT: REPACK (CONCURRENTLY) is only allowed for permanent relations. +DROP TABLE repack_conc_unlogged; +-- Doesn't support tables with REPLICA IDENTITY NOTHING, even if they have a primary key +CREATE TABLE repack_conc_replident (i int PRIMARY KEY); +ALTER TABLE repack_conc_replident REPLICA IDENTITY NOTHING; +REPACK (CONCURRENTLY) repack_conc_replident; +ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident" +DETAIL: REPACK (CONCURRENTLY) does not support tables with REPLICA IDENTITY NOTHING. +-- Doesn't support tables without a primary key or replica identity index +ALTER TABLE repack_conc_replident DROP CONSTRAINT repack_conc_replident_pkey; +ALTER TABLE repack_conc_replident REPLICA IDENTITY DEFAULT; +REPACK (CONCURRENTLY) repack_conc_replident; +ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident" +HINT: Relation "repack_conc_replident" has no identity index. +-- Doesn't support tables with deferrable primary keys +ALTER TABLE repack_conc_replident ADD PRIMARY KEY (i) DEFERRABLE; +REPACK (CONCURRENTLY) repack_conc_replident; +ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident" +DETAIL: REPACK (CONCURRENTLY) does not support deferrable primary keys. +HINT: Use ALTER TABLE ... REPLICA IDENTITY USING INDEX to designate another index as replica identity. +-- clean up +DROP TABLE repack_conc_replident, clstrpart; diff --git a/contrib/test_decoding/sql/repack.sql b/contrib/test_decoding/sql/repack.sql index 6164dd4235f..cea3bd33689 100644 --- a/contrib/test_decoding/sql/repack.sql +++ b/contrib/test_decoding/sql/repack.sql @@ -32,3 +32,46 @@ SELECT * FROM rpk_missing; REPACK (CONCURRENTLY) rpk_missing; SELECT * FROM rpk_missing; DROP TABLE rpk_missing; + +-- Error cases for concurrent mode + +-- Doesn't like partitioned tables +CREATE TABLE clstrpart (a int) PARTITION BY RANGE (a); +REPACK (CONCURRENTLY) clstrpart; + +-- Disallowed in catalogs +REPACK (CONCURRENTLY) pg_class; + +-- Doesn't support TOAST tables directly +CREATE TABLE repack_conc_toast (t text); +SELECT reltoastrelid::regclass AS toast_rel +FROM pg_class WHERE oid = 'repack_conc_toast'::regclass \gset +\set VERBOSITY sqlstate +REPACK (CONCURRENTLY) :toast_rel; +\set VERBOSITY default +DROP TABLE repack_conc_toast; + +-- Only support permanent tables, temp and unlogged tables are not supported +CREATE TEMP TABLE repack_conc_temp (i int PRIMARY KEY); +REPACK (CONCURRENTLY) repack_conc_temp; +DROP TABLE repack_conc_temp; +CREATE UNLOGGED TABLE repack_conc_unlogged (i int PRIMARY KEY); +REPACK (CONCURRENTLY) repack_conc_unlogged; +DROP TABLE repack_conc_unlogged; + +-- Doesn't support tables with REPLICA IDENTITY NOTHING, even if they have a primary key +CREATE TABLE repack_conc_replident (i int PRIMARY KEY); +ALTER TABLE repack_conc_replident REPLICA IDENTITY NOTHING; +REPACK (CONCURRENTLY) repack_conc_replident; + +-- Doesn't support tables without a primary key or replica identity index +ALTER TABLE repack_conc_replident DROP CONSTRAINT repack_conc_replident_pkey; +ALTER TABLE repack_conc_replident REPLICA IDENTITY DEFAULT; +REPACK (CONCURRENTLY) repack_conc_replident; + +-- Doesn't support tables with deferrable primary keys +ALTER TABLE repack_conc_replident ADD PRIMARY KEY (i) DEFERRABLE; +REPACK (CONCURRENTLY) repack_conc_replident; + +-- clean up +DROP TABLE repack_conc_replident, clstrpart; diff --git a/src/test/regress/expected/cluster.out b/src/test/regress/expected/cluster.out index 23f312c62a3..d1bc8a13286 100644 --- a/src/test/regress/expected/cluster.out +++ b/src/test/regress/expected/cluster.out @@ -697,6 +697,39 @@ SELECT * FROM clstr_expression WHERE -a = -3 ORDER BY -a, b; (4 rows) COMMIT; +-- verify some error cases +CREATE TABLE clstr_table_one (id int, val text); +CREATE TABLE clstr_table_two (id int, val text); +CREATE INDEX clstr_idx_b ON clstr_table_two (id); +CLUSTER clstr_table_one USING clstr_idx_b; +ERROR: "clstr_idx_b" is not an index for table "clstr_table_one" +CLUSTER clstr_table_one USING nonexistant; +ERROR: index "nonexistant" for table "clstr_table_one" does not exist +CREATE INDEX clstr_hash_idx ON clstr_table_one USING hash (id); +CLUSTER clstr_table_one USING clstr_hash_idx; +ERROR: cannot cluster on index "clstr_hash_idx" because access method does not support clustering +CREATE INDEX clstr_partial_idx ON clstr_table_one (id) WHERE id > 0; +CLUSTER clstr_table_one USING clstr_partial_idx; +ERROR: cannot cluster on partial index "clstr_partial_idx" +REPACK pg_class USING INDEX pg_class_oid_index; +ERROR: permission denied: "pg_class" is a system catalog +DETAIL: System catalogs can only be clustered by the index they're already clustered on, if any, unless "allow_system_table_mods" is enabled. +DROP TABLE clstr_table_one, clstr_table_two; +-- verify that CLUSTER/REPACK don't touch a NO DATA matview +CREATE MATERIALIZED VIEW clstr_matview AS + SELECT i FROM generate_series(1, 5) i + WITH NO DATA; +CREATE INDEX clstr_matview_idx ON clstr_matview (i); +SELECT relfilenode FROM pg_class WHERE oid = 'clstr_matview'::regclass \gset +CLUSTER clstr_matview USING clstr_matview_idx; +REPACK clstr_matview USING INDEX clstr_matview_idx; +SELECT relfilenode = :relfilenode FROM pg_class WHERE oid = 'clstr_matview'::regclass; + ?column? +---------- + t +(1 row) + +DROP MATERIALIZED VIEW clstr_matview; ---------------------------------------------------------------------- -- -- REPACK @@ -796,61 +829,7 @@ ORDER BY o.relname; clstr_3 (2 rows) --- --- Check concurrent mode requirements --- --- Disallowed in catalogs -REPACK (CONCURRENTLY) pg_class; -ERROR: cannot execute REPACK (CONCURRENTLY) on relation "pg_class" -HINT: REPACK (CONCURRENTLY) is not supported for catalog relations. --- Doesn't like partitioned tables -REPACK (CONCURRENTLY) clstrpart; -ERROR: REPACK (CONCURRENTLY) is not supported for partitioned tables -HINT: Consider running the command on individual partitions. --- Doesn't support catalog tables -REPACK (CONCURRENTLY) pg_class; -ERROR: cannot execute REPACK (CONCURRENTLY) on relation "pg_class" -HINT: REPACK (CONCURRENTLY) is not supported for catalog relations. --- Only support permanent tables, temp and unlogged tables are not supported -CREATE TEMP TABLE repack_conc_temp (i int PRIMARY KEY); -REPACK (CONCURRENTLY) repack_conc_temp; -ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_temp" -HINT: REPACK (CONCURRENTLY) is only allowed for permanent relations. -DROP TABLE repack_conc_temp; -CREATE UNLOGGED TABLE repack_conc_unlogged (i int PRIMARY KEY); -REPACK (CONCURRENTLY) repack_conc_unlogged; -ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_unlogged" -HINT: REPACK (CONCURRENTLY) is only allowed for permanent relations. -DROP TABLE repack_conc_unlogged; --- Doesn't support TOAST tables directly -CREATE TABLE repack_conc_toast (t text); -SELECT reltoastrelid::regclass AS toast_rel -FROM pg_class WHERE oid = 'repack_conc_toast'::regclass \gset -\set VERBOSITY sqlstate -REPACK (CONCURRENTLY) :toast_rel; -ERROR: 0A000 -\set VERBOSITY default -DROP TABLE repack_conc_toast; --- Doesn't support tables with REPLICA IDENTITY NOTHING, even if they have a primary key -CREATE TABLE repack_conc_replident (i int PRIMARY KEY); -ALTER TABLE repack_conc_replident REPLICA IDENTITY NOTHING; -REPACK (CONCURRENTLY) repack_conc_replident; -ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident" -DETAIL: REPACK (CONCURRENTLY) does not support tables with REPLICA IDENTITY NOTHING. --- Doesn't support tables without a primary key or replica identity index -ALTER TABLE repack_conc_replident DROP CONSTRAINT repack_conc_replident_pkey; -ALTER TABLE repack_conc_replident REPLICA IDENTITY DEFAULT; -REPACK (CONCURRENTLY) repack_conc_replident; -ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident" -HINT: Relation "repack_conc_replident" has no identity index. --- Doesn't support tables with deferrable primary keys -ALTER TABLE repack_conc_replident ADD PRIMARY KEY (i) DEFERRABLE; -REPACK (CONCURRENTLY) repack_conc_replident; -ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident" -DETAIL: REPACK (CONCURRENTLY) does not support deferrable primary keys. -HINT: Use ALTER TABLE ... REPLICA IDENTITY USING INDEX to designate another index as replica identity. -- clean up -DROP TABLE repack_conc_replident; DROP TABLE clustertest; DROP TABLE clstr_1; DROP TABLE clstr_2; diff --git a/src/test/regress/sql/cluster.sql b/src/test/regress/sql/cluster.sql index c2f329ecd1b..e7a62367adf 100644 --- a/src/test/regress/sql/cluster.sql +++ b/src/test/regress/sql/cluster.sql @@ -328,6 +328,34 @@ EXPLAIN (COSTS OFF) SELECT * FROM clstr_expression WHERE -a = -3 ORDER BY -a, b; SELECT * FROM clstr_expression WHERE -a = -3 ORDER BY -a, b; COMMIT; +-- verify some error cases +CREATE TABLE clstr_table_one (id int, val text); +CREATE TABLE clstr_table_two (id int, val text); +CREATE INDEX clstr_idx_b ON clstr_table_two (id); +CLUSTER clstr_table_one USING clstr_idx_b; +CLUSTER clstr_table_one USING nonexistant; + +CREATE INDEX clstr_hash_idx ON clstr_table_one USING hash (id); +CLUSTER clstr_table_one USING clstr_hash_idx; + +CREATE INDEX clstr_partial_idx ON clstr_table_one (id) WHERE id > 0; +CLUSTER clstr_table_one USING clstr_partial_idx; + +REPACK pg_class USING INDEX pg_class_oid_index; + +DROP TABLE clstr_table_one, clstr_table_two; + +-- verify that CLUSTER/REPACK don't touch a NO DATA matview +CREATE MATERIALIZED VIEW clstr_matview AS + SELECT i FROM generate_series(1, 5) i + WITH NO DATA; +CREATE INDEX clstr_matview_idx ON clstr_matview (i); +SELECT relfilenode FROM pg_class WHERE oid = 'clstr_matview'::regclass \gset +CLUSTER clstr_matview USING clstr_matview_idx; +REPACK clstr_matview USING INDEX clstr_matview_idx; +SELECT relfilenode = :relfilenode FROM pg_class WHERE oid = 'clstr_matview'::regclass; +DROP MATERIALIZED VIEW clstr_matview; + ---------------------------------------------------------------------- -- -- REPACK @@ -383,52 +411,7 @@ JOIN relnodes_new n ON o.relname = n.relname WHERE o.relfilenode <> n.relfilenode ORDER BY o.relname; --- --- Check concurrent mode requirements --- - --- Disallowed in catalogs -REPACK (CONCURRENTLY) pg_class; - --- Doesn't like partitioned tables -REPACK (CONCURRENTLY) clstrpart; - --- Doesn't support catalog tables -REPACK (CONCURRENTLY) pg_class; - --- Only support permanent tables, temp and unlogged tables are not supported -CREATE TEMP TABLE repack_conc_temp (i int PRIMARY KEY); -REPACK (CONCURRENTLY) repack_conc_temp; -DROP TABLE repack_conc_temp; -CREATE UNLOGGED TABLE repack_conc_unlogged (i int PRIMARY KEY); -REPACK (CONCURRENTLY) repack_conc_unlogged; -DROP TABLE repack_conc_unlogged; - --- Doesn't support TOAST tables directly -CREATE TABLE repack_conc_toast (t text); -SELECT reltoastrelid::regclass AS toast_rel -FROM pg_class WHERE oid = 'repack_conc_toast'::regclass \gset -\set VERBOSITY sqlstate -REPACK (CONCURRENTLY) :toast_rel; -\set VERBOSITY default -DROP TABLE repack_conc_toast; - --- Doesn't support tables with REPLICA IDENTITY NOTHING, even if they have a primary key -CREATE TABLE repack_conc_replident (i int PRIMARY KEY); -ALTER TABLE repack_conc_replident REPLICA IDENTITY NOTHING; -REPACK (CONCURRENTLY) repack_conc_replident; - --- Doesn't support tables without a primary key or replica identity index -ALTER TABLE repack_conc_replident DROP CONSTRAINT repack_conc_replident_pkey; -ALTER TABLE repack_conc_replident REPLICA IDENTITY DEFAULT; -REPACK (CONCURRENTLY) repack_conc_replident; - --- Doesn't support tables with deferrable primary keys -ALTER TABLE repack_conc_replident ADD PRIMARY KEY (i) DEFERRABLE; -REPACK (CONCURRENTLY) repack_conc_replident; - -- clean up -DROP TABLE repack_conc_replident; DROP TABLE clustertest; DROP TABLE clstr_1; DROP TABLE clstr_2;