diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c index bafdca80810..ce5b99c38b1 100644 --- a/src/backend/commands/repack.c +++ b/src/backend/commands/repack.c @@ -62,6 +62,7 @@ #include "miscadmin.h" #include "optimizer/optimizer.h" #include "pgstat.h" +#include "replication/logicalrelation.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "storage/predicate.h" @@ -919,14 +920,12 @@ check_concurrent_repack_requirements(Relation rel, Oid *ident_idx_p) /* * Obtain the replica identity index -- either one that has been set - * explicitly, or the primary key. If none of these cases apply, the - * table cannot be repacked concurrently. It might be possible to have - * repack work with a FULL replica identity; however that requires more - * work and is not implemented yet. + * explicitly, or a non-deferrable primary key. If none of these cases + * apply, the table cannot be repacked concurrently. It might be possible + * to have repack work with a FULL replica identity; however that requires + * more work and is not implemented yet. */ - ident_idx = RelationGetReplicaIndex(rel); - if (!OidIsValid(ident_idx) && OidIsValid(rel->rd_pkindex)) - ident_idx = rel->rd_pkindex; + ident_idx = GetRelationIdentityOrPK(rel); if (!OidIsValid(ident_idx)) ereport(ERROR, errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), diff --git a/src/test/regress/expected/cluster.out b/src/test/regress/expected/cluster.out index 96089bb0fa2..8f80f9f752d 100644 --- a/src/test/regress/expected/cluster.out +++ b/src/test/regress/expected/cluster.out @@ -796,15 +796,63 @@ ORDER BY o.relname; clstr_3 (2 rows) --- concurrently disallowed in catalogs +-- +-- Check concurrent mode requirements +-- +-- Disallowed in catalogs REPACK (CONCURRENTLY) pg_class; ERROR: cannot repack relation "pg_class" HINT: REPACK CONCURRENTLY is not supported for catalog relations. --- CONCURRENTLY doesn't like partitioned tables +-- 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 repack 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 repack 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 repack 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 repack relation "repack_conc_replident" +HINT: Relation "repack_conc_replident" has insufficient replication identity. +-- Doesn't support tables with REPLICA IDENTITY FULL, even if they have a primary key +ALTER TABLE repack_conc_replident REPLICA IDENTITY FULL; +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; +ERROR: cannot process 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 process relation "repack_conc_replident" +HINT: Relation "repack_conc_replident" has no identity index. -- 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 6b3219bab94..a8cb7ca982d 100644 --- a/src/test/regress/sql/cluster.sql +++ b/src/test/regress/sql/cluster.sql @@ -383,13 +383,56 @@ JOIN relnodes_new n ON o.relname = n.relname WHERE o.relfilenode <> n.relfilenode ORDER BY o.relname; --- concurrently disallowed in catalogs +-- +-- Check concurrent mode requirements +-- + +-- Disallowed in catalogs REPACK (CONCURRENTLY) pg_class; --- CONCURRENTLY doesn't like partitioned tables +-- 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 with REPLICA IDENTITY FULL, even if they have a primary key +ALTER TABLE repack_conc_replident REPLICA IDENTITY FULL; +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;