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

◆ SEQ_MAGIC

#define SEQ_MAGIC   0x1717

Definition at line 62 of file sequence.c.

Typedef Documentation

◆ SeqTable

Definition at line 88 of file sequence.c.

◆ SeqTableData

typedef struct SeqTableData SeqTableData

◆ sequence_magic

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:3954
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define ERROR
Definition: elog.h:35
#define NOTICE
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:145
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
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:600
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationNeedsWAL(relation)
Definition: rel.h:626
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3708
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
List * options
Definition: parsenodes.h:2748
RangeVar * sequence
Definition: parsenodes.h:2747
bool for_identity
Definition: parsenodes.h:2749
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:52
char * relname
Definition: primnodes.h:77
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:16994
#define InvalidTransactionId
Definition: transam.h:31
TransactionId GetTopTransactionId(void)
Definition: xact.c:416

References Assert(), buf, SeqTableData::cached, CatalogTupleUpdate(), elog(), ereport, errmsg(), ERROR, fill_seq_with_data(), AlterSeqStmt::for_identity, GETSTRUCT, GetTopTransactionId(), heap_copytuple(), HeapTupleIsValid, init_params(), init_sequence(), InvalidMultiXactId, InvalidObjectAddress, InvalidOid, InvalidTransactionId, InvokeObjectPostAlterHook, SeqTableData::last, AlterSeqStmt::missing_ok, NoLock, NOTICE, ObjectAddressSet, ObjectIdGetDatum(), AlterSeqStmt::options, process_owned_by(), RangeVarCallbackOwnsRelation(), RangeVarGetRelidExtended(), RelationData::rd_rel, read_seq_tuple(), relation_close(), RelationNeedsWAL, RelationSetNewRelfilenumber(), RangeVar::relname, RowExclusiveLock, RVR_MISSING_OK, SearchSysCacheCopy1, SEQRELID, AlterSeqStmt::sequence, ShareRowExclusiveLock, 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 1119 of file sequence.c.

1120 {
1121  HASHCTL ctl;
1122 
1123  ctl.keysize = sizeof(Oid);
1124  ctl.entrysize = sizeof(SeqTableData);
1125 
1126  seqhashtab = hash_create("Sequence values", 16, &ctl,
1127  HASH_ELEM | HASH_BLOBS);
1128 }
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
static HTAB * seqhashtab
Definition: sequence.c:90
struct SeqTableData SeqTableData
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

References HASHCTL::entrysize, HASH_BLOBS, hash_create(), HASH_ELEM, HASHCTL::keysize, and seqhashtab.

Referenced by init_sequence().

◆ currval_oid()

Datum currval_oid ( PG_FUNCTION_ARGS  )

Definition at line 872 of file sequence.c.

873 {
874  Oid relid = PG_GETARG_OID(0);
875  int64 result;
876  SeqTable elm;
877  Relation seqrel;
878 
879  /* open and lock sequence */
880  init_sequence(relid, &elm, &seqrel);
881 
882  if (pg_class_aclcheck(elm->relid, GetUserId(),
884  ereport(ERROR,
885  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
886  errmsg("permission denied for sequence %s",
887  RelationGetRelationName(seqrel))));
888 
889  if (!elm->last_valid)
890  ereport(ERROR,
891  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
892  errmsg("currval of sequence \"%s\" is not yet defined in this session",
893  RelationGetRelationName(seqrel))));
894 
895  result = elm->last;
896 
897  relation_close(seqrel, NoLock);
898 
899  PG_RETURN_INT64(result);
900 }
@ ACLCHECK_OK
Definition: acl.h:184
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4746
int errcode(int sqlerrcode)
Definition: elog.c:695
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
Oid GetUserId(void)
Definition: miscinit.c:497
#define ACL_USAGE
Definition: parsenodes.h:91
#define ACL_SELECT
Definition: parsenodes.h:84
#define RelationGetRelationName(relation)
Definition: rel.h:535
bool last_valid
Definition: sequence.c:80

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, relation_close(), RelationGetRelationName, and SeqTableData::relid.

