From 6835f259dc90be3f76fda918b55cb5f5622b84b2 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Fri, 4 Jan 2019 20:48:40 +0000
Subject: [PATCH v2 3/6] Add --disable-page-skipping and --skip-locked to
 vacuumdb.

---
 doc/src/sgml/ref/vacuumdb.sgml    | 30 ++++++++++++++++++++++++++++
 src/bin/scripts/t/100_vacuumdb.pl | 13 +++++++++++-
 src/bin/scripts/vacuumdb.c        | 42 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/doc/src/sgml/ref/vacuumdb.sgml b/doc/src/sgml/ref/vacuumdb.sgml
index 955a17a849..50b6228f90 100644
--- a/doc/src/sgml/ref/vacuumdb.sgml
+++ b/doc/src/sgml/ref/vacuumdb.sgml
@@ -102,6 +102,21 @@ PostgreSQL documentation
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><option>--disable-page-skipping</option></term>
+      <listitem>
+       <para>
+        Disable all page-skipping behavior during processing.
+       </para>
+       <note>
+        <para>
+         This option is only available for servers running PostgreSQL 9.6 and
+         later.
+        </para>
+       </note>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><option>-e</option></term>
       <term><option>--echo</option></term>
@@ -167,6 +182,21 @@ PostgreSQL documentation
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><option>--skip-locked</option></term>
+      <listitem>
+       <para>
+        Skip relations that cannot be immediately locked for processing.
+       </para>
+       <note>
+        <para>
+         This option is only available for servers running PostgreSQL 12 and
+         later.
+        </para>
+       </note>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><option>-t <replaceable class="parameter">table</replaceable> [ (<replaceable class="parameter">column</replaceable> [,...]) ]</option></term>
       <term><option>--table=<replaceable class="parameter">table</replaceable> [ (<replaceable class="parameter">column</replaceable> [,...]) ]</option></term>
diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl
index 4c477a27aa..5f22323006 100644
--- a/src/bin/scripts/t/100_vacuumdb.pl
+++ b/src/bin/scripts/t/100_vacuumdb.pl
@@ -3,7 +3,7 @@ use warnings;
 
 use PostgresNode;
 use TestLib;
-use Test::More tests => 23;
+use Test::More tests => 28;
 
 program_help_ok('vacuumdb');
 program_version_ok('vacuumdb');
@@ -33,6 +33,17 @@ $node->issues_sql_like(
 	[ 'vacuumdb', '-Z', 'postgres' ],
 	qr/statement: ANALYZE;/,
 	'vacuumdb -Z');
+$node->issues_sql_like(
+	[ 'vacuumdb', '--disable-page-skipping', 'postgres' ],
+	qr/statement: VACUUM \(DISABLE_PAGE_SKIPPING\);/,
+	'vacuumdb --disable-page-skipping');
+$node->issues_sql_like(
+	[ 'vacuumdb', '--skip-locked', 'postgres' ],
+	qr/statement: VACUUM \(SKIP_LOCKED\);/,
+	'vacuumdb --skip-locked');
+$node->command_fails(
+	[qw|vacuumdb --analyze-only --disable-page-skipping postgres|],
+	'--analyze-only and --disable-page-skipping specified together');
 $node->command_ok([qw(vacuumdb -Z --table=pg_am dbname=template1)],
 	'vacuumdb with connection string');
 
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
index 4e2bf713ae..bdc4fcfe35 100644
--- a/src/bin/scripts/vacuumdb.c
+++ b/src/bin/scripts/vacuumdb.c
@@ -40,6 +40,8 @@ typedef struct vacuumingOptions
 	bool		and_analyze;
 	bool		full;
 	bool		freeze;
+	bool		disable_page_skipping;
+	bool		skip_locked;
 } vacuumingOptions;
 
 
@@ -110,6 +112,8 @@ main(int argc, char *argv[])
 		{"jobs", required_argument, NULL, 'j'},
 		{"maintenance-db", required_argument, NULL, 2},
 		{"analyze-in-stages", no_argument, NULL, 3},
+		{"disable-page-skipping", no_argument, NULL, 4},
+		{"skip-locked", no_argument, NULL, 5},
 		{NULL, 0, NULL, 0}
 	};
 
@@ -213,6 +217,12 @@ main(int argc, char *argv[])
 			case 3:
 				analyze_in_stages = vacopts.analyze_only = true;
 				break;
+			case 4:
+				vacopts.disable_page_skipping = true;
+				break;
+			case 5:
+				vacopts.skip_locked = true;
+				break;
 			default:
 				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 				exit(1);
@@ -251,6 +261,12 @@ main(int argc, char *argv[])
 					progname, "freeze");
 			exit(1);
 		}
+		if (vacopts.disable_page_skipping)
+		{
+			fprintf(stderr, _("%s: cannot use the \"%s\" option when performing only analyze\n"),
+					progname, "disable-page-skipping");
+			exit(1);
+		}
 		/* allow 'and_analyze' with 'analyze_only' */
 	}
 
@@ -367,6 +383,20 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
 	conn = connectDatabase(dbname, host, port, username, prompt_password,
 						   progname, echo, false, true);
 
+	if (vacopts->disable_page_skipping && PQserverVersion(conn) < 90600)
+	{
+		fprintf(stderr, _("%s: cannot use the \"%s\" option on server versions older than PostgreSQL 9.6\n"),
+				progname, "disable-page-skipping");
+		exit(1);
+	}
+
+	if (vacopts->skip_locked && PQserverVersion(conn) < 120000)
+	{
+		fprintf(stderr, _("%s: cannot use the \"%s\" option on server versions older than PostgreSQL 12\n"),
+				progname, "skip-locked");
+		exit(1);
+	}
+
 	if (!quiet)
 	{
 		if (stage != ANALYZE_NO_STAGE)
@@ -670,6 +700,16 @@ prepare_vacuum_command(PQExpBuffer sql, PGconn *conn,
 			appendPQExpBuffer(sql, "%sANALYZE", sep);
 			sep = comma;
 		}
+		if (vacopts->disable_page_skipping)
+		{
+			appendPQExpBuffer(sql, "%sDISABLE_PAGE_SKIPPING", sep);
+			sep = comma;
+		}
+		if (vacopts->skip_locked)
+		{
+			appendPQExpBuffer(sql, "%sSKIP_LOCKED", sep);
+			sep = comma;
+		}
 		if (sep != paren)
 			appendPQExpBufferChar(sql, ')');
 	}
@@ -1002,11 +1042,13 @@ help(const char *progname)
 	printf(_("\nOptions:\n"));
 	printf(_("  -a, --all                       vacuum all databases\n"));
 	printf(_("  -d, --dbname=DBNAME             database to vacuum\n"));
+	printf(_("      --disable-page-skipping     disable all page-skipping behavior\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"));
 	printf(_("  -j, --jobs=NUM                  use this many concurrent connections to vacuum\n"));
 	printf(_("  -q, --quiet                     don't write any messages\n"));
+	printf(_("      --skip-locked               skip relations that cannot be immediately locked\n"));
 	printf(_("  -t, --table='TABLE[(COLUMNS)]'  vacuum specific table(s) only\n"));
 	printf(_("  -v, --verbose                   write a lot of output\n"));
 	printf(_("  -V, --version                   output version information, then exit\n"));
-- 
2.16.5

