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 450 of file sequence.c.

451 {
452  Oid relid;
453  SeqTable elm;
454  Relation seqrel;
455  Buffer buf;
456  HeapTupleData datatuple;
457  Form_pg_sequence seqform;
458  Form_pg_sequence_data newdataform;
459  bool need_seq_rewrite;
460  List *owned_by;
461  ObjectAddress address;
462  Relation rel;
463  HeapTuple seqtuple;
464  HeapTuple newdatatuple;
465 
466  /* Open and lock sequence, and check for ownership along the way. */
467  relid = RangeVarGetRelidExtended(stmt->sequence,
469  stmt->missing_ok ? RVR_MISSING_OK : 0,
471  NULL);
472  if (relid == InvalidOid)
473  {
474  ereport(NOTICE,
475  (errmsg("relation \"%s\" does not exist, skipping",
476  stmt->sequence->relname)));
477  return InvalidObjectAddress;
478  }
479 
480  init_sequence(relid, &elm, &seqrel);
481 
482  rel = table_open(SequenceRelationId, RowExclusiveLock);
483  seqtuple = SearchSysCacheCopy1(SEQRELID,
484  ObjectIdGetDatum(relid));
485  if (!HeapTupleIsValid(seqtuple))
486  elog(ERROR, "cache lookup failed for sequence %u",
487  relid);
488 
489  seqform = (Form_pg_sequence) GETSTRUCT(seqtuple);
490 
491  /* lock page's buffer and read tuple into new sequence structure */
492  (void) read_seq_tuple(seqrel, &buf, &datatuple);
493 
494  /* copy the existing sequence data tuple, so it can be modified locally */
495  newdatatuple = heap_copytuple(&datatuple);
496  newdataform = (Form_pg_sequence_data) GETSTRUCT(newdatatuple);
497 
499 
500  /* Check and set new values */
501  init_params(pstate, stmt->options, stmt->for_identity, false,
502  seqform, newdataform,
503  &need_seq_rewrite, &owned_by);
504 
505  /* Clear local cache so that we don't think we have cached numbers */
506  /* Note that we do not change the currval() state */
507  elm->cached = elm->last;
508 
509  /* If needed, rewrite the sequence relation itself */
510  if (need_seq_rewrite)
511  {
512  /* check the comment above nextval_internal()'s equivalent call. */
513  if (RelationNeedsWAL(seqrel))
515 
516  /*
517  * Create a new storage file for the sequence, making the state
518  * changes transactional.
519  */
520  RelationSetNewRelfilenumber(seqrel, seqrel->rd_rel->relpersistence);
521 
522  /*
523  * Ensure sequence's relfrozenxid is at 0, since it won't contain any
524  * unfrozen XIDs. Same with relminmxid, since a sequence will never
525  * contain multixacts.
526  */
527  Assert(seqrel->rd_rel->relfrozenxid == InvalidTransactionId);
528  Assert(seqrel->rd_rel->relminmxid == InvalidMultiXactId);
529 
530  /*
531  * Insert the modified tuple into the new storage file.
532  */
533  fill_seq_with_data(seqrel, newdatatuple);
534  }
535 
536  /* process OWNED BY if given */
537  if (owned_by)
538  process_owned_by(seqrel, owned_by, stmt->for_identity);
539 
540  /* update the pg_sequence tuple (we could skip this in some cases...) */
541  CatalogTupleUpdate(rel, &seqtuple->t_self, seqtuple);
542 
543  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
544 
545  ObjectAddressSet(address, RelationRelationId, relid);
546 
548  relation_close(seqrel, NoLock);
549 
550  return address;
551 }
int Buffer
Definition: buf.h:23
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4027
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
#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
Assert(fmt[strlen(fmt) - 1] !='\n')
#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:239
@ RVR_MISSING_OK
Definition: namespace.h:71
#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:67
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:3709
static void fill_seq_with_data(Relation rel, HeapTuple tuple)
Definition: sequence.c:350
static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
Definition: sequence.c:1135
static Form_pg_sequence_data read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
Definition: sequence.c:1202
static void process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
Definition: sequence.c:1602
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:1269
FormData_pg_sequence_data * Form_pg_sequence_data
Definition: sequence.h:32
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
Form_pg_class rd_rel
Definition: rel.h:110
int64 cached
Definition: sequence.c:82
int64 last
Definition: sequence.c:81
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ SEQRELID
Definition: syscache.h:93
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:16983
#define InvalidTransactionId
Definition: transam.h:31
TransactionId GetTopTransactionId(void)
Definition: xact.c:417

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(), relation_close(), RelationNeedsWAL, RelationSetNewRelfilenumber(), RowExclusiveLock, RVR_MISSING_OK, SearchSysCacheCopy1, SEQRELID, ShareRowExclusiveLock, stmt, HeapTupleData::t_self, table_close(), table_open(), and UnlockReleaseBuffer().

