PostgreSQL Source Code git master
sequence.h File Reference
#include "access/xlogreader.h"
#include "catalog/objectaddress.h"
#include "fmgr.h"
#include "lib/stringinfo.h"
#include "nodes/parsenodes.h"
#include "parser/parse_node.h"
#include "storage/relfilelocator.h"
Include dependency graph for sequence.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  FormData_pg_sequence_data
 
struct  xl_seq_rec
 

Macros

#define SEQ_COL_LASTVAL   1
 
#define SEQ_COL_LOG   2
 
#define SEQ_COL_CALLED   3
 
#define SEQ_COL_FIRSTCOL   SEQ_COL_LASTVAL
 
#define SEQ_COL_LASTCOL   SEQ_COL_CALLED
 
#define XLOG_SEQ_LOG   0x00
 

Typedefs

typedef struct FormData_pg_sequence_data FormData_pg_sequence_data
 
typedef FormData_pg_sequence_dataForm_pg_sequence_data
 
typedef struct xl_seq_rec xl_seq_rec
 

Functions

int64 nextval_internal (Oid relid, bool check_permissions)
 
Datum nextval (PG_FUNCTION_ARGS)
 
Listsequence_options (Oid relid)
 
ObjectAddress DefineSequence (ParseState *pstate, CreateSeqStmt *seq)
 
ObjectAddress AlterSequence (ParseState *pstate, AlterSeqStmt *stmt)
 
void SequenceChangePersistence (Oid relid, char newrelpersistence)
 
void DeleteSequenceTuple (Oid relid)
 
void ResetSequence (Oid seq_relid)
 
void ResetSequenceCaches (void)
 
void seq_redo (XLogReaderState *record)
 
void seq_desc (StringInfo buf, XLogReaderState *record)
 
const char * seq_identify (uint8 info)
 
void seq_mask (char *page, BlockNumber blkno)
 

Macro Definition Documentation

◆ SEQ_COL_CALLED

#define SEQ_COL_CALLED   3

Definition at line 40 of file sequence.h.

◆ SEQ_COL_FIRSTCOL

#define SEQ_COL_FIRSTCOL   SEQ_COL_LASTVAL

Definition at line 42 of file sequence.h.

◆ SEQ_COL_LASTCOL

#define SEQ_COL_LASTCOL   SEQ_COL_CALLED

Definition at line 43 of file sequence.h.

◆ SEQ_COL_LASTVAL

#define SEQ_COL_LASTVAL   1

Definition at line 38 of file sequence.h.

◆ SEQ_COL_LOG

#define SEQ_COL_LOG   2

Definition at line 39 of file sequence.h.

◆ XLOG_SEQ_LOG

#define XLOG_SEQ_LOG   0x00

Definition at line 46 of file sequence.h.

Typedef Documentation

◆ Form_pg_sequence_data

Definition at line 32 of file sequence.h.

◆ FormData_pg_sequence_data

◆ xl_seq_rec

typedef struct xl_seq_rec xl_seq_rec

Function Documentation

◆ AlterSequence()

ObjectAddress AlterSequence ( ParseState pstate,
AlterSeqStmt stmt 
)

Definition at line 437 of file sequence.c.

