Introduce pg_sequence_read_tuple().
authorNathan Bossart <[email protected]>
Wed, 31 Jul 2024 15:12:42 +0000 (10:12 -0500)
committerNathan Bossart <[email protected]>
Wed, 31 Jul 2024 15:12:42 +0000 (10:12 -0500)
This new function returns the data for the given sequence, i.e.,
the values within the sequence tuple.  Since this function is a
substitute for SELECT from the sequence, the SELECT privilege is
required on the sequence in question.  It returns all NULLs for
sequences for which we lack privileges, other sessions' temporary
sequences, and unlogged sequences on standbys.

This function is primarily intended for use by pg_dump in a
follow-up commit that will use it to optimize dumpSequenceData().
Like pg_sequence_last_value(), which is a support function for the
pg_sequences system view, pg_sequence_read_tuple() is left
undocumented.

Bumps catversion.

Reviewed-by: Michael Paquier, Tom Lane
Discussion: https://postgr.es/m/20240503025140.GA1227404%40nathanxps13

src/backend/commands/sequence.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.dat
src/test/regress/expected/sequence.out
src/test/regress/sql/sequence.sql

index 9f28d40466b5a06762f4f4dde269377aea005783..8c1131f02028595316f3a06248b770f13f8c08bc 100644 (file)
@@ -1773,6 +1773,67 @@ 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] = {0};
+   bool        isnull[SEQ_COL_LASTCOL] = {0};
+   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);
+
+       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
  *
index 2f221b6ad0a49076238a5a338b628684a43e3365..d588daebb4617c063ba735243e641a5e242d0010 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202407252
+#define CATALOG_VERSION_NO 202407311
 
 #endif
index 06b2f4ba66c7569527225e0d2878676485946be3..54b50ee5d61b540dd273d1dc245731d40e57a81b 100644 (file)
   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',
index 2b47b7796b10892515fca03e56f8ca433397df8f..e749c4574e35e8603b7cc4a7524df13ca05fdf04 100644 (file)
@@ -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;
index 674f5f1f668189dbeddaede21e8f269c799d552b..ea447938aea12562f2828edbb54052683c264183 100644 (file)
@@ -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;