v15-0006-logical-replication-allow-combined-conflict_log_.patch

application/octet-stream

Filename: v15-0006-logical-replication-allow-combined-conflict_log_.patch
Type: application/octet-stream
Part: 5
Message: Re: Proposal: Conflict log history table for Logical Replication
From e6a1c0a6f88f421f66a93a2483ca585f2a298c46 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 24 Dec 2025 15:47:01 +0530
Subject: [PATCH v15 6/6] logical replication: allow combined
 conflict_log_destination settings

Extend conflict_log_destination handling to support combined destination
specifications. Previously, only log, table, or all were accepted. This change
allows combinations of them like log, table and all, log, table etc
---
 src/backend/catalog/pg_subscription.c      |  2 +-
 src/backend/commands/subscriptioncmds.c    | 95 +++++++++++++++-------
 src/backend/replication/logical/conflict.c |  9 +-
 src/bin/pg_dump/pg_dump.c                  | 42 ++++++----
 src/bin/pg_dump/t/002_pg_dump.pl           |  4 +-
 src/include/catalog/pg_subscription.h      |  4 +-
 src/include/commands/subscriptioncmds.h    |  2 +-
 src/include/replication/conflict.h         | 23 +++---
 src/test/regress/expected/subscription.out | 72 +++++++++-------
 src/test/regress/sql/subscription.sql      | 11 ++-
 src/tools/pgindent/typedefs.list           |  3 +-
 11 files changed, 170 insertions(+), 97 deletions(-)

diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c
index dae44c659f8..c1b8c2870c5 100644
--- a/src/backend/catalog/pg_subscription.c
+++ b/src/backend/catalog/pg_subscription.c
@@ -147,7 +147,7 @@ GetSubscription(Oid subid, bool missing_ok)
 	datum = SysCacheGetAttrNotNull(SUBSCRIPTIONOID,
 								   tup,
 								   Anum_pg_subscription_sublogdestination);
-	sub->logdestination = TextDatumGetCString(datum);
+	sub->logdestination = textarray_to_stringlist(DatumGetArrayTypeP(datum));
 
 	/* Is the subscription owner a superuser? */
 	sub->ownersuperuser = superuser_arg(sub->owner);
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 1fbe0d474cf..9809b8b56f4 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -59,6 +59,7 @@
 #include "utils/pg_lsn.h"
 #include "utils/regproc.h"
 #include "utils/syscache.h"
+#include "utils/varlena.h"
 
 /*
  * Options that can be specified by the user in CREATE/ALTER SUBSCRIPTION
@@ -417,23 +418,22 @@ parse_subscription_options(ParseState *pstate, List *stmt_options,
 		else if (IsSet(supported_opts, SUBOPT_CONFLICT_LOG_DESTINATION) &&
 				 strcmp(defel->defname, "conflict_log_destination") == 0)
 		{
-			char *val;
-			ConflictLogDest dest;
+			char	   *val;
+			List	   *dest;
 
 			if (IsSet(opts->specified_opts, SUBOPT_CONFLICT_LOG_DESTINATION))
 				errorConflictingDefElem(defel, pstate);
 
 			val = defGetString(defel);
 
-			dest = GetLogDestination(val);
-
-			if (dest == CONFLICT_LOG_DEST_INVALID)
+			if (!SplitIdentifierString(val, ',', &dest))
 				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("unrecognized conflict_log_destination value: \"%s\"", val),
-						 errhint("Valid values are \"log\", \"table\", and \"all\".")));
+						errcode(ERRCODE_SYNTAX_ERROR),
+						errmsg("invalid list syntax in parameter \"%s\"",
+							   "conflict_log_destination"));
+
+			opts->logdest = GetLogDestination(dest, false);
 
-			opts->logdest = dest;
 			opts->specified_opts |= SUBOPT_CONFLICT_LOG_DESTINATION;
 		}
 		else
@@ -613,6 +613,30 @@ publicationListToArray(List *publist)
 	return PointerGetDatum(arr);
 }
 
+/*
+ * Build a text[] array representing the conflict_log_destination flags.
+ */
+static Datum
+ConflictLogDestFlagsToArray(ConflictLogDest logdest)
+{
+	Datum		datums[3];
+	int			ndatums = 0;
+
+	if (CONFLICT_LOG_DEST_ALL_ENABLED(logdest))
+		datums[ndatums++] = CStringGetTextDatum("all");
+	else
+	{
+		if (CONFLICT_LOG_DEST_LOG_ENABLED(logdest))
+			datums[ndatums++] = CStringGetTextDatum("log");
+
+		if (CONFLICT_LOG_DEST_TABLE_ENABLED(logdest))
+			datums[ndatums++] = CStringGetTextDatum("table");
+	}
+
+	return PointerGetDatum(
+						   construct_array_builtin(datums, ndatums, TEXTOID));
+}
+
 /*
  * Create new subscription.
  */
