Thread

Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Reserve replication slots specifically for REPACK

  1. [PATCH 1/2] REPACK: do not require the user to have REPLICATION

    Álvaro Herrera <alvherre@kurilemu.de> — 2026-04-20T09:38:48Z

    Although REPACK (CONCURRENTLY) uses replication slots, there is no
    concern that the slot will leak data of other users, because the
    MAINTAIN privilege on the table is required anyway; requiring
    REPLICATION is user-unfriendly without providing any actual protection.
    
    A related aspect is that the REPLICATION attribute is not needed to
    prevent REPACK from stealing slots from logical replication, since
    commit e76d8c749c31 made REPACK use a separate pool of replication
    slots.
    
    Because there are now successful concurrent repack runs in the
    regression tests, we're forced to run test_plan_advice under
    wal_level=replica.
    
    Author: Antonin Houska <ah@cybertec.at>
    Reported-by: Justin Pryzby <pryzby@telsasoft.com>
    Reviewed-by: Chao Li <lic@highgo.com>
    Discussion: https://postgr.es/m/aeJHPNmL4vVy3oPw@pryzbyj2023
    ---
     src/backend/commands/repack_worker.c          |  1 -
     .../test_plan_advice/t/001_replan_regress.pl  |  1 +
     src/test/regress/expected/cluster.out         | 20 +++++++++++++++++--
     src/test/regress/sql/cluster.sql              | 11 ++++++++--
     4 files changed, 28 insertions(+), 5 deletions(-)
    
    diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
    index b17edd771e2..e4a4860805b 100644
    --- a/src/backend/commands/repack_worker.c
    +++ b/src/backend/commands/repack_worker.c
    @@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
     	/*
     	 * Make sure we can use logical decoding.
     	 */
    -	CheckSlotPermissions();
     	CheckLogicalDecodingRequirements(true);
     
     	/*
    diff --git a/src/test/modules/test_plan_advice/t/001_replan_regress.pl b/src/test/modules/test_plan_advice/t/001_replan_regress.pl
    index 38ffa4d11ae..452b179a665 100644
    --- a/src/test/modules/test_plan_advice/t/001_replan_regress.pl
    +++ b/src/test/modules/test_plan_advice/t/001_replan_regress.pl
    @@ -18,6 +18,7 @@ $node->init();
     # Set up our desired configuration.
     $node->append_conf('postgresql.conf', <<EOM);
     shared_preload_libraries='test_plan_advice'
    +wal_level=replica
     pg_plan_advice.always_explain_supplied_advice=false
     pg_plan_advice.feedback_warnings=true
     EOM
    diff --git a/src/test/regress/expected/cluster.out b/src/test/regress/expected/cluster.out
    index 6127b215a86..e17bc91fae1 100644
    --- a/src/test/regress/expected/cluster.out
    +++ b/src/test/regress/expected/cluster.out
    @@ -543,15 +543,17 @@ ERROR:  REPACK (CONCURRENTLY) is not supported for partitioned tables
     HINT:  Consider running the command on individual partitions.
     DROP TABLE clstrpart;
     -- Ownership of partitions is checked
    -CREATE TABLE ptnowner(i int unique) PARTITION BY LIST (i);
    +CREATE TABLE ptnowner(i int unique not null) PARTITION BY LIST (i);
     CREATE INDEX ptnowner_i_idx ON ptnowner(i);
     CREATE TABLE ptnowner1 PARTITION OF ptnowner FOR VALUES IN (1);
    -CREATE ROLE regress_ptnowner;
    +CREATE ROLE regress_ptnowner LOGIN;
     CREATE TABLE ptnowner2 PARTITION OF ptnowner FOR VALUES IN (2);
     ALTER TABLE ptnowner1 OWNER TO regress_ptnowner;
     SET SESSION AUTHORIZATION regress_ptnowner;
     CLUSTER ptnowner USING ptnowner_i_idx;
     ERROR:  permission denied for table ptnowner
    +ALTER TABLE ptnowner1 REPLICA IDENTITY USING INDEX ptnowner1_i_key;
    +REPACK (CONCURRENTLY) ptnowner1;
     RESET SESSION AUTHORIZATION;
     ALTER TABLE ptnowner OWNER TO regress_ptnowner;
     CREATE TEMP TABLE ptnowner_oldnodes AS
    @@ -560,6 +562,11 @@ CREATE TEMP TABLE ptnowner_oldnodes AS
     SET SESSION AUTHORIZATION regress_ptnowner;
     CLUSTER ptnowner USING ptnowner_i_idx;
     WARNING:  permission denied to execute CLUSTER on "ptnowner2", skipping it
    +-- still can't repack without a replica identity
    +ALTER TABLE ptnowner1 REPLICA IDENTITY DEFAULT;
    +REPACK (CONCURRENTLY) ptnowner1;
    +ERROR:  cannot process relation "ptnowner1"
    +HINT:  Relation "ptnowner1" has no identity index.
     RESET SESSION AUTHORIZATION;
     SELECT a.relname, a.relfilenode=b.relfilenode FROM pg_class a
       JOIN ptnowner_oldnodes b USING (oid) ORDER BY a.relname COLLATE "C";
    @@ -570,6 +577,15 @@ SELECT a.relname, a.relfilenode=b.relfilenode FROM pg_class a
      ptnowner2 | t
     (3 rows)
     
    +SELECT a.relname, a.relfilenode=b.relfilenode FROM pg_class a
    +  JOIN ptnowner_oldnodes b USING (oid) ORDER BY a.relname COLLATE "C";
    +  relname  | ?column? 
    +-----------+----------
    + ptnowner  | t
    + ptnowner1 | f
    + ptnowner2 | t
    +(3 rows)
    +
     DROP TABLE ptnowner;
     DROP ROLE regress_ptnowner;
     -- Test CLUSTER with external tuplesorting
    diff --git a/src/test/regress/sql/cluster.sql b/src/test/regress/sql/cluster.sql
    index d14063a9683..1f471a8821a 100644
    --- a/src/test/regress/sql/cluster.sql
    +++ b/src/test/regress/sql/cluster.sql
    @@ -254,14 +254,16 @@ REPACK (CONCURRENTLY) clstrpart;
     DROP TABLE clstrpart;
     
     -- Ownership of partitions is checked
    -CREATE TABLE ptnowner(i int unique) PARTITION BY LIST (i);
    +CREATE TABLE ptnowner(i int unique not null) PARTITION BY LIST (i);
     CREATE INDEX ptnowner_i_idx ON ptnowner(i);
     CREATE TABLE ptnowner1 PARTITION OF ptnowner FOR VALUES IN (1);
    -CREATE ROLE regress_ptnowner;
    +CREATE ROLE regress_ptnowner LOGIN;
     CREATE TABLE ptnowner2 PARTITION OF ptnowner FOR VALUES IN (2);
     ALTER TABLE ptnowner1 OWNER TO regress_ptnowner;
     SET SESSION AUTHORIZATION regress_ptnowner;
     CLUSTER ptnowner USING ptnowner_i_idx;
    +ALTER TABLE ptnowner1 REPLICA IDENTITY USING INDEX ptnowner1_i_key;
    +REPACK (CONCURRENTLY) ptnowner1;
     RESET SESSION AUTHORIZATION;
     ALTER TABLE ptnowner OWNER TO regress_ptnowner;
     CREATE TEMP TABLE ptnowner_oldnodes AS
    @@ -269,7 +271,12 @@ CREATE TEMP TABLE ptnowner_oldnodes AS
       JOIN pg_class AS c ON c.oid=tree.relid;
     SET SESSION AUTHORIZATION regress_ptnowner;
     CLUSTER ptnowner USING ptnowner_i_idx;
    +-- still can't repack without a replica identity
    +ALTER TABLE ptnowner1 REPLICA IDENTITY DEFAULT;
    +REPACK (CONCURRENTLY) ptnowner1;
     RESET SESSION AUTHORIZATION;
    +SELECT a.relname, a.relfilenode=b.relfilenode FROM pg_class a
    +  JOIN ptnowner_oldnodes b USING (oid) ORDER BY a.relname COLLATE "C";
     SELECT a.relname, a.relfilenode=b.relfilenode FROM pg_class a
       JOIN ptnowner_oldnodes b USING (oid) ORDER BY a.relname COLLATE "C";
     DROP TABLE ptnowner;
    -- 
    2.47.3
    
    
    --m6zy3l65ushq557m
    Content-Type: text/x-diff; charset=utf-8
    Content-Disposition: attachment;
    	filename="0002-REPACK-do-not-require-LOGIN-privileges.patch"