On 9/5/16 10:35 PM, Tom Lane wrote:
> In this viewpoint, we'd keep the sequence-specific data in a pg_sequence
> catalog.  pg_sequence rows would be extensions of the associated pg_class
> rows in much the same way that pg_index rows extend the pg_class entries
> for indexes.  We should supply a view pg_sequences that performs the
> implied join, and encourage users to select from that rather than directly
> from pg_sequence (compare pg_indexes view).

Let's start with that.  Here is a patch that adds a pg_sequences view in
the style of pg_tables, pg_indexes, etc.  This seems useful independent
of anything else, but would give us more freedom to change things around
behind the scenes.

A slight naming wart: I added a function lastval(regclass) for internal
use to get a sequence's "last value".  But we already have a public
function lastval(), which gets the most recent nextval() result of any
sequence.  Those are two quite different things.  I don't want to
abandon the term "last value" here, however, because that is what the
sequence relation uses internally, and also Oracle uses it in its system
views with the same semantics that I propose here.  We could use a more
verbose name like sequence_last_value(regclass), perhaps.

lastval has been kept separate from pg_sequence_parameters, because if
we were to go ahead with a new catalog layout later, then
pg_sequence_parameters would become obsolescent while we would possibly
still need a lastval function.

The column names of the new view have been deliberately tuned to use a
more conventional style than the information schema while avoiding what
I would consider some past naming mistakes.  (For example, I hate
"is_cycled", which reads like "sequence has wrapped around at least once
in the past").

Here are some similar views in other places:

https://docs.oracle.com/cd/B28359_01/server.111/b28320/statviews_2053.htm
https://www.ibm.com/support/knowledgecenter/en/SSEPGG_9.7.0/com.ibm.db2.luw.sql.ref.doc/doc/r0004203.html
https://msdn.microsoft.com/en-us/library/ff877934.aspx

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From f74e1cc1f6ee4a56abc9f46c413c0af5086e1e40 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pete...@gmx.net>
Date: Fri, 9 Sep 2016 12:00:00 -0400
Subject: [PATCH] Add pg_sequences view

Like pg_tables, pg_views, and others, this view contains information
about sequences in a way that is independent of the system catalog
layout but more comprehensive than the information schema.
---
 doc/src/sgml/catalogs.sgml               | 90 ++++++++++++++++++++++++++++++++
 src/backend/catalog/system_views.sql     | 16 ++++++
 src/backend/commands/sequence.c          | 45 ++++++++++++++--
 src/include/catalog/pg_proc.h            |  4 +-
 src/include/commands/sequence.h          |  1 +
 src/test/regress/expected/rules.out      | 14 +++++
 src/test/regress/expected/sequence.out   | 16 ++++++
 src/test/regress/expected/sequence_1.out | 16 ++++++
 src/test/regress/sql/sequence.sql        |  7 +++
 9 files changed, 205 insertions(+), 4 deletions(-)

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 322d8d6..1c440e3 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -7379,6 +7379,11 @@ <title>System Views</title>
      </row>
 
      <row>
+      <entry><link linkend="view-pg-sequences"><structname>pg_sequences</structname></link></entry>
+      <entry>sequences</entry>
+     </row>
+
+     <row>
       <entry><link linkend="view-pg-settings"><structname>pg_settings</structname></link></entry>
       <entry>parameter settings</entry>
      </row>
@@ -9114,6 +9119,91 @@ <title><structname>pg_seclabels</> Columns</title>
   </table>
  </sect1>
 
+ <sect1 id="view-pg-sequences">
+  <title><structname>pg_sequences</structname></title>
+
+  <indexterm zone="view-pg-sequences">
+   <primary>pg_sequences</primary>
+  </indexterm>
+
+  <para>
+   The view <structname>pg_sequences</structname> provides access to
+   useful information about each sequence in the database.
+  </para>
+
+  <table>
+   <title><structname>pg_sequences</> Columns</title>
+
+   <tgroup cols="4">
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+    <tbody>
+     <row>
+      <entry><structfield>schemaname</structfield></entry>
+      <entry><type>name</type></entry>
+      <entry><literal><link linkend="catalog-pg-namespace"><structname>pg_namespace</structname></link>.nspname</literal></entry>
+      <entry>Name of schema containing sequence</entry>
+     </row>
+     <row>
+      <entry><structfield>sequencename</structfield></entry>
+      <entry><type>name</type></entry>
+      <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relname</literal></entry>
+      <entry>Name of sequence</entry>
+     </row>
+     <row>
+      <entry><structfield>sequenceowner</structfield></entry>
+      <entry><type>name</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.rolname</literal></entry>
+      <entry>Name of sequence's owner</entry>
+     </row>
+     <row>
+      <entry><structfield>start_value</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry></entry>
+      <entry>Start value of the sequence</entry>
+     </row>
+     <row>
+      <entry><structfield>min_value</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry></entry>
+      <entry>Minimum value of the sequence</entry>
+     </row>
+     <row>
+      <entry><structfield>max_value</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry></entry>
+      <entry>Maximum value of the sequence</entry>
+     </row>
+     <row>
+      <entry><structfield>increment_by</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry></entry>
+      <entry>Increment value of the sequence</entry>
+     </row>
+     <row>
+      <entry><structfield>cycle</structfield></entry>
+      <entry><type>boolean</type></entry>
+      <entry></entry>
+      <entry>Whether the sequence cycles</entry>
+     </row>
+     <row>
+      <entry><structfield>cache_size</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry></entry>
+      <entry>Cache size of the sequence</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect1>
+
  <sect1 id="view-pg-settings">
   <title><structname>pg_settings</structname></title>
 
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index ada2142..99a9b41 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -158,6 +158,22 @@ CREATE VIEW pg_indexes AS
          LEFT JOIN pg_tablespace T ON (T.oid = I.reltablespace)
     WHERE C.relkind IN ('r', 'm') AND I.relkind = 'i';
 
+CREATE OR REPLACE VIEW pg_sequences AS
+    SELECT
+        N.nspname AS schemaname,
+        C.relname AS sequencename,
+        pg_get_userbyid(C.relowner) AS sequenceowner,
+        p.start_value AS start_value,
+        p.minimum_value AS min_value,
+        p.maximum_value AS max_value,
+        p.increment AS increment_by,
+        p.cycle_option AS cycle,
+        p.cache_size AS cache_size,
+        lastval(C.oid) AS last_value
+    FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace),
+         LATERAL pg_sequence_parameters(C.oid) p
+    WHERE relkind = 'S';
+
 CREATE VIEW pg_stats WITH (security_barrier) AS
     SELECT
         nspname AS schemaname,
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index fc3a8ee..4f3ca0e 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -835,6 +835,42 @@ lastval(PG_FUNCTION_ARGS)
 }
 
 /*
+ * Return the last value from the sequence
+ *
+ * XXX This has completely different semantics from lastval() without
+ * arguments.
+ */
+Datum
+lastval1(PG_FUNCTION_ARGS)
+{
+	Oid			relid = PG_GETARG_OID(0);
+	SeqTable	elm;
+	Relation	seqrel;
+	Buffer		buf;
+	HeapTupleData seqtuple;
+	Form_pg_sequence seq;
+	int64		result;
+
+	/* open and AccessShareLock sequence */
+	init_sequence(relid, &elm, &seqrel);
+
+	if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				 errmsg("permission denied for sequence %s",
+						RelationGetRelationName(seqrel))));
+
+	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
+
+	result = seq->last_value;
+
+	UnlockReleaseBuffer(buf);
+	relation_close(seqrel, NoLock);
+
+	PG_RETURN_INT64(result);
+}
+
+/*
  * Main internal procedure that handles 2 & 3 arg forms of SETVAL.
  *
  * Note that the 3 arg version (which sets the is_called flag) is
@@ -1534,8 +1570,8 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 {
 	Oid			relid = PG_GETARG_OID(0);
 	TupleDesc	tupdesc;
-	Datum		values[5];
-	bool		isnull[5];
+	Datum		values[6];
+	bool		isnull[6];
 	SeqTable	elm;
 	Relation	seqrel;
 	Buffer		buf;
@@ -1551,7 +1587,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 				 errmsg("permission denied for sequence %s",
 						RelationGetRelationName(seqrel))));
 
-	tupdesc = CreateTemplateTupleDesc(5, false);
+	tupdesc = CreateTemplateTupleDesc(6, false);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "start_value",
 					   INT8OID, -1, 0);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "minimum_value",
@@ -1562,6 +1598,8 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 					   INT8OID, -1, 0);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 5, "cycle_option",
 					   BOOLOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 6, "cache_size",
+					   INT8OID, -1, 0);
 
 	BlessTupleDesc(tupdesc);
 
@@ -1574,6 +1612,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 	values[2] = Int64GetDatum(seq->max_value);
 	values[3] = Int64GetDatum(seq->increment_by);
 	values[4] = BoolGetDatum(seq->is_cycled);
+	values[5] = Int64GetDatum(seq->cache_value);
 
 	UnlockReleaseBuffer(buf);
 	relation_close(seqrel, NoLock);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index e2d08ba..1220bad 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1762,11 +1762,13 @@ DATA(insert OID = 1574 (  nextval			PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 2
 DESCR("sequence next value");
 DATA(insert OID = 1575 (  currval			PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 20 "2205" _null_ _null_ _null_ _null_ _null_ currval_oid _null_ _null_ _null_ ));
 DESCR("sequence current value");
+DATA(insert OID = 4032 ( lastval			PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 20 "2205" _null_ _null_ _null_ _null_ _null_	lastval1 _null_ _null_ _null_ ));
+DESCR("sequence last value");
 DATA(insert OID = 1576 (  setval			PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 20 "2205 20" _null_ _null_ _null_ _null_  _null_ setval_oid _null_ _null_ _null_ ));
 DESCR("set sequence value");
 DATA(insert OID = 1765 (  setval			PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 20 "2205 20 16" _null_ _null_ _null_ _null_ _null_ setval3_oid _null_ _null_ _null_ ));
 DESCR("set sequence value and is_called status");
-DATA(insert OID = 3078 (  pg_sequence_parameters	PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 2249 "26" "{26,20,20,20,20,16}" "{i,o,o,o,o,o}" "{sequence_oid,start_value,minimum_value,maximum_value,increment,cycle_option}" _null_ _null_ pg_sequence_parameters _null_ _null_ _null_));
+DATA(insert OID = 3078 (  pg_sequence_parameters	PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 2249 "26" "{26,20,20,20,20,16,20}" "{i,o,o,o,o,o,o}" "{sequence_oid,start_value,minimum_value,maximum_value,increment,cycle_option,cache_size}" _null_ _null_ pg_sequence_parameters _null_ _null_ _null_));
 DESCR("sequence parameters, for use by information schema");
 
 DATA(insert OID = 1579 (  varbit_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1562 "2275 26 23" _null_ _null_ _null_ _null_ _null_ varbit_in _null_ _null_ _null_ ));
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 392a626..0b115d6 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -71,6 +71,7 @@ extern Datum currval_oid(PG_FUNCTION_ARGS);
 extern Datum setval_oid(PG_FUNCTION_ARGS);
 extern Datum setval3_oid(PG_FUNCTION_ARGS);
 extern Datum lastval(PG_FUNCTION_ARGS);
+extern Datum lastval1(PG_FUNCTION_ARGS);
 
 extern Datum pg_sequence_parameters(PG_FUNCTION_ARGS);
 
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 00700f2..0ce8b24 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1615,6 +1615,20 @@ UNION ALL
     l.label
    FROM (pg_shseclabel l
      JOIN pg_authid rol ON (((l.classoid = rol.tableoid) AND (l.objoid = rol.oid))));
+pg_sequences| SELECT n.nspname AS schemaname,
+    c.relname AS sequencename,
+    pg_get_userbyid(c.relowner) AS sequenceowner,
+    p.start_value,
+    p.minimum_value AS min_value,
+    p.maximum_value AS max_value,
+    p.increment AS increment_by,
+    p.cycle_option AS cycle,
+    p.cache_size,
+    lastval((c.oid)::regclass) AS last_value
+   FROM (pg_class c
+     LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))),
+    LATERAL pg_sequence_parameters(c.oid) p(start_value, minimum_value, maximum_value, increment, cycle_option, cache_size)
+  WHERE (c.relkind = 'S'::"char");
 pg_settings| SELECT a.name,
     a.setting,
     a.unit,
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 4ffbe92..5231c27 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -315,6 +315,22 @@ SELECT * FROM information_schema.sequences WHERE sequence_name IN
  regression       | public          | serialtest2_f6_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
 (6 rows)
 
+SELECT schemaname, sequencename, start_value, min_value, max_value, increment_by, cycle, cache_size, last_value
+FROM pg_sequences
+WHERE sequencename IN
+  ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
+   'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq')
+  ORDER BY sequencename ASC;
+ schemaname |    sequencename    | start_value | min_value |      max_value      | increment_by | cycle | cache_size | last_value 
+------------+--------------------+-------------+-----------+---------------------+--------------+-------+------------+------------
+ public     | sequence_test2     |          32 |         5 |                  36 |            4 | t     |          1 |          5
+ public     | serialtest2_f2_seq |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |          2
+ public     | serialtest2_f3_seq |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |          2
+ public     | serialtest2_f4_seq |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |          2
+ public     | serialtest2_f5_seq |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |          2
+ public     | serialtest2_f6_seq |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |          2
+(6 rows)
+
 -- Test comments
 COMMENT ON SEQUENCE asdf IS 'won''t work';
 ERROR:  relation "asdf" does not exist
diff --git a/src/test/regress/expected/sequence_1.out b/src/test/regress/expected/sequence_1.out
index 05da2bf..977bf02 100644
--- a/src/test/regress/expected/sequence_1.out
+++ b/src/test/regress/expected/sequence_1.out
@@ -315,6 +315,22 @@ SELECT * FROM information_schema.sequences WHERE sequence_name IN
  regression       | public          | serialtest2_f6_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
 (6 rows)
 
+SELECT schemaname, sequencename, start_value, min_value, max_value, increment_by, cycle, cache_size, last_value
+FROM pg_sequences
+WHERE sequencename IN
+  ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
+   'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq')
+  ORDER BY sequencename ASC;
+ schemaname |    sequencename    | start_value | min_value |      max_value      | increment_by | cycle | cache_size | last_value 
+------------+--------------------+-------------+-----------+---------------------+--------------+-------+------------+------------
+ public     | sequence_test2     |          32 |         5 |                  36 |            4 | t     |          1 |          5
+ public     | serialtest2_f2_seq |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |          2
+ public     | serialtest2_f3_seq |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |          2
+ public     | serialtest2_f4_seq |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |          2
+ public     | serialtest2_f5_seq |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |          2
+ public     | serialtest2_f6_seq |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |          2
+(6 rows)
+
 -- Test comments
 COMMENT ON SEQUENCE asdf IS 'won''t work';
 ERROR:  relation "asdf" does not exist
diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql
index 98a2e7d..5333b20 100644
--- a/src/test/regress/sql/sequence.sql
+++ b/src/test/regress/sql/sequence.sql
@@ -144,6 +144,13 @@ CREATE SEQUENCE sequence_test2 START WITH 32;
    'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq')
   ORDER BY sequence_name ASC;
 
+SELECT schemaname, sequencename, start_value, min_value, max_value, increment_by, cycle, cache_size, last_value
+FROM pg_sequences
+WHERE sequencename IN
+  ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
+   'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq')
+  ORDER BY sequencename ASC;
+
 -- Test comments
 COMMENT ON SEQUENCE asdf IS 'won''t work';
 COMMENT ON SEQUENCE sequence_test2 IS 'will work';
-- 
2.10.0

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to