@@ -784,7 +808,7 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
 
 	/* Always set the destination, default will be log. */
 	values[Anum_pg_subscription_sublogdestination - 1] =
-		CStringGetTextDatum(ConflictLogDestLabels[opts.logdest]);
+		ConflictLogDestFlagsToArray(opts.logdest);
 
 	/*
 	 * If the conflict log destination includes 'table', generate an internal
@@ -793,8 +817,8 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
 	 * format in the pg_subscription catalog tuple., then  physically create
 	 * the table.
 	 */
-	if (opts.logdest == CONFLICT_LOG_DEST_TABLE ||
-		opts.logdest == CONFLICT_LOG_DEST_ALL)
+	if (CONFLICT_LOG_DEST_TABLE_ENABLED(opts.logdest) ||
+		CONFLICT_LOG_DEST_ALL_ENABLED(opts.logdest))
 	{
 		char    conflict_table_name[NAMEDATALEN];
 		Oid     namespaceId, logrelid;
@@ -1424,16 +1448,16 @@ AlterSubscriptionConflictLogDestination(Subscription *sub,
 										ConflictLogDest logdest,
 										Oid *conflicttablerelid)
 {
-	ConflictLogDest old_dest = GetLogDestination(sub->logdestination);
+	ConflictLogDest old_dest = GetLogDestination(sub->logdestination, true);
 	bool		want_table;
 	bool		has_oldtable;
 	bool		update_relid = false;
 	Oid			relid = InvalidOid;
 
-	want_table = (logdest == CONFLICT_LOG_DEST_TABLE ||
-				  logdest == CONFLICT_LOG_DEST_ALL);
-	has_oldtable = (old_dest == CONFLICT_LOG_DEST_TABLE ||
-					old_dest == CONFLICT_LOG_DEST_ALL);
+	want_table = (CONFLICT_LOG_DEST_TABLE_ENABLED(logdest) ||
+				  CONFLICT_LOG_DEST_ALL_ENABLED(logdest));
+	has_oldtable = (CONFLICT_LOG_DEST_TABLE_ENABLED(old_dest) ||
+					CONFLICT_LOG_DEST_ALL_ENABLED(old_dest));
 
 	if (want_table && !has_oldtable)
 	{
@@ -1856,7 +1880,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 				if (IsSet(opts.specified_opts, SUBOPT_CONFLICT_LOG_DESTINATION))
 				{
 					ConflictLogDest old_dest =
-						GetLogDestination(sub->logdestination);
+						GetLogDestination(sub->logdestination, true);
 
 					if (opts.logdest != old_dest)
 					{
@@ -1864,7 +1888,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 						Oid			relid = InvalidOid;
 
 						values[Anum_pg_subscription_sublogdestination - 1] =
-							CStringGetTextDatum(ConflictLogDestLabels[opts.logdest]);
+							ConflictLogDestFlagsToArray(opts.logdest);
 						replaces[Anum_pg_subscription_sublogdestination - 1] = true;
 						update_relid = AlterSubscriptionConflictLogDestination(sub, opts.logdest, &relid);
 						if (update_relid)
@@ -3544,23 +3568,38 @@ GetConflictLogTableName(char *dest, Oid subid)
 /*
  * GetLogDestination
  *
- * Convert string to enum by comparing against standardized labels.
+ * Convert log destination List of strings to enums.
  */
 ConflictLogDest
-GetLogDestination(const char *dest)
+GetLogDestination(List *destlist, bool strnodelist)
 {
-	/* Empty string or NULL defaults to LOG. */
-	if (dest == NULL || dest[0] == '\0')
+	ConflictLogDest logdest = CONFLICT_LOG_DEST_INVALID;
+	ListCell   *cell;
+
+	if (destlist == NIL)
 		return CONFLICT_LOG_DEST_LOG;
 
-	for (int i = CONFLICT_LOG_DEST_LOG; i <= CONFLICT_LOG_DEST_ALL; i++)
+	foreach(cell, destlist)
 	{
-		if (pg_strcasecmp(dest, ConflictLogDestLabels[i]) == 0)
-			return (ConflictLogDest) i;
+		char	   *name;
+
+		name = (strnodelist) ? strVal(lfirst(cell)) : (char *) lfirst(cell);
+
+		if (pg_strcasecmp(name, "log") == 0)
+			logdest |= CONFLICT_LOG_DEST_LOG;
+		else if (pg_strcasecmp(name, "table") == 0)
+			logdest |= CONFLICT_LOG_DEST_TABLE;
+		else if (pg_strcasecmp(name, "all") == 0)
+			logdest |= CONFLICT_LOG_DEST_ALL;
+		else
+			ereport(ERROR,
+					errcode(ERRCODE_SYNTAX_ERROR),
+					errmsg("unrecognized value for subscription parameter \"%s\": \"%s\"",
+						   "conflict_log_destination", name),
+					errhint("Valid values are \"log\", \"table\", and \"all\"."));
 	}
 
-	/* Unrecognized string. */
-	return CONFLICT_LOG_DEST_INVALID;
+	return logdest;
 }
 
 /*
diff --git a/src/backend/replication/logical/conflict.c b/src/backend/replication/logical/conflict.c
index 0b6e3f4a2c8..1c7ac2da6f5 100644
--- a/src/backend/replication/logical/conflict.c
+++ b/src/backend/replication/logical/conflict.c
@@ -159,8 +159,8 @@ ReportApplyConflict(EState *estate, ResultRelInfo *relinfo, int elevel,
 	/* Insert to table if destination is 'table' or 'all' */
 	if (conflictlogrel)
 	{
-		Assert(dest == CONFLICT_LOG_DEST_TABLE ||
-			   dest == CONFLICT_LOG_DEST_ALL);
+		Assert(CONFLICT_LOG_DEST_TABLE_ENABLED(dest) ||
+			   CONFLICT_LOG_DEST_ALL_ENABLED(dest));
 
 		if (ValidateConflictLogTable(conflictlogrel))
 		{
@@ -187,7 +187,8 @@ ReportApplyConflict(EState *estate, ResultRelInfo *relinfo, int elevel,
 	pgstat_report_subscription_conflict(MySubscription->oid, type);
 
 	/* Decide what detail to show in server logs. */
-	if (dest == CONFLICT_LOG_DEST_LOG || dest == CONFLICT_LOG_DEST_ALL)
+	if (CONFLICT_LOG_DEST_LOG_ENABLED(dest) ||
+		CONFLICT_LOG_DEST_ALL_ENABLED(dest))
 	{
 		/* Standard reporting with full internal details. */
 		ereport(elevel,
@@ -263,7 +264,7 @@ GetConflictLogTableInfo(ConflictLogDest *log_dest)
 	 * Convert the text log destination to the internal enum.  MySubscription
 	 * already contains the data from pg_subscription.
 	 */
-	*log_dest = GetLogDestination(MySubscription->logdestination);
+	*log_dest = GetLogDestination(MySubscription->logdestination, true);
 	conflictlogrelid = MySubscription->conflictrelid;
 
 	/* If destination is 'log' only, no table to open. */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d2477cfb5a1..85b2f3a9a47 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -5522,10 +5522,10 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
 	DumpOptions *dopt = fout->dopt;
 	PQExpBuffer delq;
 	PQExpBuffer query;
-	PQExpBuffer publications;
+	PQExpBuffer namebuf;
 	char	   *qsubname;
-	char	  **pubnames = NULL;
-	int			npubnames = 0;
+	char	  **names = NULL;
+	int			nnames = 0;
 	int			i;
 
 	/* Do nothing if not dumping schema */
@@ -5545,19 +5545,22 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
 	appendStringLiteralAH(query, subinfo->subconninfo, fout);
 
 	/* Build list of quoted publications and append them to query. */
-	if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
+	if (!parsePGArray(subinfo->subpublications, &names, &nnames))
 		pg_fatal("could not parse %s array", "subpublications");
 
-	publications = createPQExpBuffer();
-	for (i = 0; i < npubnames; i++)
+	namebuf = createPQExpBuffer();
+	for (i = 0; i < nnames; i++)
 	{
 		if (i > 0)
-			appendPQExpBufferStr(publications, ", ");
+			appendPQExpBufferStr(namebuf, ", ");
 
-		appendPQExpBufferStr(publications, fmtId(pubnames[i]));
+		appendPQExpBufferStr(namebuf, fmtId(names[i]));
 	}
 
-	appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
+	appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", namebuf->data);
+	resetPQExpBuffer(namebuf);
+	free(names);
+
 	if (subinfo->subslotname)
 		appendStringLiteralAH(query, subinfo->subslotname, fout);
 	else
@@ -5610,11 +5613,22 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
 						  tableInfo->dobj.namespace->dobj.name);
 	}
 
+	/* Build list of quoted conflict log destinations and append them to query. */
+	if (!parsePGArray(subinfo->sublogdestination, &names, &nnames))
+		pg_fatal("could not parse %s array", "conflict_log_destination");
+
+	for (i = 0; i < nnames; i++)
+	{
+		if (i > 0)
+			appendPQExpBufferStr(namebuf, ", ");
+
+		appendPQExpBuffer(namebuf, "%s", names[i]);
+	}
+
 	appendPQExpBuffer(query,
-					  "\n\nALTER SUBSCRIPTION %s SET (conflict_log_destination = %s);\n",
+					  "\n\nALTER SUBSCRIPTION %s SET (conflict_log_destination = '%s');\n",
 					  qsubname,
-					  subinfo->sublogdestination);
-
+					  namebuf->data);
 
 	if (subinfo->subconflictlogrelid)
 		appendPQExpBufferStr(query, "\n\nSELECT pg_catalog.set_config('search_path', '', false);\n");
@@ -5675,8 +5689,8 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
 					 NULL, subinfo->rolname,
 					 subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
 
-	destroyPQExpBuffer(publications);
-	free(pubnames);
+	destroyPQExpBuffer(namebuf);
+	free(names);
 
 	destroyPQExpBuffer(delq);
 	destroyPQExpBuffer(query);
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 8ec7b0069dd..e0859dddf4f 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -3204,11 +3204,11 @@ my %tests = (
 		create_order => 50,
 		create_sql => 'CREATE SUBSCRIPTION sub3
 						 CONNECTION \'dbname=doesnotexist\' PUBLICATION pub1
-						 WITH (connect = false, origin = any, streaming = on, conflict_log_destination= table);',
+						 WITH (connect = false, origin = any, streaming = on, conflict_log_destination= \'log,table\');',
 		regexp => qr/^
 			\QCREATE SUBSCRIPTION sub3 CONNECTION 'dbname=doesnotexist' PUBLICATION pub1 WITH (connect = false, slot_name = 'sub3', streaming = on);\E\n\n\n
 			\QSELECT pg_catalog.set_config('search_path', 'public', false);\E\n\n\n
-			\QALTER SUBSCRIPTION sub3 SET (conflict_log_destination = table);\E\n\n\n
+			\QALTER SUBSCRIPTION sub3 SET (conflict_log_destination = 'log, table');\E\n\n\n
 			\QSELECT pg_catalog.set_config('search_path', '', false);\E
 			/xm,
 		like => { %full_runs, section_post_data => 1, },
diff --git a/src/include/catalog/pg_subscription.h b/src/include/catalog/pg_subscription.h
index 46c446eaf8b..b3b2c29b96d 100644
--- a/src/include/catalog/pg_subscription.h
+++ b/src/include/catalog/pg_subscription.h
@@ -110,7 +110,7 @@ CATALOG(pg_subscription,6100,SubscriptionRelationId) BKI_SHARED_RELATION BKI_ROW
 	 * table - internal table only,
 	 * all - both log and table.
 	 */
-	text		sublogdestination;
+	text		sublogdestination[1] BKI_FORCE_NULL;
 
 	/* Only publish data originating from the specified origin */
 	text		suborigin BKI_DEFAULT(LOGICALREP_ORIGIN_ANY);
@@ -169,7 +169,7 @@ typedef struct Subscription
 	List	   *publications;	/* List of publication names to subscribe to */
 	char	   *origin;			/* Only publish data originating from the
 								 * specified origin */
-	char	   *logdestination;	/* Conflict log destination */
+	List	   *logdestination;	/* Conflict log destination */
 } Subscription;
 
 #ifdef EXPOSE_TO_CLIENT_CODE
diff --git a/src/include/commands/subscriptioncmds.h b/src/include/commands/subscriptioncmds.h
index 255e1e241b8..aa0bc503847 100644
--- a/src/include/commands/subscriptioncmds.h
+++ b/src/include/commands/subscriptioncmds.h
@@ -38,7 +38,7 @@ extern void CheckSubDeadTupleRetention(bool check_guc, bool sub_disabled,
 									   bool max_retention_set);
 
 extern void GetConflictLogTableName(char *dest, Oid subid);
-extern ConflictLogDest GetLogDestination(const char *dest);
+extern ConflictLogDest GetLogDestination(List *destlist, bool strnodelist);
 extern bool IsConflictLogTable(Oid relid);
 
 #endif							/* SUBSCRIPTIONCMDS_H */
diff --git a/src/include/replication/conflict.h b/src/include/replication/conflict.h
index 5f313b7a976..92b7e619eb8 100644
--- a/src/include/replication/conflict.h
+++ b/src/include/replication/conflict.h
@@ -89,19 +89,20 @@ typedef struct ConflictTupleInfo
 typedef enum ConflictLogDest
 {
 	CONFLICT_LOG_DEST_INVALID = 0,
-	CONFLICT_LOG_DEST_LOG,		/* "log" (default) */
-	CONFLICT_LOG_DEST_TABLE,	/* "table" */
-	CONFLICT_LOG_DEST_ALL		/* "all" */
+	CONFLICT_LOG_DEST_LOG = 1 << 0, /* 0x00000001 */
+	CONFLICT_LOG_DEST_TABLE = 1 << 1,	/* 0x00000002 */
+	CONFLICT_LOG_DEST_ALL = 1 << 2	/* 0x00000004 */
 } ConflictLogDest;
 
-/*
- * Array mapping for converting internal enum to string.
- */
-static const char *const ConflictLogDestLabels[] = {
-	[CONFLICT_LOG_DEST_LOG] = "log",
-	[CONFLICT_LOG_DEST_TABLE] = "table",
-	[CONFLICT_LOG_DEST_ALL] = "all"
-};
+/* Conflict log destination flags */
+#define CONFLICT_LOG_DEST_LOG_ENABLED(dest) \
+	((dest) & CONFLICT_LOG_DEST_LOG)
+
+#define CONFLICT_LOG_DEST_TABLE_ENABLED(dest) \
+	((dest) & CONFLICT_LOG_DEST_TABLE)
+
+#define CONFLICT_LOG_DEST_ALL_ENABLED(dest) \
+	((dest) & CONFLICT_LOG_DEST_ALL)
 
 /* Structure to hold metadata for one column of the conflict log table */
 typedef struct ConflictLogColumnDef
diff --git a/src/test/regress/expected/subscription.out b/src/test/regress/expected/subscription.out
index 92423c83197..471821167a0 100644
--- a/src/test/regress/expected/subscription.out
+++ b/src/test/regress/expected/subscription.out
@@ -119,7 +119,7 @@ HINT:  To initiate replication, you must manually create the replication slot, e
                                                                                                                                                                 List of subscriptions
        Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 ------------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub4 | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | none   | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub4 | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | none   | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub4 SET (origin = any);
@@ -127,7 +127,7 @@ ALTER SUBSCRIPTION regress_testsub4 SET (origin = any);
                                                                                                                                                                 List of subscriptions
        Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 ------------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub4 | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub4 | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 DROP SUBSCRIPTION regress_testsub3;
@@ -148,7 +148,7 @@ ERROR:  invalid connection string syntax: missing "=" after "foobar" in connecti
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub SET PUBLICATION testpub2, testpub3 WITH (refresh = false);
@@ -160,7 +160,7 @@ ALTER SUBSCRIPTION regress_testsub SET (run_as_owner = true);
                                                                                                                                                                     List of subscriptions
       Name       |           Owner           | Enabled |     Publication     | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |           Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+---------------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+------------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub2,testpub3} | f      | parallel  | d                | f                | any    | f                 | t             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist2 | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub2,testpub3} | f      | parallel  | d                | f                | any    | f                 | t             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist2 | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub SET (password_required = true);
@@ -179,7 +179,7 @@ ALTER SUBSCRIPTION regress_testsub SKIP (lsn = '0/12345');
                                                                                                                                                                     List of subscriptions
       Name       |           Owner           | Enabled |     Publication     | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |           Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+---------------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+------------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub2,testpub3} | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist2 | 0/00012345 | log
+ regress_testsub | regress_subscription_user | f       | {testpub2,testpub3} | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist2 | 0/00012345 | {log}
 (1 row)
 
 -- ok - with lsn = NONE
@@ -191,7 +191,7 @@ ERROR:  invalid WAL location (LSN): 0/0
                                                                                                                                                                     List of subscriptions
       Name       |           Owner           | Enabled |     Publication     | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |           Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+---------------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+------------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub2,testpub3} | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist2 | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub2,testpub3} | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist2 | 0/00000000 | {log}
 (1 row)
 
 BEGIN;
@@ -226,7 +226,7 @@ HINT:  Available values: local, remote_write, remote_apply, on, off.
                                                                                                                                                                       List of subscriptions
         Name         |           Owner           | Enabled |     Publication     | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |           Conninfo           |  Skip LSN  | Conflict log destination 
 ---------------------+---------------------------+---------+---------------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+------------------------------+------------+--------------------------
- regress_testsub_foo | regress_subscription_user | f       | {testpub2,testpub3} | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | local              | dbname=regress_doesnotexist2 | 0/00000000 | log
+ regress_testsub_foo | regress_subscription_user | f       | {testpub2,testpub3} | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | local              | dbname=regress_doesnotexist2 | 0/00000000 | {log}
 (1 row)
 
 -- rename back to keep the rest simple
@@ -258,7 +258,7 @@ HINT:  To initiate replication, you must manually create the replication slot, e
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | t      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | t      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub SET (binary = false);
@@ -267,7 +267,7 @@ ALTER SUBSCRIPTION regress_testsub SET (slot_name = NONE);
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 DROP SUBSCRIPTION regress_testsub;
@@ -282,7 +282,7 @@ HINT:  To initiate replication, you must manually create the replication slot, e
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | on        | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | on        | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub SET (streaming = parallel);
@@ -290,7 +290,7 @@ ALTER SUBSCRIPTION regress_testsub SET (streaming = parallel);
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub SET (streaming = false);
@@ -299,7 +299,7 @@ ALTER SUBSCRIPTION regress_testsub SET (slot_name = NONE);
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | off       | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | off       | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 -- fail - publication already exists
@@ -317,7 +317,7 @@ ERROR:  publication "testpub1" is already in subscription "regress_testsub"
                                                                                                                                                                        List of subscriptions
       Name       |           Owner           | Enabled |         Publication         | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-----------------------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub,testpub1,testpub2} | f      | off       | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub,testpub1,testpub2} | f      | off       | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 -- fail - publication used more than once
@@ -335,7 +335,7 @@ ALTER SUBSCRIPTION regress_testsub DROP PUBLICATION testpub1, testpub2 WITH (ref
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | off       | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | off       | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 DROP SUBSCRIPTION regress_testsub;
@@ -374,7 +374,7 @@ HINT:  To initiate replication, you must manually create the replication slot, e
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | p                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | p                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 -- we can alter streaming when two_phase enabled
@@ -383,7 +383,7 @@ ALTER SUBSCRIPTION regress_testsub SET (streaming = true);
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | on        | p                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | on        | p                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub SET (slot_name = NONE);
@@ -396,7 +396,7 @@ HINT:  To initiate replication, you must manually create the replication slot, e
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | on        | p                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | on        | p                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub SET (slot_name = NONE);
@@ -412,7 +412,7 @@ HINT:  To initiate replication, you must manually create the replication slot, e
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub SET (disable_on_error = true);
@@ -420,7 +420,7 @@ ALTER SUBSCRIPTION regress_testsub SET (disable_on_error = true);
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | t                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | t                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub SET (slot_name = NONE);
@@ -436,7 +436,7 @@ HINT:  To initiate replication, you must manually create the replication slot, e
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub SET (slot_name = NONE);
@@ -453,7 +453,7 @@ HINT:  To initiate replication, you must manually create the replication slot, e
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                   1000 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                   1000 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 -- ok
@@ -462,7 +462,7 @@ ALTER SUBSCRIPTION regress_testsub SET (max_retention_duration = 0);
                                                                                                                                                                List of subscriptions
       Name       |           Owner           | Enabled | Publication | Binary | Streaming | Two-phase commit | Disable on error | Origin | Password required | Run as owner? | Failover | Retain dead tuples | Max retention duration | Retention active | Synchronous commit |          Conninfo           |  Skip LSN  | Conflict log destination 
 -----------------+---------------------------+---------+-------------+--------+-----------+------------------+------------------+--------+-------------------+---------------+----------+--------------------+------------------------+------------------+--------------------+-----------------------------+------------+--------------------------
- regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | log
+ regress_testsub | regress_subscription_user | f       | {testpub}   | f      | parallel  | d                | f                | any    | t                 | f             | f        | f                  |                      0 | f                | off                | dbname=regress_doesnotexist | 0/00000000 | {log}
 (1 row)
 
 ALTER SUBSCRIPTION regress_testsub SET (slot_name = NONE);
@@ -523,7 +523,7 @@ DROP SUBSCRIPTION regress_testsub;
 SET SESSION AUTHORIZATION 'regress_subscription_user';
 -- fail - unrecognized format value
 CREATE SUBSCRIPTION regress_conflict_fail CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false, conflict_log_destination = 'invalid');
-ERROR:  unrecognized conflict_log_destination value: "invalid"
+ERROR:  unrecognized value for subscription parameter "conflict_log_destination": "invalid"
 HINT:  Valid values are "log", "table", and "all".
 -- verify sublogdestination is 'log' and relid is 0 (InvalidOid) for default case
 CREATE SUBSCRIPTION regress_conflict_log_default CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false);
