On Fri, Nov 06, 2020 at 11:18:35PM -0300, Alvaro Herrera wrote:
> On 2020-Oct-24, Justin Pryzby wrote:
> 
> > On Fri, Oct 23, 2020 at 12:29:40AM -0500, Justin Pryzby wrote:
> 
> > > Now that I look, it seems like this is calling PQexec(), which sends a 
> > > single,
> > > "simple" libpq message with:
> > > |CREATE TABLE ..; ALTER TABLE .. ATTACH PARTITION;
> > > ..which is transactional, so when the 2nd command fails, the CREATE is 
> > > rolled back.
> > > https://www.postgresql.org/docs/9.5/libpq-exec.html#LIBPQ-EXEC-MAIN
> > 
> > The easy fix is to add an explicit begin/commit.
> 
> Hmm, I think this throws a warning when used with "pg_restore -1",
> right?  I don't think that's sufficient reason to discard the idea, but
> it be better to find some other way.

Worse, right ?  It'd commit in the middle and then continue outside of a txn.
I guess there's no test case for this :(

> I have no ideas ATM :-(

1. Maybe pg_restore ExecuteSqlCommandBuf() should (always?) call
ExecuteSimpleCommands() instead of ExecuteSqlCommand().  It doesn't seem to
break anything (although that surprised me).

2. Otherwise, the createStmt would need to be split into a createStmt2 or a
char *createStmt[], which I think would then require changing the output
format.  It seems clearly better to keep the sql commands split up initially
than to reverse engineer them during restore.

I tried using \x01 to separate commands, and strtok to split them to run them
individually.  But that breaks the pg_dumpall tests.  As an experiment, I used
\x00, which is somewhat invasive but actually works.

Obviously patching pg_dump will affect only future backups, and the pg_restore
patch allows independently restoring parent tables in existing dumps.

-- 
Justin
>From f1ce24cb79dd4cdcd93d602ddede711efff8227e Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryz...@telsasoft.com>
Date: Thu, 19 Nov 2020 19:10:02 -0600
Subject: [PATCH v2 1/2] pg_restore: parse and run separately SQL commands

If pg_dump emits multiple DDL commands, run them in separate transactions, to
avoid failures in the 2ndary (ALTER) commands from rolling back the first,
primary (CREATE) command.

XXX: is there any performance benefit possible if can we call
ExecuteSqlCommand() in some cases?  I don't think it matters much for DDL.
---
 src/bin/pg_dump/pg_backup_db.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c
index 5ba43441f5..1565155e20 100644
--- a/src/bin/pg_dump/pg_backup_db.c
+++ b/src/bin/pg_dump/pg_backup_db.c
@@ -477,21 +477,20 @@ ExecuteSqlCommandBuf(Archive *AHX, const char *buf, size_t bufLen)
 	else
 	{
 		/*
-		 * General SQL commands; we assume that commands will not be split
-		 * across calls.
+		 * General SQL commands
 		 *
 		 * In most cases the data passed to us will be a null-terminated
 		 * string, but if it's not, we have to add a trailing null.
 		 */
 		if (buf[bufLen] == '\0')
-			ExecuteSqlCommand(AH, buf, "could not execute query");
+			ExecuteSimpleCommands(AH, buf, bufLen);
 		else
 		{
 			char	   *str = (char *) pg_malloc(bufLen + 1);
 
 			memcpy(str, buf, bufLen);
 			str[bufLen] = '\0';
-			ExecuteSqlCommand(AH, str, "could not execute query");
+			ExecuteSimpleCommands(AH, buf, bufLen);
 			free(str);
 		}
 	}
-- 
2.17.0

>From c6ec806b245a08c47f6e1d7c4909a532f49e69e1 Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryz...@telsasoft.com>
Date: Sat, 24 Oct 2020 14:51:18 -0500
Subject: [PATCH v2 2/2] pg_dump: Allow child partitions to be independently
 restored

..even if the parent doesn't exist, or has missing/incompatible columns

This seems to have been intended by commit 33a53130a
---
 src/bin/pg_dump/pg_backup_archiver.c | 50 +++++++++++++++++--
 src/bin/pg_dump/pg_dump.c            | 72 ++++++++++++++++++++++++++--
 src/bin/pg_dump/t/002_pg_dump.pl     |  2 +-
 3 files changed, 117 insertions(+), 7 deletions(-)

diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index b961a24b36..becf9ec34d 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -143,6 +143,8 @@ static void inhibit_data_for_failed_table(ArchiveHandle *AH, TocEntry *te);
 
 static void StrictNamesCheck(RestoreOptions *ropt);
 
+static size_t WriteStrs(ArchiveHandle *AH, const char *c);
+
 
 /*
  * Allocate a new DumpOptions block containing all default values.
@@ -1081,9 +1083,20 @@ ArchiveEntry(Archive *AHX, CatalogId catalogId, DumpId dumpId,
 	newToc->tableam = opts->tableam ? pg_strdup(opts->tableam) : NULL;
 	newToc->owner = opts->owner ? pg_strdup(opts->owner) : NULL;
 	newToc->desc = pg_strdup(opts->description);
-	newToc->defn = opts->createStmt ? pg_strdup(opts->createStmt) : NULL;
 	newToc->dropStmt = opts->dropStmt ? pg_strdup(opts->dropStmt) : NULL;
 	newToc->copyStmt = opts->copyStmt ? pg_strdup(opts->copyStmt) : NULL;
+	if (opts->createStmt == NULL)
+		newToc->defn = NULL;
+	else
+	{
+		const char *p = opts->createStmt;
+		size_t	len;
+		for (; *p != 0;)
+			p += 1 + strlen(p);
+		len = p - opts->createStmt + 1;
+		newToc->defn = palloc(len);
+		memcpy(newToc->defn, opts->createStmt, len);
+	}
 
 	if (opts->nDeps > 0)
 	{
@@ -2037,6 +2050,29 @@ WriteStr(ArchiveHandle *AH, const char *c)
 	return res;
 }
 
+size_t
+WriteStrs(ArchiveHandle *AH, const char *c)
+{
+	size_t		res;
+
+	if (c)
+	{
+		int			len;
+		const char *s = c;
+		for ( ; *s; )
+			s += 1 + strlen(s);
+		len = s - c + 1;
+
+		res = WriteInt(AH, len);
+		AH->WriteBufPtr(AH, c, len);
+		res += len;
+	}
+	else
+		res = WriteInt(AH, -1);
+
+	return res;
+}
+
 char *
 ReadStr(ArchiveHandle *AH)
 {
@@ -2522,7 +2558,7 @@ WriteToc(ArchiveHandle *AH)
 		WriteStr(AH, te->tag);
 		WriteStr(AH, te->desc);
 		WriteInt(AH, te->section);
-		WriteStr(AH, te->defn);
+		WriteStrs(AH, te->defn);
 		WriteStr(AH, te->dropStmt);
 		WriteStr(AH, te->copyStmt);
 		WriteStr(AH, te->namespace);
@@ -3607,7 +3643,15 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
 	else
 	{
 		if (te->defn && strlen(te->defn) > 0)
-			ahprintf(AH, "%s\n\n", te->defn);
+		{
+			char *p = te->defn;
+			for (; *p;)
+			{
+				ahprintf(AH, "%s\n", p);
+				p += 1 + strlen(p);
+			}
+			ahprintf(AH, "\n");
+		}
 	}
 
 	/*
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index dc1d41dd8d..7c8af9b19d 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -2362,6 +2362,7 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
 
 	appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
 					  fmtQualifiedDumpable(tbinfo));
+	appendPQExpBufferChar(q, '\x00');
 
 	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
 		ArchiveEntry(fout,
@@ -2925,6 +2926,7 @@ dumpDatabase(Archive *fout)
 		appendPQExpBuffer(creaQry, " TABLESPACE = %s",
 						  fmtId(tablespace));
 	appendPQExpBufferStr(creaQry, ";\n");
+	appendPQExpBufferChar(creaQry, '\x00');
 
 	appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
 					  qdatname);
@@ -2965,6 +2967,7 @@ dumpDatabase(Archive *fout)
 			appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
 			appendStringLiteralAH(dbQry, comment, fout);
 			appendPQExpBufferStr(dbQry, ";\n");
+			appendPQExpBufferChar(dbQry, '\x00');
 
 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
 						 ARCHIVE_OPTS(.tag = labelq->data,
@@ -2994,6 +2997,7 @@ dumpDatabase(Archive *fout)
 		shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
 		resetPQExpBuffer(seclabelQry);
 		emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
+		appendPQExpBufferChar(seclabelQry, '\x00');
 		if (seclabelQry->len > 0)
 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
 						 ARCHIVE_OPTS(.tag = labelq->data,
@@ -3064,6 +3068,7 @@ dumpDatabase(Archive *fout)
 						  frozenxid, minmxid);
 		appendStringLiteralAH(creaQry, datname, fout);
 		appendPQExpBufferStr(creaQry, ";\n");
+		appendPQExpBufferChar(creaQry, '\x00');
 	}
 
 	if (creaQry->len > 0)
@@ -3114,6 +3119,7 @@ dumpDatabase(Archive *fout)
 						  atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
 						  atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
 						  LargeObjectRelationId);
+		appendPQExpBufferChar(loOutQry, '\x00');
 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
 					 ARCHIVE_OPTS(.tag = "pg_largeobject",
 								  .description = "pg_largeobject",
@@ -3221,6 +3227,7 @@ dumpEncoding(Archive *AH)
 	appendPQExpBufferStr(qry, "SET client_encoding = ");
 	appendStringLiteralAH(qry, encname, AH);
 	appendPQExpBufferStr(qry, ";\n");
+	appendPQExpBufferChar(qry, '\x00');
 
 	ArchiveEntry(AH, nilCatalogId, createDumpId(),
 				 ARCHIVE_OPTS(.tag = "ENCODING",
@@ -3246,6 +3253,7 @@ dumpStdStrings(Archive *AH)
 
 	appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
 					  stdstrings);
+	appendPQExpBufferChar(qry, '\x00');
 
 	ArchiveEntry(AH, nilCatalogId, createDumpId(),
 				 ARCHIVE_OPTS(.tag = "STDSTRINGS",
@@ -3298,6 +3306,7 @@ dumpSearchPath(Archive *AH)
 	appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
 	appendStringLiteralAH(qry, path->data, AH);
 	appendPQExpBufferStr(qry, ", false);\n");
+	appendPQExpBufferChar(qry, '\x00');
 
 	pg_log_info("saving search_path = %s", path->data);
 
@@ -3468,6 +3477,7 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
 	appendPQExpBuffer(cquery,
 					  "SELECT pg_catalog.lo_create('%s');\n",
 					  binfo->dobj.name);
+	appendPQExpBufferChar(cquery, '\x00');
 
 	appendPQExpBuffer(dquery,
 					  "SELECT pg_catalog.lo_unlink('%s');\n",
@@ -3769,6 +3779,7 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 
 		appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
 						  fmtQualifiedDumpable(tbinfo));
+		appendPQExpBufferChar(query, '\x00');
 
 		/*
 		 * We must emit the ROW SECURITY object's dependency on its table
@@ -3828,6 +3839,7 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 		appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
 
 	appendPQExpBufferStr(query, ";\n");
+	appendPQExpBufferChar(query, '\x00');
 
 	appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
 	appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
@@ -4033,6 +4045,7 @@ dumpPublication(Archive *fout, PublicationInfo *pubinfo)
 		appendPQExpBufferStr(query, ", publish_via_partition_root = true");
 
 	appendPQExpBufferStr(query, ");\n");
+	appendPQExpBufferChar(query, '\x00');
 
 	ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
 				 ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
@@ -4172,6 +4185,7 @@ dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
 					  fmtId(pubrinfo->pubname));
 	appendPQExpBuffer(query, " %s;\n",
 					  fmtQualifiedDumpable(tbinfo));
+	appendPQExpBufferChar(query, '\x00');
 
 	/*
 	 * There is no point in creating drop query as the drop is done by table
@@ -4384,6 +4398,7 @@ dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
 		appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
 
 	appendPQExpBufferStr(query, ");\n");
+	appendPQExpBufferChar(query, '\x00');
 
 	ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
 				 ARCHIVE_OPTS(.tag = subinfo->dobj.name,
@@ -9801,6 +9816,7 @@ dumpComment(Archive *fout, const char *type, const char *name,
 		appendPQExpBuffer(query, "%s IS ", name);
 		appendStringLiteralAH(query, comments->descr, fout);
 		appendPQExpBufferStr(query, ";\n");
+		appendPQExpBufferChar(query, '\x00');
 
 		appendPQExpBuffer(tag, "%s %s", type, name);
 
@@ -9877,6 +9893,7 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo,
 							  fmtQualifiedDumpable(tbinfo));
 			appendStringLiteralAH(query, descr, fout);
 			appendPQExpBufferStr(query, ";\n");
+			appendPQExpBufferChar(query, '\x00');
 
 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
 						 ARCHIVE_OPTS(.tag = tag->data,
@@ -9902,6 +9919,7 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo,
 							  fmtId(tbinfo->attnames[objsubid - 1]));
 			appendStringLiteralAH(query, descr, fout);
 			appendPQExpBufferStr(query, ";\n");
+			appendPQExpBufferChar(query, '\x00');
 
 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
 						 ARCHIVE_OPTS(.tag = tag->data,
@@ -10252,6 +10270,7 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
 	appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
 
 	appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
+	appendPQExpBufferChar(q, '\x00');
 
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &nspinfo->dobj,
@@ -10392,6 +10411,7 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
 		appendPQExpBufferStr(q, ");\n");
 	}
 
+	appendPQExpBufferChar(q, '\x00');
 	if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = extinfo->dobj.name,
@@ -10540,6 +10560,7 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
 										"TYPE", qtypname,
 										tyinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
@@ -10666,6 +10687,7 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
 										"TYPE", qtypname,
 										tyinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
@@ -10738,6 +10760,7 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
 										"TYPE", qtypname,
 										tyinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
@@ -11019,6 +11042,7 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
 										"TYPE", qtypname,
 										tyinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
@@ -11175,6 +11199,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 										"DOMAIN", qtypname,
 										tyinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
@@ -11396,6 +11421,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 										"TYPE", qtypname,
 										tyinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
@@ -11531,6 +11557,7 @@ dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
 			appendPQExpBuffer(query, "%s IS ", fmtId(attname));
 			appendStringLiteralAH(query, descr, fout);
 			appendPQExpBufferStr(query, ";\n");
+			appendPQExpBufferChar(query, '\x00');
 
 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
 						 ARCHIVE_OPTS(.tag = target->data,
@@ -11587,6 +11614,7 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
 	appendPQExpBuffer(q, "CREATE TYPE %s;\n",
 					  fmtQualifiedDumpable(stinfo));
 
+	appendPQExpBufferChar(q, '\x00');
 	if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = stinfo->dobj.name,
@@ -11697,6 +11725,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
 		binary_upgrade_extension_member(defqry, &plang->dobj,
 										"LANGUAGE", qlanname, NULL);
 
+	appendPQExpBufferChar(defqry, '\x00');
 	if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = plang->dobj.name,
@@ -12318,6 +12347,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 										keyword, funcsig,
 										finfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = funcsig_tag,
@@ -12452,6 +12482,7 @@ dumpCast(Archive *fout, CastInfo *cast)
 		binary_upgrade_extension_member(defqry, &cast->dobj,
 										"CAST", castargs->data, NULL);
 
+	appendPQExpBufferChar(defqry, '\x00');
 	if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = labelq->data,
@@ -12579,6 +12610,7 @@ dumpTransform(Archive *fout, TransformInfo *transform)
 		binary_upgrade_extension_member(defqry, &transform->dobj,
 										"TRANSFORM", transformargs->data, NULL);
 
+	appendPQExpBufferChar(defqry, '\x00');
 	if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = labelq->data,
@@ -12799,6 +12831,7 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
 										"OPERATOR", oprid->data,
 										oprinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
@@ -12971,6 +13004,7 @@ dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
 		binary_upgrade_extension_member(q, &aminfo->dobj,
 										"ACCESS METHOD", qamname, NULL);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = aminfo->dobj.name,
@@ -13334,6 +13368,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 										"OPERATOR CLASS", nameusing->data,
 										opcinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
@@ -13600,6 +13635,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
 										"OPERATOR FAMILY", nameusing->data,
 										opfinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
@@ -13732,6 +13768,7 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
 										"COLLATION", qcollname,
 										collinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = collinfo->dobj.name,
@@ -13826,6 +13863,7 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
 										"CONVERSION", qconvname,
 										convinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = convinfo->dobj.name,
@@ -14200,6 +14238,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 										"AGGREGATE", aggsig,
 										agginfo->aggfn.dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
 					 agginfo->aggfn.dobj.dumpId,
@@ -14298,6 +14337,7 @@ dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
 										"TEXT SEARCH PARSER", qprsname,
 										prsinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
@@ -14376,6 +14416,7 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
 										"TEXT SEARCH DICTIONARY", qdictname,
 										dictinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
@@ -14436,6 +14477,7 @@ dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
 										"TEXT SEARCH TEMPLATE", qtmplname,
 										tmplinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
@@ -14554,6 +14596,7 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
 										"TEXT SEARCH CONFIGURATION", qcfgname,
 										cfginfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
@@ -14619,6 +14662,7 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 										"FOREIGN DATA WRAPPER", qfdwname,
 										NULL);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
@@ -14708,6 +14752,7 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
 		binary_upgrade_extension_member(q, &srvinfo->dobj,
 										"SERVER", qsrvname, NULL);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
@@ -14825,6 +14870,7 @@ dumpUserMappings(Archive *fout,
 		appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
 						  usename, servername);
 
+		appendPQExpBufferChar(q, '\x00');
 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
 					 ARCHIVE_OPTS(.tag = tag->data,
 								  .namespace = namespace,
@@ -14901,6 +14947,7 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
 		fatal("could not parse default ACL list (%s)",
 			  daclinfo->defaclacl);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
 		ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tag->data,
@@ -15011,6 +15058,7 @@ dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
 
 		aclDumpId = createDumpId();
 
+		appendPQExpBufferChar(sql, '\x00');
 		ArchiveEntry(fout, nilCatalogId, aclDumpId,
 					 ARCHIVE_OPTS(.tag = tag->data,
 								  .namespace = nspname,
@@ -15103,6 +15151,7 @@ dumpSecLabel(Archive *fout, const char *type, const char *name,
 		PQExpBuffer tag = createPQExpBuffer();
 
 		appendPQExpBuffer(tag, "%s %s", type, name);
+		appendPQExpBufferChar(query, '\x00');
 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
 					 ARCHIVE_OPTS(.tag = tag->data,
 								  .namespace = namespace,
@@ -15186,6 +15235,7 @@ dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
 		resetPQExpBuffer(target);
 		appendPQExpBuffer(target, "%s %s", reltypename,
 						  fmtId(tbinfo->dobj.name));
+		appendPQExpBufferChar(query, '\x00');
 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
 					 ARCHIVE_OPTS(.tag = target->data,
 								  .namespace = tbinfo->dobj.namespace->dobj.name,
@@ -15917,12 +15967,12 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 			PQExpBuffer result;
 
 			result = createViewAsClause(fout, tbinfo);
-			appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
-							  result->data);
+			appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;%c\n",
+							  result->data, '\x00');
 			destroyPQExpBuffer(result);
 		}
 		else
-			appendPQExpBufferStr(q, ";\n");
+			appendPQExpBuffer(q, ";%c\n", '\x00');
 
 		/* Materialized views can depend on extensions */
 		if (tbinfo->relkind == RELKIND_MATVIEW)
@@ -16279,6 +16329,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 			tbinfo->relkind == RELKIND_MATVIEW)
 			tableam = tbinfo->amname;
 
