Hi everyone,
I believe I was replying to the wrong thread earlier.
The issue I was looking into is the crash caused by executing REPACK
(ANALYZE) inside a transaction block.
REPACK (ANALYZE) performs transaction management internally, including
committing and starting a new transaction while processing the relation. It
therefore cannot safely be executed from an existing transaction block.
I have prepared a patch that rejects REPACK (ANALYZE) with
PreventInTransactionBlock(), consistent with the existing restriction
for REPACK
(CONCURRENTLY). I also added a regression test covering execution inside a
transaction block.
The patch applies cleanly to the current tree and passes git diff --check.
Patch attached.
Regards,
Osama Abdul Qader
On Wed, Sep 2, 2026 at 2:17 PM Antonin Houska <[email protected]> wrote:
> Alvaro Herrera <[email protected]> wrote:
>
> > On 2026-Sep-02, Fujii Masao wrote:
> >
> > > + * that's just consistent with VACUUM (FULL, ANALYZE), which is a
> > > + * synonym for REPACK (ANALYZE).
> > >
> > > Is VACUUM (FULL, ANALYZE) really a synonym for REPACK (ANALYZE)?
> >
> > That's the intent, at least. If there are things that work differently,
> > I would strive to change them so that they do work the same. However,
> > some such changes might be too invasive for pg19, but I would still see
> > about changing those in pg20.
> >
> > Now, maybe there are things about VACUUM FULL ANALYZE that we don't like
> > (perhaps, for instance, they exist solely because of even older
> > backwards compatibility concerns) that we would prefer not to have in
> > REPACK. I don't know if anything of that sort exists, but if so, I
> > would propose to seek decisions for each thing individually.
>
> Maybe the question was about the wording - "synonym" might indicate that
> both
> commands execute the same code. Perhaps the comment should rather say that
> REPACK (ANALYZE) is (intended to be) a replacement of VACUUM (FULL,
> ANALYZE).
>
> --
> Antonin Houska
> Web: https://www.cybertec-postgresql.com
>
>
>
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index edff54e734e..3a482a73ceb 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -314,6 +314,16 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
PreventInTransactionBlock(isTopLevel, "REPACK (CONCURRENTLY)");
}
+ else if ((params.options & CLUOPT_ANALYZE) != 0)
+ {
+ /*
+ * REPACK (ANALYZE) performs transaction management internally.
+ * It therefore cannot be executed from a transaction block or
+ * from a function.
+ */
+ 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/sql/cluster.sql b/src/test/regress/sql/cluster.sql
index e7a62367adf..cb170731147 100644
--- a/src/test/regress/sql/cluster.sql
+++ b/src/test/regress/sql/cluster.sql
@@ -380,6 +380,10 @@ INSERT INTO clstr_tst (b, c) VALUES (1111, 'this should fail');
SELECT conname FROM pg_constraint WHERE conrelid = 'clstr_tst'::regclass
ORDER BY 1;
+-- REPACK (ANALYZE) must not be executed inside a transaction block
+BEGIN;
+REPACK (ANALYZE) clstr_tst;
+ROLLBACK;
-- Verify partial analyze works
REPACK (ANALYZE) clstr_tst (a);
REPACK (ANALYZE) clstr_tst;