@@ -533,7 +533,7 @@ SELECT subname, sublogdestination, subconflictlogrelid
 FROM pg_subscription WHERE subname = 'regress_conflict_log_default';
            subname            | sublogdestination | subconflictlogrelid 
 ------------------------------+-------------------+---------------------
- regress_conflict_log_default | log               |                   0
+ regress_conflict_log_default | {log}             |                   0
 (1 row)
 
 -- verify empty string defaults to 'log'
@@ -544,11 +544,11 @@ SELECT subname, sublogdestination, subconflictlogrelid
 FROM pg_subscription WHERE subname = 'regress_conflict_empty_str';
           subname           | sublogdestination | subconflictlogrelid 
 ----------------------------+-------------------+---------------------
- regress_conflict_empty_str | log               |                   0
+ regress_conflict_empty_str | {log}             |                   0
 (1 row)
 
 -- this should generate an internal table named conflict_log_table_$subid$
-CREATE SUBSCRIPTION regress_conflict_test1 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false, conflict_log_destination = 'table');
+CREATE SUBSCRIPTION regress_conflict_test1 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false, conflict_log_destination = 'log, table');
 WARNING:  subscription was created, but is not connected
 HINT:  To initiate replication, you must manually create the replication slot, enable the subscription, and alter the subscription to refresh publications.
 -- check metadata in pg_subscription: destination should be 'table' and relid valid