438{
439 Oid relid;
440 SeqTable elm;
441 Relation seqrel;
442 Buffer buf;
443 HeapTupleData datatuple;
444 Form_pg_sequence seqform;
445 Form_pg_sequence_data newdataform;
446 bool need_seq_rewrite;
447 List *owned_by;
448 ObjectAddress address;
449 Relation rel;
450 HeapTuple seqtuple;
451 HeapTuple newdatatuple;
452
453 /* Open and lock sequence, and check for ownership along the way. */
454 relid = RangeVarGetRelidExtended(stmt->sequence,
456 stmt->missing_ok ? RVR_MISSING_OK : 0,
458 NULL);
459 if (relid == InvalidOid)
460 {
462 (errmsg("relation \"%s\" does not exist, skipping",
463 stmt->sequence->relname)));
465 }
466
467 init_sequence(relid, &elm, &seqrel);
468
469 rel = table_open(SequenceRelationId, RowExclusiveLock);
470 seqtuple = SearchSysCacheCopy1(SEQRELID,
471 ObjectIdGetDatum(relid));
472 if (!HeapTupleIsValid(seqtuple))
473 elog(ERROR, "cache lookup failed for sequence %u",
474 relid);
475
476 seqform = (Form_pg_sequence) GETSTRUCT(seqtuple);
477
478 /* lock page buffer and read tuple into new sequence structure */
479 (void) read_seq_tuple(seqrel, &buf, &datatuple);
480
481 /* copy the existing sequence data tuple, so it can be modified locally */
482 newdatatuple = heap_copytuple(&datatuple);
483 newdataform = (Form_pg_sequence_data) GETSTRUCT(newdatatuple);
484
486
487 /* Check and set new values */
488 init_params(pstate, stmt->options, stmt->for_identity, false,
489 seqform, newdataform,
490 &need_seq_rewrite, &owned_by);
491
492 /* If needed, rewrite the sequence relation itself */
493 if (need_seq_rewrite)
494 {
495 /* check the comment above nextval_internal()'s equivalent call. */
496 if (RelationNeedsWAL(seqrel))
498
499 /*
500 * Create a new storage file for the sequence, making the state
501 * changes transactional.
502 */
503 RelationSetNewRelfilenumber(seqrel, seqrel->rd_rel->relpersistence);
504
505 /*
506 * Ensure sequence's relfrozenxid is at 0, since it won't contain any
507 * unfrozen XIDs. Same with relminmxid, since a sequence will never
508 * contain multixacts.
509 */
510 Assert(seqrel->rd_rel->relfrozenxid == InvalidTransactionId);
511 Assert(seqrel->rd_rel->relminmxid == InvalidMultiXactId);
512
513 /*
514 * Insert the modified tuple into the new storage file.
515 */
516 fill_seq_with_data(seqrel, newdatatuple);
517 }
518
519 /* Clear local cache so that we don't think we have cached numbers */
520 /* Note that we do not change the currval() state */
521 elm->cached = elm->last;
522
523 /* process OWNED BY if given */
524 if (owned_by)
525 process_owned_by(seqrel, owned_by, stmt->for_identity);
526
527 /* update the pg_sequence tuple (we could skip this in some cases...) */
528 CatalogTupleUpdate(rel, &seqtuple->t_self, seqtuple);
529
530 InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
531
532 ObjectAddressSet(address, RelationRelationId, relid);
533
535 sequence_close(seqrel, NoLock);
536
537 return address;
538}
void sequence_close(Relation relation, LOCKMODE lockmode)
Definition: sequence.c:58
int Buffer
Definition: buf.h:23
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4941
#define Assert(condition)
Definition: c.h:812
static void fill_seq_with_data(Relation rel, HeapTuple tuple)
Definition: sequence.c:338
static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
Definition: sequence.c:1129
static Form_pg_sequence_data read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
Definition: sequence.c:1190
static void process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
Definition: sequence.c:1593
static void init_params(ParseState *pstate, List *options, bool for_identity, bool isInit, Form_pg_sequence seqform, Form_pg_sequence_data seqdataform, bool *need_seq_rewrite, List **owned_by)
Definition: sequence.c:1257
FormData_pg_sequence_data * Form_pg_sequence_data
Definition: sequence.h:32
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:778
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
#define NoLock
Definition: lockdefs.h:34
#define ShareRowExclusiveLock
Definition: lockdefs.h:41
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidMultiXactId
Definition: multixact.h:24
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:441
@ RVR_MISSING_OK
Definition: namespace.h:72
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
FormData_pg_sequence * Form_pg_sequence
Definition: pg_sequence.h:40
static char * buf
Definition: pg_test_fsync.c:72
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationNeedsWAL(relation)
Definition: rel.h:628
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3718
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
Form_pg_class rd_rel
Definition: rel.h:111
int64 cached
Definition: sequence.c:83
int64 last
Definition: sequence.c:82
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
void RangeVarCallbackOwnsRelation(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:18363
#define InvalidTransactionId
Definition: transam.h:31
TransactionId GetTopTransactionId(void)
Definition: xact.c:425

References Assert, buf, SeqTableData::cached, CatalogTupleUpdate(), elog, ereport, errmsg(), ERROR, fill_seq_with_data(), GETSTRUCT, GetTopTransactionId(), heap_copytuple(), HeapTupleIsValid, init_params(), init_sequence(), InvalidMultiXactId, InvalidObjectAddress, InvalidOid, InvalidTransactionId, InvokeObjectPostAlterHook, SeqTableData::last, NoLock, NOTICE, ObjectAddressSet, ObjectIdGetDatum(), process_owned_by(), RangeVarCallbackOwnsRelation(), RangeVarGetRelidExtended(), RelationData::rd_rel, read_seq_tuple(), RelationNeedsWAL, RelationSetNewRelfilenumber(), RowExclusiveLock, RVR_MISSING_OK, SearchSysCacheCopy1, sequence_close(), ShareRowExclusiveLock, stmt, HeapTupleData::t_self, table_close(), table_open(), and UnlockReleaseBuffer().

Referenced by ProcessUtilitySlow().

◆ DefineSequence()

ObjectAddress DefineSequence ( ParseState pstate,
CreateSeqStmt seq 
)

Definition at line 121 of file sequence.c.

122{
123 FormData_pg_sequence seqform;
124 FormData_pg_sequence_data seqdataform;
125 bool need_seq_rewrite;
126 List *owned_by;
128 Oid seqoid;
129 ObjectAddress address;
130 Relation rel;
131 HeapTuple tuple;
132 TupleDesc tupDesc;
134 bool null[SEQ_COL_LASTCOL];
135 Datum pgs_values[Natts_pg_sequence];
136 bool pgs_nulls[Natts_pg_sequence];
137 int i;
138
139 /*
140 * If if_not_exists was given and a relation with the same name already
141 * exists, bail out. (Note: we needn't check this when not if_not_exists,
142 * because DefineRelation will complain anyway.)
143 */
144 if (seq->if_not_exists)
145 {
147 if (OidIsValid(seqoid))
148 {
149 /*
150 * If we are in an extension script, insist that the pre-existing
151 * object be a member of the extension, to avoid security risks.
152 */
153 ObjectAddressSet(address, RelationRelationId, seqoid);
155
156 /* OK to skip */
158 (errcode(ERRCODE_DUPLICATE_TABLE),
159 errmsg("relation \"%s\" already exists, skipping",
160 seq->sequence->relname)));
162 }
163 }
164
165 /* Check and set all option values */
166 init_params(pstate, seq->options, seq->for_identity, true,
167 &seqform, &seqdataform,
168 &need_seq_rewrite, &owned_by);
169
170 /*
171 * Create relation (and fill value[] and null[] for the tuple)
172 */
173 stmt->tableElts = NIL;
174 for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
175 {
176 ColumnDef *coldef = NULL;
177
178 switch (i)
179 {
180 case SEQ_COL_LASTVAL:
181 coldef = makeColumnDef("last_value", INT8OID, -1, InvalidOid);
182 value[i - 1] = Int64GetDatumFast(seqdataform.last_value);
183 break;
184 case SEQ_COL_LOG:
185 coldef = makeColumnDef("log_cnt", INT8OID, -1, InvalidOid);
186 value[i - 1] = Int64GetDatum((int64) 0);
187 break;
188 case SEQ_COL_CALLED:
189 coldef = makeColumnDef("is_called", BOOLOID, -1, InvalidOid);
190 value[i - 1] = BoolGetDatum(false);
191 break;
192 }
193
194 coldef->is_not_null = true;
195 null[i - 1] = false;
196
197 stmt->tableElts = lappend(stmt->tableElts, coldef);
198 }
199
200 stmt->relation = seq->sequence;
201 stmt->inhRelations = NIL;
202 stmt->constraints = NIL;
203 stmt->options = NIL;
204 stmt->oncommit = ONCOMMIT_NOOP;
205 stmt->tablespacename = NULL;
206 stmt->if_not_exists = seq->if_not_exists;
207
208 address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL, NULL);
209 seqoid = address.objectId;
210 Assert(seqoid != InvalidOid);
211
212 rel = sequence_open(seqoid, AccessExclusiveLock);
213 tupDesc = RelationGetDescr(rel);
214
215 /* now initialize the sequence's data */
216 tuple = heap_form_tuple(tupDesc, value, null);
217 fill_seq_with_data(rel, tuple);
218
219 /* process OWNED BY if given */
220 if (owned_by)
221 process_owned_by(rel, owned_by, seq->for_identity);
222
224
225 /* fill in pg_sequence */
226 rel = table_open(SequenceRelationId, RowExclusiveLock);
227 tupDesc = RelationGetDescr(rel);
228
229 memset(pgs_nulls, 0, sizeof(pgs_nulls));
230
231 pgs_values[Anum_pg_sequence_seqrelid - 1] = ObjectIdGetDatum(seqoid);
232 pgs_values[Anum_pg_sequence_seqtypid - 1] = ObjectIdGetDatum(seqform.seqtypid);
233 pgs_values[Anum_pg_sequence_seqstart - 1] = Int64GetDatumFast(seqform.seqstart);
234 pgs_values[Anum_pg_sequence_seqincrement - 1] = Int64GetDatumFast(seqform.seqincrement);
235 pgs_values[Anum_pg_sequence_seqmax - 1] = Int64GetDatumFast(seqform.seqmax);
236 pgs_values[Anum_pg_sequence_seqmin - 1] = Int64GetDatumFast(seqform.seqmin);
237 pgs_values[Anum_pg_sequence_seqcache - 1] = Int64GetDatumFast(seqform.seqcache);
238 pgs_values[Anum_pg_sequence_seqcycle - 1] = BoolGetDatum(seqform.seqcycle);
239
240 tuple = heap_form_tuple(tupDesc, pgs_values, pgs_nulls);
241 CatalogTupleInsert(rel, tuple);
242
243 heap_freetuple(tuple);
245
246 return address;
247}
Relation sequence_open(Oid relationId, LOCKMODE lockmode)
Definition: sequence.c:37
int64_t int64
Definition: c.h:482
#define OidIsValid(objectId)
Definition: c.h:729
#define SEQ_COL_LASTVAL
Definition: sequence.h:38
#define SEQ_COL_CALLED
Definition: sequence.h:40
#define SEQ_COL_LASTCOL
Definition: sequence.h:43
#define SEQ_COL_LOG
Definition: sequence.h:39
#define SEQ_COL_FIRSTCOL
Definition: sequence.h:42
int errcode(int sqlerrcode)
Definition: elog.c:853
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
static struct @161 value
int i
Definition: isn.c:72
List * lappend(List *list, void *datum)
Definition: list.c:339
#define AccessExclusiveLock
Definition: lockdefs.h:43
ColumnDef * makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid)
Definition: makefuncs.c:516
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:739
#define makeNode(_type_)
Definition: nodes.h:155
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition: pg_depend.c:258
#define NIL
Definition: pg_list.h:68
FormData_pg_sequence
Definition: pg_sequence.h:33
#define Int64GetDatumFast(X)
Definition: postgres.h:554
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
@ ONCOMMIT_NOOP
Definition: primnodes.h:57
#define RelationGetDescr(relation)
Definition: rel.h:531
bool is_not_null
Definition: parsenodes.h:733
bool if_not_exists
Definition: parsenodes.h:3153
List * options
Definition: parsenodes.h:3150
RangeVar * sequence
Definition: parsenodes.h:3149
char * relname
Definition: primnodes.h:82
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:713

