PostgreSQL Source Code  git master
sequence.c File Reference
#include "postgres.h"
#include "access/bufmask.h"
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/relation.h"
#include "access/sequence.h"
#include "access/table.h"
#include "access/transam.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#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"
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "parser/parse_type.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/resowner.h"
#include "utils/syscache.h"
#include "utils/varlena.h"
Include dependency graph for sequence.c:

Go to the source code of this file.

Data Structures

struct  sequence_magic
 
struct  SeqTableData
 

Macros

#define SEQ_LOG_VALS   32
 
#define SEQ_MAGIC   0x1717
 

Typedefs

typedef struct sequence_magic sequence_magic
 
typedef struct SeqTableData SeqTableData
 
typedef SeqTableDataSeqTable
 

Functions

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)
 
static Form_pg_sequence_data read_seq_tuple (Relation rel, Buffer *buf, HeapTuple seqdatatuple)
 
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)
 
static void do_setval (Oid relid, int64 next, bool iscalled)
 
static void process_owned_by (Relation seqrel, List *owned_by, bool for_identity)
 
ObjectAddress DefineSequence (ParseState *pstate, CreateSeqStmt *seq)
 
void ResetSequence (Oid seq_relid)
 
ObjectAddress AlterSequence (ParseState *pstate, AlterSeqStmt *stmt)
 
void SequenceChangePersistence (Oid relid, char newrelpersistence)
 
void DeleteSequenceTuple (Oid relid)
 
Datum nextval (PG_FUNCTION_ARGS)
 
Datum nextval_oid (PG_FUNCTION_ARGS)
 
int64 nextval_internal (Oid relid, bool check_permissions)
 
Datum currval_oid (PG_FUNCTION_ARGS)
 
Datum lastval (PG_FUNCTION_ARGS)
 
Datum setval_oid (PG_FUNCTION_ARGS)
 
Datum setval3_oid (PG_FUNCTION_ARGS)
 
Listsequence_options (Oid relid)
 
Datum pg_sequence_parameters (PG_FUNCTION_ARGS)
 
Datum pg_sequence_last_value (PG_FUNCTION_ARGS)
 
void seq_redo (XLogReaderState *record)
 
void ResetSequenceCaches (void)
 
void seq_mask (char *page, BlockNumber blkno)
 

Variables

static HTABseqhashtab = NULL
 
static SeqTableDatalast_used_seq = NULL
 

Macro Definition Documentation

◆ SEQ_LOG_VALS

#define SEQ_LOG_VALS   32

Definition at line 58 of file sequence.c.

◆ SEQ_MAGIC

#define SEQ_MAGIC   0x1717

Definition at line 63 of file sequence.c.

Typedef Documentation

◆ SeqTable

Definition at line 89 of file sequence.c.

◆ SeqTableData

typedef struct SeqTableData SeqTableData

