LCOV - code coverage report
Current view: top level - src/backend/commands - sequence.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 95.4 % 895 854
Test Date: 2026-01-26 10:56:24 Functions: 96.2 % 26 25
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 68.1 % 602 410

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

Generated by: LCOV version 2.3.2-1