From df0228f6378ffa1861dd5afc2dfd3187d6fa943b Mon Sep 17 00:00:00 2001 From: Corey Huinker Date: Mon, 10 Nov 2025 14:33:41 -0500 Subject: [PATCH v6 3/3] vacuumdb: Add --dry-run. TODO Author: Corey Huinker Reviewed-by: Chao Li Reviewed-by: Kirill Reshke Discussion: https://postgr.es/m/CADkLM%3DckHkX7Of5SrK7g0LokPUwJ%3Dkk8JU1GXGF5pZ1eBVr0%3DQ%40mail.gmail.com --- doc/src/sgml/ref/vacuumdb.sgml | 10 ++++++++++ src/bin/scripts/t/100_vacuumdb.pl | 12 ++++++++++++ src/bin/scripts/vacuumdb.c | 8 ++++++++ src/bin/scripts/vacuuming.c | 30 ++++++++++++++++++++---------- src/bin/scripts/vacuuming.h | 1 + 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/ref/vacuumdb.sgml b/doc/src/sgml/ref/vacuumdb.sgml index 84c76d7350c..508c8dfa146 100644 --- a/doc/src/sgml/ref/vacuumdb.sgml +++ b/doc/src/sgml/ref/vacuumdb.sgml @@ -171,6 +171,16 @@ PostgreSQL documentation + + + + + Print, but do not execute, the vacuum and analyze commands that would + have been sent to the server. + + + + diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index a16fad593f7..fb2fecdd3c6 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -169,6 +169,10 @@ $node->issues_sql_like( [ 'vacuumdb', '--schema' => '"Foo"', 'postgres' ], qr/VACUUM \(SKIP_DATABASE_STATS\) "Foo".bar/, 'vacuumdb --schema'); +$node->issues_sql_unlike( + [ 'vacuumdb', '--schema' => '"Foo"', 'postgres', '--dry-run' ], + qr/VACUUM \(SKIP_DATABASE_STATS\) "Foo".bar/, + 'vacuumdb --dry-run'); $node->issues_sql_like( [ 'vacuumdb', '--schema' => '"Foo"', '--schema' => '"Bar"', 'postgres' ], qr/VACUUM\ \(SKIP_DATABASE_STATS\)\ "Foo".bar @@ -241,6 +245,14 @@ $node->safe_psql('postgres', q| CREATE TABLE regression_vacuumdb_test AS select generate_series(1, 10) a, generate_series(2, 11) b; ALTER TABLE regression_vacuumdb_test ADD COLUMN c INT GENERATED ALWAYS AS (a + b); |); +$node->issues_sql_unlike( + [ + 'vacuumdb', '--analyze-only', '--dry-run', + '--missing-stats-only', '-t', + 'regression_vacuumdb_test', 'postgres' + ], + qr/statement:\ ANALYZE/sx, + '--missing-stats-only --dry-run'); $node->issues_sql_like( [ 'vacuumdb', '--analyze-only', diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c index 6783c843637..6e4c809e806 100644 --- a/src/bin/scripts/vacuumdb.c +++ b/src/bin/scripts/vacuumdb.c @@ -59,6 +59,7 @@ main(int argc, char *argv[]) {"no-process-main", no_argument, NULL, 12}, {"buffer-usage-limit", required_argument, NULL, 13}, {"missing-stats-only", no_argument, NULL, 14}, + {"dry-run", no_argument, NULL, 15}, {NULL, 0, NULL, 0} }; @@ -207,6 +208,9 @@ main(int argc, char *argv[]) case 14: vacopts.missing_stats_only = true; break; + case 15: + vacopts.dry_run = true; + break; default: /* getopt_long already emitted a complaint */ pg_log_error_hint("Try \"%s --help\" for more information.", progname); @@ -303,6 +307,9 @@ main(int argc, char *argv[]) pg_fatal("cannot use the \"%s\" option without \"%s\" or \"%s\"", "missing-stats-only", "analyze-only", "analyze-in-stages"); + if (vacopts.dry_run && !vacopts.quiet) + pg_log_info("Running in dry-run mode."); + ret = vacuuming_main(&cparams, dbname, maintenance_db, &vacopts, &objects, tbl_count, concurrentCons, @@ -345,6 +352,7 @@ help(const char *progname) printf(_(" --buffer-usage-limit=SIZE size of ring buffer used for vacuum\n")); printf(_(" -d, --dbname=DBNAME database to vacuum\n")); printf(_(" --disable-page-skipping disable all page-skipping behavior\n")); + printf(_(" --dry-run show the commands that would be sent to the server\n")); printf(_(" -e, --echo show the commands being sent to the server\n")); printf(_(" -f, --full do full vacuuming\n")); printf(_(" -F, --freeze freeze row transaction information\n")); diff --git a/src/bin/scripts/vacuuming.c b/src/bin/scripts/vacuuming.c index 74a1f20e0f3..73239e86e0a 100644 --- a/src/bin/scripts/vacuuming.c +++ b/src/bin/scripts/vacuuming.c @@ -42,8 +42,9 @@ static SimpleStringList *retrieve_objects(PGconn *conn, static void free_retrieved_objects(SimpleStringList *list); static void prepare_vacuum_command(PGconn *conn, PQExpBuffer sql, vacuumingOptions *vacopts, const char *table); -static void run_vacuum_command(PGconn *conn, vacuumingOptions *vacopts, - const char *sql, const char *table); +static void run_vacuum_command(ParallelSlot *free_slot, + vacuumingOptions *vacopts, const char *sql, + const char *table); /* * Executes vacuum/analyze as indicated. Returns 0 if the plan is carried @@ -340,7 +341,11 @@ vacuum_one_database(ConnParams *cparams, if (vacopts->mode == MODE_ANALYZE_IN_STAGES) { initcmd = stage_commands[stage]; - executeCommand(conn, initcmd, vacopts->echo); + + if (vacopts->dry_run) + printf("%s\n", initcmd); + else + executeCommand(conn, initcmd, vacopts->echo); } else initcmd = NULL; @@ -383,7 +388,7 @@ vacuum_one_database(ConnParams *cparams, * through ParallelSlotsGetIdle. */ ParallelSlotSetHandler(free_slot, TableCommandResultHandler, NULL); - run_vacuum_command(free_slot->connection, vacopts, sql.data, tabname); + run_vacuum_command(free_slot, vacopts, sql.data, tabname); cell = cell->next; } while (cell != NULL); @@ -407,7 +412,7 @@ vacuum_one_database(ConnParams *cparams, } ParallelSlotSetHandler(free_slot, TableCommandResultHandler, NULL); - run_vacuum_command(free_slot->connection, vacopts, cmd, NULL); + run_vacuum_command(free_slot, vacopts, cmd, NULL); if (!ParallelSlotsWaitCompletion(sa)) ret = EXIT_FAILURE; /* error already reported by handler */ @@ -995,20 +1000,25 @@ prepare_vacuum_command(PGconn *conn, PQExpBuffer sql, /* * Send a vacuum/analyze command to the server, returning after sending the - * command. + * command. If dry_run is true, the command is printed but not sent to the + * server. * * Any errors during command execution are reported to stderr. */ static void -run_vacuum_command(PGconn *conn, vacuumingOptions *vacopts, +run_vacuum_command(ParallelSlot *free_slot, vacuumingOptions *vacopts, const char *sql, const char *table) { - bool status; + bool status = true; + PGconn *conn = free_slot->connection; - if (vacopts->echo) + if (vacopts->echo || vacopts->dry_run) printf("%s\n", sql); - status = PQsendQuery(conn, sql) == 1; + if (vacopts->dry_run) + ParallelSlotSetIdle(free_slot); + else + status = PQsendQuery(conn, sql) == 1; if (!status) { diff --git a/src/bin/scripts/vacuuming.h b/src/bin/scripts/vacuuming.h index 90db4fa1a64..586b6caa3d6 100644 --- a/src/bin/scripts/vacuuming.h +++ b/src/bin/scripts/vacuuming.h @@ -53,6 +53,7 @@ typedef struct vacuumingOptions bool missing_stats_only; bool echo; bool quiet; + bool dry_run; } vacuumingOptions; /* Valid values for vacuumingOptions->objfilter */ -- 2.39.5 (Apple Git-154)