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 [ ( option [, ...] ) ] USING Applies 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 DO block. diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c index 477c86b2ba6..89aa038d23d 100644 --- a/src/backend/commands/repack.c +++ b/src/backend/commands/repack.c @@ -303,7 +303,7 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel) if ((params.options & CLUOPT_CONCURRENT) != 0) { /* - * Make sure we're not in a transaction block. + * In concurrent mode, make sure we're not in a transaction block. * * The reason is that repack_setup_logical_decoding() could wait * indefinitely for our XID to complete. (The deadlock detector would @@ -314,6 +314,17 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel) */ PreventInTransactionBlock(isTopLevel, "REPACK (CONCURRENTLY)"); } + else if ((params.options & CLUOPT_ANALYZE) != 0) + { + /* + * With ANALYZE, process_single_relation() would commit the current + * transaction and start a new one, which would break our state if + * we're in a transaction block or PL-execution environment. Reject + * the option in that case. It may be possible to remove this + * restriction in the future. + */ + PreventInTransactionBlock(isTopLevel, "REPACK (ANALYZE)"); + } /* * If a single relation is specified, process it and we're done ... unless diff --git a/src/test/regress/expected/cluster.out b/src/test/regress/expected/cluster.out index d1bc8a13286..64a9c35fcd0 100644 --- a/src/test/regress/expected/cluster.out +++ b/src/test/regress/expected/cluster.out @@ -796,9 +796,24 @@ 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 is allowed within a PL, as long as there's no ANALYZE. +DO $$ BEGIN EXECUTE 'REPACK clstr_tst'; END $$; +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..8c8df698b31 100644 --- a/src/test/regress/sql/cluster.sql +++ b/src/test/regress/sql/cluster.sql @@ -380,9 +380,24 @@ 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 is allowed within a PL, as long as there's no ANALYZE. +DO $$ BEGIN EXECUTE 'REPACK clstr_tst'; END $$; +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