◆ sequence_magic

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  {
461  ereport(NOTICE,
462  (errmsg("relation \"%s\" does not exist, skipping",
463  stmt->sequence->relname)));
464  return InvalidObjectAddress;
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:4867
#define Assert(condition)
Definition: c.h:858
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:1122
static Form_pg_sequence_data read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
Definition: sequence.c:1183
static void process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
Definition: sequence.c:1583
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:1250
FormData_pg_sequence_data * Form_pg_sequence_data
Definition: sequence.h:32
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
#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:426
@ 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:73
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:3726
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:86
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:18474
#define InvalidTransactionId
Definition: transam.h:31
TransactionId GetTopTransactionId(void)
Definition: xact.c:423

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().

◆ create_seq_hashtable()

static void create_seq_hashtable ( void  )
static

Definition at line 1106 of file sequence.c.

1107 {
1108  HASHCTL ctl;
1109 
1110  ctl.keysize = sizeof(Oid);
1111  ctl.entrysize = sizeof(SeqTableData);
1112 
1113  seqhashtab = hash_create("Sequence values", 16, &ctl,
1114  HASH_ELEM | HASH_BLOBS);
1115 }
static HTAB * seqhashtab
Definition: sequence.c:91
struct SeqTableData SeqTableData
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
tree ctl
Definition: radixtree.h:1851

References ctl, HASH_BLOBS, hash_create(), HASH_ELEM, and seqhashtab.

Referenced by init_sequence().

◆ currval_oid()

Datum currval_oid ( PG_FUNCTION_ARGS  )

Definition at line 859 of file sequence.c.

860 {
861  Oid relid = PG_GETARG_OID(0);
862  int64 result;
863  SeqTable elm;
864  Relation seqrel;
865 
866  /* open and lock sequence */
867  init_sequence(relid, &elm, &seqrel);
868 
869  if (pg_class_aclcheck(elm->relid, GetUserId(),
871  ereport(ERROR,
872  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
873  errmsg("permission denied for sequence %s",
874  RelationGetRelationName(seqrel))));
875 
876  if (!elm->last_valid)
877  ereport(ERROR,
878  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
879  errmsg("currval of sequence \"%s\" is not yet defined in this session",
880  RelationGetRelationName(seqrel))));
881 
882  result = elm->last;
883 
884  sequence_close(seqrel, NoLock);
885 
886  PG_RETURN_INT64(result);
887 }
@ ACLCHECK_OK
Definition: acl.h:183
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4079
int errcode(int sqlerrcode)
Definition: elog.c:859
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
Oid GetUserId(void)
Definition: miscinit.c:514
#define ACL_USAGE
Definition: parsenodes.h:84
#define ACL_SELECT
Definition: parsenodes.h:77
#define RelationGetRelationName(relation)
Definition: rel.h:539
bool last_valid
Definition: sequence.c:81

References ACL_SELECT, ACL_USAGE, ACLCHECK_OK, ereport, errcode(), errmsg(), ERROR, GetUserId(), init_sequence(), SeqTableData::last, SeqTableData::last_valid, NoLock, pg_class_aclcheck(), PG_GETARG_OID, PG_RETURN_INT64, RelationGetRelationName, SeqTableData::relid, and sequence_close().

◆ 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 */
157  ereport(NOTICE,
158  (errcode(ERRCODE_DUPLICATE_TABLE),
159  errmsg("relation \"%s\" already exists, skipping",
160  seq->sequence->relname)));
161  return InvalidObjectAddress;
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 
223  sequence_close(rel, NoLock);
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
#define OidIsValid(objectId)
Definition: c.h:775
#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
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
static struct @155 value
int i
Definition: isn.c:73
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:492
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:724
#define makeNode(_type_)
Definition: nodes.h:155
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:57
#define RelationGetDescr(relation)
Definition: rel.h:531
bool is_not_null
Definition: parsenodes.h:731
bool if_not_exists
Definition: parsenodes.h:3135
List * options
Definition: parsenodes.h:3132
RangeVar * sequence
Definition: parsenodes.h:3131
char * relname
Definition: primnodes.h:82
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:700

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

564 {
565  Relation rel;
566  HeapTuple tuple;
567 
568  rel = table_open(SequenceRelationId, RowExclusiveLock);
569 
570  tuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
571  if (!HeapTupleIsValid(tuple))
572  elog(ERROR, "cache lookup failed for sequence %u", relid);
573 
574  CatalogTupleDelete(rel, &tuple->t_self);
575 
576  ReleaseSysCache(tuple);
578 }
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

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

Referenced by doDeletion().

◆ do_setval()

static void do_setval ( Oid  relid,
int64  next,
bool  iscalled 
)
static

Definition at line 938 of file sequence.c.

939 {
940  SeqTable elm;
941  Relation seqrel;
942  Buffer buf;
943  HeapTupleData seqdatatuple;
945  HeapTuple pgstuple;
946  Form_pg_sequence pgsform;
947  int64 maxv,
948  minv;
949 
950  /* open and lock sequence */
951  init_sequence(relid, &elm, &seqrel);
952 
954  ereport(ERROR,
955  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
956  errmsg("permission denied for sequence %s",
957  RelationGetRelationName(seqrel))));
958 
959  pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
960  if (!HeapTupleIsValid(pgstuple))
961  elog(ERROR, "cache lookup failed for sequence %u", relid);
962  pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
963  maxv = pgsform->seqmax;
964  minv = pgsform->seqmin;
965  ReleaseSysCache(pgstuple);
966 
967  /* read-only transactions may only modify temp sequences */
968  if (!seqrel->rd_islocaltemp)
969  PreventCommandIfReadOnly("setval()");
970 
971  /*
972  * Forbid this during parallel operation because, to make it work, the
973  * cooperating backends would need to share the backend-local cached
974  * sequence information. Currently, we don't support that.
975  */
976  PreventCommandIfParallelMode("setval()");
977 
978  /* lock page buffer and read tuple */
979  seq = read_seq_tuple(seqrel, &buf, &seqdatatuple);
980 
981  if ((next < minv) || (next > maxv))
982  ereport(ERROR,
983  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
984  errmsg("setval: value %lld is out of bounds for sequence \"%s\" (%lld..%lld)",
985  (long long) next, RelationGetRelationName(seqrel),
986  (long long) minv, (long long) maxv)));
987 
988  /* Set the currval() state only if iscalled = true */
989  if (iscalled)
990  {
991  elm->last = next; /* last returned number */
992  elm->last_valid = true;
993  }
994 
995  /* In any case, forget any future cached numbers */
996  elm->cached = elm->last;
997 
998  /* check the comment above nextval_internal()'s equivalent call. */
999  if (RelationNeedsWAL(seqrel))
1001 
1002  /* ready to change the on-disk (or really, in-buffer) tuple */
1004 
1005  seq->last_value = next; /* last fetched number */
1006  seq->is_called = iscalled;
1007  seq->log_cnt = 0;
1008 
1010 
1011  /* XLOG stuff */
1012  if (RelationNeedsWAL(seqrel))
1013  {
1014  xl_seq_rec xlrec;
1015  XLogRecPtr recptr;
1016  Page page = BufferGetPage(buf);
1017 
1018  XLogBeginInsert();
1020 
1021  xlrec.locator = seqrel->rd_locator;
1022  XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
1023  XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len);
1024 
1025  recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
1026 
1027  PageSetLSN(page, recptr);
1028  }
1029 
1030  END_CRIT_SECTION();
1031 
1033 
1034  sequence_close(seqrel, NoLock);
1035 }
static int32 next
Definition: blutils.c:221
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2474
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:408
Pointer Page
Definition: bufpage.h:78
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:388
#define XLOG_SEQ_LOG
Definition: sequence.h:46
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
#define ACL_UPDATE
Definition: parsenodes.h:78
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
RelFileLocator locator
Definition: sequence.h:50
void PreventCommandIfReadOnly(const char *cmdname)
Definition: utility.c:404
void PreventCommandIfParallelMode(const char *cmdname)
Definition: utility.c:422
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:364
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
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, ACLCHECK_OK, buf, BufferGetPage(), SeqTableData::cached, elog, END_CRIT_SECTION, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, GetTopTransactionId(), GetUserId(), HeapTupleIsValid, init_sequence(), FormData_pg_sequence_data::is_called, SeqTableData::last, SeqTableData::last_valid, FormData_pg_sequence_data::last_value, xl_seq_rec::locator, FormData_pg_sequence_data::log_cnt, MarkBufferDirty(), next, NoLock, ObjectIdGetDatum(), PageSetLSN(), pg_class_aclcheck(), PreventCommandIfParallelMode(), PreventCommandIfReadOnly(), RelationData::rd_islocaltemp, RelationData::rd_locator, read_seq_tuple(), REGBUF_WILL_INIT, RelationGetRelationName, RelationNeedsWAL, ReleaseSysCache(), SeqTableData::relid, SearchSysCache1(), sequence_close(), START_CRIT_SECTION, HeapTupleData::t_data, HeapTupleData::t_len, UnlockReleaseBuffer(), XLOG_SEQ_LOG, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by setval3_oid(), and setval_oid().

◆ fill_seq_fork_with_data()

static void fill_seq_fork_with_data ( Relation  rel,
HeapTuple  tuple,
ForkNumber  forkNum 
)
static

Definition at line 359 of file sequence.c.