Referenced by ProcessUtilitySlow().

◆ DefineSequence()

ObjectAddress DefineSequence ( ParseState pstate,
CreateSeqStmt seq 
)

Definition at line 120 of file sequence.c.

121 {
122  FormData_pg_sequence seqform;
123  FormData_pg_sequence_data seqdataform;
124  bool need_seq_rewrite;
125  List *owned_by;
127  Oid seqoid;
128  ObjectAddress address;
129  Relation rel;
130  HeapTuple tuple;
131  TupleDesc tupDesc;
133  bool null[SEQ_COL_LASTCOL];
134  Datum pgs_values[Natts_pg_sequence];
135  bool pgs_nulls[Natts_pg_sequence];
136  int i;
137 
138  /*
139  * If if_not_exists was given and a relation with the same name already
140  * exists, bail out. (Note: we needn't check this when not if_not_exists,
141  * because DefineRelation will complain anyway.)
142  */
143  if (seq->if_not_exists)
144  {
146  if (OidIsValid(seqoid))
147  {
148  /*
149  * If we are in an extension script, insist that the pre-existing
150  * object be a member of the extension, to avoid security risks.
151  */
152  ObjectAddressSet(address, RelationRelationId, seqoid);
154 
155  /* OK to skip */
156  ereport(NOTICE,
157  (errcode(ERRCODE_DUPLICATE_TABLE),
158  errmsg("relation \"%s\" already exists, skipping",
159  seq->sequence->relname)));
160  return InvalidObjectAddress;
161  }
162  }
163 
164  /* Check and set all option values */
165  init_params(pstate, seq->options, seq->for_identity, true,
166  &seqform, &seqdataform,
167  &need_seq_rewrite, &owned_by);
168 
169  /*
170  * Create relation (and fill value[] and null[] for the tuple)
171  */
172  stmt->tableElts = NIL;
173  for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
174  {
175  ColumnDef *coldef = makeNode(ColumnDef);
176 
177  coldef->inhcount = 0;
178  coldef->is_local = true;
179  coldef->is_not_null = true;
180  coldef->is_from_type = false;
181  coldef->storage = 0;
182  coldef->raw_default = NULL;
183  coldef->cooked_default = NULL;
184  coldef->collClause = NULL;
185  coldef->collOid = InvalidOid;
186  coldef->constraints = NIL;
187  coldef->location = -1;
188 
189  null[i - 1] = false;
190 
191  switch (i)
192  {
193  case SEQ_COL_LASTVAL:
194  coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
195  coldef->colname = "last_value";
196  value[i - 1] = Int64GetDatumFast(seqdataform.last_value);
197  break;
198  case SEQ_COL_LOG:
199  coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
200  coldef->colname = "log_cnt";
201  value[i - 1] = Int64GetDatum((int64) 0);
202  break;
203  case SEQ_COL_CALLED:
204  coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
205  coldef->colname = "is_called";
206  value[i - 1] = BoolGetDatum(false);
207  break;
208  }
209  stmt->tableElts = lappend(stmt->tableElts, coldef);
210  }
211 
212  stmt->relation = seq->sequence;
213  stmt->inhRelations = NIL;
214  stmt->constraints = NIL;
215  stmt->options = NIL;
216  stmt->oncommit = ONCOMMIT_NOOP;
217  stmt->tablespacename = NULL;
218  stmt->if_not_exists = seq->if_not_exists;
219 
220  address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL, NULL);
221  seqoid = address.objectId;
222  Assert(seqoid != InvalidOid);
223 
224  rel = table_open(seqoid, AccessExclusiveLock);
225  tupDesc = RelationGetDescr(rel);
226 
227  /* now initialize the sequence's data */
228  tuple = heap_form_tuple(tupDesc, value, null);
229  fill_seq_with_data(rel, tuple);
230 
231  /* process OWNED BY if given */
232  if (owned_by)
233  process_owned_by(rel, owned_by, seq->for_identity);
234 
235  table_close(rel, NoLock);
236 
237  /* fill in pg_sequence */
238  rel = table_open(SequenceRelationId, RowExclusiveLock);
239  tupDesc = RelationGetDescr(rel);
240 
241  memset(pgs_nulls, 0, sizeof(pgs_nulls));
242 
243  pgs_values[Anum_pg_sequence_seqrelid - 1] = ObjectIdGetDatum(seqoid);
244  pgs_values[Anum_pg_sequence_seqtypid - 1] = ObjectIdGetDatum(seqform.seqtypid);
245  pgs_values[Anum_pg_sequence_seqstart - 1] = Int64GetDatumFast(seqform.seqstart);
246  pgs_values[Anum_pg_sequence_seqincrement - 1] = Int64GetDatumFast(seqform.seqincrement);
247  pgs_values[Anum_pg_sequence_seqmax - 1] = Int64GetDatumFast(seqform.seqmax);
248  pgs_values[Anum_pg_sequence_seqmin - 1] = Int64GetDatumFast(seqform.seqmin);
249  pgs_values[Anum_pg_sequence_seqcache - 1] = Int64GetDatumFast(seqform.seqcache);
250  pgs_values[Anum_pg_sequence_seqcycle - 1] = BoolGetDatum(seqform.seqcycle);
251 
252  tuple = heap_form_tuple(tupDesc, pgs_values, pgs_nulls);
253  CatalogTupleInsert(rel, tuple);
254 
255  heap_freetuple(tuple);
257 
258  return address;
259 }
#define OidIsValid(objectId)
Definition: c.h:759
int errcode(int sqlerrcode)
Definition: elog.c:858
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1794
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
static struct @143 value
int i
Definition: isn.c:73
List * lappend(List *list, void *datum)
Definition: list.c:338
#define AccessExclusiveLock
Definition: lockdefs.h:43
TypeName * makeTypeNameFromOid(Oid typeOid, int32 typmod)
Definition: makefuncs.c:474
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:537
#define makeNode(_type_)
Definition: nodes.h:176
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition: pg_depend.c:257
#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:49
#define RelationGetDescr(relation)
Definition: rel.h:529
#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
bool is_not_null
Definition: parsenodes.h:726
CollateClause * collClause
Definition: parsenodes.h:736
int location
Definition: parsenodes.h:740
List * constraints
Definition: parsenodes.h:738
Node * cooked_default
Definition: parsenodes.h:731
int inhcount
Definition: parsenodes.h:724
char * colname
Definition: parsenodes.h:721
TypeName * typeName
Definition: parsenodes.h:722
bool is_from_type
Definition: parsenodes.h:727
Node * raw_default
Definition: parsenodes.h:730
char storage
Definition: parsenodes.h:728
Oid collOid
Definition: parsenodes.h:737
bool is_local
Definition: parsenodes.h:725
bool if_not_exists
Definition: parsenodes.h:2850
List * options
Definition: parsenodes.h:2847
RangeVar * sequence
Definition: parsenodes.h:2846
char * relname
Definition: primnodes.h:74
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:662

