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

Generated by: LCOV version 2.0-1