LCOV - differential code coverage report
Current view: top level - src/backend/commands - sequence.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 94.7 % 701 664 1 3 14 19 13 210 14 427 3 213 2 21
Current Date: 2023-04-08 15:15:32 Functions: 96.3 % 27 26 1 18 5 3 1 18
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a