◆ 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;
126  CreateStmt *stmt = makeNode(CreateStmt);
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:711
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1683
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:221
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:472
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:537
#define makeNode(_type_)
Definition: nodes.h:165
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition: pg_depend.c:257
#define NIL
Definition: pg_list.h:66
FormData_pg_sequence
Definition: pg_sequence.h:33
#define Int64GetDatumFast(X)
Definition: postgres.h:902
uintptr_t Datum
Definition: postgres.h:412
static Datum BoolGetDatum(bool X)
Definition: postgres.h:450
@ ONCOMMIT_NOOP
Definition: primnodes.h:49
#define RelationGetDescr(relation)
Definition: rel.h:527
#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:693
CollateClause * collClause
Definition: parsenodes.h:703
int location
Definition: parsenodes.h:707
List * constraints
Definition: parsenodes.h:705
Node * cooked_default
Definition: parsenodes.h:698
int inhcount
Definition: parsenodes.h:691
char * colname
Definition: parsenodes.h:688
TypeName * typeName
Definition: parsenodes.h:689
bool is_from_type
Definition: parsenodes.h:694
Node * raw_default
Definition: parsenodes.h:697
char storage
Definition: parsenodes.h:695
Oid collOid
Definition: parsenodes.h:704
bool is_local
Definition: parsenodes.h:692
bool if_not_exists
Definition: parsenodes.h:2741
List * options
Definition: parsenodes.h:2738
RangeVar * sequence
Definition: parsenodes.h:2737
List * tableElts
Definition: parsenodes.h:2260
OnCommitAction oncommit
Definition: parsenodes.h:2268
List * options
Definition: parsenodes.h:2267
bool if_not_exists
Definition: parsenodes.h:2271
List * inhRelations
Definition: parsenodes.h:2261
RangeVar * relation
Definition: parsenodes.h:2259
char * tablespacename
Definition: parsenodes.h:2269
List * constraints
Definition: parsenodes.h:2266
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, CreateStmt::constraints, ColumnDef::cooked_default, DefineRelation(), ereport, errcode(), errmsg(), fill_seq_with_data(), CreateSeqStmt::for_identity, FormData_pg_sequence, heap_form_tuple(), heap_freetuple(), i, CreateStmt::if_not_exists, CreateSeqStmt::if_not_exists, ColumnDef::inhcount, CreateStmt::inhRelations, 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, CreateStmt::oncommit, ONCOMMIT_NOOP, CreateStmt::options, CreateSeqStmt::options, CreateSeqStmt::ownerId, process_owned_by(), RangeVarGetAndCheckCreationNamespace(), ColumnDef::raw_default, CreateStmt::relation, RelationGetDescr, RangeVar::relname, RowExclusiveLock, SEQ_COL_CALLED, SEQ_COL_FIRSTCOL, SEQ_COL_LASTCOL, SEQ_COL_LASTVAL, SEQ_COL_LOG, CreateSeqStmt::sequence, ColumnDef::storage, table_close(), table_open(), CreateStmt::tableElts, CreateStmt::tablespacename, 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:350
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173

References CatalogTupleDelete(), elog(), ERROR, HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), SEQRELID, 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 951 of file sequence.c.

952 {
953  SeqTable elm;
954  Relation seqrel;
955  Buffer buf;
956  HeapTupleData seqdatatuple;
958  HeapTuple pgstuple;
959  Form_pg_sequence pgsform;
960  int64 maxv,
961  minv;
962 
963  /* open and lock sequence */
964  init_sequence(relid, &elm, &seqrel);
965 
967  ereport(ERROR,
968  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
969  errmsg("permission denied for sequence %s",
970  RelationGetRelationName(seqrel))));
971 
972  pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
973  if (!HeapTupleIsValid(pgstuple))
974  elog(ERROR, "cache lookup failed for sequence %u", relid);
975  pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
976  maxv = pgsform->seqmax;
977  minv = pgsform->seqmin;
978  ReleaseSysCache(pgstuple);
979 
980  /* read-only transactions may only modify temp sequences */
981  if (!seqrel->rd_islocaltemp)
982  PreventCommandIfReadOnly("setval()");
983 
984  /*
985  * Forbid this during parallel operation because, to make it work, the
986  * cooperating backends would need to share the backend-local cached
987  * sequence information. Currently, we don't support that.
988  */
989  PreventCommandIfParallelMode("setval()");
990 
991  /* lock page' buffer and read tuple */
992  seq = read_seq_tuple(seqrel, &buf, &seqdatatuple);
993 
994  if ((next < minv) || (next > maxv))
995  ereport(ERROR,
996  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
997  errmsg("setval: value %lld is out of bounds for sequence \"%s\" (%lld..%lld)",
998  (long long) next, RelationGetRelationName(seqrel),
999  (long long) minv, (long long) maxv)));
1000 
1001  /* Set the currval() state only if iscalled = true */
1002  if (iscalled)
1003  {
1004  elm->last = next; /* last returned number */
1005  elm->last_valid = true;
1006  }
1007 
1008  /* In any case, forget any future cached numbers */
1009  elm->cached = elm->last;
1010 
1011  /* check the comment above nextval_internal()'s equivalent call. */
1012  if (RelationNeedsWAL(seqrel))
1014 
1015  /* ready to change the on-disk (or really, in-buffer) tuple */
1017 
1018  seq->last_value = next; /* last fetched number */
1019  seq->is_called = iscalled;
1020  seq->log_cnt = 0;
1021 
1023 
1024  /* XLOG stuff */
1025  if (RelationNeedsWAL(seqrel))
1026  {
1027  xl_seq_rec xlrec;
1028  XLogRecPtr recptr;
1029  Page page = BufferGetPage(buf);
1030 
1031  XLogBeginInsert();
1033 
1034  xlrec.locator = seqrel->rd_locator;
1035  XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
1036  XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len);
1037 
1038  recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
1039 
1040  PageSetLSN(page, recptr);
1041  }
1042 
1043  END_CRIT_SECTION();
1044 
1046 
1047  relation_close(seqrel, NoLock);
1048 }
static int32 next
Definition: blutils.c:219
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1583
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:280
Pointer Page
Definition: bufpage.h:78
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:388
#define START_CRIT_SECTION()
Definition: miscadmin.h:148
#define END_CRIT_SECTION()
Definition: miscadmin.h:150
#define ACL_UPDATE
Definition: parsenodes.h:85
#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
RelFileLocator locator
Definition: sequence.h:50
void PreventCommandIfReadOnly(const char *cmdname)
Definition: utility.c:411
void PreventCommandIfParallelMode(const char *cmdname)
Definition: utility.c:429
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, 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, relation_close(), RelationGetRelationName, RelationNeedsWAL, ReleaseSysCache(), SeqTableData::relid, SearchSysCache1(), SEQRELID, 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 371 of file sequence.c.

372 {
373  Buffer buf;
374  Page page;
375  sequence_magic *sm;
376  OffsetNumber offnum;
377 
378  /* Initialize first page of relation with special magic number */
379 
380  buf = ReadBufferExtended(rel, forkNum, P_NEW, RBM_NORMAL, NULL);
382 
383  page = BufferGetPage(buf);
384 
385  PageInit(page, BufferGetPageSize(buf), sizeof(sequence_magic));
386  sm = (sequence_magic *) PageGetSpecialPointer(page);
387  sm->magic = SEQ_MAGIC;
388 
389  /* Now insert sequence tuple */
390 
392 
393  /*
394  * Since VACUUM does not process sequences, we have to force the tuple to
395  * have xmin = FrozenTransactionId now. Otherwise it would become
396  * invisible to SELECTs after 2G transactions. It is okay to do this
397  * because if the current transaction aborts, no other xact will ever
398  * examine the sequence tuple anyway.
399  */
406 
407  /* check the comment above nextval_internal()'s equivalent call. */
408  if (RelationNeedsWAL(rel))
410 
412 
414 
415  offnum = PageAddItem(page, (Item) tuple->t_data, tuple->t_len,
416  InvalidOffsetNumber, false, false);
417  if (offnum != FirstOffsetNumber)
418  elog(ERROR, "failed to add sequence tuple to page");
419 
420  /* XLOG stuff */
421  if (RelationNeedsWAL(rel) || forkNum == INIT_FORKNUM)
422  {
423  xl_seq_rec xlrec;
424  XLogRecPtr recptr;
425 
426  XLogBeginInsert();
428 
429  xlrec.locator = rel->rd_locator;
430 
431  XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
432  XLogRegisterData((char *) tuple->t_data, tuple->t_len);
433 
434  recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
435 
436  PageSetLSN(page, recptr);
437  }
438 
440 
442 }
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2763
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4172
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:759
#define P_NEW
Definition: bufmgr.h:100
static Size BufferGetPageSize(Buffer buffer)
Definition: bufmgr.h:266
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:107
@ RBM_NORMAL
Definition: bufmgr.h:39
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:604
#define HeapTupleHeaderSetXminFrozen(tup)
Definition: htup_details.h:347
#define HeapTupleHeaderSetXmin(tup, xid)
Definition: htup_details.h:314
#define HeapTupleHeaderSetXmax(tup, xid)
Definition: htup_details.h:375
#define HeapTupleHeaderSetCmin(tup, cid)
Definition: htup_details.h:392
#define HEAP_XMAX_INVALID
Definition: htup_details.h:207
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
#define SEQ_MAGIC
Definition: sequence.c:62
ItemPointerData t_ctid
Definition: htup_details.h:160
uint32 magic
Definition: sequence.c:66
#define FrozenTransactionId
Definition: transam.h:33

