v20250908-0001-Enhance-pg_get_sequence_data-function.patch
application/octet-stream
Filename: v20250908-0001-Enhance-pg_get_sequence_data-function.patch
Type: application/octet-stream
Part: 0
Message:
Re: Logical Replication of sequences
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v20250908-0001
Subject: Enhance pg_get_sequence_data function
| File | + | − |
|---|---|---|
| doc/src/sgml/func/func-sequence.sgml | 27 | 0 |
| src/backend/commands/sequence.c | 13 | 3 |
| src/include/catalog/pg_proc.dat | 3 | 3 |
| src/test/regress/expected/sequence.out | 4 | 4 |
| src/test/regress/sql/sequence.sql | 1 | 1 |
From fb0d47c3d6568b545467172d6b335c2137b593a8 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 5 Aug 2025 10:23:31 +0530
Subject: [PATCH v20250908 1/7] Enhance pg_get_sequence_data function
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This patch enhances 'pg_get_sequence_data' to return the sequence’s
log_cnt and associated page LSN.
In the subsequent patches, When a sequence is synchronized to the
subscriber, the page LSN of the sequence from the publisher is also
captured and stored in pg_subscription_rel.srsublsn. This LSN will
reflect the state of the sequence at the time of synchronization.
By comparing the current LSN of the sequence on the publisher
(via pg_sequence_state()) with the stored LSN on the subscriber, users
can detect if the sequence has advanced and is now out-of-sync. This
comparison will help determine whether re-synchronization is needed for a
given sequence.
Author: Vignesh C, Tomas Vondra
Reviewer: Amit Kapila, Shveta Malik, Dilip Kumar, Peter Smith, Nisha Moond
Discussion: https://www.postgresql.org/message-id/CAA4eK1LC+KJiAkSrpE_NwvNdidw9F2os7GERUeSxSKv71gXysQ@mail.gmail.com
---
doc/src/sgml/func/func-sequence.sgml | 27 ++++++++++++++++++++++++++
src/backend/commands/sequence.c | 16 ++++++++++++---
src/include/catalog/pg_proc.dat | 6 +++---
src/test/regress/expected/sequence.out | 8 ++++----
src/test/regress/sql/sequence.sql | 2 +-
5 files changed, 48 insertions(+), 11 deletions(-)
diff --git a/doc/src/sgml/func/func-sequence.sgml b/doc/src/sgml/func/func-sequence.sgml
index e9f5b4e8e6b..649f1522bb2 100644
--- a/doc/src/sgml/func/func-sequence.sgml
+++ b/doc/src/sgml/func/func-sequence.sgml
@@ -143,6 +143,33 @@ SELECT setval('myseq', 42, false); <lineannotation>Next <function>nextval</fu
or <literal>SELECT</literal> privilege on the last used sequence.
</para></entry>
</row>
+
+ <row>
+ <entry role="func_table_entry"><para role="func_signature">
+ <indexterm>
+ <primary>pg_get_sequence_data</primary>
+ </indexterm>
+ <function>pg_get_sequence_data</function> ( <type>regclass</type> )
+ <returnvalue>record</returnvalue>
+ ( <parameter>last_value</parameter> <type>bigint</type>,
+ <parameter>is_called</parameter> <type>bool</type>,
+ <parameter>log_cnt</parameter> <type>bigint</type>,
+ <parameter>page_lsn</parameter> <type>pg_lsn</type> )
+ </para>
+ <para>
+ Returns information about the sequence. <literal>last_value</literal>
+ indicates last sequence value set in sequence by nextval or setval,
+ <literal>is_called</literal> indicates whether the sequence has been
+ used, <literal>log_cnt</literal> shows how many fetches remain before a
+ new WAL record must be written, and <literal>page_lsn</literal> is the
+ LSN corresponding to the most recent WAL record that modified this
+ sequence relation.
+ </para>
+ <para>
+ This function requires <literal>USAGE</literal>
+ or <literal>SELECT</literal> privilege on the sequence.
+ </para></entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 636d3c3ec73..879c62bdccc 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -45,6 +45,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
+#include "utils/pg_lsn.h"
#include "utils/resowner.h"
#include "utils/syscache.h"
#include "utils/varlena.h"
@@ -1795,15 +1796,16 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
/*
- * Return the sequence tuple.
+ * Return the sequence tuple along with its page LSN.
*
* This is primarily intended for use by pg_dump to gather sequence data
- * without needing to individually query each sequence relation.
+ * without needing to individually query each sequence relation. This will
+ * also be used by logical replication while synchronizing sequences.
*/
Datum
pg_get_sequence_data(PG_FUNCTION_ARGS)
{
-#define PG_GET_SEQUENCE_DATA_COLS 2
+#define PG_GET_SEQUENCE_DATA_COLS 4
Oid relid = PG_GETARG_OID(0);
SeqTable elm;
Relation seqrel;
@@ -1818,6 +1820,10 @@ pg_get_sequence_data(PG_FUNCTION_ARGS)
INT8OID, -1, 0);
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "is_called",
BOOLOID, -1, 0);
+ TupleDescInitEntry(resultTupleDesc, (AttrNumber) 3, "log_cnt",
+ INT8OID, -1, 0);
+ TupleDescInitEntry(resultTupleDesc, (AttrNumber) 4, "page_lsn",
+ LSNOID, -1, 0);
resultTupleDesc = BlessTupleDesc(resultTupleDesc);
init_sequence(relid, &elm, &seqrel);
@@ -1833,11 +1839,15 @@ pg_get_sequence_data(PG_FUNCTION_ARGS)
Buffer buf;
HeapTupleData seqtuple;
Form_pg_sequence_data seq;
+ Page page;
seq = read_seq_tuple(seqrel, &buf, &seqtuple);
+ page = BufferGetPage(buf);
values[0] = Int64GetDatum(seq->last_value);
values[1] = BoolGetDatum(seq->is_called);
+ values[2] = Int64GetDatum(seq->log_cnt);
+ values[3] = LSNGetDatum(PageGetLSN(page));
UnlockReleaseBuffer(buf);
}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 118d6da1ace..62bcd9d921c 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3433,11 +3433,11 @@
proname => 'pg_sequence_last_value', provolatile => 'v', proparallel => 'u',
prorettype => 'int8', proargtypes => 'regclass',
prosrc => 'pg_sequence_last_value' },
-{ oid => '6427', descr => 'return sequence tuple, for use by pg_dump',
+{ oid => '6427', descr => 'return sequence tuple, for use by pg_dump and sequence synchronization',
proname => 'pg_get_sequence_data', provolatile => 'v', proparallel => 'u',
prorettype => 'record', proargtypes => 'regclass',
- proallargtypes => '{regclass,int8,bool}', proargmodes => '{i,o,o}',
- proargnames => '{sequence_oid,last_value,is_called}',
+ proallargtypes => '{regclass,int8,bool,int8,pg_lsn}', proargmodes => '{i,o,o,o,o}',
+ proargnames => '{sequence_oid,last_value,is_called,log_cnt,page_lsn}',
prosrc => 'pg_get_sequence_data' },
{ oid => '275', descr => 'return the next oid for a system table',
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 15925d99c8a..87433e508ca 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -840,10 +840,10 @@ SELECT nextval('test_seq1');
(1 row)
-- pg_get_sequence_data
-SELECT * FROM pg_get_sequence_data('test_seq1');
- last_value | is_called
-------------+-----------
- 10 | t
+SELECT last_value, is_called, log_cnt, page_lsn <= pg_current_wal_lsn() as lsn FROM pg_get_sequence_data('test_seq1');
+ last_value | is_called | log_cnt | lsn
+------------+-----------+---------+-----
+ 10 | t | 32 | t
(1 row)
DROP SEQUENCE test_seq1;
diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql
index 2c220b60749..c8adddbfa31 100644
--- a/src/test/regress/sql/sequence.sql
+++ b/src/test/regress/sql/sequence.sql
@@ -414,6 +414,6 @@ SELECT nextval('test_seq1');
SELECT nextval('test_seq1');
-- pg_get_sequence_data
-SELECT * FROM pg_get_sequence_data('test_seq1');
+SELECT last_value, is_called, log_cnt, page_lsn <= pg_current_wal_lsn() as lsn FROM pg_get_sequence_data('test_seq1');
DROP SEQUENCE test_seq1;
--
2.43.0