References AccessExclusiveLock, Assert, BoolGetDatum(), CatalogTupleInsert(), checkMembershipInCurrentExtension(), DefineRelation(), ereport, errcode(), errmsg(), fill_seq_with_data(), CreateSeqStmt::for_identity, FormData_pg_sequence, heap_form_tuple(), heap_freetuple(), i, CreateSeqStmt::if_not_exists, init_params(), Int64GetDatum(), Int64GetDatumFast, InvalidObjectAddress, InvalidOid, ColumnDef::is_not_null, lappend(), FormData_pg_sequence_data::last_value, makeColumnDef(), makeNode, NIL, NoLock, NOTICE, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, ONCOMMIT_NOOP, CreateSeqStmt::options, CreateSeqStmt::ownerId, process_owned_by(), RangeVarGetAndCheckCreationNamespace(), RelationGetDescr, RangeVar::relname, RowExclusiveLock, SEQ_COL_CALLED, SEQ_COL_FIRSTCOL, SEQ_COL_LASTCOL, SEQ_COL_LASTVAL, SEQ_COL_LOG, CreateSeqStmt::sequence, sequence_close(), sequence_open(), stmt, table_close(), table_open(), and value.

Referenced by ProcessUtilitySlow().

◆ DeleteSequenceTuple()

