From e9e84a09c0e63a9bb487bc6a1800de90492e4ad6 Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryzbyj@telsasoft.com>
Date: Fri, 19 Mar 2021 22:49:59 -0500
Subject: [PATCH 8/9] WIP: pg_dump: output default_toast_compression..

This is unlike default_tablespace in that tablespaces are associated with an
entire relation, whereas TOAST compression is associated with individual
columns, so cannot SET default_toast_compression between CREATE commands.
Rather, each column should have a COMPRESSION clause if its compression differs
from the dump-time default.  This commit sets the default during restore to
match the dump-time default so that does the right thing.

XXX: need to bump archive version?
---
 src/bin/pg_dump/pg_backup.h          |  1 +
 src/bin/pg_dump/pg_backup_archiver.c | 20 +++++++++++-
 src/bin/pg_dump/pg_dump.c            | 48 ++++++++++++++++++++++++++--
 3 files changed, 66 insertions(+), 3 deletions(-)

diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index 0296b9bb5e..dbe2689f23 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -209,6 +209,7 @@ typedef struct Archive
 
 	/* other important stuff */
 	char	   *searchpath;		/* search_path to set during restore */
+	char       *default_toast_compression;	/* default TOAST compression to set during restore */
 	char	   *use_role;		/* Issue SET ROLE to this */
 
 	/* error handling */
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 35bf971220..d7fcbc5410 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -86,6 +86,7 @@ static void _selectTableAccessMethod(ArchiveHandle *AH, const char *tableam);
 static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te);
 static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te);
 static void processSearchPathEntry(ArchiveHandle *AH, TocEntry *te);
+static void processToastCompressionEntry(ArchiveHandle *AH, TocEntry *te);
 static int	_tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH);
 static RestorePass _tocEntryRestorePass(TocEntry *te);
 static bool _tocEntryIsACL(TocEntry *te);
@@ -2696,6 +2697,8 @@ ReadToc(ArchiveHandle *AH)
 			processStdStringsEntry(AH, te);
 		else if (strcmp(te->desc, "SEARCHPATH") == 0)
 			processSearchPathEntry(AH, te);
+		else if (strcmp(te->desc, "TOAST_COMPRESSION") == 0)
+			processToastCompressionEntry(AH, te);
 	}
 }
 
@@ -2753,6 +2756,16 @@ processSearchPathEntry(ArchiveHandle *AH, TocEntry *te)
 	AH->public.searchpath = pg_strdup(te->defn);
 }
 
+static void
+processToastCompressionEntry(ArchiveHandle *AH, TocEntry *te)
+{
+	/*
+	 * te->defn should contain a command to set default_toast_compression.
+	 * We just copy it verbatim for use later.
+	 */
+	AH->public.default_toast_compression = pg_strdup(te->defn);
+}
+
 static void
 StrictNamesCheck(RestoreOptions *ropt)
 {
@@ -2812,7 +2825,8 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH)
 	/* These items are treated specially */
 	if (strcmp(te->desc, "ENCODING") == 0 ||
 		strcmp(te->desc, "STDSTRINGS") == 0 ||
-		strcmp(te->desc, "SEARCHPATH") == 0)
+		strcmp(te->desc, "SEARCHPATH") == 0 ||
+		strcmp(te->desc, "TOAST_COMPRESSION") == 0)
 		return REQ_SPECIAL;
 
 	/*
@@ -3135,6 +3149,10 @@ _doSetFixedOutputState(ArchiveHandle *AH)
 	if (AH->public.searchpath)
 		ahprintf(AH, "%s", AH->public.searchpath);
 
+	/* Select the dump-time default_toast_compression */
+	if (AH->public.default_toast_compression)
+		ahprintf(AH, "%s", AH->public.default_toast_compression);
+
 	/* Make sure function checking is disabled */
 	ahprintf(AH, "SET check_function_bodies = false;\n");
 
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index aa7c004147..12d1ebf466 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -270,6 +270,7 @@ static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
 static void dumpEncoding(Archive *AH);
 static void dumpStdStrings(Archive *AH);
 static void dumpSearchPath(Archive *AH);
+static void dumpToastCompression(Archive *AH);
 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
 													 PQExpBuffer upgrade_buffer,
 													 Oid pg_type_oid,
@@ -909,10 +910,14 @@ main(int argc, char **argv)
 	 * order.
 	 */
 
-	/* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
+	/*
+	 * First the special entries for ENCODING, STDSTRINGS, SEARCHPATH and
+	 * TOAST_COMPRESSION.
+	 */
 	dumpEncoding(fout);
 	dumpStdStrings(fout);
 	dumpSearchPath(fout);
+	dumpToastCompression(fout);
 
 	/* The database items are always next, unless we don't want them at all */
 	if (dopt.outputCreateDB)
@@ -1048,7 +1053,7 @@ help(const char *progname)
 	printf(_("  --no-publications            do not dump publications\n"));
 	printf(_("  --no-security-labels         do not dump security label assignments\n"));
 	printf(_("  --no-subscriptions           do not dump subscriptions\n"));
-	printf(_("  --no-toast-compression      do not dump toast compression methods\n"));
+	printf(_("  --no-toast-compression       do not dump toast compression methods\n"));
 	printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
 	printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
 	printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
@@ -3260,6 +3265,45 @@ dumpStdStrings(Archive *AH)
 	destroyPQExpBuffer(qry);
 }
 
+/*
+ * dumpToastCompression: save the dump-time default TOAST compression in the
+ * archive
+ */
+static void
+dumpToastCompression(Archive *AH)
+{
+	PQExpBuffer qry = createPQExpBuffer();
+	const char *toast_compression;
+	PGresult   *res;
+
+	if (AH->dopt->no_toast_compression)
+		return;
+
+	res = ExecuteSqlQueryForSingleRow(AH, "SHOW default_toast_compression"); /* XXX: show ?? */
+	toast_compression = PQgetvalue(res, 0, 0);
+
+	pg_log_info("saving default_toast_compression = %s", toast_compression);
+
+	appendPQExpBufferStr(qry, "SET default_toast_compression = ");
+	appendStringLiteralAH(qry, toast_compression, AH);
+	appendPQExpBufferStr(qry, ";\n");
+
+	ArchiveEntry(AH, nilCatalogId, createDumpId(),
+				 ARCHIVE_OPTS(.tag = "TOAST_COMPRESSION",
+							  .description = "TOAST_COMPRESSION",
+							  .section = SECTION_PRE_DATA,
+							  .createStmt = qry->data));
+
+	/*
+	 * Also save it in AH->default_toast_compression, in case we're doing plain
+	 * text dump
+	 */
+	AH->default_toast_compression = pg_strdup(qry->data);
+
+	PQclear(res);
+	destroyPQExpBuffer(qry);
+}
+
 /*
  * dumpSearchPath: record the active search_path in the archive
  */
-- 
2.17.0