References AccessExclusiveLock, Assert(), BoolGetDatum(), CatalogTupleInsert(), checkMembershipInCurrentExtension(), ColumnDef::collClause, ColumnDef::collOid, ColumnDef::colname, ColumnDef::constraints, ColumnDef::cooked_default, DefineRelation(), ereport, errcode(), errmsg(), fill_seq_with_data(), CreateSeqStmt::for_identity, FormData_pg_sequence, heap_form_tuple(), heap_freetuple(), i, CreateSeqStmt::if_not_exists, ColumnDef::inhcount, init_params(), Int64GetDatum(), Int64GetDatumFast, InvalidObjectAddress, InvalidOid, ColumnDef::is_from_type, ColumnDef::is_local, ColumnDef::is_not_null, lappend(), FormData_pg_sequence_data::last_value, ColumnDef::location, makeNode, makeTypeNameFromOid(), NIL, NoLock, NOTICE, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, ONCOMMIT_NOOP, CreateSeqStmt::options, CreateSeqStmt::ownerId, process_owned_by(), RangeVarGetAndCheckCreationNamespace(), ColumnDef::raw_default, RelationGetDescr, RangeVar::relname, RowExclusiveLock, SEQ_COL_CALLED, SEQ_COL_FIRSTCOL, SEQ_COL_LASTCOL, SEQ_COL_LASTVAL, SEQ_COL_LOG, CreateSeqStmt::sequence, stmt, ColumnDef::storage, table_close(), table_open(), ColumnDef::typeName, and value.