void DeleteSequenceTuple ( Oid  relid)

Definition at line 570 of file sequence.c.

571{
572 Relation rel;
573 HeapTuple tuple;
574
575 rel = table_open(SequenceRelationId, RowExclusiveLock);
576
577 tuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
578 if (!HeapTupleIsValid(tuple))
579 elog(ERROR, "cache lookup failed for sequence %u", relid);
580
581 CatalogTupleDelete(rel, &tuple->t_self);
582
583 ReleaseSysCache(tuple);
585}
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References CatalogTupleDelete(), elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ nextval()

Datum nextval ( PG_FUNCTION_ARGS  )

Definition at line 593 of file sequence.c.

594{
595 text *seqin = PG_GETARG_TEXT_PP(0);
596 RangeVar *sequence;
597 Oid relid;
598
600
601 /*
602 * XXX: This is not safe in the presence of concurrent DDL, but acquiring
603 * a lock here is more expensive than letting nextval_internal do it,
604 * since the latter maintains a cache that keeps us from hitting the lock
605 * manager more than once per transaction. It's not clear whether the
606 * performance penalty is material in practice, but for now, we do it this
607 * way.
608 */
609 relid = RangeVarGetRelid(sequence, NoLock, false);
610
611 PG_RETURN_INT64(nextval_internal(relid, true));
612}
int64 nextval_internal(Oid relid, bool check_permissions)
Definition: sequence.c:623
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3554
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:80
Definition: c.h:641
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3374

References makeRangeVarFromNameList(), nextval_internal(), NoLock, PG_GETARG_TEXT_PP, PG_RETURN_INT64, RangeVarGetRelid, and textToQualifiedNameList().

Referenced by autoinc(), and ttdummy().

◆ nextval_internal()

int64 nextval_internal ( Oid  relid,
bool  check_permissions 
)

Definition at line 623 of file sequence.c.

