Add pg_sequences view
authorPeter Eisentraut
Fri, 18 Nov 2016 17:00:00 +0000 (12:00 -0500)
committerPeter Eisentraut
Fri, 18 Nov 2016 19:59:03 +0000 (14:59 -0500)
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.

To help implement the view, add a new internal function
pg_sequence_last_value() to return the last value of a sequence.  This
is kept separate from pg_sequence_parameters() to separate querying
run-time state from catalog-like information.

Reviewed-by: Andreas Karlsson
doc/src/sgml/catalogs.sgml
src/backend/catalog/system_views.sql
src/backend/commands/sequence.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/commands/sequence.h
src/test/regress/expected/rules.out
src/test/regress/expected/sequence.out
src/test/regress/expected/sequence_1.out
src/test/regress/sql/sequence.sql

index bac169a19e4f23e5508d534112db9cf88878f411..561e228558d8fda5c17f8d66ab59532ac6b00120 100644 (file)
       security labels
      
 
+     
+      pg_sequences
+      sequences
+     
+
      
       pg_settings
       parameter settings
@@ -9135,6 +9140,98 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
   
  
 
+  <structname>pg_sequences</structname>
+
+  
+   pg_sequences
+  
+
+  
+   The view pg_sequences provides access to
+   useful information about each sequence in the database.
+  
+
+  
+   <structname>pg_sequences</> Columns
+
+   
+    
+     
+      Name
+      Type
+      References
+      Description
+     
+    
+    
+     
+      schemaname
+      name
+      pg_namespace.nspname
+      Name of schema containing sequence
+     
+     
+      sequencename
+      name
+      pg_class.relname
+      Name of sequence
+     
+     
+      sequenceowner
+      name
+      pg_authid.rolname
+      Name of sequence's owner
+     
+     
+      start_value
+      bigint
+      
+      Start value of the sequence
+     
+     
+      min_value
+      bigint
+      
+      Minimum value of the sequence
+     
+     
+      max_value
+      bigint
+      
+      Maximum value of the sequence
+     
+     
+      increment_by
+      bigint
+      
+      Increment value of the sequence
+     
+     
+      cycle
+      boolean
+      
+      Whether the sequence cycles
+     
+     
+      cache_size
+      bigint
+      
+      Cache size of the sequence
+     
+     
+      last_value
+      bigint
+      
+      The last sequence value written to disk.  If caching is used,
+       this value can be greater than the last value handed out from the
+       sequence.  Null if the sequence has not been read from yet.
+     
+    
+   
+  
+
  
   <structname>pg_settings</structname>
 
index ada214274fa26d7dd35ec58d04ed80241995d163..e011af122c5bec0d6bc6cd52e6b6fa4932ef189e 100644 (file)
@@ -158,6 +158,23 @@ 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,
+        pg_sequence_last_value(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 NOT pg_is_other_temp_schema(N.oid)
+          AND relkind = 'S';
+
 CREATE VIEW pg_stats WITH (security_barrier) AS
     SELECT
         nspname AS schemaname,
index fc3a8eebce3389f155e3e30046433ad451046865..7e37108b8d673d424a8473f21dde3a7f8031f717 100644 (file)
@@ -1534,8 +1534,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 +1551,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 +1562,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 +1576,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);
@@ -1581,6 +1584,46 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
    return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
+/*
+ * Return the last value from the sequence
+ *
+ * Note: This has a completely different meaning than lastval().
+ */
+Datum
+pg_sequence_last_value(PG_FUNCTION_ARGS)
+{
+   Oid         relid = PG_GETARG_OID(0);
+   SeqTable    elm;
+   Relation    seqrel;
+   Buffer      buf;
+   HeapTupleData seqtuple;
+   Form_pg_sequence seq;
+   bool        is_called;
+   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);
+
+   is_called = seq->is_called;
+   result = seq->last_value;
+
+   UnlockReleaseBuffer(buf);
+   relation_close(seqrel, NoLock);
+
+   if (is_called)
+       PG_RETURN_INT64(result);
+   else
+       PG_RETURN_NULL();
+}
+
 
 void
 seq_redo(XLogReaderState *record)
index 880559650ad07d7c23659cd2620f47334950e49a..ef0386ceda5da5d2f069b851cb1d0a9e74fa23ed 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201611041
+#define CATALOG_VERSION_NO 201611181
 
 #endif
index 17ec71d47eeacd586dfbf93c1d6adad07398da3d..047a1ce71c14272ab7b0c2eaf6fd48e13784e226 100644 (file)
@@ -1763,8 +1763,10 @@ DATA(insert OID = 1576 (  setval         PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 20
 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 = 4032 ( pg_sequence_last_value        PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 20 "2205" _null_ _null_ _null_ _null_ _null_ pg_sequence_last_value _null_ _null_ _null_ ));
+DESCR("sequence last value");
 
 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_ ));
 DESCR("I/O");