@@ -556,7 +556,7 @@ SELECT subname, sublogdestination, subconflictlogrelid > 0 AS has_relid
 FROM pg_subscription WHERE subname = 'regress_conflict_test1';
         subname         | sublogdestination | has_relid 
 ------------------------+-------------------+-----------
- regress_conflict_test1 | table             | t
+ regress_conflict_test1 | {log,table}       | t
 (1 row)
 
 -- verify the physical table exists and its OID matches subconflictlogrelid
@@ -581,17 +581,27 @@ WHERE s.subname = 'regress_conflict_test1' AND a.attnum > 0;
 (1 row)
 
 -- ALTER: State transitions
--- transition from 'log' to 'all'
+-- transition from 'log' to 'log, table'
 CREATE SUBSCRIPTION regress_conflict_test2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false, conflict_log_destination = 'log');
 WARNING:  subscription was created, but is not connected
 HINT:  To initiate replication, you must manually create the replication slot, enable the subscription, and alter the subscription to refresh publications.
+ALTER SUBSCRIPTION regress_conflict_test2 SET (conflict_log_destination = 'log, table');
+-- verify metadata after ALTER (destination should be 'log, table')
+SELECT subname, sublogdestination, subconflictlogrelid > 0 AS has_relid
+FROM pg_subscription WHERE subname = 'regress_conflict_test2';
+        subname         | sublogdestination | has_relid 
+------------------------+-------------------+-----------
+ regress_conflict_test2 | {log,table}       | t
+(1 row)
+
+-- transition from 'log, table' to 'all'
 ALTER SUBSCRIPTION regress_conflict_test2 SET (conflict_log_destination = 'all');
 -- verify metadata after ALTER (destination should be 'all')
 SELECT subname, sublogdestination, subconflictlogrelid > 0 AS has_relid
 FROM pg_subscription WHERE subname = 'regress_conflict_test2';
         subname         | sublogdestination | has_relid 
 ------------------------+-------------------+-----------