+		appendPQExpBufferChar(q, '\x00');
 		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
 								  .namespace = tbinfo->dobj.namespace->dobj.name,
@@ -16360,6 +16411,7 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
 
 	tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
 
+	appendPQExpBufferChar(q, '\x00');
 	if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tag,
@@ -16523,6 +16575,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
 
 		appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
 
+		appendPQExpBufferChar(q, '\x00');
 		if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 			ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
 						 ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
@@ -16544,6 +16597,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
 		appendIndexCollationVersion(q, indxinfo, fout->encoding,
 									dopt->coll_unknown, fout);
 
+		appendPQExpBufferChar(q, '\x00');
 		if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 			ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
 						 ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
@@ -16589,6 +16643,7 @@ dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
 		appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
 						  fmtQualifiedDumpable(attachinfo->partitionIdx));
 
+		appendPQExpBufferChar(q, '\x00');
 		ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
 								  .namespace = attachinfo->dobj.namespace->dobj.name,
@@ -16652,6 +16707,7 @@ dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
 	appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
 					  fmtQualifiedDumpable(statsextinfo));
 
+	appendPQExpBufferChar(q, '\x00');
 	if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, statsextinfo->dobj.catId,
 					 statsextinfo->dobj.dumpId,
@@ -16822,6 +16878,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 
 		tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
 
