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

Go to the source code of this file.

Data Structures

struct  FormData_pg_sequence_data
 
struct  xl_seq_rec
 

Macros

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

Typedefs

typedef struct FormData_pg_sequence_data FormData_pg_sequence_data
 
typedef FormData_pg_sequence_dataForm_pg_sequence_data
 
typedef struct xl_seq_rec xl_seq_rec
 

Functions

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

Macro Definition Documentation

◆ SEQ_COL_CALLED

#define SEQ_COL_CALLED   3

Definition at line 40 of file sequence.h.

Referenced by DefineSequence().

◆ SEQ_COL_FIRSTCOL

#define SEQ_COL_FIRSTCOL   SEQ_COL_LASTVAL

Definition at line 42 of file sequence.h.

Referenced by DefineSequence().

◆ SEQ_COL_LASTCOL

#define SEQ_COL_LASTCOL   SEQ_COL_CALLED

Definition at line 43 of file sequence.h.

Referenced by DefineSequence().

◆ SEQ_COL_LASTVAL

#define SEQ_COL_LASTVAL   1

Definition at line 38 of file sequence.h.

Referenced by DefineSequence().

◆ SEQ_COL_LOG

#define SEQ_COL_LOG   2

Definition at line 39 of file sequence.h.

Referenced by DefineSequence().

◆ XLOG_SEQ_LOG

#define XLOG_SEQ_LOG   0x00

Typedef Documentation

◆ Form_pg_sequence_data

◆ FormData_pg_sequence_data

◆ xl_seq_rec

Function Documentation

◆ AlterSequence()

ObjectAddress AlterSequence ( ParseState pstate,
AlterSeqStmt stmt 
)

Definition at line 416 of file sequence.c.

References buf, SeqTableData::cached, CatalogTupleUpdate(), elog, ereport, errmsg(), ERROR, fill_seq_with_data(), AlterSeqStmt::for_identity, GETSTRUCT, GetTopTransactionId(), heap_close, heap_copytuple(), heap_open(), 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, RelationSetNewRelfilenode(), RangeVar::relname, RowExclusiveLock, RVR_MISSING_OK, SearchSysCacheCopy1, SEQRELID, AlterSeqStmt::sequence, ShareRowExclusiveLock, HeapTupleData::t_self, and UnlockReleaseBuffer().

Referenced by ProcessUtilitySlow().