624{
625 SeqTable elm;
626 Relation seqrel;
627 Buffer buf;
628 Page page;
629 HeapTuple pgstuple;
630 Form_pg_sequence pgsform;
631 HeapTupleData seqdatatuple;
633 int64 incby,
634 maxv,
635 minv,
636 cache,
637 log,
638 fetch,
639 last;
640 int64 result,
641 next,
642 rescnt = 0;
643 bool cycle;
644 bool logit = false;
645
646 /* open and lock sequence */
647 init_sequence(relid, &elm, &seqrel);
648
649 if (check_permissions &&
653 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
654 errmsg("permission denied for sequence %s",
655 RelationGetRelationName(seqrel))));
656
657 /* read-only transactions may only modify temp sequences */
658 if (!seqrel->rd_islocaltemp)
659 PreventCommandIfReadOnly("nextval()");
660
661 /*
662 * Forbid this during parallel operation because, to make it work, the
663 * cooperating backends would need to share the backend-local cached
664 * sequence information. Currently, we don't support that.
665 */
666 PreventCommandIfParallelMode("nextval()");
667
668 if (elm->last != elm->cached) /* some numbers were cached */
669 {
670 Assert(elm->last_valid);
671 Assert(elm->increment != 0);
672 elm->last += elm->increment;
673 sequence_close(seqrel, NoLock);
674 last_used_seq = elm;
675 return elm->last;
676 }
677
678 pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
679 if (!HeapTupleIsValid(pgstuple))
680 elog(ERROR, "cache lookup failed for sequence %u", relid);
681 pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
682 incby = pgsform->seqincrement;
683 maxv = pgsform->seqmax;
684 minv = pgsform->seqmin;
685 cache = pgsform->seqcache;
686 cycle = pgsform->seqcycle;
687 ReleaseSysCache(pgstuple);
688
689 /* lock page buffer and read tuple */
690 seq = read_seq_tuple(seqrel, &buf, &seqdatatuple);
691 page = BufferGetPage(buf);
692
693 last = next = result = seq->last_value;
694 fetch = cache;
695 log = seq->log_cnt;
696
697 if (!seq->is_called)
698 {
699 rescnt++; /* return last_value if not is_called */
700 fetch--;
701 }
702
703 /*
704 * Decide whether we should emit a WAL log record. If so, force up the
705 * fetch count to grab SEQ_LOG_VALS more values than we actually need to
706 * cache. (These will then be usable without logging.)
707 *
708 * If this is the first nextval after a checkpoint, we must force a new
709 * WAL record to be written anyway, else replay starting from the
710 * checkpoint would fail to advance the sequence past the logged values.
711 * In this case we may as well fetch extra values.
712 */
713 if (log < fetch || !seq->is_called)
714 {
715 /* forced log to satisfy local demand for values */
716 fetch = log = fetch + SEQ_LOG_VALS;
717 logit = true;
718 }
719 else
720 {
721 XLogRecPtr redoptr = GetRedoRecPtr();
722
723 if (PageGetLSN(page) <= redoptr)
724 {
725 /* last update of seq was before checkpoint */
726 fetch = log = fetch + SEQ_LOG_VALS;
727 logit = true;
728 }
729 }
730
731 while (fetch) /* try to fetch cache [+ log ] numbers */
732 {
733 /*
734 * Check MAXVALUE for ascending sequences and MINVALUE for descending
735 * sequences
736 */
737 if (incby > 0)
738 {
739 /* ascending sequence */
740 if ((maxv >= 0 && next > maxv - incby) ||
741 (maxv < 0 && next + incby > maxv))
742 {
743 if (rescnt > 0)
744 break; /* stop fetching */
745 if (!cycle)
747 (errcode(ERRCODE_SEQUENCE_GENERATOR_LIMIT_EXCEEDED),
748 errmsg("nextval: reached maximum value of sequence \"%s\" (%lld)",
750 (long long) maxv)));
751 next = minv;
752 }
753 else
754 next += incby;
755 }
756 else
757 {
758 /* descending sequence */
759 if ((minv < 0 && next < minv - incby) ||
760 (minv >= 0 && next + incby < minv))
761 {
762 if (rescnt > 0)
763 break; /* stop fetching */
764 if (!cycle)
766 (errcode(ERRCODE_SEQUENCE_GENERATOR_LIMIT_EXCEEDED),
767 errmsg("nextval: reached minimum value of sequence \"%s\" (%lld)",
769 (long long) minv)));
770 next = maxv;
771 }
772 else
773 next += incby;
774 }
775 fetch--;
776 if (rescnt < cache)
777 {
778 log--;
779 rescnt++;
780 last = next;
781 if (rescnt == 1) /* if it's first result - */
782 result = next; /* it's what to return */
783 }
784 }
785
786 log -= fetch; /* adjust for any unfetched numbers */
787 Assert(log >= 0);
788
789 /* save info in local cache */
790 elm->increment = incby;
791 elm->last = result; /* last returned number */
792 elm->cached = last; /* last fetched number */
793 elm->last_valid = true;
794
795 last_used_seq = elm;
796
797 /*
798 * If something needs to be WAL logged, acquire an xid, so this
799 * transaction's commit will trigger a WAL flush and wait for syncrep.
800 * It's sufficient to ensure the toplevel transaction has an xid, no need
801 * to assign xids subxacts, that'll already trigger an appropriate wait.
802 * (Have to do that here, so we're outside the critical section)
803 */
804 if (logit && RelationNeedsWAL(seqrel))
806
807 /* ready to change the on-disk (or really, in-buffer) tuple */
809
810 /*
811 * We must mark the buffer dirty before doing XLogInsert(); see notes in
812 * SyncOneBuffer(). However, we don't apply the desired changes just yet.
813 * This looks like a violation of the buffer update protocol, but it is in
814 * fact safe because we hold exclusive lock on the buffer. Any other
815 * process, including a checkpoint, that tries to examine the buffer
816 * contents will block until we release the lock, and then will see the
817 * final state that we install below.
818 */
820
821 /* XLOG stuff */
822 if (logit && RelationNeedsWAL(seqrel))
823 {
824 xl_seq_rec xlrec;
825 XLogRecPtr recptr;
826
827 /*
828 * We don't log the current state of the tuple, but rather the state
829 * as it would appear after "log" more fetches. This lets us skip
830 * that many future WAL records, at the cost that we lose those
831 * sequence values if we crash.
832 */
835
836 /* set values that will be saved in xlog */
837 seq->last_value = next;
838 seq->is_called = true;
839 seq->log_cnt = 0;
840
841 xlrec.locator = seqrel->rd_locator;
842
843 XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
844 XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len);
845
846 recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
847
848 PageSetLSN(page, recptr);
849 }
850
851 /* Now update sequence tuple to the intended final state */
852 seq->last_value = last; /* last fetched number */
853 seq->is_called = true;
854 seq->log_cnt = log; /* how much is logged */
855
857
859
860 sequence_close(seqrel, NoLock);
861
862 return result;
863}
@ ACLCHECK_OK
Definition: acl.h:183
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4007
static int32 next
Definition: blutils.c:219
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2532
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:400
Pointer Page
Definition: bufpage.h:81
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:391
static XLogRecPtr PageGetLSN(const char *page)
Definition: bufpage.h:386
static SeqTableData * last_used_seq
Definition: sequence.c:97
#define SEQ_LOG_VALS
Definition: sequence.c:58
#define XLOG_SEQ_LOG
Definition: sequence.h:46
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
Oid GetUserId(void)
Definition: miscinit.c:517
#define ACL_USAGE
Definition: parsenodes.h:84
#define ACL_UPDATE
Definition: parsenodes.h:78
#define RelationGetRelationName(relation)
Definition: rel.h:539
uint32 t_len
Definition: htup.h:64
HeapTupleHeader t_data
Definition: htup.h:68
bool rd_islocaltemp
Definition: rel.h:61
RelFileLocator rd_locator
Definition: rel.h:57
bool last_valid
Definition: sequence.c:81
int64 increment
Definition: sequence.c:85
RelFileLocator locator
Definition: sequence.h:50
void PreventCommandIfReadOnly(const char *cmdname)
Definition: utility.c:404
void PreventCommandIfParallelMode(const char *cmdname)
Definition: utility.c:422
XLogRecPtr GetRedoRecPtr(void)
Definition: xlog.c:6437
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogRegisterData(const char *data, uint32 len)
Definition: xloginsert.c:364
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:242
void XLogBeginInsert(void)
Definition: xloginsert.c:149
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33

