Commit 1753b1b0 authored by Peter Eisentraut's avatar Peter Eisentraut

Add pg_sequence system catalog

Move sequence metadata (start, increment, etc.) into a proper system
catalog instead of storing it in the sequence heap object.  This
separates the metadata from the sequence data.  Sequence metadata is now
operated on transactionally by DDL commands, whereas previously
rollbacks of sequence-related DDL commands would be ignored.
Reviewed-by: default avatarAndreas Karlsson <andreas@proxel.se>
parent db80acfc
......@@ -260,6 +260,11 @@
<entry>security labels on database objects</entry>
</row>
<row>
<entry><link linkend="catalog-pg-sequence"><structname>pg_sequence</structname></link></entry>
<entry>information about sequences</entry>
</row>
<row>
<entry><link linkend="catalog-pg-shdepend"><structname>pg_shdepend</structname></link></entry>
<entry>dependencies on shared objects</entry>
......@@ -1546,7 +1551,8 @@
The catalog <structname>pg_class</structname> catalogs tables and most
everything else that has columns or is otherwise similar to a
table. This includes indexes (but see also
<structname>pg_index</structname>), sequences, views, materialized
<structname>pg_index</structname>), sequences (but see also
<structname>pg_sequence</structname>), views, materialized
views, composite types, and TOAST tables; see <structfield>relkind</>.
Below, when we mean all of these
kinds of objects we speak of <quote>relations</quote>. Not all
......@@ -5587,6 +5593,86 @@
</table>
</sect1>
<sect1 id="catalog-pg-sequence">
<title><structname>pg_sequence</structname></title>
<indexterm zone="catalog-pg-sequence">
<primary>pg_sequence</primary>
</indexterm>
<para>
The catalog <structname>pg_sequence</structname> contains information about
sequences. Some of the information about sequences, such as the name and
the schema, is in <structname>pg_class</structname>.
</para>
<table>
<title><structname>pg_sequence</> 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>seqrelid</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
<entry>The OID of the <structname>pg_class</> entry for this sequence</entry>
</row>
<row>
<entry><structfield>seqstart</structfield></entry>
<entry><type>int8</type></entry>
<entry></entry>
<entry>Start value of the sequence</entry>
</row>
<row>
<entry><structfield>seqincrement</structfield></entry>
<entry><type>int8</type></entry>
<entry></entry>
<entry>Increment value of the sequence</entry>
</row>
<row>
<entry><structfield>seqmax</structfield></entry>
<entry><type>int8</type></entry>
<entry></entry>
<entry>Maximum value of the sequence</entry>
</row>
<row>
<entry><structfield>seqmin</structfield></entry>
<entry><type>int8</type></entry>
<entry></entry>
<entry>Minimum value of the sequence</entry>
</row>
<row>
<entry><structfield>seqcache</structfield></entry>
<entry><type>int8</type></entry>
<entry></entry>
<entry>Cache size of the sequence</entry>
</row>
<row>
<entry><structfield>seqcycle</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
<entry>Whether the sequence cycles</entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1 id="catalog-pg-shdepend">
<title><structname>pg_shdepend</structname></title>
......
......@@ -42,6 +42,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_foreign_table.h pg_policy.h pg_replication_origin.h \
pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \
pg_collation.h pg_partitioned_table.h pg_range.h pg_transform.h \
pg_sequence.h \
toasting.h indexing.h \
)
......
......@@ -66,6 +66,7 @@
#include "commands/proclang.h"
#include "commands/schemacmds.h"
#include "commands/seclabel.h"
#include "commands/sequence.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
#include "nodes/nodeFuncs.h"
......@@ -1114,6 +1115,11 @@ doDeletion(const ObjectAddress *object, int flags)
else
heap_drop_with_catalog(object->objectId);
}
/* for a sequence, in addition to dropping the heap, also
* delete pg_sequence tuple */
if (relKind == RELKIND_SEQUENCE)
DeleteSequenceTuple(object->objectId);
break;
}
......
......@@ -1535,15 +1535,16 @@ CREATE VIEW sequences AS
CAST(64 AS cardinal_number) AS numeric_precision,
CAST(2 AS cardinal_number) AS numeric_precision_radix,
CAST(0 AS cardinal_number) AS numeric_scale,
CAST(p.start_value AS character_data) AS start_value,
CAST(p.minimum_value AS character_data) AS minimum_value,
CAST(p.maximum_value AS character_data) AS maximum_value,
CAST(p.increment AS character_data) AS increment,
CAST(CASE WHEN p.cycle_option THEN 'YES' ELSE 'NO' END AS yes_or_no) AS cycle_option
FROM pg_namespace nc, pg_class c, LATERAL pg_sequence_parameters(c.oid) p
CAST(s.seqstart AS character_data) AS start_value,
CAST(s.seqmin AS character_data) AS minimum_value,
CAST(s.seqmax AS character_data) AS maximum_value,
CAST(s.seqincrement AS character_data) AS increment,
CAST(CASE WHEN s.seqcycle THEN 'YES' ELSE 'NO' END AS yes_or_no) AS cycle_option
FROM pg_namespace nc, pg_class c, pg_sequence s
WHERE c.relnamespace = nc.oid
AND c.relkind = 'S'
AND (NOT pg_is_other_temp_schema(nc.oid))
AND c.oid = s.seqrelid
AND (pg_has_role(c.relowner, 'USAGE')
OR has_sequence_privilege(c.oid, 'SELECT, UPDATE, USAGE') );
......
......@@ -169,15 +169,15 @@ CREATE OR REPLACE VIEW pg_sequences AS
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,
S.seqstart AS start_value,
S.seqmin AS min_value,
S.seqmax AS max_value,
S.seqincrement AS increment_by,
S.seqcycle AS cycle,
S.seqcache 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
FROM pg_sequence S JOIN pg_class C ON (C.oid = S.seqrelid)
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE NOT pg_is_other_temp_schema(N.oid)
AND relkind = 'S';
......
This diff is collapsed.
......@@ -53,6 +53,7 @@
#include "catalog/pg_range.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_seclabel.h"
#include "catalog/pg_sequence.h"
#include "catalog/pg_shdepend.h"
#include "catalog/pg_shdescription.h"
#include "catalog/pg_shseclabel.h"
......@@ -668,6 +669,17 @@ static const struct cachedesc cacheinfo[] = {
},
8
},
{SequenceRelationId, /* SEQRELID */
SequenceRelidIndexId,
1,
{
Anum_pg_sequence_seqrelid,
0,
0,
0
},
32
},
{StatisticRelationId, /* STATRELATTINH */
StatisticRelidAttnumInhIndexId,
3,
......
......@@ -15351,7 +15351,27 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
if (fout->remoteVersion >= 80400)
if (fout->remoteVersion >= 100000)
{
appendPQExpBuffer(query,
"SELECT relname, "
"seqstart, seqincrement, "
"CASE WHEN seqincrement > 0 AND seqmax = %s THEN NULL "
" WHEN seqincrement < 0 AND seqmax = -1 THEN NULL "
" ELSE seqmax "
"END AS seqmax, "
"CASE WHEN seqincrement > 0 AND seqmin = 1 THEN NULL "
" WHEN seqincrement < 0 AND seqmin = %s THEN NULL "
" ELSE seqmin "
"END AS seqmin, "
"seqcache, seqcycle "
"FROM pg_class c "
"JOIN pg_sequence s ON (s.seqrelid = c.oid) "
"WHERE relname = ",
bufx, bufm);
appendStringLiteralAH(query, tbinfo->dobj.name, fout);
}
else if (fout->remoteVersion >= 80400)
{
appendPQExpBuffer(query,
"SELECT sequence_name, "
......
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201612121
#define CATALOG_VERSION_NO 201612201
#endif
......@@ -209,6 +209,9 @@ DECLARE_UNIQUE_INDEX(pg_rewrite_oid_index, 2692, on pg_rewrite using btree(oid o
DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index, 2693, on pg_rewrite using btree(ev_class oid_ops, rulename name_ops));
#define RewriteRelRulenameIndexId 2693
DECLARE_UNIQUE_INDEX(pg_sequence_seqrelid_index, 5002, on pg_sequence using btree(seqrelid oid_ops));
#define SequenceRelidIndexId 5002
DECLARE_INDEX(pg_shdepend_depender_index, 1232, on pg_shdepend using btree(dbid oid_ops, classid oid_ops, objid oid_ops, objsubid int4_ops));
#define SharedDependDependerIndexId 1232
DECLARE_INDEX(pg_shdepend_reference_index, 1233, on pg_shdepend using btree(refclassid oid_ops, refobjid oid_ops));
......
#ifndef PG_SEQUENCE_H
#define PG_SEQUENCE_H
#include "catalog/genbki.h"
#define SequenceRelationId 2224
CATALOG(pg_sequence,2224) BKI_WITHOUT_OIDS
{
Oid seqrelid;
int64 seqstart;
int64 seqincrement;
int64 seqmax;
int64 seqmin;
int64 seqcache;
bool seqcycle;
} FormData_pg_sequence;
typedef FormData_pg_sequence *Form_pg_sequence;
#define Natts_pg_sequence 7
#define Anum_pg_sequence_seqrelid 1
#define Anum_pg_sequence_seqstart 2
#define Anum_pg_sequence_seqincrement 3
#define Anum_pg_sequence_seqmax 4
#define Anum_pg_sequence_seqmin 5
#define Anum_pg_sequence_seqcache 6
#define Anum_pg_sequence_seqcycle 7
#endif /* PG_SEQUENCE_H */
......@@ -22,38 +22,24 @@
#include "storage/relfilenode.h"
typedef struct FormData_pg_sequence
typedef struct FormData_pg_sequence_data
{
NameData sequence_name;
int64 last_value;
int64 start_value;
int64 increment_by;
int64 max_value;
int64 min_value;
int64 cache_value;
int64 log_cnt;
bool is_cycled;
bool is_called;
} FormData_pg_sequence;
} FormData_pg_sequence_data;
typedef FormData_pg_sequence *Form_pg_sequence;
typedef FormData_pg_sequence_data *Form_pg_sequence_data;
/*
* Columns of a sequence relation
*/
#define SEQ_COL_NAME 1
#define SEQ_COL_LASTVAL 2
#define SEQ_COL_STARTVAL 3
#define SEQ_COL_INCBY 4
#define SEQ_COL_MAXVALUE 5
#define SEQ_COL_MINVALUE 6
#define SEQ_COL_CACHE 7
#define SEQ_COL_LOG 8
#define SEQ_COL_CYCLE 9
#define SEQ_COL_CALLED 10
#define SEQ_COL_LASTVAL 1
#define SEQ_COL_LOG 2
#define SEQ_COL_CALLED 3
#define SEQ_COL_FIRSTCOL SEQ_COL_NAME
#define SEQ_COL_FIRSTCOL SEQ_COL_LASTVAL
#define SEQ_COL_LASTCOL SEQ_COL_CALLED
/* XLOG stuff */
......@@ -77,6 +63,7 @@ extern Datum pg_sequence_last_value(PG_FUNCTION_ARGS);
extern ObjectAddress DefineSequence(ParseState *pstate, CreateSeqStmt *stmt);
extern ObjectAddress AlterSequence(ParseState *pstate, AlterSeqStmt *stmt);
extern void DeleteSequenceTuple(Oid relid);
extern void ResetSequence(Oid seq_relid);
extern void ResetSequenceCaches(void);
......
......@@ -81,6 +81,7 @@ enum SysCacheIdentifier
REPLORIGIDENT,
REPLORIGNAME,
RULERELNAME,
SEQRELID,
STATRELATTINH,
TABLESPACEOID,
TRFOID,
......
......@@ -1623,16 +1623,16 @@ UNION ALL
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,
s.seqstart AS start_value,
s.seqmin AS min_value,
s.seqmax AS max_value,
s.seqincrement AS increment_by,
s.seqcycle AS cycle,
s.seqcache AS 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)
FROM ((pg_sequence s
JOIN pg_class c ON ((c.oid = s.seqrelid)))
LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
WHERE ((NOT pg_is_other_temp_schema(n.oid)) AND (c.relkind = 'S'::"char"));
pg_settings| SELECT a.name,
a.setting,
......
......@@ -128,6 +128,7 @@ pg_range|t
pg_replication_origin|t
pg_rewrite|t
pg_seclabel|t
pg_sequence|t
pg_shdepend|t
pg_shdescription|t
pg_shseclabel|t
......
......@@ -173,9 +173,9 @@ DROP SEQUENCE sequence_test;
CREATE SEQUENCE foo_seq;
ALTER TABLE foo_seq RENAME TO foo_seq_new;
SELECT * FROM foo_seq_new;
sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called
---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
foo_seq | 1 | 1 | 1 | 9223372036854775807 | 1 | 1 | 0 | f | f
last_value | log_cnt | is_called
------------+---------+-----------
1 | 0 | f
(1 row)
SELECT nextval('foo_seq_new');
......@@ -191,9 +191,9 @@ SELECT nextval('foo_seq_new');
(1 row)
SELECT * FROM foo_seq_new;
sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called
---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
foo_seq | 2 | 1 | 1 | 9223372036854775807 | 1 | 1 | 31 | f | t
last_value | log_cnt | is_called
------------+---------+-----------
2 | 31 | t
(1 row)
DROP SEQUENCE foo_seq_new;
......@@ -536,3 +536,24 @@ SELECT * FROM information_schema.sequences WHERE sequence_name IN
DROP USER regress_seq_user;
DROP SEQUENCE seq;
-- cache tests
CREATE SEQUENCE test_seq1 CACHE 10;
SELECT nextval('test_seq1');
nextval
---------
1
(1 row)
SELECT nextval('test_seq1');
nextval
---------
2
(1 row)
SELECT nextval('test_seq1');
nextval
---------
3
(1 row)
DROP SEQUENCE test_seq1;
......@@ -86,55 +86,48 @@ SELECT table_name, column_name, is_updatable
FROM information_schema.columns
WHERE table_name LIKE E'r_\\_view%'
ORDER BY table_name, ordinal_position;
table_name | column_name | is_updatable
------------+---------------+--------------
ro_view1 | a | NO
ro_view1 | b | NO
ro_view10 | a | NO
ro_view11 | a | NO
ro_view11 | b | NO
ro_view12 | a | NO
ro_view13 | a | NO
ro_view13 | b | NO
ro_view17 | a | NO
ro_view17 | b | NO
ro_view18 | a | NO
ro_view19 | sequence_name | NO
ro_view19 | last_value | NO
ro_view19 | start_value | NO
ro_view19 | increment_by | NO
ro_view19 | max_value | NO
ro_view19 | min_value | NO
ro_view19 | cache_value | NO
ro_view19 | log_cnt | NO
ro_view19 | is_cycled | NO
ro_view19 | is_called | NO
ro_view2 | a | NO
ro_view2 | b | NO
ro_view20 | a | NO
ro_view20 | b | NO
ro_view20 | g | NO
ro_view3 | ?column? | NO
ro_view4 | count | NO
ro_view5 | a | NO
ro_view5 | rank | NO
ro_view6 | a | NO
ro_view6 | b | NO
ro_view7 | a | NO
ro_view7 | b | NO
ro_view8 | a | NO
ro_view8 | b | NO
ro_view9 | a | NO
ro_view9 | b | NO
rw_view14 | ctid | NO
rw_view14 | a | YES
rw_view14 | b | YES
rw_view15 | a | YES
rw_view15 | upper | NO
rw_view16 | a | YES
rw_view16 | b | YES
rw_view16 | aa | YES
(46 rows)
table_name | column_name | is_updatable
------------+-------------+--------------
ro_view1 | a | NO
ro_view1 | b | NO
ro_view10 | a | NO
ro_view11 | a | NO
ro_view11 | b | NO
ro_view12 | a | NO
ro_view13 | a | NO
ro_view13 | b | NO
ro_view17 | a | NO
ro_view17 | b | NO
ro_view18 | a | NO
ro_view19 | last_value | NO
ro_view19 | log_cnt | NO
ro_view19 | is_called | NO
ro_view2 | a | NO
ro_view2 | b | NO
ro_view20 | a | NO
ro_view20 | b | NO
ro_view20 | g | NO
ro_view3 | ?column? | NO
ro_view4 | count | NO
ro_view5 | a | NO
ro_view5 | rank | NO
ro_view6 | a | NO
ro_view6 | b | NO
ro_view7 | a | NO
ro_view7 | b | NO
ro_view8 | a | NO
ro_view8 | b | NO
ro_view9 | a | NO
ro_view9 | b | NO
rw_view14 | ctid | NO
rw_view14 | a | YES
rw_view14 | b | YES
rw_view15 | a | YES
rw_view15 | upper | NO
rw_view16 | a | YES
rw_view16 | b | YES
rw_view16 | aa | YES
(39 rows)
-- Read-only views
DELETE FROM ro_view1;
......@@ -327,7 +320,7 @@ DELETE FROM ro_view18;
ERROR: cannot delete from view "ro_view18"
DETAIL: Views that do not select from a single table or view are not automatically updatable.
HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.
UPDATE ro_view19 SET max_value=1000;
UPDATE ro_view19 SET last_value=1000;
ERROR: cannot update view "ro_view19"
DETAIL: Views that do not select from a single table or view are not automatically updatable.
HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.
......
......@@ -273,3 +273,11 @@ SELECT * FROM information_schema.sequences WHERE sequence_name IN
DROP USER regress_seq_user;
DROP SEQUENCE seq;
-- cache tests
CREATE SEQUENCE test_seq1 CACHE 10;
SELECT nextval('test_seq1');
SELECT nextval('test_seq1');
SELECT nextval('test_seq1');
DROP SEQUENCE test_seq1;
......@@ -95,7 +95,7 @@ DELETE FROM rw_view16 WHERE a=-3; -- should be OK
-- Read-only views
INSERT INTO ro_view17 VALUES (3, 'ROW 3');
DELETE FROM ro_view18;
UPDATE ro_view19 SET max_value=1000;
UPDATE ro_view19 SET last_value=1000;
UPDATE ro_view20 SET b=upper(b);
DROP TABLE base_tbl CASCADE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment