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