References ACL_UPDATE, ACL_USAGE, ACLCHECK_OK, Assert, buf, BufferGetPage(), SeqTableData::cached, elog, END_CRIT_SECTION, ereport, errcode(), errmsg(), ERROR, GetRedoRecPtr(), GETSTRUCT, GetTopTransactionId(), GetUserId(), HeapTupleIsValid, SeqTableData::increment, init_sequence(), FormData_pg_sequence_data::is_called, SeqTableData::last, last_used_seq, SeqTableData::last_valid, FormData_pg_sequence_data::last_value, xl_seq_rec::locator, FormData_pg_sequence_data::log_cnt, MarkBufferDirty(), next, NoLock, ObjectIdGetDatum(), PageGetLSN(), PageSetLSN(), pg_class_aclcheck(), PreventCommandIfParallelMode(), PreventCommandIfReadOnly(), RelationData::rd_islocaltemp, RelationData::rd_locator, read_seq_tuple(), REGBUF_WILL_INIT, RelationGetRelationName, RelationNeedsWAL, ReleaseSysCache(), SeqTableData::relid, SearchSysCache1(), SEQ_LOG_VALS, sequence_close(), START_CRIT_SECTION, HeapTupleData::t_data, HeapTupleData::t_len, UnlockReleaseBuffer(), XLOG_SEQ_LOG, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by ExecEvalNextValueExpr(), nextval(), and nextval_oid().

◆ ResetSequence()

void ResetSequence ( Oid  seq_relid)

Definition at line 262 of file sequence.c.

263{
264 Relation seq_rel;
265 SeqTable elm;
267 Buffer buf;
268 HeapTupleData seqdatatuple;
269 HeapTuple tuple;
270 HeapTuple pgstuple;
271 Form_pg_sequence pgsform;
272 int64 startv;
273
274 /*
275 * Read the old sequence. This does a bit more work than really
276 * necessary, but it's simple, and we do want to double-check that it's
277 * indeed a sequence.
278 */
279 init_sequence(seq_relid, &elm, &seq_rel);
280 (void) read_seq_tuple(seq_rel, &buf, &seqdatatuple);
281
282 pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(seq_relid));
283 if (!HeapTupleIsValid(pgstuple))
284 elog(ERROR, "cache lookup failed for sequence %u", seq_relid);
285 pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
286 startv = pgsform->seqstart;
287 ReleaseSysCache(pgstuple);
288
289 /*
290 * Copy the existing sequence tuple.
291 */
292 tuple = heap_copytuple(&seqdatatuple);
293
294 /* Now we're done with the old page */
296
297 /*
298 * Modify the copied tuple to execute the restart (compare the RESTART
299 * action in AlterSequence)
300 */
301 seq = (Form_pg_sequence_data) GETSTRUCT(tuple);
302 seq->last_value = startv;
303 seq->is_called = false;
304 seq->log_cnt = 0;
305
306 /*
307 * Create a new storage file for the sequence.
308 */
309 RelationSetNewRelfilenumber(seq_rel, seq_rel->rd_rel->relpersistence);
310
311 /*
312 * Ensure sequence's relfrozenxid is at 0, since it won't contain any
313 * unfrozen XIDs. Same with relminmxid, since a sequence will never
314 * contain multixacts.
315 */
316 Assert(seq_rel->rd_rel->relfrozenxid == InvalidTransactionId);
317 Assert(seq_rel->rd_rel->relminmxid == InvalidMultiXactId);
318
319 /*
320 * Insert the modified tuple into the new storage file.
321 */
322 fill_seq_with_data(seq_rel, tuple);
323
324 /* Clear local cache so that we don't think we have cached numbers */
325 /* Note that we do not change the currval() state */
326 elm->cached = elm->last;
327
328 sequence_close(seq_rel, NoLock);
329}