- regress_conflict_test2 | all               | t
+ regress_conflict_test2 | {all}             | t
 (1 row)
 
 -- transition from 'all' to 'table' (should NOT drop the table, only change destination string)
@@ -601,7 +611,7 @@ SELECT sublogdestination, subconflictlogrelid = :old_relid AS relid_unchanged
 FROM pg_subscription WHERE subname = 'regress_conflict_test2';
  sublogdestination | relid_unchanged 
 -------------------+-----------------
- table             | t
+ {table}           | t
 (1 row)
 
 -- transition from 'table' to 'log' (should drop the table and clear relid)
@@ -610,7 +620,7 @@ SELECT sublogdestination, subconflictlogrelid
 FROM pg_subscription WHERE subname = 'regress_conflict_test2';
  sublogdestination | subconflictlogrelid 
 -------------------+---------------------
- log               |                   0
+ {log}             |                   0
 (1 row)
 
 -- verify the physical table is gone
diff --git a/src/test/regress/sql/subscription.sql b/src/test/regress/sql/subscription.sql
index b4b98c9a178..b437c383a4e 100644
--- a/src/test/regress/sql/subscription.sql
+++ b/src/test/regress/sql/subscription.sql
@@ -385,7 +385,7 @@ SELECT subname, sublogdestination, subconflictlogrelid
 FROM pg_subscription WHERE subname = 'regress_conflict_empty_str';
 
 -- this should generate an internal table named conflict_log_table_$subid$