index 392a6265082ab36ef636397e3783d1e621796221..6695bbe4c7accafe89915e02865d946ce43ce5a1 100644 (file)
@@ -73,6 +73,7 @@ extern Datum setval3_oid(PG_FUNCTION_ARGS);
 extern Datum lastval(PG_FUNCTION_ARGS);
 
 extern Datum pg_sequence_parameters(PG_FUNCTION_ARGS);
+extern Datum pg_sequence_last_value(PG_FUNCTION_ARGS);
 
 extern ObjectAddress DefineSequence(ParseState *pstate, CreateSeqStmt *stmt);
 extern ObjectAddress AlterSequence(ParseState *pstate, AlterSeqStmt *stmt);
index 5e2962c681dd873cae8b32835a3b1b616f8c8756..031e8c2ef5307500adcbdcdafc910f38fa77ca70 100644 (file)
@@ -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,
+    pg_sequence_last_value((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 ((NOT pg_is_other_temp_schema(n.oid)) AND (c.relkind = 'S'::"char"));
 pg_settings| SELECT a.name,
     a.setting,
     a.unit,
index 4ffbe92ab37d0a65413e1059ce096f763c80771b..c5413e09f3b0e99b8629396d7342b58acba4ac2c 100644 (file)
@@ -300,20 +300,39 @@ SELECT nextval('sequence_test2');
        5
 (1 row)
 
+CREATE SEQUENCE sequence_test3;  -- not read from, to test is_called
 -- Information schema
 SELECT * FROM information_schema.sequences WHERE sequence_name IN
-  ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
+  ('sequence_test2', 'sequence_test3', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
    'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq')
   ORDER BY sequence_name ASC;
  sequence_catalog | sequence_schema |   sequence_name    | data_type | numeric_precision | numeric_precision_radix | numeric_scale | start_value | minimum_value |    maximum_value    | increment | cycle_option 
 ------------------+-----------------+--------------------+-----------+-------------------+-------------------------+---------------+-------------+---------------+---------------------+-----------+--------------
  regression       | public          | sequence_test2     | bigint    |                64 |                       2 |             0 | 32          | 5             | 36                  | 4         | YES
+ regression       | public          | sequence_test3     | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
  regression       | public          | serialtest2_f2_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
  regression       | public          | serialtest2_f3_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
  regression       | public          | serialtest2_f4_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
  regression       | public          | serialtest2_f5_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
  regression       | public          | serialtest2_f6_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
-(6 rows)
+(7 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', 'sequence_test3', '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     | sequence_test3     |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |           
+ 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
+(7 rows)
 
 -- Test comments
 COMMENT ON SEQUENCE asdf IS 'won''t work';
index 05da2bf1adedaead9db18166bb49529dc508595b..816424492780f3b68481da4d092d7a6c5acb90cd 100644 (file)
@@ -300,20 +300,39 @@ SELECT nextval('sequence_test2');
        5
 (1 row)
 
+CREATE SEQUENCE sequence_test3;  -- not read from, to test is_called
 -- Information schema
 SELECT * FROM information_schema.sequences WHERE sequence_name IN
-  ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
+  ('sequence_test2', 'sequence_test3', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
    'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq')
   ORDER BY sequence_name ASC;
  sequence_catalog | sequence_schema |   sequence_name    | data_type | numeric_precision | numeric_precision_radix | numeric_scale | start_value | minimum_value |    maximum_value    | increment | cycle_option 
 ------------------+-----------------+--------------------+-----------+-------------------+-------------------------+---------------+-------------+---------------+---------------------+-----------+--------------
  regression       | public          | sequence_test2     | bigint    |                64 |                       2 |             0 | 32          | 5             | 36                  | 4         | YES
+ regression       | public          | sequence_test3     | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
  regression       | public          | serialtest2_f2_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
  regression       | public          | serialtest2_f3_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
  regression       | public          | serialtest2_f4_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
  regression       | public          | serialtest2_f5_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
  regression       | public          | serialtest2_f6_seq | bigint    |                64 |                       2 |             0 | 1           | 1             | 9223372036854775807 | 1         | NO
-(6 rows)
+(7 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', 'sequence_test3', '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     | sequence_test3     |           1 |         1 | 9223372036854775807 |            1 | f     |          1 |           
+ 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
+(7 rows)
 
 -- Test comments
 COMMENT ON SEQUENCE asdf IS 'won''t work';
index 98a2e7db36d0456d7d098049b03a2c8721c35511..e2b6b6339305a0af59b53e778f6ec1f9d9b6e9e0 100644 (file)
@@ -138,12 +138,23 @@ SELECT nextval('sequence_test2');
 SELECT nextval('sequence_test2');
 SELECT nextval('sequence_test2');
 
+
+CREATE SEQUENCE sequence_test3;  -- not read from, to test is_called
+
+
 -- Information schema
 SELECT * FROM information_schema.sequences WHERE sequence_name IN
-  ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
+  ('sequence_test2', 'sequence_test3', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
    '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', 'sequence_test3', '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';