360 {
361  Buffer buf;
362  Page page;
363  sequence_magic *sm;
364  OffsetNumber offnum;
365 
366  /* Initialize first page of relation with special magic number */
367 
368  buf = ExtendBufferedRel(BMR_REL(rel), forkNum, NULL,
371 
372  page = BufferGetPage(buf);
373 
374  PageInit(page, BufferGetPageSize(buf), sizeof(sequence_magic));
375  sm = (sequence_magic *) PageGetSpecialPointer(page);
376  sm->magic = SEQ_MAGIC;
377 
378  /* Now insert sequence tuple */
379 
380  /*
381  * Since VACUUM does not process sequences, we have to force the tuple to
382  * have xmin = FrozenTransactionId now. Otherwise it would become
383  * invisible to SELECTs after 2G transactions. It is okay to do this
384  * because if the current transaction aborts, no other xact will ever
385  * examine the sequence tuple anyway.
386  */
393 
394  /* check the comment above nextval_internal()'s equivalent call. */
395  if (RelationNeedsWAL(rel))
397 
399 
401 
402  offnum = PageAddItem(page, (Item) tuple->t_data, tuple->t_len,
403  InvalidOffsetNumber, false, false);
404  if (offnum != FirstOffsetNumber)
405  elog(ERROR, "failed to add sequence tuple to page");
406 
407  /* XLOG stuff */
408  if (RelationNeedsWAL(rel) || forkNum == INIT_FORKNUM)
409  {
410  xl_seq_rec xlrec;
411  XLogRecPtr recptr;
412 
413  XLogBeginInsert();
415 
416  xlrec.locator = rel->rd_locator;
417 
418  XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
419  XLogRegisterData((char *) tuple->t_data, tuple->t_len);
420 
421  recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
422 
423  PageSetLSN(page, recptr);
424  }
425 
427 
429 }
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3667
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
Definition: bufmgr.c:845
static Size BufferGetPageSize(Buffer buffer)
Definition: bufmgr.h:397
@ EB_SKIP_EXTENSION_LOCK
Definition: bufmgr.h:74
@ EB_LOCK_FIRST
Definition: bufmgr.h:86
#define BMR_REL(p_rel)
Definition: bufmgr.h:107
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
#define FirstCommandId
Definition: c.h:668
#define SEQ_MAGIC
Definition: sequence.c:63
#define HeapTupleHeaderSetXminFrozen(tup)
Definition: htup_details.h:348
#define HeapTupleHeaderSetXmin(tup, xid)
Definition: htup_details.h:315
#define HeapTupleHeaderSetXmax(tup, xid)
Definition: htup_details.h:376
#define HeapTupleHeaderSetCmin(tup, cid)
Definition: htup_details.h:393
#define HEAP_XMAX_INVALID
Definition: htup_details.h:208
Pointer Item
Definition: item.h:17
static void ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
Definition: itemptr.h:135
#define InvalidOffsetNumber
Definition: off.h:26
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
@ INIT_FORKNUM
Definition: relpath.h:53
ItemPointerData t_ctid
Definition: htup_details.h:161
uint32 magic
Definition: sequence.c:67
#define FrozenTransactionId
Definition: transam.h:33

References Assert, BMR_REL, buf, BufferGetBlockNumber(), BufferGetPage(), BufferGetPageSize(), EB_LOCK_FIRST, EB_SKIP_EXTENSION_LOCK, elog, END_CRIT_SECTION, ERROR, ExtendBufferedRel(), FirstCommandId, FirstOffsetNumber, FrozenTransactionId, GetTopTransactionId(), HEAP_XMAX_INVALID, HeapTupleHeaderSetCmin, HeapTupleHeaderSetXmax, HeapTupleHeaderSetXmin, HeapTupleHeaderSetXminFrozen, INIT_FORKNUM, InvalidOffsetNumber, InvalidTransactionId, ItemPointerSet(), xl_seq_rec::locator, sequence_magic::magic, MarkBufferDirty(), PageAddItem, PageGetSpecialPointer(), PageInit(), PageSetLSN(), RelationData::rd_locator, REGBUF_WILL_INIT, RelationNeedsWAL, SEQ_MAGIC, START_CRIT_SECTION, HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleData::t_len, UnlockReleaseBuffer(), XLOG_SEQ_LOG, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by fill_seq_with_data().

◆ fill_seq_with_data()

static void fill_seq_with_data ( Relation  rel,
HeapTuple  tuple 
)
static

Definition at line 338 of file sequence.c.

339 {
341 
342  if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
343  {
344  SMgrRelation srel;
345 
347  smgrcreate(srel, INIT_FORKNUM, false);
351  smgrclose(srel);
352  }
353 }
void FlushRelationBuffers(Relation rel)
Definition: bufmgr.c:4435
static void fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum)
Definition: sequence.c:359
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
@ MAIN_FORKNUM
Definition: relpath.h:50
SMgrRelation smgropen(RelFileLocator rlocator, ProcNumber backend)
Definition: smgr.c:198
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:411
void smgrclose(SMgrRelation reln)
Definition: smgr.c:320
void log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
Definition: storage.c:186

References fill_seq_fork_with_data(), FlushRelationBuffers(), INIT_FORKNUM, INVALID_PROC_NUMBER, log_smgrcreate(), MAIN_FORKNUM, RelationData::rd_locator, RelationData::rd_rel, smgrclose(), smgrcreate(), and smgropen().

Referenced by AlterSequence(), DefineSequence(), ResetSequence(), and SequenceChangePersistence().

◆ init_params()

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 
)
static

Definition at line 1250 of file sequence.c.

