From c74861298d44ab37f6b8bf1dd864614b8131dc20 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathan@postgresql.org>
Date: Wed, 17 Jul 2024 17:09:03 -0500
Subject: [PATCH v5 3/4] introduce pg_sequence_read_tuple

XXX: NEEDS CATVERSION BUMP
---
 src/backend/commands/sequence.c        | 62 ++++++++++++++++++++++++++
 src/include/catalog/pg_proc.dat        |  6 +++
 src/test/regress/expected/sequence.out |  7 +++
 src/test/regress/sql/sequence.sql      |  3 ++
 4 files changed, 78 insertions(+)

diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 9f28d40466..364097c457 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1773,6 +1773,68 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
+
+/*
+ * Return the sequence tuple.
+ *
+ * This is primarily intended for use by pg_dump to gather sequence data
+ * without needing to individually query each sequence relation.
+ */
+Datum
+pg_sequence_read_tuple(PG_FUNCTION_ARGS)
+{
+	Oid			relid = PG_GETARG_OID(0);
+	SeqTable	elm;
+	Relation	seqrel;
+	Datum		values[SEQ_COL_LASTCOL];
+	bool		isnull[SEQ_COL_LASTCOL];
+	TupleDesc	resultTupleDesc;
+	HeapTuple	resultHeapTuple;
+	Datum		result;
+
+	resultTupleDesc = CreateTemplateTupleDesc(SEQ_COL_LASTCOL);
+	TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "last_value",
+					   INT8OID, -1, 0);
+	TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "log_cnt",
+					   INT8OID, -1, 0);
+	TupleDescInitEntry(resultTupleDesc, (AttrNumber) 3, "is_called",
+					   BOOLOID, -1, 0);
+	resultTupleDesc = BlessTupleDesc(resultTupleDesc);
+
+	init_sequence(relid, &elm, &seqrel);
+
+	/*
+	 * Return all NULLs for sequences for which we lack privileges, other
+	 * sessions' temporary sequences, and unlogged sequences on standbys.
+	 */
+	if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT) == ACLCHECK_OK &&
+		!RELATION_IS_OTHER_TEMP(seqrel) &&
+		(RelationIsPermanent(seqrel) || !RecoveryInProgress()))
+	{
+		Buffer		buf;
+		HeapTupleData seqtuple;
+		Form_pg_sequence_data seq;
+
+		seq = read_seq_tuple(seqrel, &buf, &seqtuple);
+
+		memset(isnull, false, sizeof(isnull));
+		values[0] = Int64GetDatum(seq->last_value);
+		values[1] = Int64GetDatum(seq->log_cnt);
+		values[2] = BoolGetDatum(seq->is_called);
+
+		UnlockReleaseBuffer(buf);
+	}
+	else
+		memset(isnull, true, sizeof(isnull));
+
+	sequence_close(seqrel, NoLock);
+
+	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
+	result = HeapTupleGetDatum(resultHeapTuple);
+	PG_RETURN_DATUM(result);
+}
+
+
 /*
  * Return the last value from the sequence
  *
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 73d9cf8582..a16aec302e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3329,6 +3329,12 @@
   proname => 'pg_sequence_last_value', provolatile => 'v', proparallel => 'u',
   prorettype => 'int8', proargtypes => 'regclass',
   prosrc => 'pg_sequence_last_value' },
+{ oid => '9876', descr => 'return sequence tuple, for use by pg_dump',
+  proname => 'pg_sequence_read_tuple', provolatile => 'v', proparallel => 'u',
+  prorettype => 'record', proargtypes => 'regclass',
+  proallargtypes => '{regclass,int8,int8,bool}', proargmodes => '{i,o,o,o}',
+  proargnames => '{sequence_oid,last_value,log_cnt,is_called}',
+  prosrc => 'pg_sequence_read_tuple' },
 
 { oid => '275', descr => 'return the next oid for a system table',
   proname => 'pg_nextoid', provolatile => 'v', proparallel => 'u',
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 2b47b7796b..e749c4574e 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -839,4 +839,11 @@ SELECT nextval('test_seq1');
        3
 (1 row)
 
+-- pg_sequence_read_tuple
+SELECT * FROM pg_sequence_read_tuple('test_seq1');
+ last_value | log_cnt | is_called 
+------------+---------+-----------
+         10 |      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 674f5f1f66..ea447938ae 100644
--- a/src/test/regress/sql/sequence.sql
+++ b/src/test/regress/sql/sequence.sql
@@ -413,4 +413,7 @@ SELECT nextval('test_seq1');
 SELECT nextval('test_seq1');
 SELECT nextval('test_seq1');
 
+-- pg_sequence_read_tuple
+SELECT * FROM pg_sequence_read_tuple('test_seq1');
+
 DROP SEQUENCE test_seq1;
-- 
2.39.3 (Apple Git-146)