References Assert(), buf, BUFFER_LOCK_EXCLUSIVE, BufferGetBlockNumber(), BufferGetPage(), BufferGetPageSize(), elog(), END_CRIT_SECTION, ERROR, FirstCommandId, FirstOffsetNumber, FrozenTransactionId, GetTopTransactionId(), HEAP_XMAX_INVALID, HeapTupleHeaderSetCmin, HeapTupleHeaderSetXmax, HeapTupleHeaderSetXmin, HeapTupleHeaderSetXminFrozen, INIT_FORKNUM, InvalidOffsetNumber, InvalidTransactionId, ItemPointerSet(), xl_seq_rec::locator, LockBuffer(), sequence_magic::magic, MarkBufferDirty(), P_NEW, PageAddItem, PageGetSpecialPointer(), PageInit(), PageSetLSN(), RBM_NORMAL, RelationData::rd_locator, ReadBufferExtended(), 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 350 of file sequence.c.

351 {
353 
354  if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
355  {
356  SMgrRelation srel;
357 
358  srel = smgropen(rel->rd_locator, InvalidBackendId);
359  smgrcreate(srel, INIT_FORKNUM, false);
363  smgrclose(srel);
364  }
365 }
#define InvalidBackendId
Definition: backendid.h:23
void FlushRelationBuffers(Relation rel)
Definition: bufmgr.c:3519
@ MAIN_FORKNUM
Definition: relpath.h:50
static void fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum)
Definition: sequence.c:371
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:369
void smgrclose(SMgrRelation reln)
Definition: smgr.c:256
SMgrRelation smgropen(RelFileLocator rlocator, BackendId backend)
Definition: smgr.c:146
void log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
Definition: storage.c:185

References fill_seq_fork_with_data(), FlushRelationBuffers(), INIT_FORKNUM, InvalidBackendId, 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 1269 of file sequence.c.

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

1136 {
1137  SeqTable elm;
1138  Relation seqrel;
1139  bool found;
1140 
1141  /* Find or create a hash table entry for this sequence */
1142  if (seqhashtab == NULL)
1144 
1145  elm = (SeqTable) hash_search(seqhashtab, &relid, HASH_ENTER, &found);
1146 
1147  /*
1148  * Initialize the new hash table entry if it did not exist already.
1149  *
1150  * NOTE: seqhashtab entries are stored for the life of a backend (unless
1151  * explicitly discarded with DISCARD). If the sequence itself is deleted
1152  * then the entry becomes wasted memory, but it's small enough that this
1153  * should not matter.
1154  */
1155  if (!found)
1156  {
1157  /* relid already filled in */
1160  elm->last_valid = false;
1161  elm->last = elm->cached = 0;
1162  }
1163 
1164  /*
1165  * Open the sequence relation.
1166  */
1167  seqrel = lock_and_open_sequence(elm);
1168 
1169  if (seqrel->rd_rel->relkind != RELKIND_SEQUENCE)
1170  ereport(ERROR,
1171  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1172  errmsg("\"%s\" is not a sequence",
1173  RelationGetRelationName(seqrel))));
1174 
1175  /*
1176  * If the sequence has been transactionally replaced since we last saw it,
1177  * discard any cached-but-unissued values. We do not touch the currval()
1178  * state, however.
1179  */
1180  if (seqrel->rd_rel->relfilenode != elm->filenumber)
1181  {
1182  elm->filenumber = seqrel->rd_rel->relfilenode;
1183  elm->cached = elm->last;
1184  }
1185 
1186  /* Return results */
1187  *p_elm = elm;
1188  *p_rel = seqrel;
1189 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
@ HASH_ENTER
Definition: hsearch.h:114
#define InvalidLocalTransactionId
Definition: lock.h:70
#define InvalidRelFileNumber
Definition: relpath.h:26
SeqTableData * SeqTable
Definition: sequence.c:88
static void create_seq_hashtable(void)
Definition: sequence.c:1119
static Relation lock_and_open_sequence(SeqTable seq)
Definition: sequence.c:1091
RelFileNumber filenumber
Definition: sequence.c:78
LocalTransactionId lxid
Definition: sequence.c:79