1256 {
1257  DefElem *as_type = NULL;
1258  DefElem *start_value = NULL;
1259  DefElem *restart_value = NULL;
1260  DefElem *increment_by = NULL;
1261  DefElem *max_value = NULL;
1262  DefElem *min_value = NULL;
1263  DefElem *cache_value = NULL;
1264  DefElem *is_cycled = NULL;
1265  ListCell *option;
1266  bool reset_max_value = false;
1267  bool reset_min_value = false;
1268 
1269  *need_seq_rewrite = false;
1270  *owned_by = NIL;
1271 
1272  foreach(option, options)
1273  {
1274  DefElem *defel = (DefElem *) lfirst(option);
1275 
1276  if (strcmp(defel->defname, "as") == 0)
1277  {
1278  if (as_type)
1279  errorConflictingDefElem(defel, pstate);
1280  as_type = defel;
1281  *need_seq_rewrite = true;
1282  }
1283  else if (strcmp(defel->defname, "increment") == 0)
1284  {
1285  if (increment_by)
1286  errorConflictingDefElem(defel, pstate);
1287  increment_by = defel;
1288  *need_seq_rewrite = true;
1289  }
1290  else if (strcmp(defel->defname, "start") == 0)
1291  {
1292  if (start_value)
1293  errorConflictingDefElem(defel, pstate);
1294  start_value = defel;
1295  *need_seq_rewrite = true;
1296  }
1297  else if (strcmp(defel->defname, "restart") == 0)
1298  {
1299  if (restart_value)
1300  errorConflictingDefElem(defel, pstate);
1301  restart_value = defel;
1302  *need_seq_rewrite = true;
1303  }
1304  else if (strcmp(defel->defname, "maxvalue") == 0)
1305  {
1306  if (max_value)
1307  errorConflictingDefElem(defel, pstate);
1308  max_value = defel;
1309  *need_seq_rewrite = true;
1310  }
1311  else if (strcmp(defel->defname, "minvalue") == 0)
1312  {
1313  if (min_value)
1314  errorConflictingDefElem(defel, pstate);
1315  min_value = defel;
1316  *need_seq_rewrite = true;
1317  }
1318  else if (strcmp(defel->defname, "cache") == 0)
1319  {
1320  if (cache_value)
1321  errorConflictingDefElem(defel, pstate);
1322  cache_value = defel;
1323  *need_seq_rewrite = true;
1324  }
1325  else if (strcmp(defel->defname, "cycle") == 0)
1326  {
1327  if (is_cycled)
1328  errorConflictingDefElem(defel, pstate);
1329  is_cycled = defel;
1330  *need_seq_rewrite = true;
1331  }
1332  else if (strcmp(defel->defname, "owned_by") == 0)
1333  {
1334  if (*owned_by)
1335  errorConflictingDefElem(defel, pstate);
1336  *owned_by = defGetQualifiedName(defel);
1337  }
1338  else if (strcmp(defel->defname, "sequence_name") == 0)
1339  {
1340  /*
1341  * The parser allows this, but it is only for identity columns, in
1342  * which case it is filtered out in parse_utilcmd.c. We only get
1343  * here if someone puts it into a CREATE SEQUENCE.
1344  */
1345  ereport(ERROR,
1346  (errcode(ERRCODE_SYNTAX_ERROR),
1347  errmsg("invalid sequence option SEQUENCE NAME"),
1348  parser_errposition(pstate, defel->location)));
1349  }
1350  else
1351  elog(ERROR, "option \"%s\" not recognized",
1352  defel->defname);
1353  }
1354 
1355  /*
1356  * We must reset log_cnt when isInit or when changing any parameters that
1357  * would affect future nextval allocations.
1358  */
1359  if (isInit)
1360  seqdataform->log_cnt = 0;
1361 
1362  /* AS type */
1363  if (as_type != NULL)
1364  {
1365  Oid newtypid = typenameTypeId(pstate, defGetTypeName(as_type));
1366 
1367  if (newtypid != INT2OID &&
1368  newtypid != INT4OID &&
1369  newtypid != INT8OID)
1370  ereport(ERROR,
1371  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1372  for_identity
1373  ? errmsg("identity column type must be smallint, integer, or bigint")
1374  : errmsg("sequence type must be smallint, integer, or bigint")));
1375 
1376  if (!isInit)
1377  {
1378  /*
1379  * When changing type and the old sequence min/max values were the
1380  * min/max of the old type, adjust sequence min/max values to
1381  * min/max of new type. (Otherwise, the user chose explicit
1382  * min/max values, which we'll leave alone.)
1383  */
1384  if ((seqform->seqtypid == INT2OID && seqform->seqmax == PG_INT16_MAX) ||
1385  (seqform->seqtypid == INT4OID && seqform->seqmax == PG_INT32_MAX) ||
1386  (seqform->seqtypid == INT8OID && seqform->seqmax == PG_INT64_MAX))
1387  reset_max_value = true;
1388  if ((seqform->seqtypid == INT2OID && seqform->seqmin == PG_INT16_MIN) ||
1389  (seqform->seqtypid == INT4OID && seqform->seqmin == PG_INT32_MIN) ||
1390  (seqform->seqtypid == INT8OID && seqform->seqmin == PG_INT64_MIN))
1391  reset_min_value = true;
1392  }
1393 
1394  seqform->seqtypid = newtypid;
1395  }
1396  else if (isInit)
1397  {
1398  seqform->seqtypid = INT8OID;
1399  }
1400 
1401  /* INCREMENT BY */
1402  if (increment_by != NULL)
1403  {
1404  seqform->seqincrement = defGetInt64(increment_by);
1405  if (seqform->seqincrement == 0)
1406  ereport(ERROR,
1407  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1408  errmsg("INCREMENT must not be zero")));
1409  seqdataform->log_cnt = 0;
1410  }
1411  else if (isInit)
1412  {
1413  seqform->seqincrement = 1;
1414  }
1415 
1416  /* CYCLE */
1417  if (is_cycled != NULL)
1418  {
1419  seqform->seqcycle = boolVal(is_cycled->arg);
1420  Assert(BoolIsValid(seqform->seqcycle));
1421  seqdataform->log_cnt = 0;
1422  }
1423  else if (isInit)
1424  {
1425  seqform->seqcycle = false;
1426  }
1427 
1428  /* MAXVALUE (null arg means NO MAXVALUE) */
1429  if (max_value != NULL && max_value->arg)
1430  {
1431  seqform->seqmax = defGetInt64(max_value);
1432  seqdataform->log_cnt = 0;
1433  }
1434  else if (isInit || max_value != NULL || reset_max_value)
1435  {
1436  if (seqform->seqincrement > 0 || reset_max_value)
1437  {
1438  /* ascending seq */
1439  if (seqform->seqtypid == INT2OID)
1440  seqform->seqmax = PG_INT16_MAX;
1441  else if (seqform->seqtypid == INT4OID)
1442  seqform->seqmax = PG_INT32_MAX;
1443  else
1444  seqform->seqmax = PG_INT64_MAX;
1445  }
1446  else
1447  seqform->seqmax = -1; /* descending seq */
1448  seqdataform->log_cnt = 0;
1449  }
1450 
1451  /* Validate maximum value. No need to check INT8 as seqmax is an int64 */
1452  if ((seqform->seqtypid == INT2OID && (seqform->seqmax < PG_INT16_MIN || seqform->seqmax > PG_INT16_MAX))
1453  || (seqform->seqtypid == INT4OID && (seqform->seqmax < PG_INT32_MIN || seqform->seqmax > PG_INT32_MAX)))
1454  ereport(ERROR,
1455  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1456  errmsg("MAXVALUE (%lld) is out of range for sequence data type %s",
1457  (long long) seqform->seqmax,
1458  format_type_be(seqform->seqtypid))));
1459 
1460  /* MINVALUE (null arg means NO MINVALUE) */
1461  if (min_value != NULL && min_value->arg)
1462  {
1463  seqform->seqmin = defGetInt64(min_value);
1464  seqdataform->log_cnt = 0;
1465  }
1466  else if (isInit || min_value != NULL || reset_min_value)
1467  {
1468  if (seqform->seqincrement < 0 || reset_min_value)
1469  {
1470  /* descending seq */
1471  if (seqform->seqtypid == INT2OID)
1472  seqform->seqmin = PG_INT16_MIN;
1473  else if (seqform->seqtypid == INT4OID)
1474  seqform->seqmin = PG_INT32_MIN;
1475  else
1476  seqform->seqmin = PG_INT64_MIN;
1477  }
1478  else
1479  seqform->seqmin = 1; /* ascending seq */
1480  seqdataform->log_cnt = 0;
1481  }
1482 
1483  /* Validate minimum value. No need to check INT8 as seqmin is an int64 */
1484  if ((seqform->seqtypid == INT2OID && (seqform->seqmin < PG_INT16_MIN || seqform->seqmin > PG_INT16_MAX))
1485  || (seqform->seqtypid == INT4OID && (seqform->seqmin < PG_INT32_MIN || seqform->seqmin > PG_INT32_MAX)))
1486  ereport(ERROR,
1487  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1488  errmsg("MINVALUE (%lld) is out of range for sequence data type %s",
1489  (long long) seqform->seqmin,
1490  format_type_be(seqform->seqtypid))));
1491 
1492  /* crosscheck min/max */
1493  if (seqform->seqmin >= seqform->seqmax)
1494  ereport(ERROR,
1495  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1496  errmsg("MINVALUE (%lld) must be less than MAXVALUE (%lld)",
1497  (long long) seqform->seqmin,
1498  (long long) seqform->seqmax)));
1499 
1500  /* START WITH */
1501  if (start_value != NULL)
1502  {
1503  seqform->seqstart = defGetInt64(start_value);
1504  }
1505  else if (isInit)
1506  {
1507  if (seqform->seqincrement > 0)
1508  seqform->seqstart = seqform->seqmin; /* ascending seq */
1509  else
1510  seqform->seqstart = seqform->seqmax; /* descending seq */
1511  }
1512 
1513  /* crosscheck START */
1514  if (seqform->seqstart < seqform->seqmin)
1515  ereport(ERROR,
1516  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1517  errmsg("START value (%lld) cannot be less than MINVALUE (%lld)",
1518  (long long) seqform->seqstart,
1519  (long long) seqform->seqmin)));
1520  if (seqform->seqstart > seqform->seqmax)
1521  ereport(ERROR,
1522  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1523  errmsg("START value (%lld) cannot be greater than MAXVALUE (%lld)",
1524  (long long) seqform->seqstart,
1525  (long long) seqform->seqmax)));
1526 
1527  /* RESTART [WITH] */
1528  if (restart_value != NULL)
1529  {
1530  if (restart_value->arg != NULL)
1531  seqdataform->last_value = defGetInt64(restart_value);
1532  else
1533  seqdataform->last_value = seqform->seqstart;
1534  seqdataform->is_called = false;
1535  seqdataform->log_cnt = 0;
1536  }
1537  else if (isInit)
1538  {
1539  seqdataform->last_value = seqform->seqstart;
1540  seqdataform->is_called = false;
1541  }
1542 
1543  /* crosscheck RESTART (or current value, if changing MIN/MAX) */
1544  if (seqdataform->last_value < seqform->seqmin)
1545  ereport(ERROR,
1546  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1547  errmsg("RESTART value (%lld) cannot be less than MINVALUE (%lld)",
1548  (long long) seqdataform->last_value,
1549  (long long) seqform->seqmin)));
1550  if (seqdataform->last_value > seqform->seqmax)
1551  ereport(ERROR,
1552  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1553  errmsg("RESTART value (%lld) cannot be greater than MAXVALUE (%lld)",
1554  (long long) seqdataform->last_value,
1555  (long long) seqform->seqmax)));
1556 
1557  /* CACHE */
1558  if (cache_value != NULL)
1559  {
1560  seqform->seqcache = defGetInt64(cache_value);
1561  if (seqform->seqcache <= 0)
1562  ereport(ERROR,
1563  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1564  errmsg("CACHE (%lld) must be greater than zero",
1565  (long long) seqform->seqcache)));
1566  seqdataform->log_cnt = 0;
1567  }
1568  else if (isInit)
1569  {
1570  seqform->seqcache = 1;
1571  }
1572 }
#define PG_INT32_MAX
Definition: c.h:589
#define BoolIsValid(boolean)
Definition: c.h:757
#define PG_INT16_MIN
Definition: c.h:585
#define PG_INT64_MAX
Definition: c.h:592
#define PG_INT64_MIN
Definition: c.h:591
#define PG_INT32_MIN
Definition: c.h:588
#define PG_INT16_MAX
Definition: c.h:586
List * defGetQualifiedName(DefElem *def)
Definition: define.c:252
int64 defGetInt64(DefElem *def)
Definition: define.c:186
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:384
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:284
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
#define lfirst(lc)
Definition: pg_list.h:172
char * defname
Definition: parsenodes.h:815
ParseLoc location
Definition: parsenodes.h:819
Node * arg
Definition: parsenodes.h:816
#define boolVal(v)
Definition: value.h:81

