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