Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vRHFD-00AjKi-07 for pgsql-hackers@arkaria.postgresql.org; Thu, 04 Dec 2025 21:52:11 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vRHFB-0054y2-2H for pgsql-hackers@arkaria.postgresql.org; Thu, 04 Dec 2025 21:52:10 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vRHFB-0054xu-0V for pgsql-hackers@lists.postgresql.org; Thu, 04 Dec 2025 21:52:09 +0000 Received: from mail-oo1-xc2f.google.com ([2607:f8b0:4864:20::c2f]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vRHF8-003AbD-0T for pgsql-hackers@postgresql.org; Thu, 04 Dec 2025 21:52:08 +0000 Received: by mail-oo1-xc2f.google.com with SMTP id 006d021491bc7-65968986a0cso773660eaf.3 for ; Thu, 04 Dec 2025 13:52:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1764885126; x=1765489926; darn=postgresql.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=6hPgHy/E1MjgPl5XKq0GRh8e1Xgoksf6G6W1TN9zQyQ=; b=MiRGOMP/7BER53F6cKZcU973QsoYRVaUg/7b3Zyq9tfjMFD3SeBNuD5wwzgaAFxgui sR5LK9G81kFPCaZKIGs7ukPgFRpjJW/y6pMFk+8aLcBehC1wE/X9aQZ6sTG7X4hRPyLO w8E9fRrgvvkSJjeHVp5CsFeb2Zh4sMeW/0jtAJPgNRwnOBuOv9zrqTvhIYKqsQ/mh+lV DVBCWSX0IU/F0/HryXfWRN0ygJMML55cfyBvFUpHofO8vx/NQBaFV900BbSJDUQMnjcc Sx+QLXHSYa82qE6UP6CBfzRHAxdyExMmG8hHwfjv3JaoqIDI/tCVxw1IIGIaQN5AV2N1 5n7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764885126; x=1765489926; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-gg:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6hPgHy/E1MjgPl5XKq0GRh8e1Xgoksf6G6W1TN9zQyQ=; b=D0sQJQBkYPkCfqkZK4ejU8p7UZCUo+rhv7NuboGSswEzSphAp1ieE+rVJPBpieq5Ts yzhCepqyGcQqFinokVk5Sa68zz0DzoxijsP41I0C5GsRBC+x5Kj5Zc3NOn25H50A8wA0 g5Ps513IaKKWOPpdffR9VQ70ZXmE8OsVnI2FmqfCiVdyS4WkGD392LFOKPib5DG4BxVG R8twhswhjdkMisnHv2Ve7U1OuSZtrMvx1RT5tryybQrdt7gk4zCZt8Wj2UBXHnbsXafV tqTA2nYn9w68bez64npbSQmqefLdXKngoZH8O7r0FE0Dj9IC+V12cvkHkiMvShTHPyyf Ax4w== X-Forwarded-Encrypted: i=1; AJvYcCX8sK4ijmgwS7dPi58pZQm6nc2leK7kSz1IwbKPk3lwMzo1y35E77MaO3qqJ46Dt8k1G+2dIuZC/hU08+P9@postgresql.org X-Gm-Message-State: AOJu0YyZec7EJUE3RAyJw9N/ygXLlE0CwLYbKoSiw+PpZ9MBicia9fY7 dRVtQb3DoVgsH5cJAdRMX0cb69oAaqu4x4Uyqqc2RSaNCz0C/GlOZ4xn X-Gm-Gg: ASbGncuiBsavHCj+diX4q8JFRGSNdOX0v0DxlkuMuGrP2swVzwRVKjkYLhx2YI6N82P xKxVrb/NMjKYuYVstdlI05uuHGAhD8AAMwKlt5uiLerAnoKpWBaxhl+D4BoHwQ6ahKQ2udbL18+ GimKFD2PY9JONnRteyTjkQoNRAleNROSdQNFrdt27JDl4+JmzzN9t4bw5UxW53CMHNt7O0RukOb L5xULMStlh4p6VzpdDHMxB60Uo9TB1OV4iDGBJgNn9TmTNYONAlpZ//USDgZprpTWiyrbYosb1F HCikWnJJP5ShdKts1g7SWKzGpfUsbqyA8K5EWGUjfmA7VcSvS0GZVzzHEq97pmaBRG1hSbR8VHK Q32dBVePzKxat4E2O60oEsRFS1tQ5p0SV2hO4MPT2gWD1ujLSQL0uAUyA/uY8nfN9SBTWpK3vEQ URpRZD/M6Memm7bda4kW0rGqORTyo0de7qIoZybIfijeRlExh00wxKAq+9bH5aSN7gGDMhLoaiH h5c X-Google-Smtp-Source: AGHT+IGYrAUC9TA2cK8puVzyCssC3n/t5KnM6vH4oyNNYSIY1j0OKj3DzITit+rYU26pnKYW0WxeUg== X-Received: by 2002:a05:6830:34a8:b0:7c7:60aa:6496 with SMTP id 46e09a7af769-7c958b243camr2460509a34.4.1764885126039; Thu, 04 Dec 2025 13:52:06 -0800 (PST) Received: from nathan (162-195-168-172.lightspeed.stlsmo.sbcglobal.net. [162.195.168.172]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7c95a8fa21asm2572131a34.1.2025.12.04.13.52.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Dec 2025 13:52:05 -0800 (PST) Date: Thu, 4 Dec 2025 15:52:03 -0600 From: Nathan Bossart To: Corey Huinker Cc: Chao Li , pgsql-hackers@postgresql.org Subject: Re: vacuumdb: add --dry-run Message-ID: References: <3DB353E5-944D-4E18-9DA2-4151F44AA59B@gmail.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="OiRdYY/N4j3fWsko" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --OiRdYY/N4j3fWsko Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Thu, Nov 20, 2025 at 04:16:13PM -0600, Nathan Bossart wrote: > On Thu, Nov 20, 2025 at 05:09:54PM -0500, Corey Huinker wrote: >> I have no objections to, but I am curious about the factors that went into >> making dry_run an independent boolean rather than part of vacopts. > > My thinking was that it's closer to "echo" and "quiet" than anything in > vacuumingOptions. Most of that stuff seems geared towards controlling the > precise behavior of the commands rather than the behavior of the > application. TBH I think it'd be fine either way. We could probably even > move "echo" and "quiet" into vacuumingOptions if we really wanted to. Yeah, I'm finding myself liking the idea of moving all of these things into vacuumingOptions so that we don't have to cart around so many bool arguments. Here's a new patch set that does it this way. The remaining question in my mind is where we should let the user know that we're in dry-run mode. The three options I see are 1) at the beginning of vacuumdb execution, 2) in the !quiet block for each database, and 3) in each command (via a comment). In v5, I've added a message to all three, but I'm eager to hear what folks think. -- nathan --OiRdYY/N4j3fWsko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=v5-0001-Move-some-vacuumdb-options-to-vacopts-struct.patch From 69911834a8046c226ce6c54a6afd2b51830084d0 Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Wed, 3 Dec 2025 16:12:37 -0600 Subject: [PATCH v5 1/3] Move some vacuumdb options to vacopts struct. --- src/bin/scripts/vacuumdb.c | 8 +++--- src/bin/scripts/vacuuming.c | 50 ++++++++++++++++++------------------- src/bin/scripts/vacuuming.h | 4 ++- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c index e117dac2242..f72ad9dd0ba 100644 --- a/src/bin/scripts/vacuumdb.c +++ b/src/bin/scripts/vacuumdb.c @@ -68,8 +68,6 @@ main(int argc, char *argv[]) const char *dbname = NULL; const char *maintenance_db = NULL; ConnParams cparams; - bool echo = false; - bool quiet = false; vacuumingOptions vacopts; SimpleStringList objects = {NULL, NULL}; int concurrentCons = 1; @@ -110,7 +108,7 @@ main(int argc, char *argv[]) dbname = pg_strdup(optarg); break; case 'e': - echo = true; + vacopts.echo = true; break; case 'f': vacopts.full = true; @@ -143,7 +141,7 @@ main(int argc, char *argv[]) exit(1); break; case 'q': - quiet = true; + vacopts.quiet = true; break; case 't': vacopts.objfilter |= OBJFILTER_TABLE; @@ -312,7 +310,7 @@ main(int argc, char *argv[]) ret = vacuuming_main(&cparams, dbname, maintenance_db, &vacopts, &objects, tbl_count, concurrentCons, - progname, echo, quiet); + progname); exit(ret); } diff --git a/src/bin/scripts/vacuuming.c b/src/bin/scripts/vacuuming.c index f836f21fb03..1af242b60d7 100644 --- a/src/bin/scripts/vacuuming.c +++ b/src/bin/scripts/vacuuming.c @@ -30,16 +30,15 @@ static int vacuum_one_database(ConnParams *cparams, SimpleStringList *objects, SimpleStringList **found_objs, int concurrentCons, - const char *progname, bool echo, bool quiet); + const char *progname); static int vacuum_all_databases(ConnParams *cparams, vacuumingOptions *vacopts, SimpleStringList *objects, int concurrentCons, - const char *progname, bool echo, bool quiet); + const char *progname); static SimpleStringList *retrieve_objects(PGconn *conn, vacuumingOptions *vacopts, - SimpleStringList *objects, - bool echo); + SimpleStringList *objects); static void free_retrieved_objects(SimpleStringList *list); static void prepare_vacuum_command(PGconn *conn, PQExpBuffer sql, vacuumingOptions *vacopts, const char *table); @@ -56,7 +55,7 @@ vacuuming_main(ConnParams *cparams, const char *dbname, const char *maintenance_db, vacuumingOptions *vacopts, SimpleStringList *objects, unsigned int tbl_count, int concurrentCons, - const char *progname, bool echo, bool quiet) + const char *progname) { setup_cancel_handler(NULL); @@ -71,7 +70,7 @@ vacuuming_main(ConnParams *cparams, const char *dbname, return vacuum_all_databases(cparams, vacopts, objects, concurrentCons, - progname, echo, quiet); + progname); } else { @@ -100,7 +99,7 @@ vacuuming_main(ConnParams *cparams, const char *dbname, objects, vacopts->missing_stats_only ? &found_objs : NULL, concurrentCons, - progname, echo, quiet); + progname); if (ret != 0) { free_retrieved_objects(found_objs); @@ -116,7 +115,7 @@ vacuuming_main(ConnParams *cparams, const char *dbname, ANALYZE_NO_STAGE, objects, NULL, concurrentCons, - progname, echo, quiet); + progname); } } @@ -167,7 +166,7 @@ vacuum_one_database(ConnParams *cparams, SimpleStringList *objects, SimpleStringList **found_objs, int concurrentCons, - const char *progname, bool echo, bool quiet) + const char *progname) { PQExpBufferData sql; PGconn *conn; @@ -192,7 +191,7 @@ vacuum_one_database(ConnParams *cparams, Assert(stage == ANALYZE_NO_STAGE || (stage >= 0 && stage < ANALYZE_NUM_STAGES)); - conn = connectDatabase(cparams, progname, echo, false, true); + conn = connectDatabase(cparams, progname, vacopts->echo, false, true); if (vacopts->disable_page_skipping && PQserverVersion(conn) < 90600) { @@ -281,7 +280,7 @@ vacuum_one_database(ConnParams *cparams, /* skip_database_stats is used automatically if server supports it */ vacopts->skip_database_stats = (PQserverVersion(conn) >= 160000); - if (!quiet) + if (!vacopts->quiet) { if (vacopts->mode == MODE_ANALYZE_IN_STAGES) printf(_("%s: processing database \"%s\": %s\n"), @@ -302,7 +301,7 @@ vacuum_one_database(ConnParams *cparams, retobjs = *found_objs; else { - retobjs = retrieve_objects(conn, vacopts, objects, echo); + retobjs = retrieve_objects(conn, vacopts, objects); if (found_objs) *found_objs = retobjs; else @@ -341,7 +340,7 @@ vacuum_one_database(ConnParams *cparams, if (vacopts->mode == MODE_ANALYZE_IN_STAGES) { initcmd = stage_commands[stage]; - executeCommand(conn, initcmd, echo); + executeCommand(conn, initcmd, vacopts->echo); } else initcmd = NULL; @@ -351,7 +350,8 @@ vacuum_one_database(ConnParams *cparams, * for the first slot. If not in parallel mode, the first slot in the * array contains the connection. */ - sa = ParallelSlotsSetup(concurrentCons, cparams, progname, echo, initcmd); + sa = ParallelSlotsSetup(concurrentCons, cparams, progname, + vacopts->echo, initcmd); ParallelSlotsAdoptConn(sa, conn); initPQExpBuffer(&sql); @@ -384,7 +384,7 @@ vacuum_one_database(ConnParams *cparams, */ ParallelSlotSetHandler(free_slot, TableCommandResultHandler, NULL); run_vacuum_command(free_slot->connection, sql.data, - echo, tabname); + vacopts->echo, tabname); cell = cell->next; } while (cell != NULL); @@ -408,7 +408,7 @@ vacuum_one_database(ConnParams *cparams, } ParallelSlotSetHandler(free_slot, TableCommandResultHandler, NULL); - run_vacuum_command(free_slot->connection, cmd, echo, NULL); + run_vacuum_command(free_slot->connection, cmd, vacopts->echo, NULL); if (!ParallelSlotsWaitCompletion(sa)) ret = EXIT_FAILURE; /* error already reported by handler */ @@ -436,17 +436,17 @@ vacuum_all_databases(ConnParams *cparams, vacuumingOptions *vacopts, SimpleStringList *objects, int concurrentCons, - const char *progname, bool echo, bool quiet) + const char *progname) { int ret = EXIT_SUCCESS; PGconn *conn; PGresult *result; int numdbs; - conn = connectMaintenanceDatabase(cparams, progname, echo); + conn = connectMaintenanceDatabase(cparams, progname, vacopts->echo); result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn AND datconnlimit <> -2 ORDER BY 1;", - echo); + vacopts->echo); numdbs = PQntuples(result); PQfinish(conn); @@ -474,7 +474,7 @@ vacuum_all_databases(ConnParams *cparams, objects, vacopts->missing_stats_only ? &found_objs[i] : NULL, concurrentCons, - progname, echo, quiet); + progname); if (ret != EXIT_SUCCESS) break; } @@ -499,7 +499,7 @@ vacuum_all_databases(ConnParams *cparams, objects, NULL, concurrentCons, - progname, echo, quiet); + progname); if (ret != EXIT_SUCCESS) break; } @@ -524,7 +524,7 @@ vacuum_all_databases(ConnParams *cparams, */ static SimpleStringList * retrieve_objects(PGconn *conn, vacuumingOptions *vacopts, - SimpleStringList *objects, bool echo) + SimpleStringList *objects) { PQExpBufferData buf; PQExpBufferData catalog_query; @@ -776,10 +776,10 @@ retrieve_objects(PGconn *conn, vacuumingOptions *vacopts, * query for consistency with table lookups done elsewhere by the user. */ appendPQExpBufferStr(&catalog_query, " ORDER BY c.relpages DESC;"); - executeCommand(conn, "RESET search_path;", echo); - res = executeQuery(conn, catalog_query.data, echo); + executeCommand(conn, "RESET search_path;", vacopts->echo); + res = executeQuery(conn, catalog_query.data, vacopts->echo); termPQExpBuffer(&catalog_query); - PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo)); + PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, vacopts->echo)); /* * Build qualified identifiers for each table, including the column list diff --git a/src/bin/scripts/vacuuming.h b/src/bin/scripts/vacuuming.h index 49f968b32e5..90db4fa1a64 100644 --- a/src/bin/scripts/vacuuming.h +++ b/src/bin/scripts/vacuuming.h @@ -51,6 +51,8 @@ typedef struct vacuumingOptions bool skip_database_stats; char *buffer_usage_limit; bool missing_stats_only; + bool echo; + bool quiet; } vacuumingOptions; /* Valid values for vacuumingOptions->objfilter */ @@ -65,7 +67,7 @@ extern int vacuuming_main(ConnParams *cparams, const char *dbname, SimpleStringList *objects, unsigned int tbl_count, int concurrentCons, - const char *progname, bool echo, bool quiet); + const char *progname); extern char *escape_quotes(const char *src); -- 2.39.5 (Apple Git-154) --OiRdYY/N4j3fWsko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=v5-0002-Add-ParallelSlotSetIdle.patch From 3b35624019529d8aac10dcc81b9e2e0c88cb9748 Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Thu, 20 Nov 2025 14:16:02 -0600 Subject: [PATCH v5 2/3] Add ParallelSlotSetIdle(). --- src/fe_utils/parallel_slot.c | 6 ++---- src/include/fe_utils/parallel_slot.h | 7 +++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/fe_utils/parallel_slot.c b/src/fe_utils/parallel_slot.c index 253a840865e..1b9bc8b0da8 100644 --- a/src/fe_utils/parallel_slot.c +++ b/src/fe_utils/parallel_slot.c @@ -269,8 +269,7 @@ wait_on_slots(ParallelSlotArray *sa) else { /* This connection has become idle */ - sa->slots[i].inUse = false; - ParallelSlotClearHandler(&sa->slots[i]); + ParallelSlotSetIdle(&sa->slots[i]); break; } } @@ -509,8 +508,7 @@ ParallelSlotsWaitCompletion(ParallelSlotArray *sa) if (!consumeQueryResult(&sa->slots[i])) return false; /* Mark connection as idle */ - sa->slots[i].inUse = false; - ParallelSlotClearHandler(&sa->slots[i]); + ParallelSlotSetIdle(&sa->slots[i]); } return true; diff --git a/src/include/fe_utils/parallel_slot.h b/src/include/fe_utils/parallel_slot.h index 7770a20de34..4a5fbfb3d8c 100644 --- a/src/include/fe_utils/parallel_slot.h +++ b/src/include/fe_utils/parallel_slot.h @@ -58,6 +58,13 @@ ParallelSlotClearHandler(ParallelSlot *slot) slot->handler_context = NULL; } +static inline void +ParallelSlotSetIdle(ParallelSlot *slot) +{ + slot->inUse = false; + ParallelSlotClearHandler(slot); +} + extern ParallelSlot *ParallelSlotsGetIdle(ParallelSlotArray *sa, const char *dbname); -- 2.39.5 (Apple Git-154) --OiRdYY/N4j3fWsko Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=v5-0003-Add-dry-run-to-vacuumdb.patch From 1b1860b15f4937f3d7ebbddce14de0bfe302b128 Mon Sep 17 00:00:00 2001 From: Corey Huinker Date: Mon, 10 Nov 2025 14:33:41 -0500 Subject: [PATCH v5 3/3] Add --dry-run to vacuumdb. This option answers the question "what tables would be affected if I ran a command using these options" without actually initiating those actions. --- 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 | 44 ++++++++++++++++++++----------- src/bin/scripts/vacuuming.h | 1 + 5 files changed, 59 insertions(+), 16 deletions(-) diff --git a/doc/src/sgml/ref/vacuumdb.sgml b/doc/src/sgml/ref/vacuumdb.sgml index 84c76d7350c..89aa7fac4f8 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 (performs a dry run). + + + + 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 f72ad9dd0ba..c1d8891736c 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} }; @@ -211,6 +212,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); @@ -307,6 +311,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) + pg_log_info("Executing in dry-run mode."); + ret = vacuuming_main(&cparams, dbname, maintenance_db, &vacopts, &objects, tbl_count, concurrentCons, @@ -349,6 +356,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 dry run, show 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 1af242b60d7..32df69bde82 100644 --- a/src/bin/scripts/vacuuming.c +++ b/src/bin/scripts/vacuuming.c @@ -42,8 +42,8 @@ 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, const char *sql, bool echo, - const char *table); +static void run_vacuum_command(ParallelSlot *free_slot, const char *sql, + bool echo, bool dry_run, const char *table); /* * Executes vacuum/analyze as indicated. Returns 0 if the plan is carried @@ -283,11 +283,14 @@ vacuum_one_database(ConnParams *cparams, if (!vacopts->quiet) { if (vacopts->mode == MODE_ANALYZE_IN_STAGES) - printf(_("%s: processing database \"%s\": %s\n"), - progname, PQdb(conn), _(stage_messages[stage])); + printf(_("%s: processing database \"%s\"%s: %s\n"), + progname, PQdb(conn), + vacopts->dry_run ? " (dry-run)" : "", + _(stage_messages[stage])); else - printf(_("%s: vacuuming database \"%s\"\n"), - progname, PQdb(conn)); + printf(_("%s: vacuuming database \"%s\"%s\n"), + progname, PQdb(conn), + vacopts->dry_run ? " (dry-run)" : ""); fflush(stdout); } @@ -340,7 +343,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 -- not executed\n", initcmd); + else + executeCommand(conn, initcmd, vacopts->echo); } else initcmd = NULL; @@ -383,8 +390,8 @@ vacuum_one_database(ConnParams *cparams, * through ParallelSlotsGetIdle. */ ParallelSlotSetHandler(free_slot, TableCommandResultHandler, NULL); - run_vacuum_command(free_slot->connection, sql.data, - vacopts->echo, tabname); + run_vacuum_command(free_slot, sql.data, vacopts->echo, + vacopts->dry_run, tabname); cell = cell->next; } while (cell != NULL); @@ -408,7 +415,8 @@ vacuum_one_database(ConnParams *cparams, } ParallelSlotSetHandler(free_slot, TableCommandResultHandler, NULL); - run_vacuum_command(free_slot->connection, cmd, vacopts->echo, NULL); + run_vacuum_command(free_slot, cmd, vacopts->echo, + vacopts->dry_run, NULL); if (!ParallelSlotsWaitCompletion(sa)) ret = EXIT_FAILURE; /* error already reported by handler */ @@ -1001,15 +1009,19 @@ prepare_vacuum_command(PGconn *conn, PQExpBuffer sql, * Any errors during command execution are reported to stderr. */ static void -run_vacuum_command(PGconn *conn, const char *sql, bool echo, - const char *table) +run_vacuum_command(ParallelSlot *free_slot, const char *sql, + bool echo, bool dry_run, const char *table) { - bool status; + bool status = true; + PGconn *conn = free_slot->connection; - if (echo) - printf("%s\n", sql); + if (echo || dry_run) + printf("%s%s\n", sql, dry_run ? " -- not executed" : ""); - status = PQsendQuery(conn, sql) == 1; + if (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) --OiRdYY/N4j3fWsko--