References SeqTableData::cached, create_seq_hashtable(), ereport, errcode(), errmsg(), ERROR, SeqTableData::filenumber, HASH_ENTER, hash_search(), InvalidLocalTransactionId, InvalidRelFileNumber, SeqTableData::last, SeqTableData::last_valid, lock_and_open_sequence(), SeqTableData::lxid, RelationData::rd_rel, RelationGetRelationName, 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 903 of file sequence.c.

904 {
905  Relation seqrel;
906  int64 result;
907 
908  if (last_used_seq == NULL)
909  ereport(ERROR,
910  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
911  errmsg("lastval is not yet defined in this session")));
912 
913  /* Someone may have dropped the sequence since the last nextval() */
915  ereport(ERROR,
916  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
917  errmsg("lastval is not yet defined in this session")));
918 
920 
921  /* nextval() must have already been called for this sequence */
923 
926  ereport(ERROR,
927  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
928  errmsg("permission denied for sequence %s",
929  RelationGetRelationName(seqrel))));
930 
931  result = last_used_seq->last;
932  relation_close(seqrel, NoLock);
933 
934  PG_RETURN_INT64(result);
935 }
static SeqTableData * last_used_seq
Definition: sequence.c:96
@ RELOID
Definition: syscache.h:89
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:188

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, relation_close(), RelationGetRelationName, SeqTableData::relid, RELOID, and SearchSysCacheExists1.

◆ lock_and_open_sequence()

static Relation lock_and_open_sequence ( SeqTable  seq)
static

Definition at line 1091 of file sequence.c.

1092 {
1093  LocalTransactionId thislxid = MyProc->lxid;
1094 
1095  /* Get the lock if not already held in this xact */
1096  if (seq->lxid != thislxid)
1097  {
1098  ResourceOwner currentOwner;
1099 
1100  currentOwner = CurrentResourceOwner;
1102 
1104 
1105  CurrentResourceOwner = currentOwner;
1106 
1107  /* Flag that we have a lock in the current xact */
1108  seq->lxid = thislxid;
1109  }
1110 
1111  /* We now know we have the lock, and can safely open the rel */
1112  return relation_open(seq->relid, NoLock);
1113 }
uint32 LocalTransactionId
Definition: c.h:590
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:148
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
PGPROC * MyProc
Definition: proc.c:68
LocalTransactionId lxid
Definition: proc.h:183

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

Referenced by init_sequence(), and lastval().

◆ 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
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:623
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3654

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 }
static XLogRecPtr PageGetLSN(Page page)
Definition: bufpage.h:383
#define SEQ_LOG_VALS
Definition: sequence.c:57
int64 increment
Definition: sequence.c:84
XLogRecPtr GetRedoRecPtr(void)
Definition: xlog.c:6015

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

◆ nextval_oid()

Datum nextval_oid ( PG_FUNCTION_ARGS  )

Definition at line 621 of file sequence.c.

622 {
623  Oid relid = PG_GETARG_OID(0);
624 
625  PG_RETURN_INT64(nextval_internal(relid, true));
626 }

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

1810 {
1811  Oid relid = PG_GETARG_OID(0);
1812  SeqTable elm;
1813  Relation seqrel;
1814  Buffer buf;
1815  HeapTupleData seqtuple;
1817  bool is_called;
1818  int64 result;
1819 
1820  /* open and lock sequence */
1821  init_sequence(relid, &elm, &seqrel);
1822 
1824  ereport(ERROR,
1825  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1826  errmsg("permission denied for sequence %s",
1827  RelationGetRelationName(seqrel))));
1828 
1829  seq = read_seq_tuple(seqrel, &buf, &seqtuple);
1830 
1831  is_called = seq->is_called;
1832  result = seq->last_value;
1833 
1835  relation_close(seqrel, NoLock);
1836 
1837  if (is_called)
1838  PG_RETURN_INT64(result);
1839  else
1840  PG_RETURN_NULL();
1841 }
#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(), relation_close(), RelationGetRelationName, and UnlockReleaseBuffer().