417 {
418  Oid relid;
419  SeqTable elm;
420  Relation seqrel;
421  Buffer buf;
422  HeapTupleData datatuple;
423  Form_pg_sequence seqform;
424  Form_pg_sequence_data newdataform;
425  bool need_seq_rewrite;
426  List *owned_by;
427  ObjectAddress address;
428  Relation rel;
429  HeapTuple seqtuple;
430  HeapTuple newdatatuple;
431 
432  /* Open and lock sequence, and check for ownership along the way. */
433  relid = RangeVarGetRelidExtended(stmt->sequence,
435  stmt->missing_ok ? RVR_MISSING_OK : 0,
437  NULL);
438  if (relid == InvalidOid)
439  {
440  ereport(NOTICE,
441  (errmsg("relation \"%s\" does not exist, skipping",
442  stmt->sequence->relname)));
443  return InvalidObjectAddress;
444  }
445 
446  init_sequence(relid, &elm, &seqrel);
447 
448  rel = heap_open(SequenceRelationId, RowExclusiveLock);
449  seqtuple = SearchSysCacheCopy1(SEQRELID,
450  ObjectIdGetDatum(relid));
451  if (!HeapTupleIsValid(seqtuple))
452  elog(ERROR, "cache lookup failed for sequence %u",
453  relid);
454 
455  seqform = (Form_pg_sequence) GETSTRUCT(seqtuple);
456 
457  /* lock page's buffer and read tuple into new sequence structure */
458  (void) read_seq_tuple(seqrel, &buf, &datatuple);
459 
460  /* copy the existing sequence data tuple, so it can be modified locally */
461  newdatatuple = heap_copytuple(&datatuple);
462  newdataform = (Form_pg_sequence_data) GETSTRUCT(newdatatuple);
463 
464  UnlockReleaseBuffer(buf);
465 
466  /* Check and set new values */
467  init_params(pstate, stmt->options, stmt->for_identity, false,
468  seqform, newdataform,
469  &need_seq_rewrite, &owned_by);
470 
471  /* Clear local cache so that we don't think we have cached numbers */
472  /* Note that we do not change the currval() state */
473  elm->cached = elm->last;
474 
475  /* If needed, rewrite the sequence relation itself */
476  if (need_seq_rewrite)
477  {
478  /* check the comment above nextval_internal()'s equivalent call. */
479  if (RelationNeedsWAL(seqrel))
481 
482  /*
483  * Create a new storage file for the sequence, making the state
484  * changes transactional. We want to keep the sequence's relfrozenxid
485  * at 0, since it won't contain any unfrozen XIDs. Same with
486  * relminmxid, since a sequence will never contain multixacts.
487  */
488  RelationSetNewRelfilenode(seqrel, seqrel->rd_rel->relpersistence,
490 
491  /*
492  * Insert the modified tuple into the new storage file.
493  */
494  fill_seq_with_data(seqrel, newdatatuple);
495  }
496 
497  /* process OWNED BY if given */
498  if (owned_by)
499  process_owned_by(seqrel, owned_by, stmt->for_identity);
500 
501  /* update the pg_sequence tuple (we could skip this in some cases...) */
502  CatalogTupleUpdate(rel, &seqtuple->t_self, seqtuple);
503 
504  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
505 
506  ObjectAddressSet(address, RelationRelationId, relid);
507 
509  relation_close(seqrel, NoLock);
510 
511  return address;
512 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:722
int64 cached
Definition: sequence.c:79
void RelationSetNewRelfilenode(Relation relation, char persistence, TransactionId freezeXid, MultiXactId minmulti)
Definition: relcache.c:3264
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
FormData_pg_sequence * Form_pg_sequence
Definition: pg_sequence.h:40
#define heap_close(r, l)
Definition: heapam.h:97
TransactionId GetTopTransactionId(void)
Definition: xact.c:389
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
List * options
Definition: parsenodes.h:2495
char * relname
Definition: primnodes.h:69
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
void RangeVarCallbackOwnsRelation(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:13406
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define NoLock
Definition: lockdefs.h:34
static char * buf
Definition: pg_test_fsync.c:67
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidTransactionId
Definition: transam.h:31
static void process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
Definition: sequence.c:1630
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:227
int64 last
Definition: sequence.c:78
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
static Form_pg_sequence_data read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
Definition: sequence.c:1159
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidMultiXactId
Definition: multixact.h:23
#define InvalidOid
Definition: postgres_ext.h:36
RangeVar * sequence
Definition: parsenodes.h:2494
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
#define RelationNeedsWAL(relation)
Definition: rel.h:510
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
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:1225
static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
Definition: sequence.c:1092
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool for_identity
Definition: parsenodes.h:2496
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
int Buffer
Definition: buf.h:23
static void fill_seq_with_data(Relation rel, HeapTuple tuple)
Definition: sequence.c:337
FormData_pg_sequence_data * Form_pg_sequence_data
Definition: sequence.h:32

◆ DefineSequence()

ObjectAddress DefineSequence ( ParseState pstate,
CreateSeqStmt stmt 
)

Definition at line 116 of file sequence.c.

References AccessExclusiveLock, Assert, BoolGetDatum, CatalogTupleInsert(), ColumnDef::collClause, ColumnDef::collOid, ColumnDef::colname, ColumnDef::constraints, CreateStmt::constraints, ColumnDef::cooked_default, DefineRelation(), ereport, errcode(), errmsg(), ERROR, fill_seq_with_data(), CreateSeqStmt::for_identity, FormData_pg_sequence, heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), i, CreateStmt::if_not_exists, CreateSeqStmt::if_not_exists, ColumnDef::inhcount, CreateStmt::inhRelations, init_params(), Int64GetDatum(), Int64GetDatumFast, InvalidObjectAddress, InvalidOid, ColumnDef::is_from_parent, 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, 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, RangeVar::relpersistence, RowExclusiveLock, SEQ_COL_CALLED, SEQ_COL_FIRSTCOL, SEQ_COL_LASTCOL, SEQ_COL_LASTVAL, SEQ_COL_LOG, CreateSeqStmt::sequence, ColumnDef::storage, CreateStmt::tableElts, CreateStmt::tablespacename, ColumnDef::typeName, and value.

Referenced by ProcessUtilitySlow().

117 {
118  FormData_pg_sequence seqform;
119  FormData_pg_sequence_data seqdataform;
120  bool need_seq_rewrite;
121  List *owned_by;
122  CreateStmt *stmt = makeNode(CreateStmt);
123  Oid seqoid;
124  ObjectAddress address;
125  Relation rel;
126  HeapTuple tuple;
127  TupleDesc tupDesc;
129  bool null[SEQ_COL_LASTCOL];
130  Datum pgs_values[Natts_pg_sequence];
131  bool pgs_nulls[Natts_pg_sequence];
132  int i;
133 
134  /* Unlogged sequences are not implemented -- not clear if useful. */
135  if (seq->sequence->relpersistence == RELPERSISTENCE_UNLOGGED)
136  ereport(ERROR,
137  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
138  errmsg("unlogged sequences are not supported")));
139 
140  /*
141  * If if_not_exists was given and a relation with the same name already
142  * exists, bail out. (Note: we needn't check this when not if_not_exists,
143  * because DefineRelation will complain anyway.)
144  */
145  if (seq->if_not_exists)
146  {
147  RangeVarGetAndCheckCreationNamespace(seq->sequence, NoLock, &seqoid);
148  if (OidIsValid(seqoid))
149  {
150  ereport(NOTICE,
151  (errcode(ERRCODE_DUPLICATE_TABLE),
152  errmsg("relation \"%s\" already exists, skipping",
153  seq->sequence->relname)));
154  return InvalidObjectAddress;
155  }
156  }
157 
158  /* Check and set all option values */
159  init_params(pstate, seq->options, seq->for_identity, true,
160  &seqform, &seqdataform,
161  &need_seq_rewrite, &owned_by);
162 
163  /*
164  * Create relation (and fill value[] and null[] for the tuple)
165  */
166  stmt->tableElts = NIL;
167  for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
168  {
169  ColumnDef *coldef = makeNode(ColumnDef);
170 
171  coldef->inhcount = 0;
172  coldef->is_local = true;
173  coldef->is_not_null = true;
174  coldef->is_from_type = false;
175  coldef->is_from_parent = false;
176  coldef->storage = 0;
177  coldef->raw_default = NULL;
178  coldef->cooked_default = NULL;
179  coldef->collClause = NULL;
180  coldef->collOid = InvalidOid;
181  coldef->constraints = NIL;
182  coldef->location = -1;
183 
184  null[i - 1] = false;
185 
186  switch (i)
187  {
188  case SEQ_COL_LASTVAL:
189  coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
190  coldef->colname = "last_value";
191  value[i - 1] = Int64GetDatumFast(seqdataform.last_value);
192  break;
193  case SEQ_COL_LOG:
194  coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
195  coldef->colname = "log_cnt";
196  value[i - 1] = Int64GetDatum((int64) 0);
197  break;
198  case SEQ_COL_CALLED:
199  coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
200  coldef->colname = "is_called";
201  value[i - 1] = BoolGetDatum(false);
202  break;
203  }
204  stmt->tableElts = lappend(stmt->tableElts, coldef);
205  }
206 
207  stmt->relation = seq->sequence;
208  stmt->inhRelations = NIL;
209  stmt->constraints = NIL;
210  stmt->options = NIL;
211  stmt->oncommit = ONCOMMIT_NOOP;
212  stmt->tablespacename = NULL;
213  stmt->if_not_exists = seq->if_not_exists;
214 
215  address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL, NULL);
216  seqoid = address.objectId;
217  Assert(seqoid != InvalidOid);
218 
219  rel = heap_open(seqoid, AccessExclusiveLock);
220  tupDesc = RelationGetDescr(rel);
221 
222  /* now initialize the sequence's data */
223  tuple = heap_form_tuple(tupDesc, value, null);
224  fill_seq_with_data(rel, tuple);
225 
226  /* process OWNED BY if given */
227  if (owned_by)
228  process_owned_by(rel, owned_by, seq->for_identity);
229 
230  heap_close(rel, NoLock);
231 
232  /* fill in pg_sequence */
233  rel = heap_open(SequenceRelationId, RowExclusiveLock);
234  tupDesc = RelationGetDescr(rel);
235 
236  memset(pgs_nulls, 0, sizeof(pgs_nulls));
237 
238  pgs_values[Anum_pg_sequence_seqrelid - 1] = ObjectIdGetDatum(seqoid);
239  pgs_values[Anum_pg_sequence_seqtypid - 1] = ObjectIdGetDatum(seqform.seqtypid);
240  pgs_values[Anum_pg_sequence_seqstart - 1] = Int64GetDatumFast(seqform.seqstart);
241  pgs_values[Anum_pg_sequence_seqincrement - 1] = Int64GetDatumFast(seqform.seqincrement);
242  pgs_values[Anum_pg_sequence_seqmax - 1] = Int64GetDatumFast(seqform.seqmax);
243  pgs_values[Anum_pg_sequence_seqmin - 1] = Int64GetDatumFast(seqform.seqmin);
244  pgs_values[Anum_pg_sequence_seqcache - 1] = Int64GetDatumFast(seqform.seqcache);
245  pgs_values[Anum_pg_sequence_seqcycle - 1] = BoolGetDatum(seqform.seqcycle);
246 
247  tuple = heap_form_tuple(tupDesc, pgs_values, pgs_nulls);
248  CatalogTupleInsert(rel, tuple);
249 
250  heap_freetuple(tuple);
252 
253  return address;
254 }
RangeVar * relation
Definition: parsenodes.h:2014
#define NIL
Definition: pg_list.h:69
OnCommitAction oncommit
Definition: parsenodes.h:2023
List * inhRelations
Definition: parsenodes.h:2016
char storage
Definition: parsenodes.h:654
bool is_local
Definition: parsenodes.h:650
#define RelationGetDescr(relation)
Definition: rel.h:433
List * constraints
Definition: parsenodes.h:662
bool is_from_parent
Definition: parsenodes.h:653
int errcode(int sqlerrcode)
Definition: elog.c:575
#define SEQ_COL_FIRSTCOL
Definition: sequence.h:42
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1074
#define heap_close(r, l)
Definition: heapam.h:97
bool is_not_null
Definition: parsenodes.h:651
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
List * constraints
Definition: parsenodes.h:2021
bool if_not_exists
Definition: parsenodes.h:2025
Node * cooked_default
Definition: parsenodes.h:656
#define SEQ_COL_LASTVAL
Definition: sequence.h:38
FormData_pg_sequence
Definition: pg_sequence.h:33
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:163
#define NoLock
Definition: lockdefs.h:34
Oid collOid
Definition: parsenodes.h:661
#define RowExclusiveLock
Definition: lockdefs.h:38
List * options
Definition: parsenodes.h:2022
static void process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
Definition: sequence.c:1630
int location
Definition: parsenodes.h:664
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1876
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:519
#define ereport(elevel, rest)
Definition: elog.h:122
#define SEQ_COL_LOG
Definition: sequence.h:39
Node * raw_default
Definition: parsenodes.h:655
List * lappend(List *list, void *datum)
Definition: list.c:128
char * tablespacename
Definition: parsenodes.h:2024
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:527
uintptr_t Datum
Definition: postgres.h:365
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define Int64GetDatumFast(X)
Definition: postgres.h:758
static struct @131 value
#define BoolGetDatum(X)
Definition: postgres.h:385
TypeName * makeTypeNameFromOid(Oid typeOid, int32 typmod)
Definition: makefuncs.c:471
#define InvalidOid
Definition: postgres_ext.h:36
bool is_from_type
Definition: parsenodes.h:652
#define NOTICE
Definition: elog.h:37
List * tableElts
Definition: parsenodes.h:2015
#define makeNode(_type_)
Definition: nodes.h:565
#define Assert(condition)
Definition: c.h:699
TypeName * typeName
Definition: parsenodes.h:648
CollateClause * collClause
Definition: parsenodes.h:660
#define SEQ_COL_LASTCOL
Definition: sequence.h:43
#define AccessExclusiveLock
Definition: lockdefs.h:45
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:1225
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define SEQ_COL_CALLED
Definition: sequence.h:40
int i
int inhcount
Definition: parsenodes.h:649
char * colname
Definition: parsenodes.h:647
Definition: pg_list.h:45
static void fill_seq_with_data(Relation rel, HeapTuple tuple)
Definition: sequence.c:337

