From 44096f1c6644a97c92da6c96dc1d8d4e200d4a38 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 11 Jan 2015 13:28:26 -0500
Subject: [PATCH] Fix portability breakage in pg_dump.

Commit 0eea8047bf0e15b402b951e383e39236bdfe57d5 introduced some overly
optimistic assumptions about what could be in a local struct variable's
initializer.  (This might in fact be valid code according to C99, but I've
got at least one pre-C99 compiler that falls over on those nonconstant
address expressions.)  There is no reason whatsoever for main()'s workspace
to not be static, so revert long_options[] to a static and make the
DumpOptions struct static as well.
---
 src/bin/pg_dump/pg_backup.h          |   1 +
 src/bin/pg_dump/pg_backup_archiver.c |  20 ++--
 src/bin/pg_dump/pg_dump.c            | 154 ++++++++++++++-------------
 3 files changed, 91 insertions(+), 84 deletions(-)

diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index c2ebcd4f745..a936ff81b9d 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -269,6 +269,7 @@ extern void PrintTOCSummary(Archive *AH, RestoreOptions *ropt);
 extern RestoreOptions *NewRestoreOptions(void);
 
 extern DumpOptions *NewDumpOptions(void);
+extern void InitDumpOptions(DumpOptions *opts);
 extern DumpOptions *dumpOptionsFromRestoreOptions(RestoreOptions *ropt);
 
 /* Rearrange and filter TOC entries */
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 43065e84b2f..9e6455861d9 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -109,23 +109,27 @@ static void mark_create_done(ArchiveHandle *AH, TocEntry *te);
 static void inhibit_data_for_failed_table(ArchiveHandle *AH, TocEntry *te);
 
 /*
- * Allocate a new DumpOptions block.
- * This is mainly so we can initialize it, but also for future expansion.
- * We pg_malloc0 the structure, so we don't need to initialize whatever is
- * 0, NULL or false anyway.
+ * Allocate a new DumpOptions block containing all default values.
  */
 DumpOptions *
 NewDumpOptions(void)
 {
-	DumpOptions *opts;
+	DumpOptions *opts = (DumpOptions *) pg_malloc(sizeof(DumpOptions));
 
-	opts = (DumpOptions *) pg_malloc0(sizeof(DumpOptions));
+	InitDumpOptions(opts);
+	return opts;
+}
 
+/*
+ * Initialize a DumpOptions struct to all default values
+ */
+void
+InitDumpOptions(DumpOptions *opts)
+{
+	memset(opts, 0, sizeof(DumpOptions));
 	/* set any fields that shouldn't default to zeroes */
 	opts->include_everything = true;
 	opts->dumpSections = DUMP_UNSECTIONED;
-
-	return opts;
 }
 
 /*
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 981fdf149ed..dc062e67eed 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -279,9 +279,9 @@ main(int argc, char **argv)
 	ArchiveFormat archiveFormat = archUnknown;
 	ArchiveMode archiveMode;
 
-	DumpOptions *dopt = NewDumpOptions();
+	static DumpOptions dopt;
 
-	struct option long_options[] = {
+	static struct option long_options[] = {
 		{"data-only", no_argument, NULL, 'a'},
 		{"blobs", no_argument, NULL, 'b'},
 		{"clean", no_argument, NULL, 'c'},
@@ -316,26 +316,26 @@ main(int argc, char **argv)
 		/*
 		 * the following options don't have an equivalent short option letter
 		 */
