diff options
author | Peter Eisentraut <peter@eisentraut.org> | 2022-04-07 16:13:23 +0200 |
---|---|---|
committer | Peter Eisentraut <peter@eisentraut.org> | 2022-04-07 16:18:00 +0200 |
commit | 344d62fb9a978a72cf8347f0369b9ee643fd0b31 (patch) | |
tree | d91171f80e9447b6e64614b76fe4b53045e74585 /src/backend/commands/sequence.c | |
parent | bab588cd5cbbeb43cda6e20c967b43000ea2aa80 (diff) | |
download | postgresql-344d62fb9a978a72cf8347f0369b9ee643fd0b31.tar.gz postgresql-344d62fb9a978a72cf8347f0369b9ee643fd0b31.zip |
Unlogged sequences
Add support for unlogged sequences. Unlike for unlogged tables, this
is not a performance feature. It allows sequences associated with
unlogged tables to be excluded from replication.
A new subcommand ALTER SEQUENCE ... SET LOGGED/UNLOGGED is added.
An identity/serial sequence now automatically gets and follows the
persistence level (logged/unlogged) of its owning table. (The
sequences owned by temporary tables were already temporary through the
separate mechanism in RangeVarAdjustRelationPersistence().) But you
can still change the persistence of an owned sequence separately.
Also, pg_dump and pg_upgrade preserve the persistence of existing
sequences.
Discussion: https://www.postgresql.org/message-id/flat/04e12818-2f98-257c-b926-2845d74ed04f%402ndquadrant.com
Diffstat (limited to 'src/backend/commands/sequence.c')
-rw-r--r-- | src/backend/commands/sequence.c | 58 |
1 files changed, 50 insertions, 8 deletions
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 717bb0b2aa9..47f62c28d42 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -30,6 +30,7 @@ #include "catalog/objectaccess.h" #include "catalog/pg_sequence.h" #include "catalog/pg_type.h" +#include "catalog/storage_xlog.h" #include "commands/defrem.h" #include "commands/sequence.h" #include "commands/tablecmds.h" @@ -95,6 +96,7 @@ static HTAB *seqhashtab = NULL; /* hash table for SeqTable items */ static SeqTableData *last_used_seq = NULL; static void fill_seq_with_data(Relation rel, HeapTuple tuple); +static void fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum); static Relation lock_and_open_sequence(SeqTable seq); static void create_seq_hashtable(void); static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel); @@ -133,12 +135,6 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq) bool pgs_nulls[Natts_pg_sequence]; int i; - /* Unlogged sequences are not implemented -- not clear if useful. */ - if (seq->sequence->relpersistence == RELPERSISTENCE_UNLOGGED) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("unlogged sequences are not supported"))); - /* * If if_not_exists was given and a relation with the same name already * exists, bail out. (Note: we needn't check this when not if_not_exists, @@ -492,10 +488,34 @@ SetSequence(Oid seq_relid, bool transactional, int64 last_value, int64 log_cnt, /* * Initialize a sequence's relation with the specified tuple as content + * + * This handles unlogged sequences by writing to both the main and the init + * fork as necessary. */ static void fill_seq_with_data(Relation rel, HeapTuple tuple) { + fill_seq_fork_with_data(rel, tuple, MAIN_FORKNUM); + + if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED) + { + SMgrRelation srel; + + srel = smgropen(rel->rd_node, InvalidBackendId); + smgrcreate(srel, INIT_FORKNUM, false); + log_smgrcreate(&rel->rd_node, INIT_FORKNUM); + fill_seq_fork_with_data(rel, tuple, INIT_FORKNUM); + FlushRelationBuffers(rel); + smgrclose(srel); + } +} + +/* + * Initialize a sequence's relation fork with the specified tuple as content + */ +static void +fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum) +{ Buffer buf; Page page; sequence_magic *sm; @@ -503,7 +523,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple) /* Initialize first page of relation with special magic number */ - buf = ReadBuffer(rel, P_NEW); + buf = ReadBufferExtended(rel, forkNum, P_NEW, RBM_NORMAL, NULL); Assert(BufferGetBlockNumber(buf) == 0); page = BufferGetPage(buf); @@ -549,7 +569,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple) elog(ERROR, "failed to add sequence tuple to page"); /* XLOG stuff */ - if (RelationNeedsWAL(rel)) + if (RelationNeedsWAL(rel) || forkNum == INIT_FORKNUM) { xl_seq_rec xlrec; XLogRecPtr recptr; @@ -683,6 +703,28 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt) } void +SequenceChangePersistence(Oid relid, char newrelpersistence) +{ + SeqTable elm; + Relation seqrel; + Buffer buf; + HeapTupleData seqdatatuple; + + init_sequence(relid, &elm, &seqrel); + + /* check the comment above nextval_internal()'s equivalent call. */ + if (RelationNeedsWAL(seqrel)) + GetTopTransactionId(); + + (void) read_seq_tuple(seqrel, &buf, &seqdatatuple); + RelationSetNewRelfilenode(seqrel, newrelpersistence); + fill_seq_with_data(seqrel, &seqdatatuple); + UnlockReleaseBuffer(buf); + + relation_close(seqrel, NoLock); +} + +void DeleteSequenceTuple(Oid relid) { Relation rel; |