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

Generated by: LCOV version 1.11