◆ DeleteSequenceTuple()

void DeleteSequenceTuple ( Oid  relid)

Definition at line 515 of file sequence.c.

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

Referenced by doDeletion().

516 {
517  Relation rel;
518  HeapTuple tuple;
519 
520  rel = heap_open(SequenceRelationId, RowExclusiveLock);
521 
522  tuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
523  if (!HeapTupleIsValid(tuple))
524  elog(ERROR, "cache lookup failed for sequence %u", relid);
525 
526  CatalogTupleDelete(rel, &tuple->t_self);
527 
528  ReleaseSysCache(tuple);
530 }
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:256
#define heap_close(r, l)
Definition: heapam.h:97
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog
Definition: elog.h:219

◆ nextval()

Datum nextval ( PG_FUNCTION_ARGS  )

Definition at line 538 of file sequence.c.

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

Referenced by autoinc(), and ttdummy().

539 {
540  text *seqin = PG_GETARG_TEXT_PP(0);
541  RangeVar *sequence;
542  Oid relid;
543 
545 
546  /*
547  * XXX: This is not safe in the presence of concurrent DDL, but acquiring
548  * a lock here is more expensive than letting nextval_internal do it,
549  * since the latter maintains a cache that keeps us from hitting the lock
550  * manager more than once per transaction. It's not clear whether the
551  * performance penalty is material in practice, but for now, we do it this
552  * way.
553  */
554  relid = RangeVarGetRelid(sequence, NoLock, false);
555 
556  PG_RETURN_INT64(nextval_internal(relid, true));
557 }
#define PG_RETURN_INT64(x)
Definition: fmgr.h:332
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:63
int64 nextval_internal(Oid relid, bool check_permissions)
Definition: sequence.c:568
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3042
unsigned int Oid
Definition: postgres_ext.h:31
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:278
#define NoLock
Definition: lockdefs.h:34
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3232
Definition: c.h:516