+		appendPQExpBufferChar(q, '\x00');
 		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
 						 ARCHIVE_OPTS(.tag = tag,
@@ -16862,6 +16919,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 
 		tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
 
+		appendPQExpBufferChar(q, '\x00');
 		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
 						 ARCHIVE_OPTS(.tag = tag,
@@ -16893,6 +16951,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 
 			tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
 
+			appendPQExpBufferChar(q, '\x00');
 			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
 							 ARCHIVE_OPTS(.tag = tag,
@@ -16925,6 +16984,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 
 			tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
 
+			appendPQExpBufferChar(q, '\x00');
 			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
 							 ARCHIVE_OPTS(.tag = tag,
@@ -17201,6 +17261,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 										"SEQUENCE", qseqname,
 										tbinfo->dobj.namespace->dobj.name);
 
+	appendPQExpBufferChar(query, '\x00');
 	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
@@ -17241,6 +17302,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 			appendPQExpBuffer(query, ".%s;\n",
 							  fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
 
+			appendPQExpBufferChar(query, '\x00');
 			if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 				ArchiveEntry(fout, nilCatalogId, createDumpId(),
 							 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
@@ -17309,6 +17371,7 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 	appendPQExpBuffer(query, ", %s, %s);\n",
 					  last, (called ? "true" : "false"));
 
+	appendPQExpBufferChar(query, '\x00');
 	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
 					 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
@@ -17516,6 +17579,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 
 	tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
 
+	appendPQExpBufferChar(query, '\x00');
 	if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tag,
@@ -17605,6 +17669,7 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
 		binary_upgrade_extension_member(query, &evtinfo->dobj,
 										"EVENT TRIGGER", qevtname, NULL);
 
+	appendPQExpBufferChar(query, '\x00');
 	if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
@@ -17763,6 +17828,7 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
 
 	tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
 
+	appendPQExpBufferChar(cmd, '\x00');
 	if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 		ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
 					 ARCHIVE_OPTS(.tag = tag,
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index ec63662060..9eab65e4f3 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -2351,7 +2351,7 @@ my %tests = (
 			\s+\QCONSTRAINT measurement_peaktemp_check CHECK ((peaktemp >= '-460'::integer))\E\n
 			\)\n
 			\QPARTITION BY RANGE (logdate);\E\n
-			/xm,
+			/xm, # XXX: how to test that it's in a separate txn ?
 		like =>
 		  { %full_runs, %dump_test_schema_runs, section_pre_data => 1, },
 		unlike => {
-- 
2.17.0

Reply via email to