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