◆ nextval_internal()

int64 nextval_internal ( Oid  relid,
bool  check_permissions 
)

Definition at line 568 of file sequence.c.

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(), INT64_FORMAT, FormData_pg_sequence_data::is_called, SeqTableData::last, SeqTableData::last_valid, FormData_pg_sequence_data::last_value, FormData_pg_sequence_data::log_cnt, MarkBufferDirty(), next, xl_seq_rec::node, NoLock, ObjectIdGetDatum, PageGetLSN, PageSetLSN, pg_class_aclcheck(), PreventCommandIfParallelMode(), PreventCommandIfReadOnly(), RelationData::rd_islocaltemp, RelationData::rd_node, read_seq_tuple(), REGBUF_WILL_INIT, relation_close(), RelationGetRelationName, RelationNeedsWAL, ReleaseSysCache(), SeqTableData::relid, SearchSysCache1(), SEQ_LOG_VALS, SEQRELID, snprintf(), 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().

569 {
570  SeqTable elm;
571  Relation seqrel;
572  Buffer buf;
573  Page page;
574  HeapTuple pgstuple;
575  Form_pg_sequence pgsform;
576  HeapTupleData seqdatatuple;
578  int64 incby,
579  maxv,
580  minv,
581  cache,
582  log,
583  fetch,
584  last;
585  int64 result,
586  next,
587  rescnt = 0;
588  bool cycle;
589  bool logit = false;
590 
591  /* open and lock sequence */
592  init_sequence(relid, &elm, &seqrel);
593 
594  if (check_permissions &&
597  ereport(ERROR,
598  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
599  errmsg("permission denied for sequence %s",
600  RelationGetRelationName(seqrel))));
601 
602  /* read-only transactions may only modify temp sequences */
603  if (!seqrel->rd_islocaltemp)
604  PreventCommandIfReadOnly("nextval()");
605 
606  /*
607  * Forbid this during parallel operation because, to make it work, the
608  * cooperating backends would need to share the backend-local cached
609  * sequence information. Currently, we don't support that.
610  */
611  PreventCommandIfParallelMode("nextval()");
612 
613  if (elm->last != elm->cached) /* some numbers were cached */
614  {
615  Assert(elm->last_valid);
616  Assert(elm->increment != 0);
617  elm->last += elm->increment;
618  relation_close(seqrel, NoLock);
619  last_used_seq = elm;
620  return elm->last;
621  }
622 
623  pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
624  if (!HeapTupleIsValid(pgstuple))
625  elog(ERROR, "cache lookup failed for sequence %u", relid);
626  pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
627  incby = pgsform->seqincrement;
628  maxv = pgsform->seqmax;
629  minv = pgsform->seqmin;
630  cache = pgsform->seqcache;
631  cycle = pgsform->seqcycle;
632  ReleaseSysCache(pgstuple);
633 
634  /* lock page' buffer and read tuple */
635  seq = read_seq_tuple(seqrel, &buf, &seqdatatuple);
636  page = BufferGetPage(buf);
637 
638  elm->increment = incby;
639  last = next = result = seq->last_value;
640  fetch = cache;
641  log = seq->log_cnt;
642 
643  if (!seq->is_called)
644  {
645  rescnt++; /* return last_value if not is_called */
646  fetch--;
647  }
648 
649  /*
650  * Decide whether we should emit a WAL log record. If so, force up the
651  * fetch count to grab SEQ_LOG_VALS more values than we actually need to
652  * cache. (These will then be usable without logging.)
653  *
654  * If this is the first nextval after a checkpoint, we must force a new
655  * WAL record to be written anyway, else replay starting from the
656  * checkpoint would fail to advance the sequence past the logged values.
657  * In this case we may as well fetch extra values.
658  */
659  if (log < fetch || !seq->is_called)
660  {
661  /* forced log to satisfy local demand for values */
662  fetch = log = fetch + SEQ_LOG_VALS;
663  logit = true;
664  }
665  else
666  {
667  XLogRecPtr redoptr = GetRedoRecPtr();
668 
669  if (PageGetLSN(page) <= redoptr)
670  {
671  /* last update of seq was before checkpoint */
672  fetch = log = fetch + SEQ_LOG_VALS;
673  logit = true;
674  }
675  }
676 
677  while (fetch) /* try to fetch cache [+ log ] numbers */
678  {
679  /*
680  * Check MAXVALUE for ascending sequences and MINVALUE for descending
681  * sequences
682  */
683  if (incby > 0)
684  {
685  /* ascending sequence */
686  if ((maxv >= 0 && next > maxv - incby) ||
687  (maxv < 0 && next + incby > maxv))
688  {
689  if (rescnt > 0)
690  break; /* stop fetching */
691  if (!cycle)
692  {
693  char buf[100];
694 
695  snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
696  ereport(ERROR,
697  (errcode(ERRCODE_SEQUENCE_GENERATOR_LIMIT_EXCEEDED),
698  errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
699  RelationGetRelationName(seqrel), buf)));
700  }
701  next = minv;
702  }
703  else
704  next += incby;
705  }
706  else
707  {
708  /* descending sequence */
709  if ((minv < 0 && next < minv - incby) ||
710  (minv >= 0 && next + incby < minv))
711  {
712  if (rescnt > 0)
713  break; /* stop fetching */
714  if (!cycle)
715  {
716  char buf[100];
717 
718  snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
719  ereport(ERROR,
720  (errcode(ERRCODE_SEQUENCE_GENERATOR_LIMIT_EXCEEDED),
721  errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
722  RelationGetRelationName(seqrel), buf)));
723  }
724  next = maxv;
725  }
726  else
727  next += incby;
728  }
729  fetch--;
730  if (rescnt < cache)
731  {
732  log--;
733  rescnt++;
734  last = next;
735  if (rescnt == 1) /* if it's first result - */
736  result = next; /* it's what to return */
737  }
738  }
739 
740  log -= fetch; /* adjust for any unfetched numbers */
741  Assert(log >= 0);
742 
743  /* save info in local cache */
744  elm->last = result; /* last returned number */
745  elm->cached = last; /* last fetched number */
746  elm->last_valid = true;
747 
748  last_used_seq = elm;
749 
750  /*
751  * If something needs to be WAL logged, acquire an xid, so this
752  * transaction's commit will trigger a WAL flush and wait for syncrep.
753  * It's sufficient to ensure the toplevel transaction has an xid, no need
754  * to assign xids subxacts, that'll already trigger an appropriate wait.
755  * (Have to do that here, so we're outside the critical section)
756  */
757  if (logit && RelationNeedsWAL(seqrel))
759 
760  /* ready to change the on-disk (or really, in-buffer) tuple */
762 
763  /*
764  * We must mark the buffer dirty before doing XLogInsert(); see notes in
765  * SyncOneBuffer(). However, we don't apply the desired changes just yet.
766  * This looks like a violation of the buffer update protocol, but it is in
767  * fact safe because we hold exclusive lock on the buffer. Any other
768  * process, including a checkpoint, that tries to examine the buffer
769  * contents will block until we release the lock, and then will see the
770  * final state that we install below.
771  */
772  MarkBufferDirty(buf);
773 
774  /* XLOG stuff */
775  if (logit && RelationNeedsWAL(seqrel))
776  {
777  xl_seq_rec xlrec;
778  XLogRecPtr recptr;
779 
780  /*
781  * We don't log the current state of the tuple, but rather the state
782  * as it would appear after "log" more fetches. This lets us skip
783  * that many future WAL records, at the cost that we lose those
784  * sequence values if we crash.
785  */
786  XLogBeginInsert();
788 
789  /* set values that will be saved in xlog */
790  seq->last_value = next;
791  seq->is_called = true;
792  seq->log_cnt = 0;
793 
794  xlrec.node = seqrel->rd_node;
795 
796  XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
797  XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len);
798 
799  recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
800 
801  PageSetLSN(page, recptr);
802  }
803 
804  /* Now update sequence tuple to the intended final state */
805  seq->last_value = last; /* last fetched number */
806  seq->is_called = true;
807  seq->log_cnt = log; /* how much is logged */
808 
810 
811  UnlockReleaseBuffer(buf);
812 
813  relation_close(seqrel, NoLock);
814 
815  return result;
816 }
int64 cached
Definition: sequence.c:79
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
static int32 next
Definition: blutils.c:211
void PreventCommandIfParallelMode(const char *cmdname)
Definition: utility.c:256
Oid GetUserId(void)
Definition: miscinit.c:379
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
bool last_valid
Definition: sequence.c:77
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
static void check_permissions(void)
Definition: logicalfuncs.c:109
bool rd_islocaltemp
Definition: rel.h:60
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
FormData_pg_sequence * Form_pg_sequence
Definition: pg_sequence.h:40
TransactionId GetTopTransactionId(void)
Definition: xact.c:389
RelFileNode node
Definition: sequence.h:50
HeapTupleHeader t_data
Definition: htup.h:68
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
uint32 t_len
Definition: htup.h:64
#define NoLock
Definition: lockdefs.h:34
static char * buf
Definition: pg_test_fsync.c:67
#define RelationGetRelationName(relation)
Definition: rel.h:441
int64 last
Definition: sequence.c:78
#define ACL_USAGE
Definition: parsenodes.h:82
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
static Form_pg_sequence_data read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
Definition: sequence.c:1159
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define ACL_UPDATE
Definition: parsenodes.h:76
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
RelFileNode rd_node
Definition: rel.h:55
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
#define SEQ_LOG_VALS
Definition: sequence.c:54
int64 increment
Definition: sequence.c:81
XLogRecPtr GetRedoRecPtr(void)
Definition: xlog.c:8212
#define RelationNeedsWAL(relation)
Definition: rel.h:510
#define INT64_FORMAT
Definition: c.h:367
void PreventCommandIfReadOnly(const char *cmdname)
Definition: utility.c:238
static SeqTableData * last_used_seq
Definition: sequence.c:93
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4624
#define PageGetLSN(page)
Definition: bufpage.h:362
static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
Definition: sequence.c:1092
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
#define XLOG_SEQ_LOG
Definition: sequence.h:46
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ ResetSequence()

