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