References DefElem::arg, Assert, BoolIsValid, boolVal, defGetInt64(), defGetQualifiedName(), defGetTypeName(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, errorConflictingDefElem(), format_type_be(), FormData_pg_sequence_data::is_called, FormData_pg_sequence_data::last_value, lfirst, DefElem::location, FormData_pg_sequence_data::log_cnt, NIL, parser_errposition(), PG_INT16_MAX, PG_INT16_MIN, PG_INT32_MAX, PG_INT32_MIN, PG_INT64_MAX, PG_INT64_MIN, and typenameTypeId().

Referenced by AlterSequence(), and DefineSequence().

◆ init_sequence()

static void init_sequence ( Oid  relid,
SeqTable p_elm,
Relation p_rel 
)
static

Definition at line 1122 of file sequence.c.

1123 {
1124  SeqTable elm;
1125  Relation seqrel;
1126  bool found;
1127 
1128  /* Find or create a hash table entry for this sequence */
1129  if (seqhashtab == NULL)
1131 
1132  elm = (SeqTable) hash_search(seqhashtab, &relid, HASH_ENTER, &found);
1133 
1134  /*
1135  * Initialize the new hash table entry if it did not exist already.
1136  *
1137  * NOTE: seqhashtab entries are stored for the life of a backend (unless
1138  * explicitly discarded with DISCARD). If the sequence itself is deleted
1139  * then the entry becomes wasted memory, but it's small enough that this
1140  * should not matter.
1141  */
1142  if (!found)
1143  {
1144  /* relid already filled in */
1147  elm->last_valid = false;
1148  elm->last = elm->cached = 0;
1149  }
1150 
1151  /*
1152  * Open the sequence relation.
1153  */
1154  seqrel = lock_and_open_sequence(elm);
1155 
1156  /*
1157  * If the sequence has been transactionally replaced since we last saw it,
1158  * discard any cached-but-unissued values. We do not touch the currval()
1159  * state, however.
1160  */
1161  if (seqrel->rd_rel->relfilenode != elm->filenumber)
1162  {
1163  elm->filenumber = seqrel->rd_rel->relfilenode;
1164  elm->cached = elm->last;
1165  }
1166 
1167  /* Return results */
1168  *p_elm = elm;
1169  *p_rel = seqrel;
1170 }
SeqTableData * SeqTable
Definition: sequence.c:89
static void create_seq_hashtable(void)
Definition: sequence.c:1106
static Relation lock_and_open_sequence(SeqTable seq)
Definition: sequence.c:1078
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
@ HASH_ENTER
Definition: hsearch.h:114
#define InvalidLocalTransactionId
Definition: lock.h:65
#define InvalidRelFileNumber
Definition: relpath.h:26
RelFileNumber filenumber
Definition: sequence.c:79
LocalTransactionId lxid
Definition: sequence.c:80

References SeqTableData::cached, create_seq_hashtable(), SeqTableData::filenumber, HASH_ENTER, hash_search(), InvalidLocalTransactionId, InvalidRelFileNumber, SeqTableData::last, SeqTableData::last_valid, lock_and_open_sequence(), SeqTableData::lxid, RelationData::rd_rel, and seqhashtab.

Referenced by AlterSequence(), currval_oid(), do_setval(), nextval_internal(), pg_sequence_last_value(), ResetSequence(), and SequenceChangePersistence().

◆ lastval()

Datum lastval ( PG_FUNCTION_ARGS  )

Definition at line 890 of file sequence.c.

891 {
892  Relation seqrel;
893  int64 result;
894 
895  if (last_used_seq == NULL)
896  ereport(ERROR,
897  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
898  errmsg("lastval is not yet defined in this session")));
899 
900  /* Someone may have dropped the sequence since the last nextval() */
902  ereport(ERROR,
903  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
904  errmsg("lastval is not yet defined in this session")));
905 
907 
908  /* nextval() must have already been called for this sequence */
910 
913  ereport(ERROR,
914  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
915  errmsg("permission denied for sequence %s",
916  RelationGetRelationName(seqrel))));
917 
918  result = last_used_seq->last;
919  sequence_close(seqrel, NoLock);
920 
921  PG_RETURN_INT64(result);
922 }
static SeqTableData * last_used_seq
Definition: sequence.c:97
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:95