void ResetSequence ( Oid  seq_relid)

Definition at line 269 of file sequence.c.

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

Referenced by ExecuteTruncateGuts().

270 {
271  Relation seq_rel;
272  SeqTable elm;
274  Buffer buf;
275  HeapTupleData seqdatatuple;
276  HeapTuple tuple;
277  HeapTuple pgstuple;
278  Form_pg_sequence pgsform;
279  int64 startv;
280 
281  /*
282  * Read the old sequence. This does a bit more work than really
283  * necessary, but it's simple, and we do want to double-check that it's
284  * indeed a sequence.
285  */
286  init_sequence(seq_relid, &elm, &seq_rel);
287  (void) read_seq_tuple(seq_rel, &buf, &seqdatatuple);
288 
289  pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(seq_relid));
290  if (!HeapTupleIsValid(pgstuple))
291  elog(ERROR, "cache lookup failed for sequence %u", seq_relid);
292  pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
293  startv = pgsform->seqstart;
294  ReleaseSysCache(pgstuple);
295 
296  /*
297  * Copy the existing sequence tuple.
298  */
299  tuple = heap_copytuple(&seqdatatuple);
300 
301  /* Now we're done with the old page */
302  UnlockReleaseBuffer(buf);
303 
304  /*
305  * Modify the copied tuple to execute the restart (compare the RESTART
306  * action in AlterSequence)
307  */
308  seq = (Form_pg_sequence_data) GETSTRUCT(tuple);
309  seq->last_value = startv;
310  seq->is_called = false;
311  seq->log_cnt = 0;
312 
313  /*
314  * Create a new storage file for the sequence. We want to keep the
315  * sequence's relfrozenxid at 0, since it won't contain any unfrozen XIDs.
316  * Same with relminmxid, since a sequence will never contain multixacts.
317  */
318  RelationSetNewRelfilenode(seq_rel, seq_rel->rd_rel->relpersistence,
320 
321  /*
322  * Insert the modified tuple into the new storage file.
323  */
324  fill_seq_with_data(seq_rel, tuple);
325 
326  /* Clear local cache so that we don't think we have cached numbers */
327  /* Note that we do not change the currval() state */
328  elm->cached = elm->last;
329 
330  relation_close(seq_rel, NoLock);
331 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:722
int64 cached
Definition: sequence.c:79
void RelationSetNewRelfilenode(Relation relation, char persistence, TransactionId freezeXid, MultiXactId minmulti)
Definition: relcache.c:3264
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
FormData_pg_sequence * Form_pg_sequence
Definition: pg_sequence.h:40
Form_pg_class rd_rel
Definition: rel.h:84
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
static char * buf
Definition: pg_test_fsync.c:67
#define InvalidTransactionId
Definition: transam.h:31
int64 last
Definition: sequence.c:78
static Form_pg_sequence_data read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
Definition: sequence.c:1159
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define InvalidMultiXactId
Definition: multixact.h:23
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
Definition: sequence.c:1092
#define elog
Definition: elog.h:219
int Buffer
Definition: buf.h:23
static void fill_seq_with_data(Relation rel, HeapTuple tuple)
Definition: sequence.c:337
FormData_pg_sequence_data * Form_pg_sequence_data
Definition: sequence.h:32

◆ ResetSequenceCaches()

void ResetSequenceCaches ( void  )

Definition at line 1925 of file sequence.c.

References hash_destroy().

Referenced by DiscardAll(), and DiscardCommand().

1926 {
1927  if (seqhashtab)
1928  {
1930  seqhashtab = NULL;
1931  }
1932 
1933  last_used_seq = NULL;
1934 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:814
static HTAB * seqhashtab
Definition: sequence.c:87
static SeqTableData * last_used_seq
Definition: sequence.c:93

◆ seq_desc()

void seq_desc ( StringInfo  buf,
XLogReaderState rptr 
)

Definition at line 21 of file seqdesc.c.

References appendStringInfo(), RelFileNode::dbNode, xl_seq_rec::node, RelFileNode::relNode, RelFileNode::spcNode, XLOG_SEQ_LOG, XLogRecGetData, XLogRecGetInfo, and XLR_INFO_MASK.

22 {
23  char *rec = XLogRecGetData(record);
24  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
25  xl_seq_rec *xlrec = (xl_seq_rec *) rec;
26 
27  if (info == XLOG_SEQ_LOG)
28  appendStringInfo(buf, "rel %u/%u/%u",
29  xlrec->node.spcNode, xlrec->node.dbNode,
30  xlrec->node.relNode);
31 }
unsigned char uint8
Definition: c.h:323
RelFileNode node
Definition: sequence.h:50
#define XLogRecGetData(decoder)
Definition: xlogreader.h:226
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:222
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#define XLOG_SEQ_LOG
Definition: sequence.h:46

◆ seq_identify()

const char* seq_identify ( uint8  info)

Definition at line 34 of file seqdesc.c.

References XLOG_SEQ_LOG, and XLR_INFO_MASK.

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

◆ seq_mask()

void seq_mask ( char *  pagedata,
BlockNumber  blkno 
)

Definition at line 1940 of file sequence.c.

References mask_page_lsn_and_checksum(), and mask_unused_space().

1941 {
1943 
1944  mask_unused_space(page);
1945 }
void mask_unused_space(Page page)
Definition: bufmask.c:71
void mask_page_lsn_and_checksum(Page page)
Definition: bufmask.c:31

◆ seq_redo()

void seq_redo ( XLogReaderState rptr)

Definition at line 1872 of file sequence.c.

References buffer, 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.

1873 {
1874  XLogRecPtr lsn = record->EndRecPtr;
1875  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
1876  Buffer buffer;
1877  Page page;
1878  Page localpage;
1879  char *item;
1880  Size itemsz;
1881  xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
1882  sequence_magic *sm;
1883 
1884  if (info != XLOG_SEQ_LOG)
1885  elog(PANIC, "seq_redo: unknown op code %u", info);
1886 
1887  buffer = XLogInitBufferForRedo(record, 0);
1888  page = (Page) BufferGetPage(buffer);
1889 
1890  /*
1891  * We always reinit the page. However, since this WAL record type is also
1892  * used for updating sequences, it's possible that a hot-standby backend
1893  * is examining the page concurrently; so we mustn't transiently trash the
1894  * buffer. The solution is to build the correct new page contents in
1895  * local workspace and then memcpy into the buffer. Then only bytes that
1896  * are supposed to change will change, even transiently. We must palloc
1897  * the local page for alignment reasons.
1898  */
1899  localpage = (Page) palloc(BufferGetPageSize(buffer));
1900 
1901  PageInit(localpage, BufferGetPageSize(buffer), sizeof(sequence_magic));
1902  sm = (sequence_magic *) PageGetSpecialPointer(localpage);
1903  sm->magic = SEQ_MAGIC;
1904 
1905  item = (char *) xlrec + sizeof(xl_seq_rec);
1906  itemsz = XLogRecGetDataLen(record) - sizeof(xl_seq_rec);
1907 
1908  if (PageAddItem(localpage, (Item) item, itemsz,
1909  FirstOffsetNumber, false, false) == InvalidOffsetNumber)
1910  elog(PANIC, "seq_redo: failed to add item to page");
1911 
1912  PageSetLSN(localpage, lsn);
1913 
1914  memcpy(page, localpage, BufferGetPageSize(buffer));
1915  MarkBufferDirty(buffer);
1916  UnlockReleaseBuffer(buffer);
1917 
1918  pfree(localpage);
1919 }
#define SEQ_MAGIC
Definition: sequence.c:59
struct xl_seq_rec xl_seq_rec
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
unsigned char uint8
Definition: c.h:323
Pointer Item
Definition: item.h:17
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:412
#define PANIC
Definition: elog.h:53
void pfree(void *pointer)
Definition: mcxt.c:1031
#define XLogRecGetData(decoder)
Definition: xlogreader.h:226
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define XLogRecGetDataLen(decoder)
Definition: xlogreader.h:227
Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id)
Definition: xlogutils.c:301
#define FirstOffsetNumber
Definition: off.h:27
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:222
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:147
#define InvalidOffsetNumber
Definition: off.h:26
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
uint32 magic
Definition: sequence.c:63
size_t Size
Definition: c.h:433
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
void * palloc(Size size)
Definition: mcxt.c:924
#define elog
Definition: elog.h:219
#define XLOG_SEQ_LOG
Definition: sequence.h:46
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:41

◆ sequence_options()

List* sequence_options ( Oid  relid)

Definition at line 1743 of file sequence.c.

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

Referenced by transformTableLikeClause().

1744 {
1745  HeapTuple pgstuple;
1746  Form_pg_sequence pgsform;
1747  List *options = NIL;
1748 
1749  pgstuple = SearchSysCache1(SEQRELID, relid);
1750  if (!HeapTupleIsValid(pgstuple))
1751  elog(ERROR, "cache lookup failed for sequence %u", relid);
1752  pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
1753 
1754  /* Use makeFloat() for 64-bit integers, like gram.y does. */
1755  options = lappend(options,
1756  makeDefElem("cache", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqcache)), -1));
1757  options = lappend(options,
1758  makeDefElem("cycle", (Node *) makeInteger(pgsform->seqcycle), -1));
1759  options = lappend(options,
1760  makeDefElem("increment", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqincrement)), -1));
1761  options = lappend(options,
1762  makeDefElem("maxvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmax)), -1));
1763  options = lappend(options,
1764  makeDefElem("minvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmin)), -1));
1765  options = lappend(options,
1766  makeDefElem("start", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqstart)), -1));
1767 
1768  ReleaseSysCache(pgstuple);
1769 
1770  return options;
1771 }
#define NIL
Definition: pg_list.h:69
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
Definition: nodes.h:517
FormData_pg_sequence * Form_pg_sequence
Definition: pg_sequence.h:40
DefElem * makeDefElem(char *name, Node *arg, int location)
Definition: makefuncs.c:546
#define ERROR
Definition: elog.h:43
List * lappend(List *list, void *datum)
Definition: list.c:128
static char ** options
Value * makeInteger(int i)
Definition: value.c:23
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Value * makeFloat(char *numericStr)
Definition: value.c:38
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define INT64_FORMAT
Definition: c.h:367
#define elog
Definition: elog.h:219
Definition: pg_list.h:45