Hi Chao
On 22/10/2026 08:23, Chao Li wrote:
> When ONLY_DATABASE_STATS is enabled, no other option except VERBOSE may be
> enabled. But the current implementation does not check all options, for
> example:
> ```
> evantest=# vacuum (ONLY_DATABASE_STATS, SKIP_LOCKED);
> ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
> evantest=# vacuum (ONLY_DATABASE_STATS, PARALLEL 1);
> VACUUM
> ```
Thanks for the patch!
A few observations:
== error message ==
Instead of creating the new only_database_stats_conflict flag you could
simply add a check in the if (params.options &
VACOPT_ONLY_DATABASE_STATS) block:
@@ -378,15 +378,17 @@ ExecVacuum(ParseState *pstate, VacuumStmt
*vacstmt, bool isTopLevel)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("ONLY_DATABASE_STATS
cannot be specified with a list of tables")));
- /* don't require people to turn off PROCESS_TOAST/MAIN
explicitly */
- if (params.options & ~(VACOPT_VACUUM |
- VACOPT_VERBOSE |
-
VACOPT_PROCESS_MAIN |
-
VACOPT_PROCESS_TOAST |
-
VACOPT_ONLY_DATABASE_STATS))
- ereport(ERROR,
-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("ONLY_DATABASE_STATS
cannot be specified with other VACUUM options")));
+ /* only VERBOSE may be specified alongside
ONLY_DATABASE_STATS */
+ foreach(lc, vacstmt->options)
+ {
+ DefElem *opt = lfirst_node(DefElem, lc);
+
+ if (strcmp(opt->defname, "verbose") != 0 &&
+ strcmp(opt->defname,
"only_database_stats") != 0)
+ ereport(ERROR,
+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+
errmsg("ONLY_DATABASE_STATS cannot be specified with other VACUUM
options")));
+ }
v2 attached implements this handling in ExecVacuum -- feel free to
revert it if you disagree.
== regression tests ==
All error cases are handled in the same path, so theoretically only a
few options (representative ones) would suffice. But I realise that if
the code ever changes, we might end up with untested code. I'd be
inclined to leave them as-is, but I thought I should bring it up. If
it's supposed to cover all possible options, you could consider adding
VACUUM (ONLY_DATABASE_STATS, VERBOSE false).
Thanks!
Best, Jim
From aed78dfb8a321416583198aa2497530b6ec40c9f Mon Sep 17 00:00:00 2001
From: Jim Jones <[email protected]>
Date: Sat, 24 Oct 2026 17:42:38 +0200
Subject: [PATCH v2] Reject incompatible options specified with VACUUM
ONLY_DATABASE_STATS
The existing check examines only option bits, so it misses PARALLEL,
INDEX_CLEANUP, TRUNCATE, and BUFFER_USAGE_LIMIT. These options are
accepted even though they have no effect with ONLY_DATABASE_STATS.
Track incompatible options while parsing and reject any explicitly
specified option other than VERBOSE, regardless of its value. This also
rejects explicitly disabled options and explicit PROCESS_MAIN and
PROCESS_TOAST options, while allowing their implicit defaults.
Update the documentation and add regression coverage.
Author: Chao Li <[email protected]>
---
doc/src/sgml/ref/vacuum.sgml | 2 +-
src/backend/commands/vacuum.c | 20 +++++++++--------
src/test/regress/expected/vacuum.out | 32 ++++++++++++++++++++++++++++
src/test/regress/sql/vacuum.sql | 17 +++++++++++++++
4 files changed, 61 insertions(+), 10 deletions(-)
diff --git a/doc/src/sgml/ref/vacuum.sgml b/doc/src/sgml/ref/vacuum.sgml
index 3c85846df26..0df6082f27b 100644
--- a/doc/src/sgml/ref/vacuum.sgml
+++ b/doc/src/sgml/ref/vacuum.sgml
@@ -303,7 +303,7 @@ VACUUM [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] [ <re
update the database-wide statistics about oldest unfrozen XIDs.
When this option is specified,
the <replaceable class="parameter">table_and_columns</replaceable>
- list must be empty, and no other option may be enabled
+ list must be empty, and no other option may be specified
except <literal>VERBOSE</literal>.
</para>
</listitem>
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index c7595d59bb2..7df7f302967 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -378,15 +378,17 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("ONLY_DATABASE_STATS cannot be specified with a list of tables")));
- /* don't require people to turn off PROCESS_TOAST/MAIN explicitly */
- if (params.options & ~(VACOPT_VACUUM |
- VACOPT_VERBOSE |
- VACOPT_PROCESS_MAIN |
- VACOPT_PROCESS_TOAST |
- VACOPT_ONLY_DATABASE_STATS))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("ONLY_DATABASE_STATS cannot be specified with other VACUUM options")));
+ /* only VERBOSE may be specified alongside ONLY_DATABASE_STATS */
+ foreach(lc, vacstmt->options)
+ {
+ DefElem *opt = lfirst_node(DefElem, lc);
+
+ if (strcmp(opt->defname, "verbose") != 0 &&
+ strcmp(opt->defname, "only_database_stats") != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("ONLY_DATABASE_STATS cannot be specified with other VACUUM options")));
+ }
}
/*
diff --git a/src/test/regress/expected/vacuum.out b/src/test/regress/expected/vacuum.out
index d4696bc3325..e3f544d428a 100644
--- a/src/test/regress/expected/vacuum.out
+++ b/src/test/regress/expected/vacuum.out
@@ -551,6 +551,38 @@ VACUUM (SKIP_DATABASE_STATS) vactst;
VACUUM (ONLY_DATABASE_STATS);
VACUUM (ONLY_DATABASE_STATS) vactst; -- error
ERROR: ONLY_DATABASE_STATS cannot be specified with a list of tables
+VACUUM (ONLY_DATABASE_STATS, FREEZE); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, ANALYZE); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, FULL); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, SKIP_LOCKED); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, DISABLE_PAGE_SKIPPING); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, SKIP_DATABASE_STATS); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, PARALLEL 1); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, INDEX_CLEANUP ON); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, INDEX_CLEANUP AUTO); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, INDEX_CLEANUP); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, TRUNCATE ON); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, BUFFER_USAGE_LIMIT '1MB'); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, PROCESS_MAIN ON); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (ONLY_DATABASE_STATS, PROCESS_TOAST ON); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+VACUUM (PARALLEL 1, ONLY_DATABASE_STATS); -- error
+ERROR: ONLY_DATABASE_STATS cannot be specified with other VACUUM options
+-- VERBOSE is allowed.
+VACUUM (ONLY_DATABASE_STATS, VERBOSE);
DROP VIEW vac_option_tab_counts;
DROP TABLE vac_option_tab;
DROP TABLE vaccluster;
diff --git a/src/test/regress/sql/vacuum.sql b/src/test/regress/sql/vacuum.sql
index 247b8e23b23..8f1fc17d299 100644
--- a/src/test/regress/sql/vacuum.sql
+++ b/src/test/regress/sql/vacuum.sql
@@ -411,6 +411,23 @@ VACUUM (SKIP_DATABASE_STATS) vactst;
-- ONLY_DATABASE_STATS option
VACUUM (ONLY_DATABASE_STATS);
VACUUM (ONLY_DATABASE_STATS) vactst; -- error
+VACUUM (ONLY_DATABASE_STATS, FREEZE); -- error
+VACUUM (ONLY_DATABASE_STATS, ANALYZE); -- error
+VACUUM (ONLY_DATABASE_STATS, FULL); -- error
+VACUUM (ONLY_DATABASE_STATS, SKIP_LOCKED); -- error
+VACUUM (ONLY_DATABASE_STATS, DISABLE_PAGE_SKIPPING); -- error
+VACUUM (ONLY_DATABASE_STATS, SKIP_DATABASE_STATS); -- error
+VACUUM (ONLY_DATABASE_STATS, PARALLEL 1); -- error
+VACUUM (ONLY_DATABASE_STATS, INDEX_CLEANUP ON); -- error
+VACUUM (ONLY_DATABASE_STATS, INDEX_CLEANUP AUTO); -- error
+VACUUM (ONLY_DATABASE_STATS, INDEX_CLEANUP); -- error
+VACUUM (ONLY_DATABASE_STATS, TRUNCATE ON); -- error
+VACUUM (ONLY_DATABASE_STATS, BUFFER_USAGE_LIMIT '1MB'); -- error
+VACUUM (ONLY_DATABASE_STATS, PROCESS_MAIN ON); -- error
+VACUUM (ONLY_DATABASE_STATS, PROCESS_TOAST ON); -- error
+VACUUM (PARALLEL 1, ONLY_DATABASE_STATS); -- error
+-- VERBOSE is allowed.
+VACUUM (ONLY_DATABASE_STATS, VERBOSE);
DROP VIEW vac_option_tab_counts;
DROP TABLE vac_option_tab;
--
2.56.0