-CREATE SUBSCRIPTION regress_conflict_test1 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false, conflict_log_destination = 'table');
+CREATE SUBSCRIPTION regress_conflict_test1 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false, conflict_log_destination = 'log, table');
 
 -- check metadata in pg_subscription: destination should be 'table' and relid valid
 SELECT subname, sublogdestination, subconflictlogrelid > 0 AS has_relid
@@ -405,8 +405,15 @@ JOIN pg_subscription s ON c.relname = 'conflict_log_table_' || s.oid
 WHERE s.subname = 'regress_conflict_test1' AND a.attnum > 0;
 
 -- ALTER: State transitions
--- transition from 'log' to 'all'
+-- transition from 'log' to 'log, table'
 CREATE SUBSCRIPTION regress_conflict_test2 CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false, conflict_log_destination = 'log');
+ALTER SUBSCRIPTION regress_conflict_test2 SET (conflict_log_destination = 'log, table');
+
+-- verify metadata after ALTER (destination should be 'log, table')
+SELECT subname, sublogdestination, subconflictlogrelid > 0 AS has_relid
+FROM pg_subscription WHERE subname = 'regress_conflict_test2';
+
+-- transition from 'log, table' to 'all'
 ALTER SUBSCRIPTION regress_conflict_test2 SET (conflict_log_destination = 'all');
 
 -- verify metadata after ALTER (destination should be 'all')
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 21826be5bd7..65ba5074331 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -501,8 +501,9 @@ ConditionalStack
 ConfigData
 ConfigVariable
 ConflictLogColumnDef
+ConflictLogDest
 ConflictTupleInfo
-ConflictType
+ConflictTyp
 ConnCacheEntry
 ConnCacheKey
 ConnParams
-- 
2.43.0