◆ pg_sequence_parameters()

Datum pg_sequence_parameters ( PG_FUNCTION_ARGS  )

Definition at line 1750 of file sequence.c.

1751 {
1752  Oid relid = PG_GETARG_OID(0);
1753  TupleDesc tupdesc;
1754  Datum values[7];
1755  bool isnull[7];
1756  HeapTuple pgstuple;
1757  Form_pg_sequence pgsform;
1758 
1760  ereport(ERROR,
1761  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1762  errmsg("permission denied for sequence %s",
1763  get_rel_name(relid))));
1764 
1765  tupdesc = CreateTemplateTupleDesc(7);
1766  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "start_value",
1767  INT8OID, -1, 0);
1768  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "minimum_value",
1769  INT8OID, -1, 0);
1770  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "maximum_value",
1771  INT8OID, -1, 0);
1772  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "increment",
1773  INT8OID, -1, 0);
1774  TupleDescInitEntry(tupdesc, (AttrNumber) 5, "cycle_option",
1775  BOOLOID, -1, 0);
1776  TupleDescInitEntry(tupdesc, (AttrNumber) 6, "cache_size",
1777  INT8OID, -1, 0);
1778  TupleDescInitEntry(tupdesc, (AttrNumber) 7, "data_type",
1779  OIDOID, -1, 0);
1780 
1781  BlessTupleDesc(tupdesc);
1782 
1783  memset(isnull, 0, sizeof(isnull));
1784 
1785  pgstuple = SearchSysCache1(SEQRELID, relid);
1786  if (!HeapTupleIsValid(pgstuple))
1787  elog(ERROR, "cache lookup failed for sequence %u", relid);
1788  pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
1789 
1790  values[0] = Int64GetDatum(pgsform->seqstart);
1791  values[1] = Int64GetDatum(pgsform->seqmin);
1792  values[2] = Int64GetDatum(pgsform->seqmax);
1793  values[3] = Int64GetDatum(pgsform->seqincrement);
1794  values[4] = BoolGetDatum(pgsform->seqcycle);
1795  values[5] = Int64GetDatum(pgsform->seqcache);
1796  values[6] = ObjectIdGetDatum(pgsform->seqtypid);
1797 
1798  ReleaseSysCache(pgstuple);
1799 
1800  return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
1801 }
int16 AttrNumber
Definition: attnum.h:21
static Datum values[MAXATTR]
Definition: bootstrap.c:156
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2071
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1910
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:45
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:583

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

◆ process_owned_by()

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

Definition at line 1602 of file sequence.c.

