Thread

  1. [PATCH v7 3/3] vacuumdb: Add --dry-run.

    Nathan Bossart <nathan@postgresql.org> — 2025-12-08T19:22:22Z

    TODO
    
    Author: Corey Huinker <corey.huinker@gmail.com>
    Reviewed-by: Chao Li <li.evan.chao@gmail.com>
    Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
    Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
    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        |  9 +++++++++
     src/bin/scripts/vacuuming.c       | 30 ++++++++++++++++++++----------
     src/bin/scripts/vacuuming.h       |  1 +
     5 files changed, 52 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
           </listitem>
          </varlistentry>
     
    +     <varlistentry>
    +      <term><option>--dry-run</option></term>
    +      <listitem>
    +       <para>
    +        Print, but do not execute, the vacuum and analyze commands that would
    +        have been sent to the server.
    +       </para>
    +      </listitem>
    +     </varlistentry>
    +
          <varlistentry>
           <term><option>-e</option></term>
           <term><option>--echo</option></term>
    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..0bc443be348 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,10 @@ 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("Executing in dry-run mode.\n"
    +					"No commands will be sent to the server.");
    +
     	ret = vacuuming_main(&cparams, dbname, maintenance_db, &vacopts,
     						 &objects, tbl_count,
     						 concurrentCons,
    @@ -345,6 +353,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)
    
    
    --HKUlytnvEo5xYpWt--