References ACL_SELECT, ACL_USAGE, ACLCHECK_OK, Assert, ereport, errcode(), errmsg(), ERROR, GetUserId(), SeqTableData::last, last_used_seq, SeqTableData::last_valid, lock_and_open_sequence(), NoLock, ObjectIdGetDatum(), pg_class_aclcheck(), PG_RETURN_INT64, RelationGetRelationName, SeqTableData::relid, SearchSysCacheExists1, and sequence_close().

◆ lock_and_open_sequence()

static Relation lock_and_open_sequence ( SeqTable  seq)
static

Definition at line 1078 of file sequence.c.

1079 {
1080  LocalTransactionId thislxid = MyProc->vxid.lxid;
1081 
1082  /* Get the lock if not already held in this xact */
1083  if (seq->lxid != thislxid)
1084  {
1085  ResourceOwner currentOwner;
1086 
1087  currentOwner = CurrentResourceOwner;
1089 
1091 
1092  CurrentResourceOwner = currentOwner;
1093 
1094  /* Flag that we have a lock in the current xact */
1095  seq->lxid = thislxid;
1096  }
1097 
1098  /* We now know we have the lock, and can safely open the rel */
1099  return sequence_open(seq->relid, NoLock);
1100 }
uint32 LocalTransactionId
Definition: c.h:654
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:167
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165
PGPROC * MyProc
Definition: proc.c:66
LocalTransactionId lxid
Definition: proc.h:196
struct PGPROC::@117 vxid

References CurrentResourceOwner, LockRelationOid(), SeqTableData::lxid, PGPROC::lxid, MyProc, NoLock, SeqTableData::relid, RowExclusiveLock, sequence_open(), TopTransactionResourceOwner, and PGPROC::vxid.

Referenced by init_sequence(), and lastval().

◆ nextval()

Datum nextval ( PG_FUNCTION_ARGS  )

Definition at line 586 of file sequence.c.

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

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

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

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().

◆ nextval_oid()

Datum nextval_oid ( PG_FUNCTION_ARGS  )

Definition at line 608 of file sequence.c.

609 {
610  Oid relid = PG_GETARG_OID(0);
611 
612  PG_RETURN_INT64(nextval_internal(relid, true));
613 }

References nextval_internal(), PG_GETARG_OID, and PG_RETURN_INT64.

◆ pg_sequence_last_value()

Datum pg_sequence_last_value ( PG_FUNCTION_ARGS  )

Definition at line 1775 of file sequence.c.

1776 {
1777  Oid relid = PG_GETARG_OID(0);
1778  SeqTable elm;
1779  Relation seqrel;
1780  Buffer buf;
1781  HeapTupleData seqtuple;
1783  bool is_called;
1784  int64 result;
1785 
1786  /* open and lock sequence */
1787  init_sequence(relid, &elm, &seqrel);
1788 
1790  ereport(ERROR,
1791  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1792  errmsg("permission denied for sequence %s",
1793  RelationGetRelationName(seqrel))));
1794 
1795  seq = read_seq_tuple(seqrel, &buf, &seqtuple);
1796 
1797  is_called = seq->is_called;
1798  result = seq->last_value;
1799 
1801  sequence_close(seqrel, NoLock);
1802 
1803  if (is_called)
1804  PG_RETURN_INT64(result);
1805  else
1806  PG_RETURN_NULL();
1807 }
#define PG_RETURN_NULL()
Definition: fmgr.h:345

References ACL_SELECT, ACL_USAGE, ACLCHECK_OK, buf, ereport, errcode(), errmsg(), ERROR, GetUserId(), init_sequence(), FormData_pg_sequence_data::is_called, FormData_pg_sequence_data::last_value, NoLock, pg_class_aclcheck(), PG_GETARG_OID, PG_RETURN_INT64, PG_RETURN_NULL, read_seq_tuple(), RelationGetRelationName, sequence_close(), and UnlockReleaseBuffer().

◆ pg_sequence_parameters()

Datum pg_sequence_parameters ( PG_FUNCTION_ARGS  )

Definition at line 1731 of file sequence.c.

1732 {
1733  Oid relid = PG_GETARG_OID(0);
1734  TupleDesc tupdesc;
1735  Datum values[7];
1736  bool isnull[7];
1737  HeapTuple pgstuple;
1738  Form_pg_sequence pgsform;
1739 
1741  ereport(ERROR,
1742  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1743  errmsg("permission denied for sequence %s",
1744  get_rel_name(relid))));
1745 
1746  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1747  elog(ERROR, "return type must be a row type");
1748 
1749  memset(isnull, 0, sizeof(isnull));
1750 
1751  pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
1752  if (!HeapTupleIsValid(pgstuple))
1753  elog(ERROR, "cache lookup failed for sequence %u", relid);
1754  pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
1755 
1756  values[0] = Int64GetDatum(pgsform->seqstart);
1757  values[1] = Int64GetDatum(pgsform->seqmin);
1758  values[2] = Int64GetDatum(pgsform->seqmax);
1759  values[3] = Int64GetDatum(pgsform->seqincrement);
1760  values[4] = BoolGetDatum(pgsform->seqcycle);
1761  values[5] = Int64GetDatum(pgsform->seqcache);
1762  values[6] = ObjectIdGetDatum(pgsform->seqtypid);
1763 
1764  ReleaseSysCache(pgstuple);
1765 
1766  return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
1767 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928

References ACL_SELECT, ACL_UPDATE, ACL_USAGE, ACLCHECK_OK, BoolGetDatum(), elog, ereport, errcode(), errmsg(), ERROR, get_call_result_type(), get_rel_name(), GETSTRUCT, GetUserId(), heap_form_tuple(), HeapTupleGetDatum(), HeapTupleIsValid, Int64GetDatum(), ObjectIdGetDatum(), pg_class_aclcheck(), PG_GETARG_OID, ReleaseSysCache(), SearchSysCache1(), TYPEFUNC_COMPOSITE, and values.

◆ process_owned_by()

static void process_owned_by ( Relation  seqrel,
List owned_by,
bool  for_identity 
)
static

Definition at line 1583 of file sequence.c.

