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

Definition at line 32 of file sequence.h.

◆ FormData_pg_sequence_data

◆ xl_seq_rec

typedef struct xl_seq_rec xl_seq_rec

Function Documentation

◆ AlterSequence()

ObjectAddress AlterSequence ( ParseState pstate,
AlterSeqStmt stmt 
)

Definition at line 422 of file sequence.c.

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, RelationSetNewRelfilenode(), RangeVar::relname, RowExclusiveLock, RVR_MISSING_OK, SearchSysCacheCopy1, SEQRELID, AlterSeqStmt::sequence, ShareRowExclusiveLock, HeapTupleData::t_self, table_close(), table_open(), and UnlockReleaseBuffer().

Referenced by ProcessUtilitySlow().

423 {
424  Oid relid;
425  SeqTable elm;
426  Relation seqrel;
427  Buffer buf;
428  HeapTupleData datatuple;
429  Form_pg_sequence seqform;
430  Form_pg_sequence_data newdataform;
431  bool need_seq_rewrite;
432  List *owned_by;
433  ObjectAddress address;
434  Relation rel;
435  HeapTuple seqtuple;
436  HeapTuple newdatatuple;
437 
438  /* Open and lock sequence, and check for ownership along the way. */
439  relid = RangeVarGetRelidExtended(stmt->sequence,
441  stmt->missing_ok ? RVR_MISSING_OK : 0,
443  NULL);
444  if (relid == InvalidOid)
445  {
446  ereport(NOTICE,
447  (errmsg("relation \"%s\" does not exist, skipping",
448  stmt->sequence->relname)));
449  return InvalidObjectAddress;
450  }
451 
452  init_sequence(relid, &elm, &seqrel);
453 
454  rel = table_open(SequenceRelationId, RowExclusiveLock);
455  seqtuple = SearchSysCacheCopy1(SEQRELID,
456  ObjectIdGetDatum(relid));
457  if (!HeapTupleIsValid(seqtuple))
458  elog(ERROR, "cache lookup failed for sequence %u",
459  relid);
460 
461  seqform = (Form_pg_sequence) GETSTRUCT(seqtuple);
462 
463  /* lock page's buffer and read tuple into new sequence structure */
464  (void) read_seq_tuple(seqrel, &buf, &datatuple);
465 
466  /* copy the existing sequence data tuple, so it can be modified locally */
467  newdatatuple = heap_copytuple(&datatuple);
468  newdataform = (Form_pg_sequence_data) GETSTRUCT(newdatatuple);
469 
470  UnlockReleaseBuffer(buf);
471 
472  /* Check and set new values */
473  init_params(pstate, stmt->options, stmt->for_identity, false,
474  seqform, newdataform,
475  &need_seq_rewrite, &owned_by);
476 
477  /* Clear local cache so that we don't think we have cached numbers */
478  /* Note that we do not change the currval() state */
479  elm->cached = elm->last;
480 
481  /* If needed, rewrite the sequence relation itself */
482  if (need_seq_rewrite)
483  {
484  /* check the comment above nextval_internal()'s equivalent call. */
485  if (RelationNeedsWAL(seqrel))
487 
488  /*
489  * Create a new storage file for the sequence, making the state
490  * changes transactional.
491  */
492  RelationSetNewRelfilenode(seqrel, seqrel->rd_rel->relpersistence);
493 
494  /*
495  * Ensure sequence's relfrozenxid is at 0, since it won't contain any
496  * unfrozen XIDs. Same with relminmxid, since a sequence will never
497  * contain multixacts.
498  */
499  Assert(seqrel->rd_rel->relfrozenxid == InvalidTransactionId);
500  Assert(seqrel->rd_rel->relminmxid == InvalidMultiXactId);
501 
502  /*
503  * Insert the modified tuple into the new storage file.
504  */
505  fill_seq_with_data(seqrel, newdatatuple);
506  }
507 
508  /* process OWNED BY if given */
509  if (owned_by)
510  process_owned_by(seqrel, owned_by, stmt->for_identity);
511 
512  /* update the pg_sequence tuple (we could skip this in some cases...) */
513  CatalogTupleUpdate(rel, &seqtuple->t_self, seqtuple);
514 
515  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
516 
517  ObjectAddressSet(address, RelationRelationId, relid);
518 
520  relation_close(seqrel, NoLock);
521 
522  return address;
523 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
int64 cached
Definition: sequence.c:81
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
FormData_pg_sequence * Form_pg_sequence
Definition: pg_sequence.h:40
TransactionId GetTopTransactionId(void)
Definition: xact.c:395
Form_pg_class rd_rel
Definition: rel.h:83
unsigned int Oid
Definition: postgres_ext.h:31
List * options
Definition: parsenodes.h:2533
void RelationSetNewRelfilenode(Relation relation, char persistence)
Definition: relcache.c:3418
char * relname
Definition: primnodes.h:68
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
void RangeVarCallbackOwnsRelation(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:14831
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#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:68
#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:1641
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
int64 last
Definition: sequence.c:80
#define ereport(elevel, rest)
Definition: elog.h:141
#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:1170
#define InvalidMultiXactId
Definition: multixact.h:23
#define InvalidOid
Definition: postgres_ext.h:36
RangeVar * sequence
Definition: parsenodes.h:2532
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:732
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
#define RelationNeedsWAL(relation)
Definition: rel.h:521
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
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:1236
static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
Definition: sequence.c:1103
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
bool for_identity
Definition: parsenodes.h:2534
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
int Buffer
Definition: buf.h:23
static void fill_seq_with_data(Relation rel, HeapTuple tuple)
Definition: sequence.c:343
FormData_pg_sequence_data * Form_pg_sequence_data
Definition: sequence.h:32

◆ DefineSequence()

ObjectAddress DefineSequence ( ParseState pstate,
CreateSeqStmt stmt 
)

Definition at line 118 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_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, 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, table_close(), table_open(), CreateStmt::tableElts, CreateStmt::tablespacename, ColumnDef::typeName, and value.

Referenced by ProcessUtilitySlow().

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

◆ DeleteSequenceTuple()

void DeleteSequenceTuple ( Oid  relid)

Definition at line 526 of file sequence.c.

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

Referenced by doDeletion().

527 {
528  Relation rel;
529  HeapTuple tuple;
530 
531  rel = table_open(SequenceRelationId, RowExclusiveLock);
532 
533  tuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
534  if (!HeapTupleIsValid(tuple))
535  elog(ERROR, "cache lookup failed for sequence %u", relid);
536 
537  CatalogTupleDelete(rel, &tuple->t_self);
538 
539  ReleaseSysCache(tuple);
541 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#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:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog(elevel,...)
Definition: elog.h:226
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ nextval()

Datum nextval ( PG_FUNCTION_ARGS  )

Definition at line 549 of file sequence.c.

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

Referenced by autoinc(), and ttdummy().

550 {
551  text *seqin = PG_GETARG_TEXT_PP(0);
552  RangeVar *sequence;
553  Oid relid;
554 
556 
557  /*
558  * XXX: This is not safe in the presence of concurrent DDL, but acquiring
559  * a lock here is more expensive than letting nextval_internal do it,
560  * since the latter maintains a cache that keeps us from hitting the lock
561  * manager more than once per transaction. It's not clear whether the
562  * performance penalty is material in practice, but for now, we do it this
563  * way.
564  */
565  relid = RangeVarGetRelid(sequence, NoLock, false);
566 
567  PG_RETURN_INT64(nextval_internal(relid, true));
568 }
#define PG_RETURN_INT64(x)
Definition: fmgr.h:357
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:63
int64 nextval_internal(Oid relid, bool check_permissions)
Definition: sequence.c:579
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3054
unsigned int Oid
Definition: postgres_ext.h:31
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:303
#define NoLock
Definition: lockdefs.h:34
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3586
Definition: c.h:549

◆ nextval_internal()

int64 nextval_internal ( Oid  relid,
bool  check_permissions 
)

Definition at line 579 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().

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

◆ ResetSequence()

void ResetSequence ( Oid  seq_relid)

Definition at line 270 of file sequence.c.

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

Referenced by ExecuteTruncateGuts().

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

◆ ResetSequenceCaches()

void ResetSequenceCaches ( void  )

Definition at line 1936 of file sequence.c.

References hash_destroy().

Referenced by DiscardAll(), and DiscardCommand().

1937 {
1938  if (seqhashtab)
1939  {
1941  seqhashtab = NULL;
1942  }
1943 
1944  last_used_seq = NULL;
1945 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:814
static HTAB * seqhashtab
Definition: sequence.c:89
static SeqTableData * last_used_seq
Definition: sequence.c:95

◆ 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:356
RelFileNode node
Definition: sequence.h:50
#define XLogRecGetData(decoder)
Definition: xlogreader.h:246
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:242
#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 1951 of file sequence.c.

References mask_page_lsn_and_checksum(), and mask_unused_space().

1952 {
1954 
1955  mask_unused_space(page);
1956 }
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 1883 of file sequence.c.

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.

1884 {
1885  XLogRecPtr lsn = record->EndRecPtr;
1886  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
1887  Buffer buffer;
1888  Page page;
1889  Page localpage;
1890  char *item;
1891  Size itemsz;
1892  xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
1893  sequence_magic *sm;
1894 
1895  if (info != XLOG_SEQ_LOG)
1896  elog(PANIC, "seq_redo: unknown op code %u", info);
1897 
1898  buffer = XLogInitBufferForRedo(record, 0);
1899  page = (Page) BufferGetPage(buffer);
1900 
1901  /*
1902  * We always reinit the page. However, since this WAL record type is also
1903  * used for updating sequences, it's possible that a hot-standby backend
1904  * is examining the page concurrently; so we mustn't transiently trash the
1905  * buffer. The solution is to build the correct new page contents in
1906  * local workspace and then memcpy into the buffer. Then only bytes that
1907  * are supposed to change will change, even transiently. We must palloc
1908  * the local page for alignment reasons.
1909  */
1910  localpage = (Page) palloc(BufferGetPageSize(buffer));
1911 
1912  PageInit(localpage, BufferGetPageSize(buffer), sizeof(sequence_magic));
1913  sm = (sequence_magic *) PageGetSpecialPointer(localpage);
1914  sm->magic = SEQ_MAGIC;
1915 
1916  item = (char *) xlrec + sizeof(xl_seq_rec);
1917  itemsz = XLogRecGetDataLen(record) - sizeof(xl_seq_rec);
1918 
1919  if (PageAddItem(localpage, (Item) item, itemsz,
1920  FirstOffsetNumber, false, false) == InvalidOffsetNumber)
1921  elog(PANIC, "seq_redo: failed to add item to page");
1922 
1923  PageSetLSN(localpage, lsn);
1924 
1925  memcpy(page, localpage, BufferGetPageSize(buffer));
1926  MarkBufferDirty(buffer);
1927  UnlockReleaseBuffer(buffer);
1928 
1929  pfree(localpage);
1930 }
#define SEQ_MAGIC
Definition: sequence.c:61
struct xl_seq_rec xl_seq_rec
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
unsigned char uint8
Definition: c.h:356
Pointer Item
Definition: item.h:17
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:416
#define PANIC
Definition: elog.h:53
void pfree(void *pointer)
Definition: mcxt.c:1056
#define XLogRecGetData(decoder)
Definition: xlogreader.h:246
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
#define XLogRecGetDataLen(decoder)
Definition: xlogreader.h:247
Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id)
Definition: xlogutils.c:301
#define FirstOffsetNumber
Definition: off.h:27
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:242
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:146
#define InvalidOffsetNumber
Definition: off.h:26
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
uint32 magic
Definition: sequence.c:65
size_t Size
Definition: c.h:466
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:226
#define XLOG_SEQ_LOG
Definition: sequence.h:46
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:42

◆ sequence_options()

List* sequence_options ( Oid  relid)

Definition at line 1754 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().

1755 {
1756  HeapTuple pgstuple;
1757  Form_pg_sequence pgsform;
1758  List *options = NIL;
1759 
1760  pgstuple = SearchSysCache1(SEQRELID, relid);
1761  if (!HeapTupleIsValid(pgstuple))
1762  elog(ERROR, "cache lookup failed for sequence %u", relid);
1763  pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
1764 
1765  /* Use makeFloat() for 64-bit integers, like gram.y does. */
1766  options = lappend(options,
1767  makeDefElem("cache", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqcache)), -1));
1768  options = lappend(options,
1769  makeDefElem("cycle", (Node *) makeInteger(pgsform->seqcycle), -1));
1770  options = lappend(options,
1771  makeDefElem("increment", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqincrement)), -1));
1772  options = lappend(options,
1773  makeDefElem("maxvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmax)), -1));
1774  options = lappend(options,
1775  makeDefElem("minvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmin)), -1));
1776  options = lappend(options,
1777  makeDefElem("start", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqstart)), -1));
1778 
1779  ReleaseSysCache(pgstuple);
1780 
1781  return options;
1782 }
#define NIL
Definition: pg_list.h:65
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
Definition: nodes.h:525
FormData_pg_sequence * Form_pg_sequence
Definition: pg_sequence.h:40
DefElem * makeDefElem(char *name, Node *arg, int location)
Definition: makefuncs.c:544
#define ERROR
Definition: elog.h:43
List * lappend(List *list, void *datum)
Definition: list.c:322
static char ** options
Value * makeInteger(int i)
Definition: value.c:23
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
Value * makeFloat(char *numericStr)
Definition: value.c:38
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define INT64_FORMAT
Definition: c.h:400
#define elog(elevel,...)
Definition: elog.h:226
Definition: pg_list.h:50