=== Applying patches on top of PostgreSQL commit ID 1200dfd60c367e97a5e1f31100d82072eb0178b6 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Thu Aug 6 01:22:35 UTC 2026 On branch cf/6514 nothing to commit, working tree clean === using 'git am' to apply patch ./v12-0001-Support-automatic-sequence-replication.patch === Applying: Support automatic sequence replication. Using index info to reconstruct a base tree... M doc/src/sgml/logical-replication.sgml M doc/src/sgml/ref/alter_subscription.sgml M src/backend/replication/logical/sequencesync.c M src/backend/replication/logical/worker.c M src/backend/utils/activity/wait_event_names.txt M src/include/replication/worker_internal.h M src/test/subscription/t/036_sequences.pl Falling back to patching base and 3-way merge... Auto-merging src/test/subscription/t/036_sequences.pl Auto-merging src/include/replication/worker_internal.h Auto-merging src/backend/utils/activity/wait_event_names.txt Auto-merging src/backend/replication/logical/worker.c Auto-merging src/backend/replication/logical/sequencesync.c CONFLICT (content): Merge conflict in src/backend/replication/logical/sequencesync.c Auto-merging doc/src/sgml/ref/alter_subscription.sgml Auto-merging doc/src/sgml/logical-replication.sgml error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 Support automatic sequence replication. When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". === using patch(1) to apply patch ./v12-0001-Support-automatic-sequence-replication.patch === patching file doc/src/sgml/logical-replication.sgml Hunk #1 succeeded at 1808 (offset 17 lines). Hunk #2 succeeded at 1846 (offset 24 lines). Hunk #3 succeeded at 2372 (offset 24 lines). patching file doc/src/sgml/ref/alter_subscription.sgml patching file src/backend/commands/sequence.c patching file src/backend/replication/logical/sequencesync.c Hunk #3 FAILED at 79. Hunk #4 succeeded at 122 (offset 1 line). Hunk #5 succeeded at 167 (offset 1 line). Hunk #6 FAILED at 193. Hunk #7 succeeded at 210 (offset 5 lines). Hunk #8 FAILED at 216. Hunk #9 succeeded at 262 (offset 35 lines). Hunk #10 succeeded at 286 (offset 35 lines). Hunk #11 succeeded at 299 (offset 36 lines). Hunk #12 FAILED at 348. Hunk #13 FAILED at 390. Hunk #14 succeeded at 497 with fuzz 1 (offset 78 lines). Hunk #15 FAILED at 428. Hunk #16 succeeded at 604 (offset 81 lines). Hunk #17 FAILED at 553. Hunk #18 succeeded at 673 (offset 93 lines). Hunk #19 FAILED at 601. Hunk #20 FAILED at 636. Hunk #21 succeeded at 799 with fuzz 1 (offset 104 lines). Hunk #22 FAILED at 725. Hunk #23 succeeded at 871 (offset 104 lines). 10 out of 23 hunks FAILED -- saving rejects to file src/backend/replication/logical/sequencesync.c.rej patching file src/backend/replication/logical/syncutils.c patching file src/backend/replication/logical/worker.c Hunk #1 succeeded at 5129 with fuzz 2 (offset 26 lines). Hunk #2 succeeded at 5147 (offset 26 lines). Hunk #3 succeeded at 5169 (offset 26 lines). patching file src/backend/utils/activity/wait_event_names.txt patching file src/include/catalog/pg_subscription_rel.h patching file src/include/commands/sequence.h patching file src/include/replication/worker_internal.h Hunk #1 succeeded at 286 (offset 1 line). patching file src/test/subscription/t/026_stats.pl patching file src/test/subscription/t/036_sequences.pl Hunk #1 succeeded at 79 (offset 4 lines). Hunk #2 succeeded at 97 (offset 4 lines). Hunk #3 succeeded at 106 (offset 4 lines). Hunk #4 succeeded at 120 with fuzz 1 (offset 4 lines). Unstaged changes after reset: M doc/src/sgml/logical-replication.sgml M doc/src/sgml/ref/alter_subscription.sgml M src/backend/commands/sequence.c M src/backend/replication/logical/sequencesync.c M src/backend/replication/logical/syncutils.c M src/backend/replication/logical/worker.c M src/backend/utils/activity/wait_event_names.txt M src/include/catalog/pg_subscription_rel.h M src/include/commands/sequence.h M src/include/replication/worker_internal.h M src/test/subscription/t/026_stats.pl M src/test/subscription/t/036_sequences.pl Removing src/backend/replication/logical/sequencesync.c.rej === using 'git apply' to apply patch ./v12-0001-Support-automatic-sequence-replication.patch === Applied patch to 'doc/src/sgml/logical-replication.sgml' cleanly. Applied patch to 'doc/src/sgml/ref/alter_subscription.sgml' cleanly. Applied patch to 'src/backend/commands/sequence.c' cleanly. Applied patch to 'src/backend/replication/logical/sequencesync.c' with conflicts. Applied patch to 'src/backend/replication/logical/syncutils.c' cleanly. Applied patch to 'src/backend/replication/logical/worker.c' cleanly. Applied patch to 'src/backend/utils/activity/wait_event_names.txt' cleanly. Applied patch to 'src/include/catalog/pg_subscription_rel.h' cleanly. Applied patch to 'src/include/commands/sequence.h' cleanly. Applied patch to 'src/include/replication/worker_internal.h' cleanly. Applied patch to 'src/test/subscription/t/026_stats.pl' cleanly. Applied patch to 'src/test/subscription/t/036_sequences.pl' cleanly. U src/backend/replication/logical/sequencesync.c diff --cc src/backend/replication/logical/sequencesync.c index 6d551d45791,22e32dbba57..00000000000 --- a/src/backend/replication/logical/sequencesync.c +++ b/src/backend/replication/logical/sequencesync.c @@@ -71,22 -79,28 +79,34 @@@ #include "utils/pg_lsn.h" #include "utils/syscache.h" #include "utils/usercontext.h" + #include "utils/wait_event.h" -#define REMOTE_SEQ_COL_COUNT 10 +#define REMOTE_SEQ_COL_COUNT 11 typedef enum CopySeqResult { COPYSEQ_SUCCESS, + COPYSEQ_ALLOWED, COPYSEQ_MISMATCH, ++<<<<<<< ours + COPYSEQ_SUBSCRIBER_INSUFFICIENT_PERM, + COPYSEQ_PUBLISHER_INSUFFICIENT_PERM, + COPYSEQ_SKIPPED ++======= + COPYSEQ_INSUFFICIENT_PERM, + COPYSEQ_SKIPPED, + COPYSEQ_NO_DRIFT, ++>>>>>>> theirs } CopySeqResult; - static List *seqinfos = NIL; + /* Sleep intervals for sync */ + #define SEQSYNC_MIN_SLEEP_MS 2000 /* 2 seconds */ + #define SEQSYNC_MAX_SLEEP_MS 30000 /* 30 seconds */ + + static MemoryContext SequenceSyncContext = NULL; /* - * Apply worker determines if sequence synchronization is needed. + * Apply worker determines whether a sequence sync worker is needed. * * Start a sequencesync worker if one is not already running. The active * sequencesync worker will handle all pending sequence synchronization. If any @@@ -173,10 -203,8 +210,15 @@@ get_sequences_string(List *seqindexes, * Then raises an ERROR to indicate synchronization failure. */ static void ++<<<<<<< ours +report_sequence_errors(List *mismatched_seqs_idx, + List *sub_insuffperm_seqs_idx, + List *pub_insuffperm_seqs_idx, + List *missing_seqs_idx) ++======= + report_sequence_errors(List *mismatched_seqs_idx, List *insuffperm_seqs_idx, + List *missing_seqs_idx, List *seqinfos) ++>>>>>>> theirs { StringInfoData seqstr; @@@ -198,45 -225,15 +240,49 @@@ seqstr.data)); } - if (insuffperm_seqs_idx) + if (sub_insuffperm_seqs_idx) { ++<<<<<<< ours + get_sequences_string(sub_insuffperm_seqs_idx, &seqstr); + + /* + * With run_as_owner enabled, sequence synchronization runs as the + * subscription owner, so a missing UPDATE privilege should be granted + * to that role. Otherwise, the worker switches to the sequence owner + * before checking privileges, so no useful GRANT hint can be + * provided. + */ ++======= + get_sequences_string(insuffperm_seqs_idx, seqinfos, &seqstr); ++>>>>>>> theirs ereport(WARNING, errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg_plural("insufficient privileges on sequence (%s)", - "insufficient privileges on sequences (%s)", - list_length(insuffperm_seqs_idx), - seqstr.data)); + errmsg_plural("insufficient privileges on subscriber sequence (%s)", + "insufficient privileges on subscriber sequences (%s)", + list_length(sub_insuffperm_seqs_idx), + seqstr.data), + MySubscription->runasowner ? + errhint_plural("Grant UPDATE on the sequence to the subscription " + "owner on the subscriber.", + "Grant UPDATE on the sequences to the subscription " + "owner on the subscriber.", + list_length(sub_insuffperm_seqs_idx)) : 0); + } + + if (pub_insuffperm_seqs_idx) + { + get_sequences_string(pub_insuffperm_seqs_idx, &seqstr); + ereport(WARNING, + errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg_plural("insufficient privileges on publisher sequence (%s)", + "insufficient privileges on publisher sequences (%s)", + list_length(pub_insuffperm_seqs_idx), + seqstr.data), + errhint_plural("Grant SELECT on the sequence to the role used for " + "the replication connection on the publisher.", + "Grant SELECT on the sequences to the role used for " + "the replication connection on the publisher.", + list_length(pub_insuffperm_seqs_idx))); } if (missing_seqs_idx) @@@ -418,7 -429,7 +510,11 @@@ copy_sequence(LogicalRepSequenceInfo *s if (!run_as_owner) RestoreUserContext(&ucxt); ++<<<<<<< ours + return COPYSEQ_SUBSCRIBER_INSUFFICIENT_PERM; ++======= + return result; ++>>>>>>> theirs } /* @@@ -454,8 -492,8 +577,13 @@@ copy_sequences(WalReceiverConn *conn, L int n_seqinfos = list_length(seqinfos); List *mismatched_seqs_idx = NIL; List *missing_seqs_idx = NIL; ++<<<<<<< ours + List *sub_insuffperm_seqs_idx = NIL; + List *pub_insuffperm_seqs_idx = NIL; ++======= + List *insuffperm_seqs_idx = NIL; + bool sequence_copied = false; ++>>>>>>> theirs StringInfoData seqstr; StringInfoData cmd; MemoryContext oldctx; @@@ -475,21 -503,18 +603,22 @@@ #define MAX_SEQUENCES_SYNC_PER_BATCH 100 - elog(DEBUG1, - "logical replication sequence synchronization for subscription \"%s\" - total unsynchronized: %d", - MySubscription->name, n_seqinfos); - while (cur_batch_base_index < n_seqinfos) { - Oid seqRow[REMOTE_SEQ_COL_COUNT] = {INT8OID, INT8OID, + Oid seqRow[REMOTE_SEQ_COL_COUNT] = {INT8OID, BOOLOID, INT8OID, BOOLOID, LSNOID, OIDOID, INT8OID, INT8OID, INT8OID, INT8OID, BOOLOID}; int batch_size = 0; int batch_succeeded_count = 0; int batch_mismatched_count = 0; int batch_skipped_count = 0; ++<<<<<<< ours + int batch_sub_insuffperm_count = 0; + int batch_pub_insuffperm_count = 0; ++======= + int batch_insuffperm_count = 0; + int batch_no_drift = 0; ++>>>>>>> theirs int batch_missing_count; - Relation sequence_rel = NULL; WalRcvExecResult *res; TupleTableSlot *slot; @@@ -613,30 -635,18 +742,36 @@@ MemoryContextSwitchTo(oldctx); batch_mismatched_count++; break; - case COPYSEQ_INSUFFICIENT_PERM: + case COPYSEQ_SUBSCRIBER_INSUFFICIENT_PERM: /* - * Remember sequences with insufficient privileges in a - * long-lived memory context since these will be used - * after the transaction is committed. + * Remember sequences with insufficient privileges in + * SequenceSyncContext since these will be used after the + * transaction is committed. */ ++<<<<<<< ours + oldctx = MemoryContextSwitchTo(ApplyContext); + sub_insuffperm_seqs_idx = lappend_int(sub_insuffperm_seqs_idx, + seqidx); ++======= + oldctx = MemoryContextSwitchTo(SequenceSyncContext); + insuffperm_seqs_idx = lappend_int(insuffperm_seqs_idx, + seqidx); ++>>>>>>> theirs + MemoryContextSwitchTo(oldctx); + batch_sub_insuffperm_count++; + break; + case COPYSEQ_PUBLISHER_INSUFFICIENT_PERM: + + /* + * Remember sequences for which the publisher lacks the + * privileges required by pg_get_sequence_data(). + */ + oldctx = MemoryContextSwitchTo(ApplyContext); + pub_insuffperm_seqs_idx = lappend_int(pub_insuffperm_seqs_idx, + seqidx); MemoryContextSwitchTo(oldctx); - batch_insuffperm_count++; + batch_pub_insuffperm_count++; break; case COPYSEQ_SKIPPED: @@@ -668,16 -685,16 +810,29 @@@ batch_missing_count = batch_size - (batch_succeeded_count + batch_mismatched_count + ++<<<<<<< ours + batch_sub_insuffperm_count + + batch_pub_insuffperm_count + + batch_skipped_count); + + elog(DEBUG1, + "logical replication sequence synchronization for subscription \"%s\" - batch #%d = %d attempted, %d succeeded, %d mismatched, %d subscriber insufficient permission, %d publisher insufficient permission, %d missing from publisher, %d skipped", + MySubscription->name, + (cur_batch_base_index / MAX_SEQUENCES_SYNC_PER_BATCH) + 1, + batch_size, batch_succeeded_count, batch_mismatched_count, + batch_sub_insuffperm_count, batch_pub_insuffperm_count, batch_missing_count, batch_skipped_count); ++======= + batch_insuffperm_count + + batch_skipped_count + + batch_no_drift); + + elog(DEBUG1, + "logical replication sequence synchronization for subscription \"%s\" - batch #%d = %d attempted, %d succeeded, %d mismatched, %d insufficient permission, %d missing from publisher, %d skipped, %d no drift", + MySubscription->name, + (cur_batch_base_index / MAX_SEQUENCES_SYNC_PER_BATCH) + 1, + batch_size, batch_succeeded_count, batch_mismatched_count, + batch_insuffperm_count, batch_missing_count, batch_skipped_count, batch_no_drift); ++>>>>>>> theirs /* Commit this batch, and prepare for next batch */ CommitTransactionCommand(); @@@ -704,28 -721,33 +859,39 @@@ } /* Report mismatches, permission issues, or missing sequences */ ++<<<<<<< ours + report_sequence_errors(mismatched_seqs_idx, sub_insuffperm_seqs_idx, + pub_insuffperm_seqs_idx, missing_seqs_idx); ++======= + report_sequence_errors(mismatched_seqs_idx, insuffperm_seqs_idx, + missing_seqs_idx, seqinfos); + + return sequence_copied; ++>>>>>>> theirs } /* * Identifies sequences that require synchronization and initiates the * synchronization process. + * + * Returns true if sequences have been updated. */ - static void - LogicalRepSyncSequences(void) + static bool + LogicalRepSyncSequences(WalReceiverConn *conn, bool update_lsn) { - char *err; - bool must_use_password; Relation rel; HeapTuple tup; - ScanKeyData skey[2]; + ScanKeyData skey[1]; SysScanDesc scan; Oid subid = MyLogicalRepWorker->subid; - StringInfoData app_name; + bool sequence_copied = false; + List *seqinfos = NIL; + MemoryContext oldctx; + + Assert(SequenceSyncContext); StartTransactionCommand(); + maybe_reread_subscription(); rel = table_open(SubscriptionRelRelationId, AccessShareLock); @@@ -784,11 -797,11 +950,11 @@@ seq->localrelid = subrel->srrelid; seq->nspname = get_namespace_name(RelationGetNamespace(sequence_rel)); seq->seqname = pstrdup(RelationGetRelationName(sequence_rel)); + seq->relstate = relstate; seqinfos = lappend(seqinfos, seq); - MemoryContextSwitchTo(oldctx); - table_close(sequence_rel, NoLock); + table_close(sequence_rel, AccessShareLock); } /* Cleanup */ @@@ -801,32 -814,12 +967,31 @@@ * Exit early if no catalog entries found, likely due to concurrent drops. */ if (!seqinfos) - return; - - /* Is the use of a password mandatory? */ - must_use_password = MySubscription->passwordrequired && - !MySubscription->ownersuperuser; + return false; - initStringInfo(&app_name); - appendStringInfo(&app_name, "pg_%u_sequence_sync_" UINT64_FORMAT, - MySubscription->oid, GetSystemIdentifier()); + /* Process sequences */ + sequence_copied = copy_sequences(conn, seqinfos, update_lsn); ++<<<<<<< ours + /* + * Establish the connection to the publisher for sequence synchronization. + */ + LogRepWorkerWalRcvConn = + walrcv_connect(MySubscriptionConninfo, true, true, + must_use_password, + app_name.data, &err); + if (LogRepWorkerWalRcvConn == NULL) + ereport(ERROR, + errcode(ERRCODE_CONNECTION_FAILURE), + errmsg("sequencesync worker for subscription \"%s\" could not connect to the publisher: %s", + MySubscription->name, err)); + + pfree(app_name.data); + + copy_sequences(LogRepWorkerWalRcvConn); ++======= + return sequence_copied; ++>>>>>>> theirs } /*