From 688833dc069a546e2acb37002571f0694ce2239c Mon Sep 17 00:00:00 2001 From: Vignesh C Date: Tue, 10 Nov 2026 09:32:03 +0530 Subject: [PATCH v93 2/3] Preserve conflict log destination and subscription OID across pg_upgrade. A subscription's conflict log table name is derived from its OID, and the table is linked through pg_subscription.subconflictlogrelid. Neither was preserved across pg_upgrade. In binary-upgrade mode, pg_dump now preserves subscription OIDs and dumps conflict log tables with their original OIDs. It also preserves conflict_log_destination, omitting the default value ('log'). During restore, CreateSubscription() uses the preserved subscription OID and links it to the already restored conflict log table, raising an error if the table is missing rather than creating a new one. Outside binary-upgrade mode, conflict log tables are recreated when the subscription is restored. --- doc/src/sgml/ref/pg_dump.sgml | 11 +++ src/backend/commands/subscriptioncmds.c | 49 +++++++++-- src/backend/replication/logical/conflict.c | 2 +- src/backend/utils/adt/pg_upgrade_support.c | 10 +++ src/bin/pg_dump/pg_dump.c | 87 +++++++++++++++++-- src/bin/pg_dump/pg_dump.h | 1 + src/bin/pg_dump/t/002_pg_dump.pl | 37 +++++++- src/bin/pg_upgrade/pg_upgrade.c | 4 + src/bin/pg_upgrade/t/004_subscription.pl | 29 ++++++- src/include/catalog/binary_upgrade.h | 1 + src/include/catalog/pg_proc.dat | 4 + src/include/catalog/pg_subscription.h | 3 + .../expected/spgist_name_ops.out | 6 +- 13 files changed, 225 insertions(+), 19 deletions(-) diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index 3c97facb657..83e48ef1cfb 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -1735,6 +1735,17 @@ CREATE DATABASE foo WITH TEMPLATE template0; had been originally created with two_phase = true option. + + If a subscription has been created with the + conflict_log_destination + option set to log conflicts to a table, pg_dump + does not dump that conflict log table or its contents. Restoring the + subscription creates a new, empty conflict log table, whose name is derived + from the OID of the new subscription. Privileges that had been granted on + the old conflict log table are not restored, and must be granted again on + the new table if needed. + + It is generally recommended to use the () option when restoring a database from a diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c index 62c4b13274b..0afb32b8bac 100644 --- a/src/backend/commands/subscriptioncmds.c +++ b/src/backend/commands/subscriptioncmds.c @@ -19,6 +19,7 @@ #include "access/table.h" #include "access/twophase.h" #include "access/xact.h" +#include "catalog/binary_upgrade.h" #include "catalog/catalog.h" #include "catalog/dependency.h" #include "catalog/indexing.h" @@ -88,6 +89,12 @@ /* check if the 'val' has 'bits' set */ #define IsSet(val, bits) (((val) & (bits)) == (bits)) +/* + * This will be set by the pg_upgrade_support function -- + * binary_upgrade_set_next_pg_subscription_oid(). + */ +Oid binary_upgrade_next_pg_subscription_oid = InvalidOid; + /* * Structure to hold a bitmap representing the user-provided CREATE/ALTER * SUBSCRIPTION command options and the parsed/default values of each of them. @@ -846,8 +853,21 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); - subid = GetNewOidWithIndex(rel, SubscriptionObjectIndexId, - Anum_pg_subscription_oid); + /* Use binary-upgrade override for pg_subscription.oid? */ + if (IsBinaryUpgrade) + { + if (!OidIsValid(binary_upgrade_next_pg_subscription_oid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_subscription OID value not set when in binary upgrade mode"))); + + subid = binary_upgrade_next_pg_subscription_oid; + binary_upgrade_next_pg_subscription_oid = InvalidOid; + } + else + subid = GetNewOidWithIndex(rel, SubscriptionObjectIndexId, + Anum_pg_subscription_oid); + values[Anum_pg_subscription_oid - 1] = ObjectIdGetDatum(subid); values[Anum_pg_subscription_subdbid - 1] = ObjectIdGetDatum(MyDatabaseId); values[Anum_pg_subscription_subskiplsn - 1] = LSNGetDatum(InvalidXLogRecPtr); @@ -901,12 +921,29 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, CStringGetTextDatum(ConflictLogDestNames[opts.conflictlogdest]); /* - * We create the conflict log table here, if required, so that its - * relation OID can be stored when inserting the pg_subscription tuple - * below. + * Create the conflict log table here, if required, so that its relation + * OID can be stored when inserting the pg_subscription tuple below. In + * binary-upgrade mode, the table was already restored earlier in the dump + * with its original OID and filenode, so look it up and reuse it. */ if (CONFLICTS_LOGGED_TO_TABLE(opts.conflictlogdest)) - logrelid = create_conflict_log_table(subid, stmt->subname, owner); + { + if (IsBinaryUpgrade) + { + char relname[NAMEDATALEN]; + + snprintf(relname, NAMEDATALEN, CONFLICT_LOG_RELATION_NAME_FMT, + subid); + logrelid = get_relname_relid(relname, PG_CONFLICT_NAMESPACE); + if (!OidIsValid(logrelid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("could not find conflict log table \"%s\" when in binary upgrade mode", + relname))); + } + else + logrelid = create_conflict_log_table(subid, stmt->subname, owner); + } /* Store table OID in the catalog. */ values[Anum_pg_subscription_subconflictlogrelid - 1] = diff --git a/src/backend/replication/logical/conflict.c b/src/backend/replication/logical/conflict.c index 9ba885da4a0..00cd575b9f2 100644 --- a/src/backend/replication/logical/conflict.c +++ b/src/backend/replication/logical/conflict.c @@ -211,7 +211,7 @@ create_conflict_log_table(Oid subid, char *subname, Oid subowner) Oid relid; char relname[NAMEDATALEN]; - snprintf(relname, NAMEDATALEN, "pg_conflict_log_%u", subid); + snprintf(relname, NAMEDATALEN, CONFLICT_LOG_RELATION_NAME_FMT, subid); /* Build the tuple descriptor for the new table. */ tupdesc = create_conflict_log_table_tupdesc(); diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c index d7b1c56b2ea..b66ba0c5212 100644 --- a/src/backend/utils/adt/pg_upgrade_support.c +++ b/src/backend/utils/adt/pg_upgrade_support.c @@ -238,6 +238,16 @@ binary_upgrade_set_next_pg_authid_oid(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } +Datum +binary_upgrade_set_next_pg_subscription_oid(PG_FUNCTION_ARGS) +{ + Oid subid = PG_GETARG_OID(0); + + CHECK_IS_BINARY_UPGRADE; + binary_upgrade_next_pg_subscription_oid = subid; + PG_RETURN_VOID(); +} + Datum binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS) { diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 4fc74e6e26e..740a02e9372 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -2049,6 +2049,17 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout) (void) checkExtensionMembership(&nsinfo->dobj, fout); } +/* + * is_conflict_log_table: is this a subscription's conflict log table? + * + * Conflict log tables are the tables of the pg_conflict schema. + */ +static bool +is_conflict_log_table(const TableInfo *tbinfo) +{ + return strcmp(tbinfo->dobj.namespace->dobj.name, "pg_conflict") == 0; +} + /* * selectDumpableTable: policy-setting subroutine * Mark a table as to be dumped or not @@ -2056,9 +2067,33 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout) static void selectDumpableTable(TableInfo *tbinfo, Archive *fout) { + DumpOptions *dopt = fout->dopt; + if (checkExtensionMembership(&tbinfo->dobj, fout)) return; /* extension membership overrides all else */ + if (is_conflict_log_table(tbinfo)) + { + /* + * Conflict log tables are dumped only during binary upgrade, where + * the table must be restored with the same OIDs and filenode so that + * CREATE SUBSCRIPTION can reuse it. Otherwise the table is created + * again when the subscription is restored. Also dump the privileges + * that were granted on the table, for example to let non-superusers + * delete conflicts. + * + * The pg_conflict schema itself is created by initdb and is not + * dumped, so the tables in it are selected here, regardless of the + * schema and table switches. + */ + if (dopt->binary_upgrade) + tbinfo->dobj.dump = DUMP_COMPONENT_DEFINITION | DUMP_COMPONENT_ACL; + else + tbinfo->dobj.dump = DUMP_COMPONENT_NONE; + + return; + } + /* * If specific tables are being dumped, dump just those tables; else, dump * according to the parent namespace's dump flag. @@ -5142,6 +5177,7 @@ getSubscriptions(Archive *fout) int i_subfailover; int i_subretaindeadtuples; int i_submaxretention; + int i_sublogdestination; int i, ntups; @@ -5240,9 +5276,16 @@ getSubscriptions(Archive *fout) " '-1' AS subwalrcvtimeout,\n"); if (fout->remoteVersion >= 190000) - appendPQExpBufferStr(query, " fs.srvname AS subservername\n"); + appendPQExpBufferStr(query, " fs.srvname AS subservername,\n"); else - appendPQExpBufferStr(query, " NULL AS subservername\n"); + appendPQExpBufferStr(query, " NULL AS subservername,\n"); + + if (fout->remoteVersion >= 200000) + appendPQExpBufferStr(query, + " s.subconflictlogdest\n"); + else + appendPQExpBufferStr(query, + " NULL AS subconflictlogdest\n"); appendPQExpBufferStr(query, "FROM pg_subscription s\n"); @@ -5291,6 +5334,7 @@ getSubscriptions(Archive *fout) i_subpublications = PQfnumber(res, "subpublications"); i_suborigin = PQfnumber(res, "suborigin"); i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn"); + i_sublogdestination = PQfnumber(res, "subconflictlogdest"); subinfo = pg_malloc_array(SubscriptionInfo, ntups); @@ -5349,6 +5393,12 @@ getSubscriptions(Archive *fout) subinfo[i].suboriginremotelsn = pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn)); + if (PQgetisnull(res, i, i_sublogdestination)) + subinfo[i].subconflictlogdest = NULL; + else + subinfo[i].subconflictlogdest = + pg_strdup(PQgetvalue(res, i, i_sublogdestination)); + /* Decide whether we want to dump it */ selectDumpableObject(&(subinfo[i].dobj), fout); } @@ -5541,6 +5591,14 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo) appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n", qsubname); + if (dopt->binary_upgrade) + { + appendPQExpBufferStr(query, "\n-- For binary upgrade, must preserve pg_subscription.oid\n"); + appendPQExpBuffer(query, + "SELECT pg_catalog.binary_upgrade_set_next_pg_subscription_oid('%u'::pg_catalog.oid);\n\n", + subinfo->dobj.catId.oid); + } + appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s ", qsubname); if (subinfo->subservername) @@ -5612,6 +5670,11 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo) if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0) appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin); + if (subinfo->subconflictlogdest && + pg_strcasecmp(subinfo->subconflictlogdest, "log") != 0) + appendPQExpBuffer(query, ", conflict_log_destination = %s", + subinfo->subconflictlogdest); + appendPQExpBufferStr(query, ");\n"); /* @@ -17147,6 +17210,14 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo) int j, k; + /* + * Do not emit "ALTER TABLE ... OWNER TO ..." for a conflict log table: + * changing its owner is not allowed. Its owner follows the owner of the + * subscription, and is set when the ALTER SUBSCRIPTION ... OWNER TO of + * the dump is restored. + */ + bool conflict_log_table = is_conflict_log_table(tbinfo); + /* We had better have loaded per-column details about this table */ Assert(tbinfo->interesting); @@ -18053,7 +18124,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo) .tablespace = tablespace, .tableam = tableam, .relkind = tbinfo->relkind, - .owner = tbinfo->rolname, + .owner = conflict_log_table ? NULL : tbinfo->rolname, .description = reltypename, .section = tbinfo->postponed_def ? SECTION_POST_DATA : SECTION_PRE_DATA, @@ -20390,12 +20461,16 @@ getDependencies(Archive *fout) * Ordinarily, table rowtypes have implicit dependencies on their * tables. However, for a composite type the implicit dependency goes * the other way in pg_depend; which is the right thing for DROP but - * it doesn't produce the dependency ordering we need. So in that one - * case, we reverse the direction of the dependency. + * it doesn't produce the dependency ordering we need. The same is + * true for a subscription's conflict log table, which has an internal + * dependency on its subscription for DROP, but must be dumped before + * the subscription in binary-upgrade mode. So in those cases, we + * reverse the direction of the dependency. */ if (deptype == 'i' && dobj->objType == DO_TABLE && - refdobj->objType == DO_TYPE) + (refdobj->objType == DO_TYPE || + refdobj->objType == DO_SUBSCRIPTION)) addObjectDependency(refdobj, dobj->dumpId); else /* normal case */ diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 41d932f003b..aa6e3e96a54 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -730,6 +730,7 @@ typedef struct _SubscriptionInfo char *subpublications; char *suborigin; char *suboriginremotelsn; + char *subconflictlogdest; } SubscriptionInfo; /* diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index ec73c4d5be9..0282b3cc0d7 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -3424,9 +3424,9 @@ my %tests = ( create_order => 50, create_sql => 'CREATE SUBSCRIPTION sub3 CONNECTION \'dbname=doesnotexist\' PUBLICATION pub1 - WITH (connect = false, origin = any, streaming = on);', + WITH (connect = false, origin = any, streaming = on, conflict_log_destination = table);', regexp => qr/^ - \QCREATE SUBSCRIPTION sub3 CONNECTION 'dbname=doesnotexist' PUBLICATION pub1 WITH (connect = false, slot_name = 'sub3', streaming = on);\E + \QCREATE SUBSCRIPTION sub3 CONNECTION 'dbname=doesnotexist' PUBLICATION pub1 WITH (connect = false, slot_name = 'sub3', streaming = on, conflict_log_destination = table);\E /xm, like => { %full_runs, section_post_data => 1, }, unlike => { @@ -3435,6 +3435,39 @@ my %tests = ( }, }, + # In binary-upgrade mode, the subscription OID is preserved and the + # conflict log table is dumped, to be reused by the CREATE SUBSCRIPTION + # above. + 'binary upgrade: pg_subscription OID of sub3' => { + regexp => qr/^ + \Q-- For binary upgrade, must preserve pg_subscription.oid\E\n + \QSELECT pg_catalog.binary_upgrade_set_next_pg_subscription_oid(\E'\d+'\Q::pg_catalog.oid);\E\n+ + \QCREATE SUBSCRIPTION sub3 \E + /xm, + like => { binary_upgrade => 1, }, + }, + + 'binary upgrade: conflict log table of sub3' => { + regexp => qr/^ + \QCREATE TABLE pg_conflict.pg_conflict_log_\E\d+\Q (\E + /xm, + like => { binary_upgrade => 1, }, + }, + + 'CREATE SUBSCRIPTION sub4' => { + create_order => 50, + create_sql => 'CREATE SUBSCRIPTION sub4 + CONNECTION \'dbname=doesnotexist\' PUBLICATION pub1 + WITH (connect = false, conflict_log_destination = all);', + regexp => qr/^ + \QCREATE SUBSCRIPTION sub4 CONNECTION 'dbname=doesnotexist' PUBLICATION pub1 WITH (connect = false, slot_name = 'sub4', streaming = parallel, conflict_log_destination = all);\E + /xm, + like => { %full_runs, section_post_data => 1, }, + unlike => { + no_subscriptions => 1, + no_subscriptions_restore => 1, + }, + }, # Regardless of whether the table or schema is excluded, publications must # still be dumped, as excluded objects do not apply to publications. We diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c index 6d01084e4b0..6a46ceca83c 100644 --- a/src/bin/pg_upgrade/pg_upgrade.c +++ b/src/bin/pg_upgrade/pg_upgrade.c @@ -35,6 +35,10 @@ * * We control all assignments of pg_database.oid because we want the directory * names to match between the old and new cluster. + * + * We control assignment of pg_subscription.oid because we want the oid to + * match between the old and new cluster to make use of subscription's + * conflict log table which is named using the subscription oid. */ diff --git a/src/bin/pg_upgrade/t/004_subscription.pl b/src/bin/pg_upgrade/t/004_subscription.pl index 36f059faa2e..534a69f6311 100644 --- a/src/bin/pg_upgrade/t/004_subscription.pl +++ b/src/bin/pg_upgrade/t/004_subscription.pl @@ -290,7 +290,7 @@ $publisher->safe_psql( $old_sub->safe_psql( 'postgres', qq[ CREATE TABLE tab_upgraded2(id int); - CREATE SUBSCRIPTION regress_sub5 CONNECTION '$connstr' PUBLICATION regress_pub5; + CREATE SUBSCRIPTION regress_sub5 CONNECTION '$connstr' PUBLICATION regress_pub5 with (conflict_log_destination = 'table'); ]); # The table tab_upgraded2 will be in the init state as the subscriber's @@ -312,7 +312,19 @@ my $tab_upgraded1_oid = $old_sub->safe_psql('postgres', "SELECT oid FROM pg_class WHERE relname = 'tab_upgraded1'"); my $tab_upgraded2_oid = $old_sub->safe_psql('postgres', "SELECT oid FROM pg_class WHERE relname = 'tab_upgraded2'"); - +my $sub5_oid = $old_sub->safe_psql('postgres', + "SELECT oid FROM pg_subscription where subname = 'regress_sub5'"); +my $sub_clt_relid = $old_sub->safe_psql('postgres', + "SELECT subconflictlogrelid FROM pg_subscription WHERE subname = 'regress_sub5'"); + +# A privilege granted on the conflict log table must survive the upgrade. +my $sub_clt_name = $old_sub->safe_psql('postgres', + "SELECT relname FROM pg_class WHERE oid = $sub_clt_relid"); +$old_sub->safe_psql( + 'postgres', qq[ + CREATE ROLE regress_clt_reader; + GRANT DELETE ON pg_conflict.$sub_clt_name TO regress_clt_reader; +]); $old_sub->stop; # Change configuration so that initial table sync does not get started @@ -394,6 +406,19 @@ $result = $new_sub->safe_psql('postgres', ); is($result, qq(t), "conflict detection slot exists"); +# The subscription oid and the subscription conflict log table relid should be preserved +$result = $new_sub->safe_psql('postgres', "SELECT oid FROM pg_subscription WHERE subname = 'regress_sub5'"); +is($result, qq($sub5_oid), "subscription oid should have been preserved"); + +$result = $new_sub->safe_psql('postgres', "SELECT subconflictlogrelid FROM pg_subscription WHERE subname = 'regress_sub5'"); +is($result, qq($sub_clt_relid), "subscription conflict log table relid should have been preserved"); + +$result = $new_sub->safe_psql('postgres', + "SELECT has_table_privilege('regress_clt_reader', $sub_clt_relid, 'DELETE'), has_table_privilege('regress_clt_reader', $sub_clt_relid, 'INSERT')" +); +is($result, qq(t|f), + "privileges granted on the subscription conflict log table should have been preserved"); + # Resume the initial sync and wait until all tables of subscription # 'regress_sub5' are synchronized $new_sub->append_conf('postgresql.conf', diff --git a/src/include/catalog/binary_upgrade.h b/src/include/catalog/binary_upgrade.h index 8fad20e4c78..7319756200d 100644 --- a/src/include/catalog/binary_upgrade.h +++ b/src/include/catalog/binary_upgrade.h @@ -46,6 +46,7 @@ extern PGDLLIMPORT BinaryUpgradeAttributeVersions *binary_upgrade_next_attribute extern PGDLLIMPORT Oid binary_upgrade_next_pg_enum_oid; extern PGDLLIMPORT Oid binary_upgrade_next_pg_authid_oid; +extern PGDLLIMPORT Oid binary_upgrade_next_pg_subscription_oid; extern PGDLLIMPORT bool binary_upgrade_record_init_privs; diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 50fb182cb79..af7a4d75dae 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12064,6 +12064,10 @@ proname => 'binary_upgrade_set_next_attribute_versions', provolatile => 'v', proparallel => 'u', prorettype => 'void', proargtypes => '_pg_lsn', prosrc => 'binary_upgrade_set_next_attribute_versions' }, +{ oid => '8407', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_pg_subscription_oid', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_pg_subscription_oid' }, # conversion functions { oid => '4310', descr => 'internal conversion function for KOI8R to WIN1251', diff --git a/src/include/catalog/pg_subscription.h b/src/include/catalog/pg_subscription.h index b860f02d166..dd8bfd6eb5b 100644 --- a/src/include/catalog/pg_subscription.h +++ b/src/include/catalog/pg_subscription.h @@ -221,6 +221,9 @@ typedef struct Subscription #endif /* EXPOSE_TO_CLIENT_CODE */ +/* Conflict log table name format. %u is replaced with the subscription OID. */ +#define CONFLICT_LOG_RELATION_NAME_FMT "pg_conflict_log_%u" + extern Subscription *GetSubscription(Oid subid, bool missing_ok); extern char *SubscriptionConninfo(Subscription *sub); extern void DisableSubscription(Oid subid); diff --git a/src/test/modules/spgist_name_ops/expected/spgist_name_ops.out b/src/test/modules/spgist_name_ops/expected/spgist_name_ops.out index 1839ba3ce71..f8805a08e70 100644 --- a/src/test/modules/spgist_name_ops/expected/spgist_name_ops.out +++ b/src/test/modules/spgist_name_ops/expected/spgist_name_ops.out @@ -60,12 +60,13 @@ select * from t binary_upgrade_set_next_multirange_pg_type_oid | 1 | binary_upgrade_set_next_multirange_pg_type_oid binary_upgrade_set_next_pg_authid_oid | | binary_upgrade_set_next_pg_authid_oid binary_upgrade_set_next_pg_enum_oid | | binary_upgrade_set_next_pg_enum_oid + binary_upgrade_set_next_pg_subscription_oid | | binary_upgrade_set_next_pg_subscription_oid binary_upgrade_set_next_pg_tablespace_oid | | binary_upgrade_set_next_pg_tablespace_oid binary_upgrade_set_next_pg_type_oid | | binary_upgrade_set_next_pg_type_oid binary_upgrade_set_next_toast_chunk_id_typoid | | binary_upgrade_set_next_toast_chunk_id_typoid binary_upgrade_set_next_toast_pg_class_oid | 1 | binary_upgrade_set_next_toast_pg_class_oid binary_upgrade_set_next_toast_relfilenode | | binary_upgrade_set_next_toast_relfilenode -(15 rows) +(16 rows) -- Verify clean failure when INCLUDE'd columns result in overlength tuple -- The error message details are platform-dependent, so show only SQLSTATE @@ -111,12 +112,13 @@ select * from t binary_upgrade_set_next_multirange_pg_type_oid | 1 | binary_upgrade_set_next_multirange_pg_type_oid binary_upgrade_set_next_pg_authid_oid | | binary_upgrade_set_next_pg_authid_oid binary_upgrade_set_next_pg_enum_oid | | binary_upgrade_set_next_pg_enum_oid + binary_upgrade_set_next_pg_subscription_oid | | binary_upgrade_set_next_pg_subscription_oid binary_upgrade_set_next_pg_tablespace_oid | | binary_upgrade_set_next_pg_tablespace_oid binary_upgrade_set_next_pg_type_oid | | binary_upgrade_set_next_pg_type_oid binary_upgrade_set_next_toast_chunk_id_typoid | | binary_upgrade_set_next_toast_chunk_id_typoid binary_upgrade_set_next_toast_pg_class_oid | 1 | binary_upgrade_set_next_toast_pg_class_oid binary_upgrade_set_next_toast_relfilenode | | binary_upgrade_set_next_toast_relfilenode -(15 rows) +(16 rows) \set VERBOSITY sqlstate insert into t values(repeat('xyzzy', 12), 42, repeat('xyzzy', 4000)); -- 2.55.0