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 43649b6a53 now causes servers with
wal_level=minimal to error out earlier than before.

Author: Álvaro Herrera <alvherre@kurilemu.de>
Reviewed-by: Baji Shaik <baji.pgdev@gmail.com>
Discussion: https://postgr.es/m/ahiwD29RNfVT4tjQ@alvherre.pgsql
This commit is contained in:
Álvaro Herrera 2026-05-29 11:54:00 +02:00
parent e2b35735b0
commit 2670cc298f
No known key found for this signature in database
GPG key ID: 1C20ACB9D5C564AE
4 changed files with 154 additions and 99 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;