>
> In [1] I added a comment explaining why it's a problem to run REPACK
> (ANALYZE)
> from function. I thought it's important so that, when we conclude (in the
> future) that running in block is fine, we still keep checking for execution
> from a function. (PreventInTransactionBlock() checks both at the moment.)
I removed that part because I interpreted the earlier request to make the
comment more precise as a request to remove the explanation and retain only
the current transaction-block restriction.
I understand the distinction now. Allowing REPACK (ANALYZE) in a
transaction block in the future would not necessarily mean that it is safe
to execute it from a function, procedure, or DO block, since ANALYZE may
start a new transaction in process_single_relation() while an SPI session
is active.
I've restored this explanation in the comment and kept the
transaction-block restriction explicitly as a current restriction for now.
In [2] I was advised to make the comment more precise, but as you appear to
> have taken the patch over, I expected that you'll do that. However, you
> simply
> removed that part of the comment. Can you please explain why?
The removal was due to my misunderstanding of that feedback. I should have
made the explanation more precise rather than removing it. Sorry about that.
BTW, "top posting" is not the preferred style in this mailing list [3].
Understood. I'll use inline replies going forward.
Also, the regenerated patch has been attached.
On Fri, Sep 4, 2026 at 7:00 PM Osama Abdul Qader <
[email protected]> wrote:
> I removed that path because I interpreted the earlier discussion as asking
> me to avoid claiming that REPACK (ANALYZE) inherently performs transaction
> management, and I replaced it with a shorter comment explaining the current
> restriction.
>
> I now understand your point that the comment should also explain the
> separate restriction on execution from a function/procedure/DO block. In
> particular, even if running REPACK (ANALYZE) inside a transaction block is
> reconsidered in the future, the restriction on execution from a function
> may still need to remain.
>
> I'll update the comment to make that distinction explicit and will also
> follow the mailing-list preferred inline-posting style in future replies.
>
> Thanks for pointing this out.
>
> With Regards,
> Osama Abdul Qader
>
> On Fri, 4 Sept, 2026, 6:24 pm Antonin Houska, <[email protected]> wrote:
>
>> Osama Abdul Qader <[email protected]> wrote:
>>
>> > I've updated the patch to address your comments:
>> >
>> > * Documented that 'REPACK (ANALYZE)' cannot be used inside a
>> transaction block, or from a function, procedure or 'DO' block.
>> > * Updated the comment in repack.c to clarify that this restriction is
>> intentional for now, consistently with VACUUM (FULL, ANALYZE).
>>
>> In [1] I added a comment explaining why it's a problem to run REPACK
>> (ANALYZE)
>> from function. I thought it's important so that, when we conclude (in the
>> future) that running in block is fine, we still keep checking for
>> execution
>> from a function. (PreventInTransactionBlock() checks both at the moment.)
>>
>> In [2] I was advised to make the comment more precise, but as you appear
>> to
>> have taken the patch over, I expected that you'll do that. However, you
>> simply
>> removed that part of the comment. Can you please explain why?
>>
>>
>> BTW, "top posting" is not the preferred style in this mailing list [3].
>>
>> [1] https://www.postgresql.org/message-id/49398.1787944525%40localhost
>> [2]
>> https://www.postgresql.org/message-id/CAHGQGwEezdMUixhJ-N0YO0OFUmh0uPaXRDkds5FS-5dmdwz4Bg%40mail.gmail.com
>> [3] https://wiki.postgresql.org/wiki/Mailing_Lists
>>
>> --
>> Antonin Houska
>> Web: https://www.cybertec-postgresql.com
>>
>
diff --git a/doc/src/sgml/ref/repack.sgml b/doc/src/sgml/ref/repack.sgml
index 0cb72b6b289..d9c7c9e6b95 100644
--- a/doc/src/sgml/ref/repack.sgml
+++ b/doc/src/sgml/ref/repack.sgml
@@ -329,6 +329,8 @@ REPACK [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] USING
<para>
Applies <xref linkend="sql-analyze"/> on the table after repacking. This is
currently only supported when a single (non-partitioned) table is specified.
+ This option cannot be used inside a transaction block, or from a function,
+ procedure, or <command>DO</command> block.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index edff54e734e..05ad3ebece7 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -314,6 +314,18 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
PreventInTransactionBlock(isTopLevel, "REPACK (CONCURRENTLY)");
}
+ else if ((params.options & CLUOPT_ANALYZE) != 0)
+ {
+ /*
+ * ANALYZE may start a new transaction in process_single_relation(),
+ * which is not safe while an SPI session is active. Prevent execution
+ * from a function, procedure, or DO block. For now, also prohibit
+ * execution in a transaction block, consistently with VACUUM (FULL,
+ * ANALYZE).
+ */
+ PreventInTransactionBlock(isTopLevel, "REPACK (ANALYZE)");
+ }
+
/*
* If a single relation is specified, process it and we're done ... unless
* the relation is a partitioned table, in which case we fall through.
diff --git a/src/test/regress/expected/cluster.out b/src/test/regress/expected/cluster.out
index d1bc8a13286..9ad7e2e21c0 100644
--- a/src/test/regress/expected/cluster.out
+++ b/src/test/regress/expected/cluster.out
@@ -796,9 +796,23 @@ ORDER BY 1;
clstr_tst_pkey
(3 rows)
--- Verify partial analyze works
+-- Verify REPACK (ANALYZE) works, including partial analyze.
REPACK (ANALYZE) clstr_tst (a);
REPACK (ANALYZE) clstr_tst;
+-- Plain REPACK is allowed in a transaction block.
+BEGIN;
+REPACK clstr_tst;
+ROLLBACK;
+-- REPACK (ANALYZE) is not allowed in a transaction block.
+BEGIN;
+REPACK (ANALYZE) clstr_tst;
+ERROR: REPACK (ANALYZE) cannot run inside a transaction block
+ROLLBACK;
+-- REPACK (ANALYZE) is not allowed from a function.
+DO $$ BEGIN EXECUTE 'REPACK (ANALYZE) clstr_tst'; END $$;
+ERROR: REPACK (ANALYZE) cannot be executed from a function or procedure
+CONTEXT: SQL statement "REPACK (ANALYZE) clstr_tst"
+PL/pgSQL function inline_code_block line 1 at EXECUTE
REPACK (VERBOSE) clstr_tst (a);
ERROR: ANALYZE option must be specified when a column list is provided
-- REPACK w/o argument performs no ordering, so we can only check which tables
diff --git a/src/test/regress/sql/cluster.sql b/src/test/regress/sql/cluster.sql
index e7a62367adf..dcc91e73698 100644
--- a/src/test/regress/sql/cluster.sql
+++ b/src/test/regress/sql/cluster.sql
@@ -380,9 +380,23 @@ INSERT INTO clstr_tst (b, c) VALUES (1111, 'this should fail');
SELECT conname FROM pg_constraint WHERE conrelid = 'clstr_tst'::regclass
ORDER BY 1;
--- Verify partial analyze works
+-- Verify REPACK (ANALYZE) works, including partial analyze.
REPACK (ANALYZE) clstr_tst (a);
REPACK (ANALYZE) clstr_tst;
+
+-- Plain REPACK is allowed in a transaction block.
+BEGIN;
+REPACK clstr_tst;
+ROLLBACK;
+
+-- REPACK (ANALYZE) is not allowed in a transaction block.
+BEGIN;
+REPACK (ANALYZE) clstr_tst;
+ROLLBACK;
+
+-- REPACK (ANALYZE) is not allowed from a function.
+DO $$ BEGIN EXECUTE 'REPACK (ANALYZE) clstr_tst'; END $$;
+
REPACK (VERBOSE) clstr_tst (a);
-- REPACK w/o argument performs no ordering, so we can only check which tables