LCOV - code coverage report
Current view: top level - src/backend/commands - sequence.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16beta1 Lines: 650 687 94.6 %
Date: 2023-05-30 17:15:13 Functions: 26 27 96.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14