1603 {
1604  DependencyType deptype;
1605  int nnames;
1606  Relation tablerel;
1608 
1609  deptype = for_identity ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO;
1610 
1611  nnames = list_length(owned_by);
1612  Assert(nnames > 0);
1613  if (nnames == 1)
1614  {
1615  /* Must be OWNED BY NONE */
1616  if (strcmp(strVal(linitial(owned_by)), "none") != 0)
1617  ereport(ERROR,
1618  (errcode(ERRCODE_SYNTAX_ERROR),
1619  errmsg("invalid OWNED BY option"),
1620  errhint("Specify OWNED BY table.column or OWNED BY NONE.")));
1621  tablerel = NULL;
1622  attnum = 0;
1623  }
1624  else
1625  {
1626  List *relname;
1627  char *attrname;
1628  RangeVar *rel;
1629 
1630  /* Separate relname and attr name */
1631  relname = list_copy_head(owned_by, nnames - 1);
1632  attrname = strVal(llast(owned_by));
1633 
1634  /* Open and lock rel to ensure it won't go away meanwhile */
1636  tablerel = relation_openrv(rel, AccessShareLock);
1637 
1638  /* Must be a regular or foreign table */
1639  if (!(tablerel->rd_rel->relkind == RELKIND_RELATION ||
1640  tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
1641  tablerel->rd_rel->relkind == RELKIND_VIEW ||
1642  tablerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
1643  ereport(ERROR,
1644  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1645  errmsg("sequence cannot be owned by relation \"%s\"",
1646  RelationGetRelationName(tablerel)),
1647  errdetail_relkind_not_supported(tablerel->rd_rel->relkind)));
1648 
1649  /* We insist on same owner and schema */
1650  if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
1651  ereport(ERROR,
1652  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1653  errmsg("sequence must have same owner as table it is linked to")));
1654  if (RelationGetNamespace(seqrel) != RelationGetNamespace(tablerel))
1655  ereport(ERROR,
1656  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1657  errmsg("sequence must be in same schema as table it is linked to")));
1658 
1659  /* Now, fetch the attribute number from the system cache */
1660  attnum = get_attnum(RelationGetRelid(tablerel), attrname);
1661  if (attnum == InvalidAttrNumber)
1662  ereport(ERROR,
1663  (errcode(ERRCODE_UNDEFINED_COLUMN),
1664  errmsg("column \"%s\" of relation \"%s\" does not exist",
1665  attrname, RelationGetRelationName(tablerel))));
1666  }
1667 
1668  /*
1669  * Catch user explicitly running OWNED BY on identity sequence.
1670  */
1671  if (deptype == DEPENDENCY_AUTO)
1672  {
1673  Oid tableId;
1674  int32 colId;
1675 
1676  if (sequenceIsOwned(RelationGetRelid(seqrel), DEPENDENCY_INTERNAL, &tableId, &colId))
1677  ereport(ERROR,
1678  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1679  errmsg("cannot change ownership of identity sequence"),
1680  errdetail("Sequence \"%s\" is linked to table \"%s\".",
1681  RelationGetRelationName(seqrel),
1682  get_rel_name(tableId))));
1683  }
1684 
1685  /*
1686  * OK, we are ready to update pg_depend. First remove any existing
1687  * dependencies for the sequence, then optionally add a new one.
1688  */
1689  deleteDependencyRecordsForClass(RelationRelationId, RelationGetRelid(seqrel),
1690  RelationRelationId, deptype);
1691 
1692  if (tablerel)
1693  {
1694  ObjectAddress refobject,
1695  depobject;
1696 
1697  refobject.classId = RelationRelationId;
1698  refobject.objectId = RelationGetRelid(tablerel);
1699  refobject.objectSubId = attnum;
1700  depobject.classId = RelationRelationId;
1701  depobject.objectId = RelationGetRelid(seqrel);
1702  depobject.objectSubId = 0;
1703  recordDependencyOn(&depobject, &refobject, deptype);
1704  }
1705 
1706  /* Done, but hold lock until commit */
1707  if (tablerel)
1708  relation_close(tablerel, NoLock);
1709 }
#define InvalidAttrNumber
Definition: attnum.h:23
signed int int32
Definition: c.h:430
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:1039
int errhint(const char *fmt,...)
Definition: elog.c:1153
List * list_copy_head(const List *oldlist, int len)
Definition: list.c:1592
#define AccessShareLock
Definition: lockdefs.h:36
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:857
int16 attnum
Definition: pg_attribute.h:83
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:196
static int list_length(const List *l)
Definition: pg_list.h:150
#define linitial(l)
Definition: pg_list.h:176
#define RelationGetRelid(relation)
Definition: rel.h:501
#define RelationGetNamespace(relation)
Definition: rel.h:542
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: relation.c:138
#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 1202 of file sequence.c.

1203 {
1204  Page page;
1205  ItemId lp;
1206  sequence_magic *sm;
1208 
1209  *buf = ReadBuffer(rel, 0);
1211 
1212  page = BufferGetPage(*buf);
1213  sm = (sequence_magic *) PageGetSpecialPointer(page);
1214 
1215  if (sm->magic != SEQ_MAGIC)
1216  elog(ERROR, "bad magic number in sequence \"%s\": %08X",
1217  RelationGetRelationName(rel), sm->magic);
1218 
1219  lp = PageGetItemId(page, FirstOffsetNumber);
1220  Assert(ItemIdIsNormal(lp));
1221 
1222  /* Note we currently only bother to set these two fields of *seqdatatuple */
1223  seqdatatuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
1224  seqdatatuple->t_len = ItemIdGetLength(lp);
1225 
1226  /*
1227  * Previous releases of Postgres neglected to prevent SELECT FOR UPDATE on
1228  * a sequence, which would leave a non-frozen XID in the sequence tuple's
1229  * xmax, which eventually leads to clog access failures or worse. If we
1230  * see this has happened, clean up after it. We treat this like a hint
1231  * bit update, ie, don't bother to WAL-log it, since we can certainly do
1232  * this again if the update gets lost.
1233  */
1234  Assert(!(seqdatatuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI));
1236  {
1238  seqdatatuple->t_data->t_infomask &= ~HEAP_XMAX_COMMITTED;
1239  seqdatatuple->t_data->t_infomask |= HEAP_XMAX_INVALID;
1240  MarkBufferDirtyHint(*buf, true);
1241  }
1242 
1243  seq = (Form_pg_sequence_data) GETSTRUCT(seqdatatuple);
1244 
1245  return seq;
1246 }
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:4001
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:712
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:208
#define HEAP_XMAX_COMMITTED
Definition: htup_details.h:206
#define HeapTupleHeaderGetRawXmax(tup)
Definition: htup_details.h:370
#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 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 1898 of file sequence.c.