Referenced by ProcessUtilitySlow().

◆ DeleteSequenceTuple()

void DeleteSequenceTuple ( Oid  relid)

Definition at line 576 of file sequence.c.

577 {
578  Relation rel;
579  HeapTuple tuple;
580 
581  rel = table_open(SequenceRelationId, RowExclusiveLock);
582 
583  tuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
584  if (!HeapTupleIsValid(tuple))
585  elog(ERROR, "cache lookup failed for sequence %u", relid);
586 
587  CatalogTupleDelete(rel, &tuple->t_self);
588 
589  ReleaseSysCache(tuple);
591 }
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:865
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:817

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

Referenced by doDeletion().

◆ nextval()

Datum nextval ( PG_FUNCTION_ARGS  )

Definition at line 599 of file sequence.c.

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

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 629 of file sequence.c.

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

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

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(), relation_close(), RelationSetNewRelfilenumber(), ReleaseSysCache(), SearchSysCache1(), SEQRELID, and UnlockReleaseBuffer().

Referenced by ExecuteTruncateGuts().

◆ ResetSequenceCaches()

void ResetSequenceCaches ( void  )

Definition at line 1883 of file sequence.c.

1884 {
1885  if (seqhashtab)
1886  {
1888  seqhashtab = NULL;
1889  }
1890 
1891  last_used_seq = NULL;
1892 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:863
static HTAB * seqhashtab
Definition: sequence.c:90

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 }
unsigned char uint8
Definition: c.h:488
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
RelFileNumber relNumber
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:409
#define XLogRecGetData(decoder)
Definition: xlogreader.h:414
#define XLR_INFO_MASK
Definition: xlogrecord.h:62

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

◆ 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 }

References XLOG_SEQ_LOG, and XLR_INFO_MASK.

◆ seq_mask()

void seq_mask ( char *  page,
BlockNumber  blkno 
)

Definition at line 1898 of file sequence.c.

1899 {
1901 
1902  mask_unused_space(page);
1903 }
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 1830 of file sequence.c.