1584 {
1585  DependencyType deptype;
1586  int nnames;
1587  Relation tablerel;
1589 
1590  deptype = for_identity ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO;
1591 
1592  nnames = list_length(owned_by);
1593  Assert(nnames > 0);
1594  if (nnames == 1)
1595  {
1596  /* Must be OWNED BY NONE */
1597  if (strcmp(strVal(linitial(owned_by)), "none") != 0)
1598  ereport(ERROR,
1599  (errcode(ERRCODE_SYNTAX_ERROR),
1600  errmsg("invalid OWNED BY option"),
1601  errhint("Specify OWNED BY table.column or OWNED BY NONE.")));
1602  tablerel = NULL;
1603  attnum = 0;
1604  }
1605  else
1606  {
1607  List *relname;
1608  char *attrname;
1609  RangeVar *rel;
1610 
1611  /* Separate relname and attr name */
1612  relname = list_copy_head(owned_by, nnames - 1);
1613  attrname = strVal(llast(owned_by));
1614 
1615  /* Open and lock rel to ensure it won't go away meanwhile */
1617  tablerel = relation_openrv(rel, AccessShareLock);
1618 
1619  /* Must be a regular or foreign table */
1620  if (!(tablerel->rd_rel->relkind == RELKIND_RELATION ||
1621  tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
1622  tablerel->rd_rel->relkind == RELKIND_VIEW ||
1623  tablerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
1624  ereport(ERROR,
1625  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1626  errmsg("sequence cannot be owned by relation \"%s\"",
1627  RelationGetRelationName(tablerel)),
1628  errdetail_relkind_not_supported(tablerel->rd_rel->relkind)));
1629 
1630  /* We insist on same owner and schema */
1631  if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
1632  ereport(ERROR,
1633  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1634  errmsg("sequence must have same owner as table it is linked to")));
1635  if (RelationGetNamespace(seqrel) != RelationGetNamespace(tablerel))
1636  ereport(ERROR,
1637  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1638  errmsg("sequence must be in same schema as table it is linked to")));
1639 
1640  /* Now, fetch the attribute number from the system cache */
1641  attnum = get_attnum(RelationGetRelid(tablerel), attrname);
1642  if (attnum == InvalidAttrNumber)
1643  ereport(ERROR,
1644  (errcode(ERRCODE_UNDEFINED_COLUMN),
1645  errmsg("column \"%s\" of relation \"%s\" does not exist",
1646  attrname, RelationGetRelationName(tablerel))));
1647  }
1648 
1649  /*
1650  * Catch user explicitly running OWNED BY on identity sequence.
1651  */
1652  if (deptype == DEPENDENCY_AUTO)
1653  {
1654  Oid tableId;
1655  int32 colId;
1656 
1657  if (sequenceIsOwned(RelationGetRelid(seqrel), DEPENDENCY_INTERNAL, &tableId, &colId))
1658  ereport(ERROR,
1659  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1660  errmsg("cannot change ownership of identity sequence"),
1661  errdetail("Sequence \"%s\" is linked to table \"%s\".",
1662  RelationGetRelationName(seqrel),
1663  get_rel_name(tableId))));
1664  }
1665 
1666  /*
1667  * OK, we are ready to update pg_depend. First remove any existing
1668  * dependencies for the sequence, then optionally add a new one.
1669  */
1670  deleteDependencyRecordsForClass(RelationRelationId, RelationGetRelid(seqrel),
1671  RelationRelationId, deptype);
1672 
1673  if (tablerel)
1674  {
1675  ObjectAddress refobject,
1676  depobject;
1677 
1678  refobject.classId = RelationRelationId;
1679  refobject.objectId = RelationGetRelid(tablerel);
1680  refobject.objectSubId = attnum;
1681  depobject.classId = RelationRelationId;
1682  depobject.objectId = RelationGetRelid(seqrel);
1683  depobject.objectSubId = 0;
1684  recordDependencyOn(&depobject, &refobject, deptype);
1685  }
1686 
1687  /* Done, but hold lock until commit */
1688  if (tablerel)
1689  relation_close(tablerel, NoLock);
1690 }
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
signed int int32
Definition: c.h:494
DependencyType
Definition: dependency.h:32
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errhint(const char *fmt,...)
Definition: elog.c:1319
List * list_copy_head(const List *oldlist, int len)
Definition: list.c:1593
#define AccessShareLock
Definition: lockdefs.h:36
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858
int16 attnum
Definition: pg_attribute.h:74
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
NameData relname
Definition: pg_class.h:38
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:350
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:827
#define llast(l)
Definition: pg_list.h:198
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial(l)
Definition: pg_list.h:178
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetNamespace(relation)
Definition: rel.h:546
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: relation.c:137
#define strVal(v)
Definition: value.h:82

