LCOV - code coverage report
Current view: top level - src/backend/commands - sequence.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 635 672 94.5 %
Date: 2024-04-25 03:11:44 Functions: 26 27 96.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * sequence.c
       4             :  *    PostgreSQL sequences support code.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/commands/sequence.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "access/bufmask.h"
      18             : #include "access/htup_details.h"
      19             : #include "access/multixact.h"
      20             : #include "access/relation.h"
      21             : #include "access/sequence.h"
      22             : #include "access/table.h"
      23             : #include "access/transam.h"
      24             : #include "access/xact.h"
      25             : #include "access/xlog.h"
      26             : #include "access/xloginsert.h"
      27             : #include "access/xlogutils.h"
      28             : #include "catalog/dependency.h"
      29             : #include "catalog/indexing.h"
      30             : #include "catalog/namespace.h"
      31             : #include "catalog/objectaccess.h"
      32             : #include "catalog/pg_sequence.h"
      33             : #include "catalog/pg_type.h"
      34             : #include "catalog/storage_xlog.h"
      35             : #include "commands/defrem.h"
      36             : #include "commands/sequence.h"
      37             : #include "commands/tablecmds.h"
      38             : #include "funcapi.h"
      39             : #include "miscadmin.h"
      40             : #include "nodes/makefuncs.h"
      41             : #include "parser/parse_type.h"
      42             : #include "storage/lmgr.h"
      43             : #include "storage/proc.h"
      44             : #include "storage/smgr.h"
      45             : #include "utils/acl.h"
      46             : #include "utils/builtins.h"
      47             : #include "utils/lsyscache.h"
      48             : #include "utils/resowner.h"
      49             : #include "utils/syscache.h"
      50             : #include "utils/varlena.h"
      51             : 
      52             : 
      53             : /*
      54             :  * We don't want to log each fetching of a value from a sequence,
      55             :  * so we pre-log a few fetches in advance. In the event of
      56             :  * crash we can lose (skip over) as many values as we pre-logged.
      57             :  */
      58             : #define SEQ_LOG_VALS    32
      59             : 
      60             : /*
      61             :  * The "special area" of a sequence's buffer page looks like this.
      62             :  */
      63             : #define SEQ_MAGIC     0x1717
      64             : 
      65             : typedef struct sequence_magic
      66             : {
      67             :     uint32      magic;
      68             : } sequence_magic;
      69             : 
      70             : /*
      71             :  * We store a SeqTable item for every sequence we have touched in the current
      72             :  * session.  This is needed to hold onto nextval/currval state.  (We can't
      73             :  * rely on the relcache, since it's only, well, a cache, and may decide to
      74             :  * discard entries.)
      75             :  */
      76             : typedef struct SeqTableData
      77             : {
      78             :     Oid         relid;          /* pg_class OID of this sequence (hash key) */
      79             :     RelFileNumber filenumber;   /* last seen relfilenumber of this sequence */
      80             :     LocalTransactionId lxid;    /* xact in which we last did a seq op */
      81             :     bool        last_valid;     /* do we have a valid "last" value? */
      82             :     int64       last;           /* value last returned by nextval */
      83             :     int64       cached;         /* last value already cached for nextval */
      84             :     /* if last != cached, we have not used up all the cached values */
      85             :     int64       increment;      /* copy of sequence's increment field */
      86             :     /* note that increment is zero until we first do nextval_internal() */
      87             : } SeqTableData;
      88             : 
      89             : typedef SeqTableData *SeqTable;
      90             : 
      91             : static HTAB *seqhashtab = NULL; /* hash table for SeqTable items */
      92             : 
      93             : /*
      94             :  * last_used_seq is updated by nextval() to point to the last used
      95             :  * sequence.
      96             :  */
      97             : static SeqTableData *last_used_seq = NULL;
      98             : 
      99             : static void fill_seq_with_data(Relation rel, HeapTuple tuple);
     100             : static void fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum);
     101             : static Relation lock_and_open_sequence(SeqTable seq);
     102             : static void create_seq_hashtable(void);
     103             : static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
     104             : static Form_pg_sequence_data read_seq_tuple(Relation rel,
     105             :                                             Buffer *buf, HeapTuple seqdatatuple);
     106             : static void init_params(ParseState *pstate, List *options, bool for_identity,
     107             :                         bool isInit,
     108             :                         Form_pg_sequence seqform,
     109             :                         Form_pg_sequence_data seqdataform,
     110             :                         bool *need_seq_rewrite,
     111             :                         List **owned_by);
     112             : static void do_setval(Oid relid, int64 next, bool iscalled);
     113             : static void process_owned_by(Relation seqrel, List *owned_by, bool for_identity);
     114             : 
     115             : 
     116             : /*
     117             :  * DefineSequence
     118             :  *              Creates a new sequence relation
     119             :  */
     120             : ObjectAddress
     121        1764 : DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
     122             : {
     123             :     FormData_pg_sequence seqform;
     124             :     FormData_pg_sequence_data seqdataform;
     125             :     bool        need_seq_rewrite;
     126             :     List       *owned_by;
     127        1764 :     CreateStmt *stmt = makeNode(CreateStmt);
     128             :     Oid         seqoid;
     129             :     ObjectAddress address;
     130             :     Relation    rel;
     131             :     HeapTuple   tuple;
     132             :     TupleDesc   tupDesc;
     133             :     Datum       value[SEQ_COL_LASTCOL];
     134             :     bool        null[SEQ_COL_LASTCOL];
     135             :     Datum       pgs_values[Natts_pg_sequence];
     136             :     bool        pgs_nulls[Natts_pg_sequence];
     137             :     int         i;
     138             : 
     139             :     /*
     140             :      * If if_not_exists was given and a relation with the same name already
     141             :      * exists, bail out. (Note: we needn't check this when not if_not_exists,
     142             :      * because DefineRelation will complain anyway.)
     143             :      */
     144        1764 :     if (seq->if_not_exists)
     145             :     {
     146          16 :         RangeVarGetAndCheckCreationNamespace(seq->sequence, NoLock, &seqoid);
     147          16 :         if (OidIsValid(seqoid))
     148             :         {
     149             :             /*
     150             :              * If we are in an extension script, insist that the pre-existing
     151             :              * object be a member of the extension, to avoid security risks.
     152             :              */
     153          10 :             ObjectAddressSet(address, RelationRelationId, seqoid);
     154          10 :             checkMembershipInCurrentExtension(&address);
     155             : 
     156             :             /* OK to skip */
     157           8 :             ereport(NOTICE,
     158             :                     (errcode(ERRCODE_DUPLICATE_TABLE),
     159             :                      errmsg("relation \"%s\" already exists, skipping",
     160             :                             seq->sequence->relname)));
     161           8 :             return InvalidObjectAddress;
     162             :         }
     163             :     }
     164             : 
     165             :     /* Check and set all option values */
     166        1754 :     init_params(pstate, seq->options, seq->for_identity, true,
     167             :                 &seqform, &seqdataform,
     168             :                 &need_seq_rewrite, &owned_by);
     169             : 
     170             :     /*
     171             :      * Create relation (and fill value[] and null[] for the tuple)
     172             :      */
     173        1682 :     stmt->tableElts = NIL;
     174        6728 :     for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
     175             :     {
     176        5046 :         ColumnDef  *coldef = NULL;
     177             : 
     178        5046 :         switch (i)
     179             :         {
     180        1682 :             case SEQ_COL_LASTVAL:
     181        1682 :                 coldef = makeColumnDef("last_value", INT8OID, -1, InvalidOid);
     182        1682 :                 value[i - 1] = Int64GetDatumFast(seqdataform.last_value);
     183        1682 :                 break;
     184        1682 :             case SEQ_COL_LOG:
     185        1682 :                 coldef = makeColumnDef("log_cnt", INT8OID, -1, InvalidOid);
     186        1682 :                 value[i - 1] = Int64GetDatum((int64) 0);
     187        1682 :                 break;
     188        1682 :             case SEQ_COL_CALLED:
     189        1682 :                 coldef = makeColumnDef("is_called", BOOLOID, -1, InvalidOid);
     190        1682 :                 value[i - 1] = BoolGetDatum(false);
     191        1682 :                 break;
     192             :         }
     193             : 
     194        5046 :         coldef->is_not_null = true;
     195        5046 :         null[i - 1] = false;
     196             : 
     197        5046 :         stmt->tableElts = lappend(stmt->tableElts, coldef);
     198             :     }
     199             : 
     200        1682 :     stmt->relation = seq->sequence;
     201        1682 :     stmt->inhRelations = NIL;
     202        1682 :     stmt->constraints = NIL;
     203        1682 :     stmt->options = NIL;
     204        1682 :     stmt->oncommit = ONCOMMIT_NOOP;
     205        1682 :     stmt->tablespacename = NULL;
     206        1682 :     stmt->if_not_exists = seq->if_not_exists;
     207             : 
     208        1682 :     address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL, NULL);
     209        1682 :     seqoid = address.objectId;
     210             :     Assert(seqoid != InvalidOid);
     211             : 
     212        1682 :     rel = sequence_open(seqoid, AccessExclusiveLock);
     213        1682 :     tupDesc = RelationGetDescr(rel);
     214             : 
     215             :     /* now initialize the sequence's data */
     216        1682 :     tuple = heap_form_tuple(tupDesc, value, null);
     217        1682 :     fill_seq_with_data(rel, tuple);
     218             : 
     219             :     /* process OWNED BY if given */
     220        1682 :     if (owned_by)
     221          26 :         process_owned_by(rel, owned_by, seq->for_identity);
     222             : 
     223        1658 :     sequence_close(rel, NoLock);
     224             : 
     225             :     /* fill in pg_sequence */
     226        1658 :     rel = table_open(SequenceRelationId, RowExclusiveLock);
     227        1658 :     tupDesc = RelationGetDescr(rel);
     228             : 
     229        1658 :     memset(pgs_nulls, 0, sizeof(pgs_nulls));
     230             : 
     231        1658 :     pgs_values[Anum_pg_sequence_seqrelid - 1] = ObjectIdGetDatum(seqoid);
     232        1658 :     pgs_values[Anum_pg_sequence_seqtypid - 1] = ObjectIdGetDatum(seqform.seqtypid);
     233        1658 :     pgs_values[Anum_pg_sequence_seqstart - 1] = Int64GetDatumFast(seqform.seqstart);
     234        1658 :     pgs_values[Anum_pg_sequence_seqincrement - 1] = Int64GetDatumFast(seqform.seqincrement);
     235        1658 :     pgs_values[Anum_pg_sequence_seqmax - 1] = Int64GetDatumFast(seqform.seqmax);
     236        1658 :     pgs_values[Anum_pg_sequence_seqmin - 1] = Int64GetDatumFast(seqform.seqmin);
     237        1658 :     pgs_values[Anum_pg_sequence_seqcache - 1] = Int64GetDatumFast(seqform.seqcache);
     238        1658 :     pgs_values[Anum_pg_sequence_seqcycle - 1] = BoolGetDatum(seqform.seqcycle);
     239             : 
     240        1658 :     tuple = heap_form_tuple(tupDesc, pgs_values, pgs_nulls);
     241        1658 :     CatalogTupleInsert(rel, tuple);
     242             : 
     243        1658 :     heap_freetuple(tuple);
     244        1658 :     table_close(rel, RowExclusiveLock);
     245             : 
     246        1658 :     return address;
     247             : }
     248             : 
     249             : /*
     250             :  * Reset a sequence to its initial value.
     251             :  *
     252             :  * The change is made transactionally, so that on failure of the current
     253             :  * transaction, the sequence will be restored to its previous state.
     254             :  * We do that by creating a whole new relfilenumber for the sequence; so this
     255             :  * works much like the rewriting forms of ALTER TABLE.
     256             :  *
     257             :  * Caller is assumed to have acquired AccessExclusiveLock on the sequence,
     258             :  * which must not be released until end of transaction.  Caller is also
     259             :  * responsible for permissions checking.
     260             :  */
     261             : void
     262          36 : ResetSequence(Oid seq_relid)
     263             : {
     264             :     Relation    seq_rel;
     265             :     SeqTable    elm;
     266             :     Form_pg_sequence_data seq;
     267             :     Buffer      buf;
     268             :     HeapTupleData seqdatatuple;
     269             :     HeapTuple   tuple;
     270             :     HeapTuple   pgstuple;
     271             :     Form_pg_sequence pgsform;
     272             :     int64       startv;
     273             : 
     274             :     /*
     275             :      * Read the old sequence.  This does a bit more work than really
     276             :      * necessary, but it's simple, and we do want to double-check that it's
     277             :      * indeed a sequence.
     278             :      */
     279          36 :     init_sequence(seq_relid, &elm, &seq_rel);
     280          36 :     (void) read_seq_tuple(seq_rel, &buf, &seqdatatuple);
     281             : 
     282          36 :     pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(seq_relid));
     283          36 :     if (!HeapTupleIsValid(pgstuple))
     284           0 :         elog(ERROR, "cache lookup failed for sequence %u", seq_relid);
     285          36 :     pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
     286          36 :     startv = pgsform->seqstart;
     287          36 :     ReleaseSysCache(pgstuple);
     288             : 
     289             :     /*
     290             :      * Copy the existing sequence tuple.
     291             :      */
     292          36 :     tuple = heap_copytuple(&seqdatatuple);
     293             : 
     294             :     /* Now we're done with the old page */
     295          36 :     UnlockReleaseBuffer(buf);
     296             : 
     297             :     /*
     298             :      * Modify the copied tuple to execute the restart (compare the RESTART
     299             :      * action in AlterSequence)
     300             :      */
     301          36 :     seq = (Form_pg_sequence_data) GETSTRUCT(tuple);
     302          36 :     seq->last_value = startv;
     303          36 :     seq->is_called = false;
     304          36 :     seq->log_cnt = 0;
     305             : 
     306             :     /*
     307             :      * Create a new storage file for the sequence.
     308             :      */
     309          36 :     RelationSetNewRelfilenumber(seq_rel, seq_rel->rd_rel->relpersistence);
     310             : 
     311             :     /*
     312             :      * Ensure sequence's relfrozenxid is at 0, since it won't contain any
     313             :      * unfrozen XIDs.  Same with relminmxid, since a sequence will never
     314             :      * contain multixacts.
     315             :      */
     316             :     Assert(seq_rel->rd_rel->relfrozenxid == InvalidTransactionId);
     317             :     Assert(seq_rel->rd_rel->relminmxid == InvalidMultiXactId);
     318             : 
     319             :     /*
     320             :      * Insert the modified tuple into the new storage file.
     321             :      */
     322          36 :     fill_seq_with_data(seq_rel, tuple);
     323             : 
     324             :     /* Clear local cache so that we don't think we have cached numbers */
     325             :     /* Note that we do not change the currval() state */
     326          36 :     elm->cached = elm->last;
     327             : 
     328          36 :     sequence_close(seq_rel, NoLock);
     329          36 : }
     330             : 
     331             : /*
     332             :  * Initialize a sequence's relation with the specified tuple as content
     333             :  *
     334             :  * This handles unlogged sequences by writing to both the main and the init
     335             :  * fork as necessary.
     336             :  */
     337             : static void
     338        1940 : fill_seq_with_data(Relation rel, HeapTuple tuple)
     339             : {
     340        1940 :     fill_seq_fork_with_data(rel, tuple, MAIN_FORKNUM);
     341             : 
     342        1940 :     if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
     343             :     {
     344             :         SMgrRelation srel;
     345             : 
     346         100 :         srel = smgropen(rel->rd_locator, INVALID_PROC_NUMBER);
     347         100 :         smgrcreate(srel, INIT_FORKNUM, false);
     348         100 :         log_smgrcreate(&rel->rd_locator, INIT_FORKNUM);
     349         100 :         fill_seq_fork_with_data(rel, tuple, INIT_FORKNUM);
     350         100 :         FlushRelationBuffers(rel);
     351         100 :         smgrclose(srel);
     352             :     }
     353        1940 : }
     354             : 
     355             : /*
     356             :  * Initialize a sequence's relation fork with the specified tuple as content
     357             :  */
     358             : static void
     359        2040 : fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum)
     360             : {
     361             :     Buffer      buf;
     362             :     Page        page;
     363             :     sequence_magic *sm;
     364             :     OffsetNumber offnum;
     365             : 
     366             :     /* Initialize first page of relation with special magic number */
     367             : 
     368        2040 :     buf = ExtendBufferedRel(BMR_REL(rel), forkNum, NULL,
     369             :                             EB_LOCK_FIRST | EB_SKIP_EXTENSION_LOCK);
     370             :     Assert(BufferGetBlockNumber(buf) == 0);
     371             : 
     372        2040 :     page = BufferGetPage(buf);
     373             : 
     374        2040 :     PageInit(page, BufferGetPageSize(buf), sizeof(sequence_magic));
     375        2040 :     sm = (sequence_magic *) PageGetSpecialPointer(page);
     376        2040 :     sm->magic = SEQ_MAGIC;
     377             : 
     378             :     /* Now insert sequence tuple */
     379             : 
     380             :     /*
     381             :      * Since VACUUM does not process sequences, we have to force the tuple to
     382             :      * have xmin = FrozenTransactionId now.  Otherwise it would become
     383             :      * invisible to SELECTs after 2G transactions.  It is okay to do this
     384             :      * because if the current transaction aborts, no other xact will ever
     385             :      * examine the sequence tuple anyway.
     386             :      */
     387        2040 :     HeapTupleHeaderSetXmin(tuple->t_data, FrozenTransactionId);
     388        2040 :     HeapTupleHeaderSetXminFrozen(tuple->t_data);
     389        2040 :     HeapTupleHeaderSetCmin(tuple->t_data, FirstCommandId);
     390        2040 :     HeapTupleHeaderSetXmax(tuple->t_data, InvalidTransactionId);
     391        2040 :     tuple->t_data->t_infomask |= HEAP_XMAX_INVALID;
     392        2040 :     ItemPointerSet(&tuple->t_data->t_ctid, 0, FirstOffsetNumber);
     393             : 
     394             :     /* check the comment above nextval_internal()'s equivalent call. */
     395        2040 :     if (RelationNeedsWAL(rel))
     396        1100 :         GetTopTransactionId();
     397             : 
     398        2040 :     START_CRIT_SECTION();
     399             : 
     400        2040 :     MarkBufferDirty(buf);
     401             : 
     402        2040 :     offnum = PageAddItem(page, (Item) tuple->t_data, tuple->t_len,
     403             :                          InvalidOffsetNumber, false, false);
     404        2040 :     if (offnum != FirstOffsetNumber)
     405           0 :         elog(ERROR, "failed to add sequence tuple to page");
     406             : 
     407             :     /* XLOG stuff */
     408        2040 :     if (RelationNeedsWAL(rel) || forkNum == INIT_FORKNUM)
     409             :     {
     410             :         xl_seq_rec  xlrec;
     411             :         XLogRecPtr  recptr;
     412             : 
     413        1200 :         XLogBeginInsert();
     414        1200 :         XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
     415             : 
     416        1200 :         xlrec.locator = rel->rd_locator;
     417             : 
     418        1200 :         XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
     419        1200 :         XLogRegisterData((char *) tuple->t_data, tuple->t_len);
     420             : 
     421        1200 :         recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
     422             : 
     423        1200 :         PageSetLSN(page, recptr);
     424             :     }
     425             : 
     426        2040 :     END_CRIT_SECTION();
     427             : 
     428        2040 :     UnlockReleaseBuffer(buf);
     429        2040 : }
     430             : 
     431             : /*
     432             :  * AlterSequence
     433             :  *
     434             :  * Modify the definition of a sequence relation
     435             :  */
     436             : ObjectAddress
     437        1390 : AlterSequence(ParseState *pstate, AlterSeqStmt *stmt)
     438             : {
     439             :     Oid         relid;
     440             :     SeqTable    elm;
     441             :     Relation    seqrel;
     442             :     Buffer      buf;
     443             :     HeapTupleData datatuple;
     444             :     Form_pg_sequence seqform;
     445             :     Form_pg_sequence_data newdataform;
     446             :     bool        need_seq_rewrite;
     447             :     List       *owned_by;
     448             :     ObjectAddress address;
     449             :     Relation    rel;
     450             :     HeapTuple   seqtuple;
     451             :     HeapTuple   newdatatuple;
     452             : 
     453             :     /* Open and lock sequence, and check for ownership along the way. */
     454        1390 :     relid = RangeVarGetRelidExtended(stmt->sequence,
     455             :                                      ShareRowExclusiveLock,
     456        1390 :                                      stmt->missing_ok ? RVR_MISSING_OK : 0,
     457             :                                      RangeVarCallbackOwnsRelation,
     458             :                                      NULL);
     459        1384 :     if (relid == InvalidOid)
     460             :     {
     461           6 :         ereport(NOTICE,
     462             :                 (errmsg("relation \"%s\" does not exist, skipping",
     463             :                         stmt->sequence->relname)));
     464           6 :         return InvalidObjectAddress;
     465             :     }
     466             : 
     467        1378 :     init_sequence(relid, &elm, &seqrel);
     468             : 
     469        1372 :     rel = table_open(SequenceRelationId, RowExclusiveLock);
     470        1372 :     seqtuple = SearchSysCacheCopy1(SEQRELID,
     471             :                                    ObjectIdGetDatum(relid));
     472        1372 :     if (!HeapTupleIsValid(seqtuple))
     473           0 :         elog(ERROR, "cache lookup failed for sequence %u",
     474             :              relid);
     475             : 
     476        1372 :     seqform = (Form_pg_sequence) GETSTRUCT(seqtuple);
     477             : 
     478             :     /* lock page buffer and read tuple into new sequence structure */
     479        1372 :     (void) read_seq_tuple(seqrel, &buf, &datatuple);
     480             : 
     481             :     /* copy the existing sequence data tuple, so it can be modified locally */
     482        1372 :     newdatatuple = heap_copytuple(&datatuple);
     483        1372 :     newdataform = (Form_pg_sequence_data) GETSTRUCT(newdatatuple);
     484             : 
     485        1372 :     UnlockReleaseBuffer(buf);
     486             : 
     487             :     /* Check and set new values */
     488        1372 :     init_params(pstate, stmt->options, stmt->for_identity, false,
     489             :                 seqform, newdataform,
     490             :                 &need_seq_rewrite, &owned_by);
     491             : 
     492             :     /* If needed, rewrite the sequence relation itself */
     493        1342 :     if (need_seq_rewrite)
     494             :     {
     495             :         /* check the comment above nextval_internal()'s equivalent call. */
     496         162 :         if (RelationNeedsWAL(seqrel))
     497         158 :             GetTopTransactionId();
     498             : 
     499             :         /*
     500             :          * Create a new storage file for the sequence, making the state
     501             :          * changes transactional.
     502             :          */
     503         162 :         RelationSetNewRelfilenumber(seqrel, seqrel->rd_rel->relpersistence);
     504             : 
     505             :         /*
     506             :          * Ensure sequence's relfrozenxid is at 0, since it won't contain any
     507             :          * unfrozen XIDs.  Same with relminmxid, since a sequence will never
     508             :          * contain multixacts.
     509             :          */
     510             :         Assert(seqrel->rd_rel->relfrozenxid == InvalidTransactionId);
     511             :         Assert(seqrel->rd_rel->relminmxid == InvalidMultiXactId);
     512             : 
     513             :         /*
     514             :          * Insert the modified tuple into the new storage file.
     515             :          */
     516         162 :         fill_seq_with_data(seqrel, newdatatuple);
     517             :     }
     518             : 
     519             :     /* Clear local cache so that we don't think we have cached numbers */
     520             :     /* Note that we do not change the currval() state */
     521        1342 :     elm->cached = elm->last;
     522             : 
     523             :     /* process OWNED BY if given */
     524        1342 :     if (owned_by)
     525        1172 :         process_owned_by(seqrel, owned_by, stmt->for_identity);
     526             : 
     527             :     /* update the pg_sequence tuple (we could skip this in some cases...) */
     528        1336 :     CatalogTupleUpdate(rel, &seqtuple->t_self, seqtuple);
     529             : 
     530        1336 :     InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
     531             : 
     532        1336 :     ObjectAddressSet(address, RelationRelationId, relid);
     533             : 
     534        1336 :     table_close(rel, RowExclusiveLock);
     535        1336 :     sequence_close(seqrel, NoLock);
     536             : 
     537        1336 :     return address;
     538             : }
     539             : 
     540             : void
     541          60 : SequenceChangePersistence(Oid relid, char newrelpersistence)
     542             : {
     543             :     SeqTable    elm;
     544             :     Relation    seqrel;
     545             :     Buffer      buf;
     546             :     HeapTupleData seqdatatuple;
     547             : 
     548          60 :     init_sequence(relid, &elm, &seqrel);
     549             : 
     550             :     /* check the comment above nextval_internal()'s equivalent call. */
     551          60 :     if (RelationNeedsWAL(seqrel))
     552          34 :         GetTopTransactionId();
     553             : 
     554          60 :     (void) read_seq_tuple(seqrel, &buf, &seqdatatuple);
     555          60 :     RelationSetNewRelfilenumber(seqrel, newrelpersistence);
     556          60 :     fill_seq_with_data(seqrel, &seqdatatuple);
     557          60 :     UnlockReleaseBuffer(buf);
     558             : 
     559          60 :     sequence_close(seqrel, NoLock);
     560          60 : }
     561             : 
     562             : void
     563         926 : DeleteSequenceTuple(Oid relid)
     564             : {
     565             :     Relation    rel;
     566             :     HeapTuple   tuple;
     567             : 
     568         926 :     rel = table_open(SequenceRelationId, RowExclusiveLock);
     569             : 
     570         926 :     tuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
     571         926 :     if (!HeapTupleIsValid(tuple))
     572           0 :         elog(ERROR, "cache lookup failed for sequence %u", relid);
     573             : 
     574         926 :     CatalogTupleDelete(rel, &tuple->t_self);
     575             : 
     576         926 :     ReleaseSysCache(tuple);
     577         926 :     table_close(rel, RowExclusiveLock);
     578         926 : }
     579             : 
     580             : /*
     581             :  * Note: nextval with a text argument is no longer exported as a pg_proc
     582             :  * entry, but we keep it around to ease porting of C code that may have
     583             :  * called the function directly.
     584             :  */
     585             : Datum
     586          42 : nextval(PG_FUNCTION_ARGS)
     587             : {
     588          42 :     text       *seqin = PG_GETARG_TEXT_PP(0);
     589             :     RangeVar   *sequence;
     590             :     Oid         relid;
     591             : 
     592          42 :     sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin));
     593             : 
     594             :     /*
     595             :      * XXX: This is not safe in the presence of concurrent DDL, but acquiring
     596             :      * a lock here is more expensive than letting nextval_internal do it,
     597             :      * since the latter maintains a cache that keeps us from hitting the lock
     598             :      * manager more than once per transaction.  It's not clear whether the
     599             :      * performance penalty is material in practice, but for now, we do it this
     600             :      * way.
     601             :      */
     602          42 :     relid = RangeVarGetRelid(sequence, NoLock, false);
     603             : 
     604          42 :     PG_RETURN_INT64(nextval_internal(relid, true));
     605             : }
     606             : 
     607             : Datum
     608      199922 : nextval_oid(PG_FUNCTION_ARGS)
     609             : {
     610      199922 :     Oid         relid = PG_GETARG_OID(0);
     611             : 
     612      199922 :     PG_RETURN_INT64(nextval_internal(relid, true));
     613             : }
     614             : 
     615             : int64
     616      200960 : nextval_internal(Oid relid, bool check_permissions)
     617             : {
     618             :     SeqTable    elm;
     619             :     Relation    seqrel;
     620             :     Buffer      buf;
     621             :     Page        page;
     622             :     HeapTuple   pgstuple;
     623             :     Form_pg_sequence pgsform;
     624             :     HeapTupleData seqdatatuple;
     625             :     Form_pg_sequence_data seq;
     626             :     int64       incby,
     627             :                 maxv,
     628             :                 minv,
     629             :                 cache,
     630             :                 log,
     631             :                 fetch,
     632             :                 last;
     633             :     int64       result,
     634             :                 next,
     635      200960 :                 rescnt = 0;
     636             :     bool        cycle;
     637      200960 :     bool        logit = false;
     638             : 
     639             :     /* open and lock sequence */
     640      200960 :     init_sequence(relid, &elm, &seqrel);
     641             : 
     642      400924 :     if (check_permissions &&
     643      199964 :         pg_class_aclcheck(elm->relid, GetUserId(),
     644             :                           ACL_USAGE | ACL_UPDATE) != ACLCHECK_OK)
     645           6 :         ereport(ERROR,
     646             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     647             :                  errmsg("permission denied for sequence %s",
     648             :                         RelationGetRelationName(seqrel))));
     649             : 
     650             :     /* read-only transactions may only modify temp sequences */
     651      200954 :     if (!seqrel->rd_islocaltemp)
     652       79218 :         PreventCommandIfReadOnly("nextval()");
     653             : 
     654             :     /*
     655             :      * Forbid this during parallel operation because, to make it work, the
     656             :      * cooperating backends would need to share the backend-local cached
     657             :      * sequence information.  Currently, we don't support that.
     658             :      */
     659      200948 :     PreventCommandIfParallelMode("nextval()");
     660             : 
     661      200948 :     if (elm->last != elm->cached) /* some numbers were cached */
     662             :     {
     663             :         Assert(elm->last_valid);
     664             :         Assert(elm->increment != 0);
     665          12 :         elm->last += elm->increment;
     666          12 :         sequence_close(seqrel, NoLock);
     667          12 :         last_used_seq = elm;
     668          12 :         return elm->last;
     669             :     }
     670             : 
     671      200936 :     pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
     672      200936 :     if (!HeapTupleIsValid(pgstuple))
     673           0 :         elog(ERROR, "cache lookup failed for sequence %u", relid);
     674      200936 :     pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
     675      200936 :     incby = pgsform->seqincrement;
     676      200936 :     maxv = pgsform->seqmax;
     677      200936 :     minv = pgsform->seqmin;
     678      200936 :     cache = pgsform->seqcache;
     679      200936 :     cycle = pgsform->seqcycle;
     680      200936 :     ReleaseSysCache(pgstuple);
     681             : 
     682             :     /* lock page buffer and read tuple */
     683      200936 :     seq = read_seq_tuple(seqrel, &buf, &seqdatatuple);
     684      200936 :     page = BufferGetPage(buf);
     685             : 
     686      200936 :     last = next = result = seq->last_value;
     687      200936 :     fetch = cache;
     688      200936 :     log = seq->log_cnt;
     689             : 
     690      200936 :     if (!seq->is_called)
     691             :     {
     692        1154 :         rescnt++;               /* return last_value if not is_called */
     693        1154 :         fetch--;
     694             :     }
     695             : 
     696             :     /*
     697             :      * Decide whether we should emit a WAL log record.  If so, force up the
     698             :      * fetch count to grab SEQ_LOG_VALS more values than we actually need to
     699             :      * cache.  (These will then be usable without logging.)
     700             :      *
     701             :      * If this is the first nextval after a checkpoint, we must force a new
     702             :      * WAL record to be written anyway, else replay starting from the
     703             :      * checkpoint would fail to advance the sequence past the logged values.
     704             :      * In this case we may as well fetch extra values.
     705             :      */
     706      200936 :     if (log < fetch || !seq->is_called)
     707             :     {
     708             :         /* forced log to satisfy local demand for values */
     709        3452 :         fetch = log = fetch + SEQ_LOG_VALS;
     710        3452 :         logit = true;
     711             :     }
     712             :     else
     713             :     {
     714      197484 :         XLogRecPtr  redoptr = GetRedoRecPtr();
     715             : 
     716      197484 :         if (PageGetLSN(page) <= redoptr)
     717             :         {
     718             :             /* last update of seq was before checkpoint */
     719      123236 :             fetch = log = fetch + SEQ_LOG_VALS;
     720      123236 :             logit = true;
     721             :         }
     722             :     }
     723             : 
     724     4453120 :     while (fetch)               /* try to fetch cache [+ log ] numbers */
     725             :     {
     726             :         /*
     727             :          * Check MAXVALUE for ascending sequences and MINVALUE for descending
     728             :          * sequences
     729             :          */
     730     4252242 :         if (incby > 0)
     731             :         {
     732             :             /* ascending sequence */
     733     4251648 :             if ((maxv >= 0 && next > maxv - incby) ||
     734           0 :                 (maxv < 0 && next + incby > maxv))
     735             :             {
     736          40 :                 if (rescnt > 0)
     737          24 :                     break;      /* stop fetching */
     738          16 :                 if (!cycle)
     739          10 :                     ereport(ERROR,
     740             :                             (errcode(ERRCODE_SEQUENCE_GENERATOR_LIMIT_EXCEEDED),
     741             :                              errmsg("nextval: reached maximum value of sequence \"%s\" (%lld)",
     742             :                                     RelationGetRelationName(seqrel),
     743             :                                     (long long) maxv)));
     744           6 :                 next = minv;
     745             :             }
     746             :             else
     747     4251608 :                 next += incby;
     748             :         }
     749             :         else
     750             :         {
     751             :             /* descending sequence */
     752         594 :             if ((minv < 0 && next < minv - incby) ||
     753           0 :                 (minv >= 0 && next + incby < minv))
     754             :             {
     755          30 :                 if (rescnt > 0)
     756          18 :                     break;      /* stop fetching */
     757          12 :                 if (!cycle)
     758           6 :                     ereport(ERROR,
     759             :                             (errcode(ERRCODE_SEQUENCE_GENERATOR_LIMIT_EXCEEDED),
     760             :                              errmsg("nextval: reached minimum value of sequence \"%s\" (%lld)",
     761             :                                     RelationGetRelationName(seqrel),
     762             :                                     (long long) minv)));
     763           6 :                 next = maxv;
     764             :             }
     765             :             else
     766         564 :                 next += incby;
     767             :         }
     768     4252184 :         fetch--;
     769     4252184 :         if (rescnt < cache)
     770             :         {
     771      199820 :             log--;
     772      199820 :             rescnt++;
     773      199820 :             last = next;
     774      199820 :             if (rescnt == 1)    /* if it's first result - */
     775      199766 :                 result = next;  /* it's what to return */
     776             :         }
     777             :     }
     778             : 
     779      200920 :     log -= fetch;               /* adjust for any unfetched numbers */
     780             :     Assert(log >= 0);
     781             : 
     782             :     /* save info in local cache */
     783      200920 :     elm->increment = incby;
     784      200920 :     elm->last = result;          /* last returned number */
     785      200920 :     elm->cached = last;          /* last fetched number */
     786      200920 :     elm->last_valid = true;
     787             : 
     788      200920 :     last_used_seq = elm;
     789             : 
     790             :     /*
     791             :      * If something needs to be WAL logged, acquire an xid, so this
     792             :      * transaction's commit will trigger a WAL flush and wait for syncrep.
     793             :      * It's sufficient to ensure the toplevel transaction has an xid, no need
     794             :      * to assign xids subxacts, that'll already trigger an appropriate wait.
     795             :      * (Have to do that here, so we're outside the critical section)
     796             :      */
     797      200920 :     if (logit && RelationNeedsWAL(seqrel))
     798        3208 :         GetTopTransactionId();
     799             : 
     800             :     /* ready to change the on-disk (or really, in-buffer) tuple */
     801      200920 :     START_CRIT_SECTION();
     802             : 
     803             :     /*
     804             :      * We must mark the buffer dirty before doing XLogInsert(); see notes in
     805             :      * SyncOneBuffer().  However, we don't apply the desired changes just yet.
     806             :      * This looks like a violation of the buffer update protocol, but it is in
     807             :      * fact safe because we hold exclusive lock on the buffer.  Any other
     808             :      * process, including a checkpoint, that tries to examine the buffer
     809             :      * contents will block until we release the lock, and then will see the
     810             :      * final state that we install below.
     811             :      */
     812      200920 :     MarkBufferDirty(buf);
     813             : 
     814             :     /* XLOG stuff */
     815      200920 :     if (logit && RelationNeedsWAL(seqrel))
     816             :     {
     817             :         xl_seq_rec  xlrec;
     818             :         XLogRecPtr  recptr;
     819             : 
     820             :         /*
     821             :          * We don't log the current state of the tuple, but rather the state
     822             :          * as it would appear after "log" more fetches.  This lets us skip
     823             :          * that many future WAL records, at the cost that we lose those
     824             :          * sequence values if we crash.
     825             :          */
     826        3208 :         XLogBeginInsert();
     827        3208 :         XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
     828             : 
     829             :         /* set values that will be saved in xlog */
     830        3208 :         seq->last_value = next;
     831        3208 :         seq->is_called = true;
     832        3208 :         seq->log_cnt = 0;
     833             : 
     834        3208 :         xlrec.locator = seqrel->rd_locator;
     835             : 
     836        3208 :         XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
     837        3208 :         XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len);
     838             : 
     839        3208 :         recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
     840             : 
     841        3208 :         PageSetLSN(page, recptr);
     842             :     }
     843             : 
     844             :     /* Now update sequence tuple to the intended final state */
     845      200920 :     seq->last_value = last;      /* last fetched number */
     846      200920 :     seq->is_called = true;
     847      200920 :     seq->log_cnt = log;          /* how much is logged */
     848             : 
     849      200920 :     END_CRIT_SECTION();
     850             : 
     851      200920 :     UnlockReleaseBuffer(buf);
     852             : 
     853      200920 :     sequence_close(seqrel, NoLock);
     854             : 
     855      200920 :     return result;
     856             : }
     857             : 
     858             : Datum
     859         116 : currval_oid(PG_FUNCTION_ARGS)
     860             : {
     861         116 :     Oid         relid = PG_GETARG_OID(0);
     862             :     int64       result;
     863             :     SeqTable    elm;
     864             :     Relation    seqrel;
     865             : 
     866             :     /* open and lock sequence */
     867         116 :     init_sequence(relid, &elm, &seqrel);
     868             : 
     869         116 :     if (pg_class_aclcheck(elm->relid, GetUserId(),
     870             :                           ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
     871           6 :         ereport(ERROR,
     872             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     873             :                  errmsg("permission denied for sequence %s",
     874             :                         RelationGetRelationName(seqrel))));
     875             : 
     876         110 :     if (!elm->last_valid)
     877           6 :         ereport(ERROR,
     878             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     879             :                  errmsg("currval of sequence \"%s\" is not yet defined in this session",
     880             :                         RelationGetRelationName(seqrel))));
     881             : 
     882         104 :     result = elm->last;
     883             : 
     884         104 :     sequence_close(seqrel, NoLock);
     885             : 
     886         104 :     PG_RETURN_INT64(result);
     887             : }
     888             : 
     889             : Datum
     890          48 : lastval(PG_FUNCTION_ARGS)
     891             : {
     892             :     Relation    seqrel;
     893             :     int64       result;
     894             : 
     895          48 :     if (last_used_seq == NULL)
     896           6 :         ereport(ERROR,
     897             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     898             :                  errmsg("lastval is not yet defined in this session")));
     899             : 
     900             :     /* Someone may have dropped the sequence since the last nextval() */
     901          42 :     if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(last_used_seq->relid)))
     902           6 :         ereport(ERROR,
     903             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     904             :                  errmsg("lastval is not yet defined in this session")));
     905             : 
     906          36 :     seqrel = lock_and_open_sequence(last_used_seq);
     907             : 
     908             :     /* nextval() must have already been called for this sequence */
     909             :     Assert(last_used_seq->last_valid);
     910             : 
     911          36 :     if (pg_class_aclcheck(last_used_seq->relid, GetUserId(),
     912             :                           ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
     913           6 :         ereport(ERROR,
     914             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     915             :                  errmsg("permission denied for sequence %s",
     916             :                         RelationGetRelationName(seqrel))));
     917             : 
     918          30 :     result = last_used_seq->last;
     919          30 :     sequence_close(seqrel, NoLock);
     920             : 
     921          30 :     PG_RETURN_INT64(result);
     922             : }
     923             : 
     924             : /*
     925             :  * Main internal procedure that handles 2 & 3 arg forms of SETVAL.
     926             :  *
     927             :  * Note that the 3 arg version (which sets the is_called flag) is
     928             :  * only for use in pg_dump, and setting the is_called flag may not
     929             :  * work if multiple users are attached to the database and referencing
     930             :  * the sequence (unlikely if pg_dump is restoring it).
     931             :  *
     932             :  * It is necessary to have the 3 arg version so that pg_dump can
     933             :  * restore the state of a sequence exactly during data-only restores -
     934             :  * it is the only way to clear the is_called flag in an existing
     935             :  * sequence.
     936             :  */
     937             : static void
     938         534 : do_setval(Oid relid, int64 next, bool iscalled)
     939             : {
     940             :     SeqTable    elm;
     941             :     Relation    seqrel;
     942             :     Buffer      buf;
     943             :     HeapTupleData seqdatatuple;
     944             :     Form_pg_sequence_data seq;
     945             :     HeapTuple   pgstuple;
     946             :     Form_pg_sequence pgsform;
     947             :     int64       maxv,
     948             :                 minv;
     949             : 
     950             :     /* open and lock sequence */
     951         534 :     init_sequence(relid, &elm, &seqrel);
     952             : 
     953         534 :     if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
     954           6 :         ereport(ERROR,
     955             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     956             :                  errmsg("permission denied for sequence %s",
     957             :                         RelationGetRelationName(seqrel))));
     958             : 
     959         528 :     pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
     960         528 :     if (!HeapTupleIsValid(pgstuple))
     961           0 :         elog(ERROR, "cache lookup failed for sequence %u", relid);
     962         528 :     pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
     963         528 :     maxv = pgsform->seqmax;
     964         528 :     minv = pgsform->seqmin;
     965         528 :     ReleaseSysCache(pgstuple);
     966             : 
     967             :     /* read-only transactions may only modify temp sequences */
     968         528 :     if (!seqrel->rd_islocaltemp)
     969         270 :         PreventCommandIfReadOnly("setval()");
     970             : 
     971             :     /*
     972             :      * Forbid this during parallel operation because, to make it work, the
     973             :      * cooperating backends would need to share the backend-local cached
     974             :      * sequence information.  Currently, we don't support that.
     975             :      */
     976         522 :     PreventCommandIfParallelMode("setval()");
     977             : 
     978             :     /* lock page buffer and read tuple */
     979         522 :     seq = read_seq_tuple(seqrel, &buf, &seqdatatuple);
     980             : 
     981         522 :     if ((next < minv) || (next > maxv))
     982          12 :         ereport(ERROR,
     983             :                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     984             :                  errmsg("setval: value %lld is out of bounds for sequence \"%s\" (%lld..%lld)",
     985             :                         (long long) next, RelationGetRelationName(seqrel),
     986             :                         (long long) minv, (long long) maxv)));
     987             : 
     988             :     /* Set the currval() state only if iscalled = true */
     989         510 :     if (iscalled)
     990             :     {
     991         192 :         elm->last = next;        /* last returned number */
     992         192 :         elm->last_valid = true;
     993             :     }
     994             : 
     995             :     /* In any case, forget any future cached numbers */
     996         510 :     elm->cached = elm->last;
     997             : 
     998             :     /* check the comment above nextval_internal()'s equivalent call. */
     999         510 :     if (RelationNeedsWAL(seqrel))
    1000         188 :         GetTopTransactionId();
    1001             : 
    1002             :     /* ready to change the on-disk (or really, in-buffer) tuple */
    1003         510 :     START_CRIT_SECTION();
    1004             : 
    1005         510 :     seq->last_value = next;      /* last fetched number */
    1006         510 :     seq->is_called = iscalled;
    1007         510 :     seq->log_cnt = 0;
    1008             : 
    1009         510 :     MarkBufferDirty(buf);
    1010             : 
    1011             :     /* XLOG stuff */
    1012         510 :     if (RelationNeedsWAL(seqrel))
    1013             :     {
    1014             :         xl_seq_rec  xlrec;
    1015             :         XLogRecPtr  recptr;
    1016         188 :         Page        page = BufferGetPage(buf);
    1017             : 
    1018         188 :         XLogBeginInsert();
    1019         188 :         XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
    1020             : 
    1021         188 :         xlrec.locator = seqrel->rd_locator;
    1022         188 :         XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
    1023         188 :         XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len);
    1024             : 
    1025         188 :         recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
    1026             : 
    1027         188 :         PageSetLSN(page, recptr);
    1028             :     }
    1029             : 
    1030         510 :     END_CRIT_SECTION();
    1031             : 
    1032         510 :     UnlockReleaseBuffer(buf);
    1033             : 
    1034         510 :     sequence_close(seqrel, NoLock);
    1035         510 : }
    1036             : 
    1037             : /*
    1038             :  * Implement the 2 arg setval procedure.
    1039             :  * See do_setval for discussion.
    1040             :  */
    1041             : Datum
    1042         166 : setval_oid(PG_FUNCTION_ARGS)
    1043             : {
    1044         166 :     Oid         relid = PG_GETARG_OID(0);
    1045         166 :     int64       next = PG_GETARG_INT64(1);
    1046             : 
    1047         166 :     do_setval(relid, next, true);
    1048             : 
    1049         142 :     PG_RETURN_INT64(next);
    1050             : }
    1051             : 
    1052             : /*
    1053             :  * Implement the 3 arg setval procedure.
    1054             :  * See do_setval for discussion.
    1055             :  */
    1056             : Datum
    1057         368 : setval3_oid(PG_FUNCTION_ARGS)
    1058             : {
    1059         368 :     Oid         relid = PG_GETARG_OID(0);
    1060         368 :     int64       next = PG_GETARG_INT64(1);
    1061         368 :     bool        iscalled = PG_GETARG_BOOL(2);
    1062             : 
    1063         368 :     do_setval(relid, next, iscalled);
    1064             : 
    1065         368 :     PG_RETURN_INT64(next);
    1066             : }
    1067             : 
    1068             : 
    1069             : /*
    1070             :  * Open the sequence and acquire lock if needed
    1071             :  *
    1072             :  * If we haven't touched the sequence already in this transaction,
    1073             :  * we need to acquire a lock.  We arrange for the lock to
    1074             :  * be owned by the top transaction, so that we don't need to do it
    1075             :  * more than once per xact.
    1076             :  */
    1077             : static Relation
    1078      203234 : lock_and_open_sequence(SeqTable seq)
    1079             : {
    1080      203234 :     LocalTransactionId thislxid = MyProc->vxid.lxid;
    1081             : 
    1082             :     /* Get the lock if not already held in this xact */
    1083      203234 :     if (seq->lxid != thislxid)
    1084             :     {
    1085             :         ResourceOwner currentOwner;
    1086             : 
    1087        5000 :         currentOwner = CurrentResourceOwner;
    1088        5000 :         CurrentResourceOwner = TopTransactionResourceOwner;
    1089             : 
    1090        5000 :         LockRelationOid(seq->relid, RowExclusiveLock);
    1091             : 
    1092        5000 :         CurrentResourceOwner = currentOwner;
    1093             : 
    1094             :         /* Flag that we have a lock in the current xact */
    1095        5000 :         seq->lxid = thislxid;
    1096             :     }
    1097             : 
    1098             :     /* We now know we have the lock, and can safely open the rel */
    1099      203234 :     return sequence_open(seq->relid, NoLock);
    1100             : }
    1101             : 
    1102             : /*
    1103             :  * Creates the hash table for storing sequence data
    1104             :  */
    1105             : static void
    1106         614 : create_seq_hashtable(void)
    1107             : {
    1108             :     HASHCTL     ctl;
    1109             : 
    1110         614 :     ctl.keysize = sizeof(Oid);
    1111         614 :     ctl.entrysize = sizeof(SeqTableData);
    1112             : 
    1113         614 :     seqhashtab = hash_create("Sequence values", 16, &ctl,
    1114             :                              HASH_ELEM | HASH_BLOBS);
    1115         614 : }
    1116             : 
    1117             : /*
    1118             :  * Given a relation OID, open and lock the sequence.  p_elm and p_rel are
    1119             :  * output parameters.
    1120             :  */
    1121             : static void
    1122      203198 : init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
    1123             : {
    1124             :     SeqTable    elm;
    1125             :     Relation    seqrel;
    1126             :     bool        found;
    1127             : 
    1128             :     /* Find or create a hash table entry for this sequence */
    1129      203198 :     if (seqhashtab == NULL)
    1130         614 :         create_seq_hashtable();
    1131             : 
    1132      203198 :     elm = (SeqTable) hash_search(seqhashtab, &relid, HASH_ENTER, &found);
    1133             : 
    1134             :     /*
    1135             :      * Initialize the new hash table entry if it did not exist already.
    1136             :      *
    1137             :      * NOTE: seqhashtab entries are stored for the life of a backend (unless
    1138             :      * explicitly discarded with DISCARD). If the sequence itself is deleted
    1139             :      * then the entry becomes wasted memory, but it's small enough that this
    1140             :      * should not matter.
    1141             :      */
    1142      203198 :     if (!found)
    1143             :     {
    1144             :         /* relid already filled in */
    1145        1944 :         elm->filenumber = InvalidRelFileNumber;
    1146        1944 :         elm->lxid = InvalidLocalTransactionId;
    1147        1944 :         elm->last_valid = false;
    1148        1944 :         elm->last = elm->cached = 0;
    1149             :     }
    1150             : 
    1151             :     /*
    1152             :      * Open the sequence relation.
    1153             :      */
    1154      203198 :     seqrel = lock_and_open_sequence(elm);
    1155             : 
    1156             :     /*
    1157             :      * If the sequence has been transactionally replaced since we last saw it,
    1158             :      * discard any cached-but-unissued values.  We do not touch the currval()
    1159             :      * state, however.
    1160             :      */
    1161      203192 :     if (seqrel->rd_rel->relfilenode != elm->filenumber)
    1162             :     {
    1163        2070 :         elm->filenumber = seqrel->rd_rel->relfilenode;
    1164        2070 :         elm->cached = elm->last;
    1165             :     }
    1166             : 
    1167             :     /* Return results */
    1168      203192 :     *p_elm = elm;
    1169      203192 :     *p_rel = seqrel;
    1170      203192 : }
    1171             : 
    1172             : 
    1173             : /*
    1174             :  * Given an opened sequence relation, lock the page buffer and find the tuple
    1175             :  *
    1176             :  * *buf receives the reference to the pinned-and-ex-locked buffer
    1177             :  * *seqdatatuple receives the reference to the sequence tuple proper
    1178             :  *      (this arg should point to a local variable of type HeapTupleData)
    1179             :  *
    1180             :  * Function's return value points to the data payload of the tuple
    1181             :  */
    1182             : static Form_pg_sequence_data
    1183      203040 : read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
    1184             : {
    1185             :     Page        page;
    1186             :     ItemId      lp;
    1187             :     sequence_magic *sm;
    1188             :     Form_pg_sequence_data seq;
    1189             : 
    1190      203040 :     *buf = ReadBuffer(rel, 0);
    1191      203040 :     LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
    1192             : 
    1193      203040 :     page = BufferGetPage(*buf);
    1194      203040 :     sm = (sequence_magic *) PageGetSpecialPointer(page);
    1195             : 
    1196      203040 :     if (sm->magic != SEQ_MAGIC)
    1197           0 :         elog(ERROR, "bad magic number in sequence \"%s\": %08X",
    1198             :              RelationGetRelationName(rel), sm->magic);
    1199             : 
    1200      203040 :     lp = PageGetItemId(page, FirstOffsetNumber);
    1201             :     Assert(ItemIdIsNormal(lp));
    1202             : 
    1203             :     /* Note we currently only bother to set these two fields of *seqdatatuple */
    1204      203040 :     seqdatatuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
    1205      203040 :     seqdatatuple->t_len = ItemIdGetLength(lp);
    1206             : 
    1207             :     /*
    1208             :      * Previous releases of Postgres neglected to prevent SELECT FOR UPDATE on
    1209             :      * a sequence, which would leave a non-frozen XID in the sequence tuple's
    1210             :      * xmax, which eventually leads to clog access failures or worse. If we
    1211             :      * see this has happened, clean up after it.  We treat this like a hint
    1212             :      * bit update, ie, don't bother to WAL-log it, since we can certainly do
    1213             :      * this again if the update gets lost.
    1214             :      */
    1215             :     Assert(!(seqdatatuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI));
    1216      203040 :     if (HeapTupleHeaderGetRawXmax(seqdatatuple->t_data) != InvalidTransactionId)
    1217             :     {
    1218           0 :         HeapTupleHeaderSetXmax(seqdatatuple->t_data, InvalidTransactionId);
    1219           0 :         seqdatatuple->t_data->t_infomask &= ~HEAP_XMAX_COMMITTED;
    1220           0 :         seqdatatuple->t_data->t_infomask |= HEAP_XMAX_INVALID;
    1221           0 :         MarkBufferDirtyHint(*buf, true);
    1222             :     }
    1223             : 
    1224      203040 :     seq = (Form_pg_sequence_data) GETSTRUCT(seqdatatuple);
    1225             : 
    1226      203040 :     return seq;
    1227             : }
    1228             : 
    1229             : /*
    1230             :  * init_params: process the options list of CREATE or ALTER SEQUENCE, and
    1231             :  * store the values into appropriate fields of seqform, for changes that go
    1232             :  * into the pg_sequence catalog, and fields of seqdataform for changes to the
    1233             :  * sequence relation itself.  Set *need_seq_rewrite to true if we changed any
    1234             :  * parameters that require rewriting the sequence's relation (interesting for
    1235             :  * ALTER SEQUENCE).  Also set *owned_by to any OWNED BY option, or to NIL if
    1236             :  * there is none.
    1237             :  *
    1238             :  * If isInit is true, fill any unspecified options with default values;
    1239             :  * otherwise, do not change existing options that aren't explicitly overridden.
    1240             :  *
    1241             :  * Note: we force a sequence rewrite whenever we change parameters that affect
    1242             :  * generation of future sequence values, even if the seqdataform per se is not
    1243             :  * changed.  This allows ALTER SEQUENCE to behave transactionally.  Currently,
    1244             :  * the only option that doesn't cause that is OWNED BY.  It's *necessary* for
    1245             :  * ALTER SEQUENCE OWNED BY to not rewrite the sequence, because that would
    1246             :  * break pg_upgrade by causing unwanted changes in the sequence's
    1247             :  * relfilenumber.
    1248             :  */
    1249             : static void
    1250        3126 : init_params(ParseState *pstate, List *options, bool for_identity,
    1251             :             bool isInit,
    1252             :             Form_pg_sequence seqform,
    1253             :             Form_pg_sequence_data seqdataform,
    1254             :             bool *need_seq_rewrite,
    1255             :             List **owned_by)
    1256             : {
    1257        3126 :     DefElem    *as_type = NULL;
    1258        3126 :     DefElem    *start_value = NULL;
    1259        3126 :     DefElem    *restart_value = NULL;
    1260        3126 :     DefElem    *increment_by = NULL;
    1261        3126 :     DefElem    *max_value = NULL;
    1262        3126 :     DefElem    *min_value = NULL;
    1263        3126 :     DefElem    *cache_value = NULL;
    1264        3126 :     DefElem    *is_cycled = NULL;
    1265             :     ListCell   *option;
    1266        3126 :     bool        reset_max_value = false;
    1267        3126 :     bool        reset_min_value = false;
    1268             : 
    1269        3126 :     *need_seq_rewrite = false;
    1270        3126 :     *owned_by = NIL;
    1271             : 
    1272        6706 :     foreach(option, options)
    1273             :     {
    1274        3580 :         DefElem    *defel = (DefElem *) lfirst(option);
    1275             : 
    1276        3580 :         if (strcmp(defel->defname, "as") == 0)
    1277             :         {
    1278        1364 :             if (as_type)
    1279           0 :                 errorConflictingDefElem(defel, pstate);
    1280        1364 :             as_type = defel;
    1281        1364 :             *need_seq_rewrite = true;
    1282             :         }
    1283        2216 :         else if (strcmp(defel->defname, "increment") == 0)
    1284             :         {
    1285         226 :             if (increment_by)
    1286           0 :                 errorConflictingDefElem(defel, pstate);
    1287         226 :             increment_by = defel;
    1288         226 :             *need_seq_rewrite = true;
    1289             :         }
    1290        1990 :         else if (strcmp(defel->defname, "start") == 0)
    1291             :         {
    1292         210 :             if (start_value)
    1293           0 :                 errorConflictingDefElem(defel, pstate);
    1294         210 :             start_value = defel;
    1295         210 :             *need_seq_rewrite = true;
    1296             :         }
    1297        1780 :         else if (strcmp(defel->defname, "restart") == 0)
    1298             :         {
    1299          84 :             if (restart_value)
    1300           0 :                 errorConflictingDefElem(defel, pstate);
    1301          84 :             restart_value = defel;
    1302          84 :             *need_seq_rewrite = true;
    1303             :         }
    1304        1696 :         else if (strcmp(defel->defname, "maxvalue") == 0)
    1305             :         {
    1306         164 :             if (max_value)
    1307           0 :                 errorConflictingDefElem(defel, pstate);
    1308         164 :             max_value = defel;
    1309         164 :             *need_seq_rewrite = true;
    1310             :         }
    1311        1532 :         else if (strcmp(defel->defname, "minvalue") == 0)
    1312             :         {
    1313         168 :             if (min_value)
    1314           0 :                 errorConflictingDefElem(defel, pstate);
    1315         168 :             min_value = defel;
    1316         168 :             *need_seq_rewrite = true;
    1317             :         }
    1318        1364 :         else if (strcmp(defel->defname, "cache") == 0)
    1319             :         {
    1320         124 :             if (cache_value)
    1321           0 :                 errorConflictingDefElem(defel, pstate);
    1322         124 :             cache_value = defel;
    1323         124 :             *need_seq_rewrite = true;
    1324             :         }
    1325        1240 :         else if (strcmp(defel->defname, "cycle") == 0)
    1326             :         {
    1327          42 :             if (is_cycled)
    1328           0 :                 errorConflictingDefElem(defel, pstate);
    1329          42 :             is_cycled = defel;
    1330          42 :             *need_seq_rewrite = true;
    1331             :         }
    1332        1198 :         else if (strcmp(defel->defname, "owned_by") == 0)
    1333             :         {
    1334        1198 :             if (*owned_by)
    1335           0 :                 errorConflictingDefElem(defel, pstate);
    1336        1198 :             *owned_by = defGetQualifiedName(defel);
    1337             :         }
    1338           0 :         else if (strcmp(defel->defname, "sequence_name") == 0)
    1339             :         {
    1340             :             /*
    1341             :              * The parser allows this, but it is only for identity columns, in
    1342             :              * which case it is filtered out in parse_utilcmd.c.  We only get
    1343             :              * here if someone puts it into a CREATE SEQUENCE.
    1344             :              */
    1345           0 :             ereport(ERROR,
    1346             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    1347             :                      errmsg("invalid sequence option SEQUENCE NAME"),
    1348             :                      parser_errposition(pstate, defel->location)));
    1349             :         }
    1350             :         else
    1351           0 :             elog(ERROR, "option \"%s\" not recognized",
    1352             :                  defel->defname);
    1353             :     }
    1354             : 
    1355             :     /*
    1356             :      * We must reset log_cnt when isInit or when changing any parameters that
    1357             :      * would affect future nextval allocations.
    1358             :      */
    1359        3126 :     if (isInit)
    1360        1754 :         seqdataform->log_cnt = 0;
    1361             : 
    1362             :     /* AS type */
    1363        3126 :     if (as_type != NULL)
    1364             :     {
    1365        1364 :         Oid         newtypid = typenameTypeId(pstate, defGetTypeName(as_type));
    1366             : 
    1367        1358 :         if (newtypid != INT2OID &&
    1368         116 :             newtypid != INT4OID &&
    1369             :             newtypid != INT8OID)
    1370          24 :             ereport(ERROR,
    1371             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1372             :                      for_identity
    1373             :                      ? errmsg("identity column type must be smallint, integer, or bigint")
    1374             :                      : errmsg("sequence type must be smallint, integer, or bigint")));
    1375             : 
    1376        1334 :         if (!isInit)
    1377             :         {
    1378             :             /*
    1379             :              * When changing type and the old sequence min/max values were the
    1380             :              * min/max of the old type, adjust sequence min/max values to
    1381             :              * min/max of new type.  (Otherwise, the user chose explicit
    1382             :              * min/max values, which we'll leave alone.)
    1383             :              */
    1384          84 :             if ((seqform->seqtypid == INT2OID && seqform->seqmax == PG_INT16_MAX) ||
    1385          60 :                 (seqform->seqtypid == INT4OID && seqform->seqmax == PG_INT32_MAX) ||
    1386          30 :                 (seqform->seqtypid == INT8OID && seqform->seqmax == PG_INT64_MAX))
    1387          60 :                 reset_max_value = true;
    1388          84 :             if ((seqform->seqtypid == INT2OID && seqform->seqmin == PG_INT16_MIN) ||
    1389          66 :                 (seqform->seqtypid == INT4OID && seqform->seqmin == PG_INT32_MIN) ||
    1390          60 :                 (seqform->seqtypid == INT8OID && seqform->seqmin == PG_INT64_MIN))
    1391          24 :                 reset_min_value = true;
    1392             :         }
    1393             : 
    1394        1334 :         seqform->seqtypid = newtypid;
    1395             :     }
    1396        1762 :     else if (isInit)
    1397             :     {
    1398         480 :         seqform->seqtypid = INT8OID;
    1399             :     }
    1400             : 
    1401             :     /* INCREMENT BY */
    1402        3096 :     if (increment_by != NULL)
    1403             :     {
    1404         226 :         seqform->seqincrement = defGetInt64(increment_by);
    1405         226 :         if (seqform->seqincrement == 0)
    1406           6 :             ereport(ERROR,
    1407             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1408             :                      errmsg("INCREMENT must not be zero")));
    1409         220 :         seqdataform->log_cnt = 0;
    1410             :     }
    1411        2870 :     else if (isInit)
    1412             :     {
    1413        1548 :         seqform->seqincrement = 1;
    1414             :     }
    1415             : 
    1416             :     /* CYCLE */
    1417        3090 :     if (is_cycled != NULL)
    1418             :     {
    1419          42 :         seqform->seqcycle = boolVal(is_cycled->arg);
    1420             :         Assert(BoolIsValid(seqform->seqcycle));
    1421          42 :         seqdataform->log_cnt = 0;
    1422             :     }
    1423        3048 :     else if (isInit)
    1424             :     {
    1425        1714 :         seqform->seqcycle = false;
    1426             :     }
    1427             : 
    1428             :     /* MAXVALUE (null arg means NO MAXVALUE) */
    1429        3090 :     if (max_value != NULL && max_value->arg)
    1430             :     {
    1431          68 :         seqform->seqmax = defGetInt64(max_value);
    1432          68 :         seqdataform->log_cnt = 0;
    1433             :     }
    1434        3022 :     else if (isInit || max_value != NULL || reset_max_value)
    1435             :     {
    1436        1746 :         if (seqform->seqincrement > 0 || reset_max_value)
    1437             :         {
    1438             :             /* ascending seq */
    1439        1710 :             if (seqform->seqtypid == INT2OID)
    1440          74 :                 seqform->seqmax = PG_INT16_MAX;
    1441        1636 :             else if (seqform->seqtypid == INT4OID)
    1442        1106 :                 seqform->seqmax = PG_INT32_MAX;
    1443             :             else
    1444         530 :                 seqform->seqmax = PG_INT64_MAX;
    1445             :         }
    1446             :         else
    1447          36 :             seqform->seqmax = -1;    /* descending seq */
    1448        1746 :         seqdataform->log_cnt = 0;
    1449             :     }
    1450             : 
    1451             :     /* Validate maximum value.  No need to check INT8 as seqmax is an int64 */
    1452        3090 :     if ((seqform->seqtypid == INT2OID && (seqform->seqmax < PG_INT16_MIN || seqform->seqmax > PG_INT16_MAX))
    1453        3078 :         || (seqform->seqtypid == INT4OID && (seqform->seqmax < PG_INT32_MIN || seqform->seqmax > PG_INT32_MAX)))
    1454          12 :         ereport(ERROR,
    1455             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1456             :                  errmsg("MAXVALUE (%lld) is out of range for sequence data type %s",
    1457             :                         (long long) seqform->seqmax,
    1458             :                         format_type_be(seqform->seqtypid))));
    1459             : 
    1460             :     /* MINVALUE (null arg means NO MINVALUE) */
    1461        3078 :     if (min_value != NULL && min_value->arg)
    1462             :     {
    1463          72 :         seqform->seqmin = defGetInt64(min_value);
    1464          72 :         seqdataform->log_cnt = 0;
    1465             :     }
    1466        3006 :     else if (isInit || min_value != NULL || reset_min_value)
    1467             :     {
    1468        1696 :         if (seqform->seqincrement < 0 || reset_min_value)
    1469             :         {
    1470             :             /* descending seq */
    1471          62 :             if (seqform->seqtypid == INT2OID)
    1472          20 :                 seqform->seqmin = PG_INT16_MIN;
    1473          42 :             else if (seqform->seqtypid == INT4OID)
    1474          28 :                 seqform->seqmin = PG_INT32_MIN;
    1475             :             else
    1476          14 :                 seqform->seqmin = PG_INT64_MIN;
    1477             :         }
    1478             :         else
    1479        1634 :             seqform->seqmin = 1; /* ascending seq */
    1480        1696 :         seqdataform->log_cnt = 0;
    1481             :     }
    1482             : 
    1483             :     /* Validate minimum value.  No need to check INT8 as seqmin is an int64 */
    1484        3078 :     if ((seqform->seqtypid == INT2OID && (seqform->seqmin < PG_INT16_MIN || seqform->seqmin > PG_INT16_MAX))
    1485        3066 :         || (seqform->seqtypid == INT4OID && (seqform->seqmin < PG_INT32_MIN || seqform->seqmin > PG_INT32_MAX)))
    1486          12 :         ereport(ERROR,
    1487             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1488             :                  errmsg("MINVALUE (%lld) is out of range for sequence data type %s",
    1489             :                         (long long) seqform->seqmin,
    1490             :                         format_type_be(seqform->seqtypid))));
    1491             : 
    1492             :     /* crosscheck min/max */
    1493        3066 :     if (seqform->seqmin >= seqform->seqmax)
    1494          12 :         ereport(ERROR,
    1495             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1496             :                  errmsg("MINVALUE (%lld) must be less than MAXVALUE (%lld)",
    1497             :                         (long long) seqform->seqmin,
    1498             :                         (long long) seqform->seqmax)));
    1499             : 
    1500             :     /* START WITH */
    1501        3054 :     if (start_value != NULL)
    1502             :     {
    1503         210 :         seqform->seqstart = defGetInt64(start_value);
    1504             :     }
    1505        2844 :     else if (isInit)
    1506             :     {
    1507        1524 :         if (seqform->seqincrement > 0)
    1508        1500 :             seqform->seqstart = seqform->seqmin;  /* ascending seq */
    1509             :         else
    1510          24 :             seqform->seqstart = seqform->seqmax;  /* descending seq */
    1511             :     }
    1512             : 
    1513             :     /* crosscheck START */
    1514        3054 :     if (seqform->seqstart < seqform->seqmin)
    1515           6 :         ereport(ERROR,
    1516             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1517             :                  errmsg("START value (%lld) cannot be less than MINVALUE (%lld)",
    1518             :                         (long long) seqform->seqstart,
    1519             :                         (long long) seqform->seqmin)));
    1520        3048 :     if (seqform->seqstart > seqform->seqmax)
    1521           6 :         ereport(ERROR,
    1522             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1523             :                  errmsg("START value (%lld) cannot be greater than MAXVALUE (%lld)",
    1524             :                         (long long) seqform->seqstart,
    1525             :                         (long long) seqform->seqmax)));
    1526             : 
    1527             :     /* RESTART [WITH] */
    1528        3042 :     if (restart_value != NULL)
    1529             :     {
    1530          84 :         if (restart_value->arg != NULL)
    1531          54 :             seqdataform->last_value = defGetInt64(restart_value);
    1532             :         else
    1533          30 :             seqdataform->last_value = seqform->seqstart;
    1534          84 :         seqdataform->is_called = false;
    1535          84 :         seqdataform->log_cnt = 0;
    1536             :     }
    1537        2958 :     else if (isInit)
    1538             :     {
    1539        1688 :         seqdataform->last_value = seqform->seqstart;
    1540        1688 :         seqdataform->is_called = false;
    1541             :     }
    1542             : 
    1543             :     /* crosscheck RESTART (or current value, if changing MIN/MAX) */
    1544        3042 :     if (seqdataform->last_value < seqform->seqmin)
    1545           6 :         ereport(ERROR,
    1546             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1547             :                  errmsg("RESTART value (%lld) cannot be less than MINVALUE (%lld)",
    1548             :                         (long long) seqdataform->last_value,
    1549             :                         (long long) seqform->seqmin)));
    1550        3036 :     if (seqdataform->last_value > seqform->seqmax)
    1551           6 :         ereport(ERROR,
    1552             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1553             :                  errmsg("RESTART value (%lld) cannot be greater than MAXVALUE (%lld)",
    1554             :                         (long long) seqdataform->last_value,
    1555             :                         (long long) seqform->seqmax)));
    1556             : 
    1557             :     /* CACHE */
    1558        3030 :     if (cache_value != NULL)
    1559             :     {
    1560         124 :         seqform->seqcache = defGetInt64(cache_value);
    1561         124 :         if (seqform->seqcache <= 0)
    1562           6 :             ereport(ERROR,
    1563             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1564             :                      errmsg("CACHE (%lld) must be greater than zero",
    1565             :                             (long long) seqform->seqcache)));
    1566         118 :         seqdataform->log_cnt = 0;
    1567             :     }
    1568        2906 :     else if (isInit)
    1569             :     {
    1570        1566 :         seqform->seqcache = 1;
    1571             :     }
    1572        3024 : }
    1573             : 
    1574             : /*
    1575             :  * Process an OWNED BY option for CREATE/ALTER SEQUENCE
    1576             :  *
    1577             :  * Ownership permissions on the sequence are already checked,
    1578             :  * but if we are establishing a new owned-by dependency, we must
    1579             :  * enforce that the referenced table has the same owner and namespace
    1580             :  * as the sequence.
    1581             :  */
    1582             : static void
    1583        1198 : process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
    1584             : {
    1585             :     DependencyType deptype;
    1586             :     int         nnames;
    1587             :     Relation    tablerel;
    1588             :     AttrNumber  attnum;
    1589             : 
    1590        1198 :     deptype = for_identity ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO;
    1591             : 
    1592        1198 :     nnames = list_length(owned_by);
    1593             :     Assert(nnames > 0);
    1594        1198 :     if (nnames == 1)
    1595             :     {
    1596             :         /* Must be OWNED BY NONE */
    1597          12 :         if (strcmp(strVal(linitial(owned_by)), "none") != 0)
    1598           6 :             ereport(ERROR,
    1599             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    1600             :                      errmsg("invalid OWNED BY option"),
    1601             :                      errhint("Specify OWNED BY table.column or OWNED BY NONE.")));
    1602           6 :         tablerel = NULL;
    1603           6 :         attnum = 0;
    1604             :     }
    1605             :     else
    1606             :     {
    1607             :         List       *relname;
    1608             :         char       *attrname;
    1609             :         RangeVar   *rel;
    1610             : 
    1611             :         /* Separate relname and attr name */
    1612        1186 :         relname = list_copy_head(owned_by, nnames - 1);
    1613        1186 :         attrname = strVal(llast(owned_by));
    1614             : 
    1615             :         /* Open and lock rel to ensure it won't go away meanwhile */
    1616        1186 :         rel = makeRangeVarFromNameList(relname);
    1617        1186 :         tablerel = relation_openrv(rel, AccessShareLock);
    1618             : 
    1619             :         /* Must be a regular or foreign table */
    1620        1186 :         if (!(tablerel->rd_rel->relkind == RELKIND_RELATION ||
    1621          68 :               tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
    1622          60 :               tablerel->rd_rel->relkind == RELKIND_VIEW ||
    1623          60 :               tablerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
    1624           6 :             ereport(ERROR,
    1625             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1626             :                      errmsg("sequence cannot be owned by relation \"%s\"",
    1627             :                             RelationGetRelationName(tablerel)),
    1628             :                      errdetail_relkind_not_supported(tablerel->rd_rel->relkind)));
    1629             : 
    1630             :         /* We insist on same owner and schema */
    1631        1180 :         if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
    1632           0 :             ereport(ERROR,
    1633             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    1634             :                      errmsg("sequence must have same owner as table it is linked to")));
    1635        1180 :         if (RelationGetNamespace(seqrel) != RelationGetNamespace(tablerel))
    1636           6 :             ereport(ERROR,
    1637             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    1638             :                      errmsg("sequence must be in same schema as table it is linked to")));
    1639             : 
    1640             :         /* Now, fetch the attribute number from the system cache */
    1641        1174 :         attnum = get_attnum(RelationGetRelid(tablerel), attrname);
    1642        1174 :         if (attnum == InvalidAttrNumber)
    1643           6 :             ereport(ERROR,
    1644             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    1645             :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
    1646             :                             attrname, RelationGetRelationName(tablerel))));
    1647             :     }
    1648             : 
    1649             :     /*
    1650             :      * Catch user explicitly running OWNED BY on identity sequence.
    1651             :      */
    1652        1174 :     if (deptype == DEPENDENCY_AUTO)
    1653             :     {
    1654             :         Oid         tableId;
    1655             :         int32       colId;
    1656             : 
    1657         818 :         if (sequenceIsOwned(RelationGetRelid(seqrel), DEPENDENCY_INTERNAL, &tableId, &colId))
    1658           6 :             ereport(ERROR,
    1659             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1660             :                      errmsg("cannot change ownership of identity sequence"),
    1661             :                      errdetail("Sequence \"%s\" is linked to table \"%s\".",
    1662             :                                RelationGetRelationName(seqrel),
    1663             :                                get_rel_name(tableId))));
    1664             :     }
    1665             : 
    1666             :     /*
    1667             :      * OK, we are ready to update pg_depend.  First remove any existing
    1668             :      * dependencies for the sequence, then optionally add a new one.
    1669             :      */
    1670        1168 :     deleteDependencyRecordsForClass(RelationRelationId, RelationGetRelid(seqrel),
    1671             :                                     RelationRelationId, deptype);
    1672             : 
    1673        1168 :     if (tablerel)
    1674             :     {
    1675             :         ObjectAddress refobject,
    1676             :                     depobject;
    1677             : 
    1678        1168 :         refobject.classId = RelationRelationId;
    1679        1168 :         refobject.objectId = RelationGetRelid(tablerel);
    1680        1168 :         refobject.objectSubId = attnum;
    1681        1168 :         depobject.classId = RelationRelationId;
    1682        1168 :         depobject.objectId = RelationGetRelid(seqrel);
    1683        1168 :         depobject.objectSubId = 0;
    1684        1168 :         recordDependencyOn(&depobject, &refobject, deptype);
    1685             :     }
    1686             : 
    1687             :     /* Done, but hold lock until commit */
    1688        1168 :     if (tablerel)
    1689        1168 :         relation_close(tablerel, NoLock);
    1690        1168 : }
    1691             : 
    1692             : 
    1693             : /*
    1694             :  * Return sequence parameters in a list of the form created by the parser.
    1695             :  */
    1696             : List *
    1697           6 : sequence_options(Oid relid)
    1698             : {
    1699             :     HeapTuple   pgstuple;
    1700             :     Form_pg_sequence pgsform;
    1701           6 :     List       *options = NIL;
    1702             : 
    1703           6 :     pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
    1704           6 :     if (!HeapTupleIsValid(pgstuple))
    1705           0 :         elog(ERROR, "cache lookup failed for sequence %u", relid);
    1706           6 :     pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
    1707             : 
    1708             :     /* Use makeFloat() for 64-bit integers, like gram.y does. */
    1709           6 :     options = lappend(options,
    1710           6 :                       makeDefElem("cache", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqcache)), -1));
    1711           6 :     options = lappend(options,
    1712           6 :                       makeDefElem("cycle", (Node *) makeBoolean(pgsform->seqcycle), -1));
    1713           6 :     options = lappend(options,
    1714           6 :                       makeDefElem("increment", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqincrement)), -1));
    1715           6 :     options = lappend(options,
    1716           6 :                       makeDefElem("maxvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmax)), -1));
    1717           6 :     options = lappend(options,
    1718           6 :                       makeDefElem("minvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmin)), -1));
    1719           6 :     options = lappend(options,
    1720           6 :                       makeDefElem("start", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqstart)), -1));
    1721             : 
    1722           6 :     ReleaseSysCache(pgstuple);
    1723             : 
    1724           6 :     return options;
    1725             : }
    1726             : 
    1727             : /*
    1728             :  * Return sequence parameters (formerly for use by information schema)
    1729             :  */
    1730             : Datum
    1731           6 : pg_sequence_parameters(PG_FUNCTION_ARGS)
    1732             : {
    1733           6 :     Oid         relid = PG_GETARG_OID(0);
    1734             :     TupleDesc   tupdesc;
    1735             :     Datum       values[7];
    1736             :     bool        isnull[7];
    1737             :     HeapTuple   pgstuple;
    1738             :     Form_pg_sequence pgsform;
    1739             : 
    1740           6 :     if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_UPDATE | ACL_USAGE) != ACLCHECK_OK)
    1741           0 :         ereport(ERROR,
    1742             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1743             :                  errmsg("permission denied for sequence %s",
    1744             :                         get_rel_name(relid))));
    1745             : 
    1746           6 :     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
    1747           0 :         elog(ERROR, "return type must be a row type");
    1748             : 
    1749           6 :     memset(isnull, 0, sizeof(isnull));
    1750             : 
    1751           6 :     pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
    1752           6 :     if (!HeapTupleIsValid(pgstuple))
    1753           0 :         elog(ERROR, "cache lookup failed for sequence %u", relid);
    1754           6 :     pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
    1755             : 
    1756           6 :     values[0] = Int64GetDatum(pgsform->seqstart);
    1757           6 :     values[1] = Int64GetDatum(pgsform->seqmin);
    1758           6 :     values[2] = Int64GetDatum(pgsform->seqmax);
    1759           6 :     values[3] = Int64GetDatum(pgsform->seqincrement);
    1760           6 :     values[4] = BoolGetDatum(pgsform->seqcycle);
    1761           6 :     values[5] = Int64GetDatum(pgsform->seqcache);
    1762           6 :     values[6] = ObjectIdGetDatum(pgsform->seqtypid);
    1763             : 
    1764           6 :     ReleaseSysCache(pgstuple);
    1765             : 
    1766           6 :     return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
    1767             : }
    1768             : 
    1769             : /*
    1770             :  * Return the last value from the sequence
    1771             :  *
    1772             :  * Note: This has a completely different meaning than lastval().
    1773             :  */
    1774             : Datum
    1775         114 : pg_sequence_last_value(PG_FUNCTION_ARGS)
    1776             : {
    1777         114 :     Oid         relid = PG_GETARG_OID(0);
    1778             :     SeqTable    elm;
    1779             :     Relation    seqrel;
    1780             :     Buffer      buf;
    1781             :     HeapTupleData seqtuple;
    1782             :     Form_pg_sequence_data seq;
    1783             :     bool        is_called;
    1784             :     int64       result;
    1785             : 
    1786             :     /* open and lock sequence */
    1787         114 :     init_sequence(relid, &elm, &seqrel);
    1788             : 
    1789         114 :     if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
    1790           0 :         ereport(ERROR,
    1791             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1792             :                  errmsg("permission denied for sequence %s",
    1793             :                         RelationGetRelationName(seqrel))));
    1794             : 
    1795         114 :     seq = read_seq_tuple(seqrel, &buf, &seqtuple);
    1796             : 
    1797         114 :     is_called = seq->is_called;
    1798         114 :     result = seq->last_value;
    1799             : 
    1800         114 :     UnlockReleaseBuffer(buf);
    1801         114 :     sequence_close(seqrel, NoLock);
    1802             : 
    1803         114 :     if (is_called)
    1804          48 :         PG_RETURN_INT64(result);
    1805             :     else
    1806          66 :         PG_RETURN_NULL();
    1807             : }
    1808             : 
    1809             : 
    1810             : void
    1811        4612 : seq_redo(XLogReaderState *record)
    1812             : {
    1813        4612 :     XLogRecPtr  lsn = record->EndRecPtr;
    1814        4612 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
    1815             :     Buffer      buffer;
    1816             :     Page        page;
    1817             :     Page        localpage;
    1818             :     char       *item;
    1819             :     Size        itemsz;
    1820        4612 :     xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
    1821             :     sequence_magic *sm;
    1822             : 
    1823        4612 :     if (info != XLOG_SEQ_LOG)
    1824           0 :         elog(PANIC, "seq_redo: unknown op code %u", info);
    1825             : 
    1826        4612 :     buffer = XLogInitBufferForRedo(record, 0);
    1827        4612 :     page = (Page) BufferGetPage(buffer);
    1828             : 
    1829             :     /*
    1830             :      * We always reinit the page.  However, since this WAL record type is also
    1831             :      * used for updating sequences, it's possible that a hot-standby backend
    1832             :      * is examining the page concurrently; so we mustn't transiently trash the
    1833             :      * buffer.  The solution is to build the correct new page contents in
    1834             :      * local workspace and then memcpy into the buffer.  Then only bytes that
    1835             :      * are supposed to change will change, even transiently. We must palloc
    1836             :      * the local page for alignment reasons.
    1837             :      */
    1838        4612 :     localpage = (Page) palloc(BufferGetPageSize(buffer));
    1839             : 
    1840        4612 :     PageInit(localpage, BufferGetPageSize(buffer), sizeof(sequence_magic));
    1841        4612 :     sm = (sequence_magic *) PageGetSpecialPointer(localpage);
    1842        4612 :     sm->magic = SEQ_MAGIC;
    1843             : 
    1844        4612 :     item = (char *) xlrec + sizeof(xl_seq_rec);
    1845        4612 :     itemsz = XLogRecGetDataLen(record) - sizeof(xl_seq_rec);
    1846             : 
    1847        4612 :     if (PageAddItem(localpage, (Item) item, itemsz,
    1848             :                     FirstOffsetNumber, false, false) == InvalidOffsetNumber)
    1849           0 :         elog(PANIC, "seq_redo: failed to add item to page");
    1850             : 
    1851        4612 :     PageSetLSN(localpage, lsn);
    1852             : 
    1853        4612 :     memcpy(page, localpage, BufferGetPageSize(buffer));
    1854        4612 :     MarkBufferDirty(buffer);
    1855        4612 :     UnlockReleaseBuffer(buffer);
    1856             : 
    1857        4612 :     pfree(localpage);
    1858        4612 : }
    1859             : 
    1860             : /*
    1861             :  * Flush cached sequence information.
    1862             :  */
    1863             : void
    1864          18 : ResetSequenceCaches(void)
    1865             : {
    1866          18 :     if (seqhashtab)
    1867             :     {
    1868          12 :         hash_destroy(seqhashtab);
    1869          12 :         seqhashtab = NULL;
    1870             :     }
    1871             : 
    1872          18 :     last_used_seq = NULL;
    1873          18 : }
    1874             : 
    1875             : /*
    1876             :  * Mask a Sequence page before performing consistency checks on it.
    1877             :  */
    1878             : void
    1879           0 : seq_mask(char *page, BlockNumber blkno)
    1880             : {
    1881           0 :     mask_page_lsn_and_checksum(page);
    1882             : 
    1883           0 :     mask_unused_space(page);
    1884           0 : }

Generated by: LCOV version 1.14