1831 {
1832  XLogRecPtr lsn = record->EndRecPtr;
1833  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
1834  Buffer buffer;
1835  Page page;
1836  Page localpage;
1837  char *item;
1838  Size itemsz;
1839  xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
1840  sequence_magic *sm;
1841 
1842  if (info != XLOG_SEQ_LOG)
1843  elog(PANIC, "seq_redo: unknown op code %u", info);
1844 
1845  buffer = XLogInitBufferForRedo(record, 0);
1846  page = (Page) BufferGetPage(buffer);
1847 
1848  /*
1849  * We always reinit the page. However, since this WAL record type is also
1850  * used for updating sequences, it's possible that a hot-standby backend
1851  * is examining the page concurrently; so we mustn't transiently trash the
1852  * buffer. The solution is to build the correct new page contents in
1853  * local workspace and then memcpy into the buffer. Then only bytes that
1854  * are supposed to change will change, even transiently. We must palloc
1855  * the local page for alignment reasons.
1856  */
1857  localpage = (Page) palloc(BufferGetPageSize(buffer));
1858 
1859  PageInit(localpage, BufferGetPageSize(buffer), sizeof(sequence_magic));
1860  sm = (sequence_magic *) PageGetSpecialPointer(localpage);
1861  sm->magic = SEQ_MAGIC;
1862 
1863  item = (char *) xlrec + sizeof(xl_seq_rec);
1864  itemsz = XLogRecGetDataLen(record) - sizeof(xl_seq_rec);
1865 
1866  if (PageAddItem(localpage, (Item) item, itemsz,
1867  FirstOffsetNumber, false, false) == InvalidOffsetNumber)
1868  elog(PANIC, "seq_redo: failed to add item to page");
1869 
1870  PageSetLSN(localpage, lsn);
1871 
1872  memcpy(page, localpage, BufferGetPageSize(buffer));
1873  MarkBufferDirty(buffer);
1874  UnlockReleaseBuffer(buffer);
1875 
1876  pfree(localpage);
1877 }
static Size BufferGetPageSize(Buffer buffer)
Definition: bufmgr.h:271
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:42
static char * PageGetSpecialPointer(Page page)
Definition: bufpage.h:336
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:468
size_t Size
Definition: c.h:589
#define PANIC
Definition: elog.h:42
Pointer Item
Definition: item.h:17
void pfree(void *pointer)
Definition: mcxt.c:1436
void * palloc(Size size)
Definition: mcxt.c:1210
#define InvalidOffsetNumber
Definition: off.h:26
#define FirstOffsetNumber
Definition: off.h:27
#define SEQ_MAGIC
Definition: sequence.c:62
struct xl_seq_rec xl_seq_rec
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
uint32 magic
Definition: sequence.c:66
#define XLogRecGetDataLen(decoder)
Definition: xlogreader.h:415
Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id)
Definition: xlogutils.c:329

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, XLogRecGetInfo, and XLR_INFO_MASK.

◆ sequence_options()

List* sequence_options ( Oid  relid)

Definition at line 1716 of file sequence.c.

1717 {
1718  HeapTuple pgstuple;
1719  Form_pg_sequence pgsform;
1720  List *options = NIL;
1721 
1722  pgstuple = SearchSysCache1(SEQRELID, relid);
1723  if (!HeapTupleIsValid(pgstuple))
1724  elog(ERROR, "cache lookup failed for sequence %u", relid);
1725  pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
1726 
1727  /* Use makeFloat() for 64-bit integers, like gram.y does. */
1729  makeDefElem("cache", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqcache)), -1));
1731  makeDefElem("cycle", (Node *) makeBoolean(pgsform->seqcycle), -1));
1733  makeDefElem("increment", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqincrement)), -1));
1735  makeDefElem("maxvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmax)), -1));
1737  makeDefElem("minvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmin)), -1));
1739  makeDefElem("start", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqstart)), -1));
1740 
1741  ReleaseSysCache(pgstuple);
1742 
1743  return options;
1744 }
#define INT64_FORMAT
Definition: c.h:532
DefElem * makeDefElem(char *name, Node *arg, int location)
Definition: makefuncs.c:548
static char ** options
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
Definition: nodes.h:129
Boolean * makeBoolean(bool val)
Definition: value.c:49
Float * makeFloat(char *numericStr)
Definition: value.c:37

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

Referenced by transformTableLikeClause().

◆ SequenceChangePersistence()

void SequenceChangePersistence ( Oid  relid,
char  newrelpersistence 
)

Definition at line 554 of file sequence.c.

555 {
556  SeqTable elm;
557  Relation seqrel;
558  Buffer buf;
559  HeapTupleData seqdatatuple;
560 
561  init_sequence(relid, &elm, &seqrel);
562 
563  /* check the comment above nextval_internal()'s equivalent call. */
564  if (RelationNeedsWAL(seqrel))
566 
567  (void) read_seq_tuple(seqrel, &buf, &seqdatatuple);
568  RelationSetNewRelfilenumber(seqrel, newrelpersistence);
569  fill_seq_with_data(seqrel, &seqdatatuple);
571 
572  relation_close(seqrel, NoLock);
573 }

References buf, fill_seq_with_data(), GetTopTransactionId(), init_sequence(), NoLock, read_seq_tuple(), relation_close(), RelationNeedsWAL, RelationSetNewRelfilenumber(), and UnlockReleaseBuffer().

Referenced by ATRewriteTables().