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