References Assert, buf, SeqTableData::cached, elog, ERROR, fill_seq_with_data(), GETSTRUCT, heap_copytuple(), HeapTupleIsValid, init_sequence(), InvalidMultiXactId, InvalidTransactionId, FormData_pg_sequence_data::is_called, SeqTableData::last, FormData_pg_sequence_data::last_value, FormData_pg_sequence_data::log_cnt, NoLock, ObjectIdGetDatum(), RelationData::rd_rel, read_seq_tuple(), RelationSetNewRelfilenumber(), ReleaseSysCache(), SearchSysCache1(), sequence_close(), and UnlockReleaseBuffer().

Referenced by ExecuteTruncateGuts().

◆ ResetSequenceCaches()

void ResetSequenceCaches ( void  )

Definition at line 1943 of file sequence.c.

1944{
1945 if (seqhashtab)
1946 {
1948 seqhashtab = NULL;
1949 }
1950
1951 last_used_seq = NULL;
1952}
static HTAB * seqhashtab
Definition: sequence.c:91
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865

References hash_destroy(), last_used_seq, and seqhashtab.

Referenced by DiscardAll(), and DiscardCommand().

◆ seq_desc()

void seq_desc ( StringInfo  buf,
XLogReaderState record 
)

Definition at line 21 of file seqdesc.c.

22{
23 char *rec = XLogRecGetData(record);
24 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
25 xl_seq_rec *xlrec = (xl_seq_rec *) rec;
26
27 if (info == XLOG_SEQ_LOG)
28 appendStringInfo(buf, "rel %u/%u/%u",
29 xlrec->locator.spcOid, xlrec->locator.dbOid,
30 xlrec->locator.relNumber);
31}
uint8_t uint8
Definition: c.h:483
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
RelFileNumber relNumber
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415

References appendStringInfo(), buf, RelFileLocator::dbOid, xl_seq_rec::locator, RelFileLocator::relNumber, RelFileLocator::spcOid, XLOG_SEQ_LOG, XLogRecGetData, and XLogRecGetInfo.

◆ seq_identify()

const char * seq_identify ( uint8  info)

Definition at line 34 of file seqdesc.c.

35{
36 const char *id = NULL;
37
38 switch (info & ~XLR_INFO_MASK)
39 {
40 case XLOG_SEQ_LOG:
41 id = "LOG";
42 break;
43 }
44
45 return id;
46}
#define XLR_INFO_MASK
Definition: xlogrecord.h:62

References XLOG_SEQ_LOG, and XLR_INFO_MASK.

◆ seq_mask()

void seq_mask ( char *  page,
BlockNumber  blkno 
)

Definition at line 1958 of file sequence.c.

1959{
1961
1962 mask_unused_space(page);
1963}
void mask_page_lsn_and_checksum(Page page)
Definition: bufmask.c:31
void mask_unused_space(Page page)
Definition: bufmask.c:71

References mask_page_lsn_and_checksum(), and mask_unused_space().

◆ seq_redo()

void seq_redo ( XLogReaderState record)

Definition at line 1890 of file sequence.c.

