On 2026-07-21 18:57, solai v wrote:
Thank you for the patch. I reviewed and tested this patch on my
PostgreSQL 19beta2 tree. The patch did not apply cleanly on my branch
because of a context mismatch in
src/test/subscription/t/020_messages.pl.
Sorry for the late reply, and thanks for testing the patch.
Just to clarify, I tried applying v2 directly to the REL_19_BETA2 tag
(7873db5369b),
and git apply succeeded without any conflicts, including the change to
src/test/subscription/t/020_messages.pl.
I also checked whether that file differs between REL_19_BETA2 and
master, but found no differences:
$ git diff REL_19_BETA2 master --
src/test/subscription/t/020_messages.pl
$
The same is true for REL_19_STABLE and master:
$ git diff REL_19_STABLE master --
src/test/subscription/t/020_messages.pl
$
So I am not sure what caused the context mismatch.
Separately, I proposed fixing the issue in minor releases, but the v2
patch does not apply cleanly to 14 and 15.
Attached a patch for these versions.
--
Thanks,
--
Atsushi Torikoshi
Seconded from NTT DATA CORPORATION to SRA OSS K.K.
From 265830febb6e22b92dc181b97d773b0ab1b2e338 Mon Sep 17 00:00:00 2001
From: Atsushi Torikoshi <[email protected]>
Date: Wed, 15 Jul 2026 18:34:21 +0900
Subject: [PATCH v2] Fix LSN of logical decoding message
Report startptr, rather than endptr, as the LSN of a decoded
logical message. The logical replication protocol documentation
describes this field as the LSN of the logical decoding message, but
the current implementation reports the end of its WAL record.
This distinction matters to logical decoding consumers. A consumer
typically records the LSN up to which decoded output has been
successfully processed and uses it as the restart point after a crash
or other failure. PostgreSQL reports startptr when decoding DML
records, but reports endptr only for decoding
pg_logical_emit_message(). Consumers that handle logical messages
in the same way as other decoded records can therefore store an LSN
past the message it has just processed and restart from that later
position after a failure, potentially resulting in data loss.
The regression test is adjusted accordingly. The test emits only a
single non-transactional logical message, which is decoded with
xid = 0, so filtering on xid = 0 is sufficient to identify the
message without matching its LSN.
---
src/backend/replication/logical/decode.c | 2 +-
src/test/subscription/t/020_messages.pl | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index 466fb37719e..b1b077dd00d 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -610,7 +610,7 @@ logicalmsg_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
if (!message->transactional)
snapshot = SnapBuildGetOrBuildSnapshot(builder, xid);
- ReorderBufferQueueMessage(ctx->reorder, xid, snapshot, buf->endptr,
+ ReorderBufferQueueMessage(ctx->reorder, xid, snapshot, buf->origptr,
message->transactional,
message->message, /* first part of message is
* prefix */
diff --git a/src/test/subscription/t/020_messages.pl b/src/test/subscription/t/020_messages.pl
index 533419be29d..4a9b896287a 100644
--- a/src/test/subscription/t/020_messages.pl
+++ b/src/test/subscription/t/020_messages.pl
@@ -94,7 +94,7 @@ is($result, qq(),
$node_publisher->safe_psql('postgres', "INSERT INTO tab_test VALUES (1)");
-my $message_lsn = $node_publisher->safe_psql('postgres',
+$node_publisher->safe_psql('postgres',
"SELECT pg_logical_emit_message(false, 'pgoutput', 'a non-transactional message')"
);
@@ -107,7 +107,7 @@ $result = $node_publisher->safe_psql(
'proto_version', '1',
'publication_names', 'tap_pub',
'messages', 'true')
- WHERE lsn = '$message_lsn' AND xid = 0
+ WHERE xid = 0
));
is($result, qq(77|0), 'non-transactional message on slot is M');
--
2.48.1