-		{"attribute-inserts", no_argument, &dopt->column_inserts, 1},
-		{"binary-upgrade", no_argument, &dopt->binary_upgrade, 1},
-		{"column-inserts", no_argument, &dopt->column_inserts, 1},
-		{"disable-dollar-quoting", no_argument, &dopt->disable_dollar_quoting, 1},
-		{"disable-triggers", no_argument, &dopt->disable_triggers, 1},
-		{"enable-row-security", no_argument, &dopt->enable_row_security, 1},
+		{"attribute-inserts", no_argument, &dopt.column_inserts, 1},
+		{"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
+		{"column-inserts", no_argument, &dopt.column_inserts, 1},
+		{"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
+		{"disable-triggers", no_argument, &dopt.disable_triggers, 1},
+		{"enable-row-security", no_argument, &dopt.enable_row_security, 1},
 		{"exclude-table-data", required_argument, NULL, 4},
-		{"if-exists", no_argument, &dopt->if_exists, 1},
-		{"inserts", no_argument, &dopt->dump_inserts, 1},
+		{"if-exists", no_argument, &dopt.if_exists, 1},
+		{"inserts", no_argument, &dopt.dump_inserts, 1},
 		{"lock-wait-timeout", required_argument, NULL, 2},
-		{"no-tablespaces", no_argument, &dopt->outputNoTablespaces, 1},
+		{"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
 		{"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
 		{"role", required_argument, NULL, 3},
 		{"section", required_argument, NULL, 5},
-		{"serializable-deferrable", no_argument, &dopt->serializable_deferrable, 1},
+		{"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
 		{"snapshot", required_argument, NULL, 6},
-		{"use-set-session-authorization", no_argument, &dopt->use_setsessauth, 1},
-		{"no-security-labels", no_argument, &dopt->no_security_labels, 1},
-		{"no-synchronized-snapshots", no_argument, &dopt->no_synchronized_snapshots, 1},
-		{"no-unlogged-table-data", no_argument, &dopt->no_unlogged_table_data, 1},
+		{"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
+		{"no-security-labels", no_argument, &dopt.no_security_labels, 1},
+		{"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
+		{"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
 
 		{NULL, 0, NULL, 0}
 	};
@@ -374,29 +374,31 @@ main(int argc, char **argv)
 		}
 	}
 
+	InitDumpOptions(&dopt);
+
 	while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:n:N:oOp:RsS:t:T:U:vwWxZ:",
 							long_options, &optindex)) != -1)
 	{
 		switch (c)
 		{
 			case 'a':			/* Dump data only */
-				dopt->dataOnly = true;
+				dopt.dataOnly = true;
 				break;
 
 			case 'b':			/* Dump blobs */
-				dopt->outputBlobs = true;
+				dopt.outputBlobs = true;
 				break;
 
 			case 'c':			/* clean (i.e., drop) schema prior to create */
-				dopt->outputClean = 1;
+				dopt.outputClean = 1;
 				break;
 
 			case 'C':			/* Create DB */
-				dopt->outputCreateDB = 1;
+				dopt.outputCreateDB = 1;
 				break;
 
 			case 'd':			/* database name */
-				dopt->dbname = pg_strdup(optarg);
+				dopt.dbname = pg_strdup(optarg);
 				break;
 
 			case 'E':			/* Dump encoding */
@@ -412,7 +414,7 @@ main(int argc, char **argv)
 				break;
 
 			case 'h':			/* server host */
-				dopt->pghost = pg_strdup(optarg);
+				dopt.pghost = pg_strdup(optarg);
 				break;
 
 			case 'i':
@@ -425,7 +427,7 @@ main(int argc, char **argv)
 
 			case 'n':			/* include schema(s) */
 				simple_string_list_append(&schema_include_patterns, optarg);
-				dopt->include_everything = false;
+				dopt.include_everything = false;
 				break;
 
 			case 'N':			/* exclude schema(s) */
@@ -433,15 +435,15 @@ main(int argc, char **argv)
 				break;
 
 			case 'o':			/* Dump oids */
-				dopt->oids = true;
+				dopt.oids = true;
 				break;
 
 			case 'O':			/* Don't reconnect to match owner */
-				dopt->outputNoOwner = 1;
+				dopt.outputNoOwner = 1;
 				break;
 
 			case 'p':			/* server port */
-				dopt->pgport = pg_strdup(optarg);
+				dopt.pgport = pg_strdup(optarg);
 				break;
 
 			case 'R':
@@ -449,16 +451,16 @@ main(int argc, char **argv)
 				break;
 
 			case 's':			/* dump schema only */
-				dopt->schemaOnly = true;
+				dopt.schemaOnly = true;
 				break;
 
 			case 'S':			/* Username for superuser in plain text output */
-				dopt->outputSuperuser = pg_strdup(optarg);
+				dopt.outputSuperuser = pg_strdup(optarg);
 				break;
 
 			case 't':			/* include table(s) */
 				simple_string_list_append(&table_include_patterns, optarg);
-				dopt->include_everything = false;
+				dopt.include_everything = false;
 				break;
 
 			case 'T':			/* exclude table(s) */
@@ -466,7 +468,7 @@ main(int argc, char **argv)
 				break;
 
 			case 'U':
-				dopt->username = pg_strdup(optarg);
+				dopt.username = pg_strdup(optarg);
 				break;
 
 			case 'v':			/* verbose */
@@ -482,7 +484,7 @@ main(int argc, char **argv)
 				break;
 
 			case 'x':			/* skip ACL dump */
-				dopt->aclsSkip = true;
+				dopt.aclsSkip = true;
 				break;
 
 			case 'Z':			/* Compression Level */
@@ -494,7 +496,7 @@ main(int argc, char **argv)
 				break;
 
 			case 2:				/* lock-wait-timeout */
-				dopt->lockWaitTimeout = pg_strdup(optarg);
+				dopt.lockWaitTimeout = pg_strdup(optarg);
 				break;
 
 			case 3:				/* SET ROLE */
@@ -506,7 +508,7 @@ main(int argc, char **argv)
 				break;
 
 			case 5:				/* section */
-				set_dump_section(optarg, &dopt->dumpSections);
+				set_dump_section(optarg, &dopt.dumpSections);
 				break;
 
 			case 6:				/* snapshot */
@@ -523,8 +525,8 @@ main(int argc, char **argv)
 	 * Non-option argument specifies database name as long as it wasn't
 	 * already specified with -d / --dbname
 	 */
-	if (optind < argc && dopt->dbname == NULL)
-		dopt->dbname = argv[optind++];
+	if (optind < argc && dopt.dbname == NULL)
+		dopt.dbname = argv[optind++];
 
 	/* Complain if any arguments remain */
 	if (optind < argc)
@@ -537,29 +539,29 @@ main(int argc, char **argv)
 	}
 
 	/* --column-inserts implies --inserts */
-	if (dopt->column_inserts)
-		dopt->dump_inserts = 1;
+	if (dopt.column_inserts)
+		dopt.dump_inserts = 1;
 
-	if (dopt->dataOnly && dopt->schemaOnly)
+	if (dopt.dataOnly && dopt.schemaOnly)
 	{
 		write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
 		exit_nicely(1);
 	}
 
-	if (dopt->dataOnly && dopt->outputClean)
+	if (dopt.dataOnly && dopt.outputClean)
 	{
 		write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
 		exit_nicely(1);
 	}
 
-	if (dopt->dump_inserts && dopt->oids)
+	if (dopt.dump_inserts && dopt.oids)
 	{
 		write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
 		write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
 		exit_nicely(1);
 	}
 
-	if (dopt->if_exists && !dopt->outputClean)
+	if (dopt.if_exists && !dopt.outputClean)
 		exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
 
 	/* Identify archive format to emit */
@@ -620,15 +622,15 @@ main(int argc, char **argv)
 	 * Open the database using the Archiver, so it knows about it. Errors mean
 	 * death.
 	 */
-	ConnectDatabase(fout, dopt->dbname, dopt->pghost, dopt->pgport, dopt->username, prompt_password);
-	setup_connection(fout, dopt, dumpencoding, dumpsnapshot, use_role);
+	ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
+	setup_connection(fout, &dopt, dumpencoding, dumpsnapshot, use_role);
 
 	/*
 	 * Disable security label support if server version < v9.1.x (prevents
 	 * access to nonexistent pg_seclabel catalog)
 	 */
 	if (fout->remoteVersion < 90100)
-		dopt->no_security_labels = 1;
+		dopt.no_security_labels = 1;
 
 	/*
 	 * When running against 9.0 or later, check if we are in recovery mode,
@@ -644,7 +646,7 @@ main(int argc, char **argv)
 			 * On hot standby slaves, never try to dump unlogged table data,
 			 * since it will just throw an error.
 			 */
-			dopt->no_unlogged_table_data = true;
+			dopt.no_unlogged_table_data = true;
 		}
 		PQclear(res);
 	}
@@ -659,7 +661,7 @@ main(int argc, char **argv)
 
 	/* check the version for the synchronized snapshots feature */
 	if (numWorkers > 1 && fout->remoteVersion < 90200
-		&& !dopt->no_synchronized_snapshots)
+		&& !dopt.no_synchronized_snapshots)
 		exit_horribly(NULL,
 		 "Synchronized snapshots are not supported by this server version.\n"
 		  "Run with --no-synchronized-snapshots instead if you do not need\n"
@@ -714,27 +716,27 @@ main(int argc, char **argv)
 	 * Dumping blobs is now default unless we saw an inclusion switch or -s
 	 * ... but even if we did see one of these, -b turns it back on.
 	 */
-	if (dopt->include_everything && !dopt->schemaOnly)
-		dopt->outputBlobs = true;
+	if (dopt.include_everything && !dopt.schemaOnly)
+		dopt.outputBlobs = true;
 
 	/*
 	 * Now scan the database and create DumpableObject structs for all the
 	 * objects we intend to dump.
 	 */
-	tblinfo = getSchemaData(fout, dopt, &numTables);
+	tblinfo = getSchemaData(fout, &dopt, &numTables);
 
 	if (fout->remoteVersion < 80400)
 		guessConstraintInheritance(tblinfo, numTables);
 
-	if (!dopt->schemaOnly)
+	if (!dopt.schemaOnly)
 	{
-		getTableData(dopt, tblinfo, numTables, dopt->oids);
+		getTableData(&dopt, tblinfo, numTables, dopt.oids);
 		buildMatViewRefreshDependencies(fout);
-		if (dopt->dataOnly)
+		if (dopt.dataOnly)
 			getTableDataFKConstraints();
 	}
 
-	if (dopt->outputBlobs)
+	if (dopt.outputBlobs)
 		getBlobs(fout);
 
 	/*
@@ -784,12 +786,12 @@ main(int argc, char **argv)
 	dumpStdStrings(fout);
 
 	/* The database item is always next, unless we don't want it at all */
-	if (dopt->include_everything && !dopt->dataOnly)
-		dumpDatabase(fout, dopt);
+	if (dopt.include_everything && !dopt.dataOnly)
+		dumpDatabase(fout, &dopt);
 
 	/* Now the rearrangeable objects. */
 	for (i = 0; i < numObjs; i++)
-		dumpDumpableObject(fout, dopt, dobjs[i]);
+		dumpDumpableObject(fout, &dopt, dobjs[i]);
 
 	/*
 	 * Set up options info to ensure we dump what we want.
@@ -798,25 +800,25 @@ main(int argc, char **argv)
 	ropt->filename = filename;
 
 	/* if you change this list, see dumpOptionsFromRestoreOptions */
-	ropt->dropSchema = dopt->outputClean;
-	ropt->dataOnly = dopt->dataOnly;
-	ropt->schemaOnly = dopt->schemaOnly;
-	ropt->if_exists = dopt->if_exists;
-	ropt->column_inserts = dopt->column_inserts;
-	ropt->dumpSections = dopt->dumpSections;
-	ropt->aclsSkip = dopt->aclsSkip;
-	ropt->superuser = dopt->outputSuperuser;
-	ropt->createDB = dopt->outputCreateDB;
-	ropt->noOwner = dopt->outputNoOwner;
-	ropt->noTablespace = dopt->outputNoTablespaces;
-	ropt->disable_triggers = dopt->disable_triggers;
-	ropt->use_setsessauth = dopt->use_setsessauth;
-	ropt->disable_dollar_quoting = dopt->disable_dollar_quoting;
-	ropt->dump_inserts = dopt->dump_inserts;
-	ropt->no_security_labels = dopt->no_security_labels;
-	ropt->lockWaitTimeout = dopt->lockWaitTimeout;
-	ropt->include_everything = dopt->include_everything;
-	ropt->enable_row_security = dopt->enable_row_security;
+	ropt->dropSchema = dopt.outputClean;
+	ropt->dataOnly = dopt.dataOnly;
+	ropt->schemaOnly = dopt.schemaOnly;
+	ropt->if_exists = dopt.if_exists;
+	ropt->column_inserts = dopt.column_inserts;
+	ropt->dumpSections = dopt.dumpSections;
+	ropt->aclsSkip = dopt.aclsSkip;
+	ropt->superuser = dopt.outputSuperuser;
+	ropt->createDB = dopt.outputCreateDB;
+	ropt->noOwner = dopt.outputNoOwner;
+	ropt->noTablespace = dopt.outputNoTablespaces;
+	ropt->disable_triggers = dopt.disable_triggers;
+	ropt->use_setsessauth = dopt.use_setsessauth;
+	ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
+	ropt->dump_inserts = dopt.dump_inserts;
+	ropt->no_security_labels = dopt.no_security_labels;
+	ropt->lockWaitTimeout = dopt.lockWaitTimeout;
+	ropt->include_everything = dopt.include_everything;
+	ropt->enable_row_security = dopt.enable_row_security;
 
 	if (compressLevel == -1)
 		ropt->compression = 0;
@@ -845,7 +847,7 @@ main(int argc, char **argv)
 	if (plainText)
 		RestoreArchive(fout);
 
-	CloseArchive(fout, dopt);
+	CloseArchive(fout, &dopt);
 
 	exit_nicely(0);
 }
-- 
GitLab