1891{
1892 XLogRecPtr lsn = record->EndRecPtr;
1893 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
1894 Buffer buffer;
1895 Page page;
1896 Page localpage;
1897 char *item;
1898 Size itemsz;
1899 xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
1900 sequence_magic *sm;
1901
1902 if (info != XLOG_SEQ_LOG)
1903 elog(PANIC, "seq_redo: unknown op code %u", info);
1904
1905 buffer = XLogInitBufferForRedo(record, 0);
1906 page = (Page) BufferGetPage(buffer);
1907
1908 /*
1909 * We always reinit the page. However, since this WAL record type is also
1910 * used for updating sequences, it's possible that a hot-standby backend
1911 * is examining the page concurrently; so we mustn't transiently trash the
1912 * buffer. The solution is to build the correct new page contents in
1913 * local workspace and then memcpy into the buffer. Then only bytes that
1914 * are supposed to change will change, even transiently. We must palloc
1915 * the local page for alignment reasons.
1916 */
1917 localpage = (Page) palloc(BufferGetPageSize(buffer));
1918
1919 PageInit(localpage, BufferGetPageSize(buffer), sizeof(sequence_magic));
1920 sm = (sequence_magic *) PageGetSpecialPointer(localpage);
1921 sm->magic = SEQ_MAGIC;
1922
1923 item = (char *) xlrec + sizeof(xl_seq_rec);
1924 itemsz = XLogRecGetDataLen(record) - sizeof(xl_seq_rec);
1925
1926 if (PageAddItem(localpage, (Item) item, itemsz,
1927 FirstOffsetNumber, false, false) == InvalidOffsetNumber)
1928 elog(PANIC, "seq_redo: failed to add item to page");
1929
1930 PageSetLSN(localpage, lsn);
1931
1932 memcpy(page, localpage, BufferGetPageSize(buffer));
1933 MarkBufferDirty(buffer);
1934 UnlockReleaseBuffer(buffer);
1935
1936 pfree(localpage);
1937}
static Size BufferGetPageSize(Buffer buffer)
Definition: bufmgr.h:389
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:42
static char * PageGetSpecialPointer(Page page)
Definition: bufpage.h:339
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:471
size_t Size
Definition: c.h:559
#define SEQ_MAGIC
Definition: sequence.c:63
struct xl_seq_rec xl_seq_rec
#define PANIC
Definition: elog.h:42
Pointer Item
Definition: item.h:17
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
#define InvalidOffsetNumber
Definition: off.h:26
#define FirstOffsetNumber
Definition: off.h:27
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
uint32 magic
Definition: sequence.c:67
#define XLogRecGetDataLen(decoder)
Definition: xlogreader.h:416
Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id)
Definition: xlogutils.c:326

References BufferGetPage(), BufferGetPageSize(), elog, XLogReaderState::EndRecPtr, FirstOffsetNumber, InvalidOffsetNumber, sequence_magic::magic, MarkBufferDirty(), PageAddItem, PageGetSpecialPointer(), PageInit(), PageSetLSN(), palloc(), PANIC, pfree(), SEQ_MAGIC, UnlockReleaseBuffer(), XLOG_SEQ_LOG, XLogInitBufferForRedo(), XLogRecGetData, XLogRecGetDataLen, and XLogRecGetInfo.

◆ sequence_options()

List * sequence_options ( Oid  relid)

Definition at line 1707 of file sequence.c.

1708{
1709 HeapTuple pgstuple;
1710 Form_pg_sequence pgsform;
1711 List *options = NIL;
1712
1713 pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
1714 if (!HeapTupleIsValid(pgstuple))
1715 elog(ERROR, "cache lookup failed for sequence %u", relid);
1716 pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
1717
1718 /* Use makeFloat() for 64-bit integers, like gram.y does. */
1720 makeDefElem("cache", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqcache)), -1));
1722 makeDefElem("cycle", (Node *) makeBoolean(pgsform->seqcycle), -1));
1724 makeDefElem("increment", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqincrement)), -1));
1726 makeDefElem("maxvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmax)), -1));
1728 makeDefElem("minvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmin)), -1));
1730 makeDefElem("start", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqstart)), -1));
1731
1732 ReleaseSysCache(pgstuple);
1733
1734 return options;
1735}
#define INT64_FORMAT
Definition: c.h:503
DefElem * makeDefElem(char *name, Node *arg, int location)
Definition: makefuncs.c:588
static char ** options
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
Definition: nodes.h:129
Float * makeFloat(char *numericStr)
Definition: value.c:37
Boolean * makeBoolean(bool val)
Definition: value.c:49

References elog, ERROR, GETSTRUCT, HeapTupleIsValid, INT64_FORMAT, lappend(), makeBoolean(), makeDefElem(), makeFloat(), NIL, ObjectIdGetDatum(), options, psprintf(), ReleaseSysCache(), and SearchSysCache1().

Referenced by transformTableLikeClause().

◆ SequenceChangePersistence()

void SequenceChangePersistence ( Oid  relid,
char  newrelpersistence 
)

Definition at line 541 of file sequence.c.

542{
543 SeqTable elm;
544 Relation seqrel;
545 Buffer buf;
546 HeapTupleData seqdatatuple;
547
548 /*
549 * ALTER SEQUENCE acquires this lock earlier. If we're processing an
550 * owned sequence for ALTER TABLE, lock now. Without the lock, we'd
551 * discard increments from nextval() calls (in other sessions) between
552 * this function's buffer unlock and this transaction's commit.
553 */
555 init_sequence(relid, &elm, &seqrel);
556
557 /* check the comment above nextval_internal()'s equivalent call. */
558 if (RelationNeedsWAL(seqrel))
560
561 (void) read_seq_tuple(seqrel, &buf, &seqdatatuple);
562 RelationSetNewRelfilenumber(seqrel, newrelpersistence);
563 fill_seq_with_data(seqrel, &seqdatatuple);
565
566 sequence_close(seqrel, NoLock);
567}
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:107

References AccessExclusiveLock, buf, fill_seq_with_data(), GetTopTransactionId(), init_sequence(), LockRelationOid(), NoLock, read_seq_tuple(), RelationNeedsWAL, RelationSetNewRelfilenumber(), sequence_close(), and UnlockReleaseBuffer().

Referenced by ATRewriteTables().