1899 {
1900  if (seqhashtab)
1901  {
1903  seqhashtab = NULL;
1904  }
1905 
1906  last_used_seq = NULL;
1907 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:863

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

1914 {
1916 
1917  mask_unused_space(page);
1918 }
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 1845 of file sequence.c.

1846 {
1847  XLogRecPtr lsn = record->EndRecPtr;
1848  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
1849  Buffer buffer;
1850  Page page;
1851  Page localpage;
1852  char *item;
1853  Size itemsz;
1854  xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
1855  sequence_magic *sm;
1856 
1857  if (info != XLOG_SEQ_LOG)
1858  elog(PANIC, "seq_redo: unknown op code %u", info);
1859 
1860  buffer = XLogInitBufferForRedo(record, 0);
1861  page = (Page) BufferGetPage(buffer);
1862 
1863  /*
1864  * We always reinit the page. However, since this WAL record type is also
1865  * used for updating sequences, it's possible that a hot-standby backend
1866  * is examining the page concurrently; so we mustn't transiently trash the
1867  * buffer. The solution is to build the correct new page contents in
1868  * local workspace and then memcpy into the buffer. Then only bytes that
1869  * are supposed to change will change, even transiently. We must palloc
1870  * the local page for alignment reasons.
1871  */
1872  localpage = (Page) palloc(BufferGetPageSize(buffer));
1873 
1874  PageInit(localpage, BufferGetPageSize(buffer), sizeof(sequence_magic));
1875  sm = (sequence_magic *) PageGetSpecialPointer(localpage);
1876  sm->magic = SEQ_MAGIC;
1877 
1878  item = (char *) xlrec + sizeof(xl_seq_rec);
1879  itemsz = XLogRecGetDataLen(record) - sizeof(xl_seq_rec);
1880 
1881  if (PageAddItem(localpage, (Item) item, itemsz,
1882  FirstOffsetNumber, false, false) == InvalidOffsetNumber)
1883  elog(PANIC, "seq_redo: failed to add item to page");
1884 
1885  PageSetLSN(localpage, lsn);
1886 
1887  memcpy(page, localpage, BufferGetPageSize(buffer));
1888  MarkBufferDirty(buffer);
1889  UnlockReleaseBuffer(buffer);
1890 
1891  pfree(localpage);
1892 }
unsigned char uint8
Definition: c.h:440
size_t Size
Definition: c.h:541
#define PANIC
Definition: elog.h:38
void pfree(void *pointer)
Definition: mcxt.c:1306
void * palloc(Size size)
Definition: mcxt.c:1199
struct xl_seq_rec xl_seq_rec
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
#define XLogRecGetDataLen(decoder)
Definition: xlogreader.h:417
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:411
#define XLogRecGetData(decoder)
Definition: xlogreader.h:416
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
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:484
DefElem * makeDefElem(char *name, Node *arg, int location)
Definition: makefuncs.c:546
static char ** options
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
Definition: nodes.h:118
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().

◆ setval3_oid()

Datum setval3_oid ( PG_FUNCTION_ARGS  )

Definition at line 1070 of file sequence.c.

1071 {
1072  Oid relid = PG_GETARG_OID(0);
1073  int64 next = PG_GETARG_INT64(1);
1074  bool iscalled = PG_GETARG_BOOL(2);
1075 
1076  do_setval(relid, next, iscalled);
1077 
1079 }
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
static void do_setval(Oid relid, int64 next, bool iscalled)
Definition: sequence.c:951

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

1056 {
1057  Oid relid = PG_GETARG_OID(0);
1058  int64 next = PG_GETARG_INT64(1);
1059 
1060  do_setval(relid, next, true);
1061 
1063 }

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

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

◆ seqhashtab

HTAB* seqhashtab = NULL
static

Definition at line 90 of file sequence.c.

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