References AccessShareLock, Assert, attnum, ObjectAddress::classId, deleteDependencyRecordsForClass(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, ereport, errcode(), errdetail(), errdetail_relkind_not_supported(), errhint(), errmsg(), ERROR, get_attnum(), get_rel_name(), InvalidAttrNumber, linitial, list_copy_head(), list_length(), llast, makeRangeVarFromNameList(), NoLock, ObjectAddress::objectId, ObjectAddress::objectSubId, RelationData::rd_rel, recordDependencyOn(), relation_close(), relation_openrv(), RelationGetNamespace, RelationGetRelationName, RelationGetRelid, relname, sequenceIsOwned(), and strVal.

Referenced by AlterSequence(), and DefineSequence().

◆ read_seq_tuple()

static Form_pg_sequence_data read_seq_tuple ( Relation  rel,
Buffer buf,
HeapTuple  seqdatatuple 
)
static

Definition at line 1183 of file sequence.c.

1184 {
1185  Page page;
1186  ItemId lp;
1187  sequence_magic *sm;
1189 
1190  *buf = ReadBuffer(rel, 0);
1192 
1193  page = BufferGetPage(*buf);
1194  sm = (sequence_magic *) PageGetSpecialPointer(page);
1195 
1196  if (sm->magic != SEQ_MAGIC)
1197  elog(ERROR, "bad magic number in sequence \"%s\": %08X",
1198  RelationGetRelationName(rel), sm->magic);
1199 
1200  lp = PageGetItemId(page, FirstOffsetNumber);
1201  Assert(ItemIdIsNormal(lp));
1202 
1203  /* Note we currently only bother to set these two fields of *seqdatatuple */
1204  seqdatatuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
1205  seqdatatuple->t_len = ItemIdGetLength(lp);
1206 
1207  /*
1208  * Previous releases of Postgres neglected to prevent SELECT FOR UPDATE on
1209  * a sequence, which would leave a non-frozen XID in the sequence tuple's
1210  * xmax, which eventually leads to clog access failures or worse. If we
1211  * see this has happened, clean up after it. We treat this like a hint
1212  * bit update, ie, don't bother to WAL-log it, since we can certainly do
1213  * this again if the update gets lost.
1214  */
1215  Assert(!(seqdatatuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI));
1217  {
1219  seqdatatuple->t_data->t_infomask &= ~HEAP_XMAX_COMMITTED;
1220  seqdatatuple->t_data->t_infomask |= HEAP_XMAX_INVALID;
1221  MarkBufferDirtyHint(*buf, true);
1222  }
1223 
1224  seq = (Form_pg_sequence_data) GETSTRUCT(seqdatatuple);
1225 
1226  return seq;
1227 }
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:5085
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:4914
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:745
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:199
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:351
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:240
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:209
#define HEAP_XMAX_COMMITTED
Definition: htup_details.h:207
#define HeapTupleHeaderGetRawXmax(tup)
Definition: htup_details.h:371
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99

References Assert, buf, BUFFER_LOCK_EXCLUSIVE, BufferGetPage(), elog, ERROR, FirstOffsetNumber, GETSTRUCT, HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_MULTI, HeapTupleHeaderGetRawXmax, HeapTupleHeaderSetXmax, InvalidTransactionId, ItemIdGetLength, ItemIdIsNormal, LockBuffer(), sequence_magic::magic, MarkBufferDirtyHint(), PageGetItem(), PageGetItemId(), PageGetSpecialPointer(), ReadBuffer(), RelationGetRelationName, SEQ_MAGIC, HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, and HeapTupleData::t_len.

Referenced by AlterSequence(), do_setval(), nextval_internal(), pg_sequence_last_value(), ResetSequence(), and SequenceChangePersistence().

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

1865 {
1866  if (seqhashtab)
1867  {
1869  seqhashtab = NULL;
1870  }
1871 
1872  last_used_seq = NULL;
1873 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865

References hash_destroy(), last_used_seq, and seqhashtab.

Referenced by DiscardAll(), and DiscardCommand().

◆ seq_mask()

void seq_mask ( char *  page,
BlockNumber  blkno 
)

Definition at line 1879 of file sequence.c.

1880 {
1882 
1883  mask_unused_space(page);
1884 }
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 1811 of file sequence.c.

1812 {
1813  XLogRecPtr lsn = record->EndRecPtr;
1814  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
1815  Buffer buffer;
1816  Page page;
1817  Page localpage;
1818  char *item;
1819  Size itemsz;
1820  xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
1821  sequence_magic *sm;
1822 
1823  if (info != XLOG_SEQ_LOG)
1824  elog(PANIC, "seq_redo: unknown op code %u", info);
1825 
1826  buffer = XLogInitBufferForRedo(record, 0);
1827  page = (Page) BufferGetPage(buffer);
1828 
1829  /*
1830  * We always reinit the page. However, since this WAL record type is also
1831  * used for updating sequences, it's possible that a hot-standby backend
1832  * is examining the page concurrently; so we mustn't transiently trash the
1833  * buffer. The solution is to build the correct new page contents in
1834  * local workspace and then memcpy into the buffer. Then only bytes that
1835  * are supposed to change will change, even transiently. We must palloc
1836  * the local page for alignment reasons.
1837  */
1838  localpage = (Page) palloc(BufferGetPageSize(buffer));
1839 
1840  PageInit(localpage, BufferGetPageSize(buffer), sizeof(sequence_magic));
1841  sm = (sequence_magic *) PageGetSpecialPointer(localpage);
1842  sm->magic = SEQ_MAGIC;
1843 
1844  item = (char *) xlrec + sizeof(xl_seq_rec);
1845  itemsz = XLogRecGetDataLen(record) - sizeof(xl_seq_rec);
1846 
1847  if (PageAddItem(localpage, (Item) item, itemsz,
1848  FirstOffsetNumber, false, false) == InvalidOffsetNumber)
1849  elog(PANIC, "seq_redo: failed to add item to page");
1850 
1851  PageSetLSN(localpage, lsn);
1852 
1853  memcpy(page, localpage, BufferGetPageSize(buffer));
1854  MarkBufferDirty(buffer);
1855  UnlockReleaseBuffer(buffer);
1856 
1857  pfree(localpage);
1858 }
unsigned char uint8
Definition: c.h:504
size_t Size
Definition: c.h:605
struct xl_seq_rec xl_seq_rec
#define PANIC
Definition: elog.h:42
void pfree(void *pointer)
Definition: mcxt.c:1520
void * palloc(Size size)
Definition: mcxt.c:1316
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
#define XLogRecGetDataLen(decoder)
Definition: xlogreader.h:416
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
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, XLogRecGetInfo, and XLR_INFO_MASK.

◆ sequence_options()

List* sequence_options ( Oid  relid)

Definition at line 1697 of file sequence.c.

1698 {
1699  HeapTuple pgstuple;
1700  Form_pg_sequence pgsform;
1701  List *options = NIL;
1702 
1703  pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
1704  if (!HeapTupleIsValid(pgstuple))
1705  elog(ERROR, "cache lookup failed for sequence %u", relid);
1706  pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
1707 
1708  /* Use makeFloat() for 64-bit integers, like gram.y does. */
1710  makeDefElem("cache", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqcache)), -1));
1712  makeDefElem("cycle", (Node *) makeBoolean(pgsform->seqcycle), -1));
1714  makeDefElem("increment", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqincrement)), -1));
1716  makeDefElem("maxvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmax)), -1));
1718  makeDefElem("minvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmin)), -1));
1720  makeDefElem("start", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqstart)), -1));
1721 
1722  ReleaseSysCache(pgstuple);
1723 
1724  return options;
1725 }
#define INT64_FORMAT
Definition: c.h:548
DefElem * makeDefElem(char *name, Node *arg, int location)
Definition: makefuncs.c:564
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, 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  init_sequence(relid, &elm, &seqrel);
549 
550  /* check the comment above nextval_internal()'s equivalent call. */
551  if (RelationNeedsWAL(seqrel))
553 
554  (void) read_seq_tuple(seqrel, &buf, &seqdatatuple);
555  RelationSetNewRelfilenumber(seqrel, newrelpersistence);
556  fill_seq_with_data(seqrel, &seqdatatuple);
558 
559  sequence_close(seqrel, NoLock);
560 }

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

Referenced by ATRewriteTables().

◆ setval3_oid()

Datum setval3_oid ( PG_FUNCTION_ARGS  )

Definition at line 1057 of file sequence.c.

1058 {
1059  Oid relid = PG_GETARG_OID(0);
1060  int64 next = PG_GETARG_INT64(1);
1061  bool iscalled = PG_GETARG_BOOL(2);
1062 
1063  do_setval(relid, next, iscalled);
1064 
1066 }
static void do_setval(Oid relid, int64 next, bool iscalled)
Definition: sequence.c:938
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274

References do_setval(), next, PG_GETARG_BOOL, PG_GETARG_INT64, PG_GETARG_OID, and PG_RETURN_INT64.

◆ setval_oid()

Datum setval_oid ( PG_FUNCTION_ARGS  )

Definition at line 1042 of file sequence.c.

1043 {
1044  Oid relid = PG_GETARG_OID(0);
1045  int64 next = PG_GETARG_INT64(1);
1046 
1047  do_setval(relid, next, true);
1048 
1050 }

References do_setval(), next, PG_GETARG_INT64, PG_GETARG_OID, and PG_RETURN_INT64.

Variable Documentation

◆ last_used_seq

SeqTableData* last_used_seq = NULL
static

Definition at line 97 of file sequence.c.

Referenced by lastval(), nextval_internal(), and ResetSequenceCaches().

◆ seqhashtab

HTAB* seqhashtab = NULL
static

Definition at line 91 of file sequence.c.

Referenced by create_seq_hashtable(), init_sequence(), and ResetSequenceCaches().