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/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 1974 : 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 1974 : 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 1974 : if (seq->if_not_exists)
138 : {
139 16 : RangeVarGetAndCheckCreationNamespace(seq->sequence, NoLock, &seqoid);
140 16 : 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 10 : ObjectAddressSet(address, RelationRelationId, seqoid);
147 10 : checkMembershipInCurrentExtension(&address);
148 :
149 : /* OK to skip */
150 8 : ereport(NOTICE,
151 : (errcode(ERRCODE_DUPLICATE_TABLE),
152 : errmsg("relation \"%s\" already exists, skipping",
153 : seq->sequence->relname)));
154 8 : return InvalidObjectAddress;
155 : }
156 : }
157 :
158 : /* Check and set all option values */
159 1964 : 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 1892 : stmt->tableElts = NIL;
167 7568 : for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
168 : {
169 5676 : ColumnDef *coldef = NULL;
170 :
171 5676 : switch (i)
172 : {
173 1892 : case SEQ_COL_LASTVAL:
174 1892 : coldef = makeColumnDef("last_value", INT8OID, -1, InvalidOid);
175 1892 : value[i - 1] = Int64GetDatumFast(last_value);
176 1892 : break;
177 1892 : case SEQ_COL_LOG:
178 1892 : coldef = makeColumnDef("log_cnt", INT8OID, -1, InvalidOid);
179 1892 : value[i - 1] = Int64GetDatum((int64) 0);
180 1892 : break;
181 1892 : case SEQ_COL_CALLED:
182 1892 : coldef = makeColumnDef("is_called", BOOLOID, -1, InvalidOid);
183 1892 : value[i - 1] = BoolGetDatum(false);
184 1892 : break;
185 : }
186 :
187 5676 : coldef->is_not_null = true;
188 5676 : null[i - 1] = false;
189 :
190 5676 : stmt->tableElts = lappend(stmt->tableElts, coldef);
191 : }
192 :
193 1892 : stmt->relation = seq->sequence;
194 1892 : stmt->inhRelations = NIL;
195 1892 : stmt->constraints = NIL;
196 1892 : stmt->options = NIL;
197 1892 : stmt->oncommit = ONCOMMIT_NOOP;
198 1892 : stmt->tablespacename = NULL;
199 1892 : stmt->if_not_exists = seq->if_not_exists;
200 :
201 1892 : address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL, NULL);
202 1892 : seqoid = address.objectId;
203 : Assert(seqoid != InvalidOid);
204 :
205 1892 : rel = sequence_open(seqoid, AccessExclusiveLock);
206 1892 : tupDesc = RelationGetDescr(rel);
207 :
208 : /* now initialize the sequence's data */
209 1892 : tuple = heap_form_tuple(tupDesc, value, null);
210 1892 : fill_seq_with_data(rel, tuple);
211 :
212 : /* process OWNED BY if given */
213 1892 : if (owned_by)
214 26 : process_owned_by(rel, owned_by, seq->for_identity);
215 :
216 1868 : sequence_close(rel, NoLock);
217 :
218 : /* fill in pg_sequence */
219 1868 : rel = table_open(SequenceRelationId, RowExclusiveLock);
220 1868 : tupDesc = RelationGetDescr(rel);
221 :
222 1868 : memset(pgs_nulls, 0, sizeof(pgs_nulls));
223 :
224 1868 : pgs_values[Anum_pg_sequence_seqrelid - 1] = ObjectIdGetDatum(seqoid);
225 1868 : pgs_values[Anum_pg_sequence_seqtypid - 1] = ObjectIdGetDatum(seqform.seqtypid);
226 1868 : pgs_values[Anum_pg_sequence_seqstart - 1] = Int64GetDatumFast(seqform.seqstart);
227 1868 : pgs_values[Anum_pg_sequence_seqincrement - 1] = Int64GetDatumFast(seqform.seqincrement);
228 1868 : pgs_values[Anum_pg_sequence_seqmax - 1] = Int64GetDatumFast(seqform.seqmax);
229 1868 : pgs_values[Anum_pg_sequence_seqmin - 1] = Int64GetDatumFast(seqform.seqmin);
230 1868 : pgs_values[Anum_pg_sequence_seqcache - 1] = Int64GetDatumFast(seqform.seqcache);
231 1868 : pgs_values[Anum_pg_sequence_seqcycle - 1] = BoolGetDatum(seqform.seqcycle);
232 :
233 1868 : tuple = heap_form_tuple(tupDesc, pgs_values, pgs_nulls);
234 1868 : CatalogTupleInsert(rel, tuple);
235 :
236 1868 : heap_freetuple(tuple);
237 1868 : table_close(rel, RowExclusiveLock);
238 :
239 1868 : 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 32 : 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 32 : init_sequence(seq_relid, &elm, &seq_rel);
273 32 : (void) read_seq_tuple(seq_rel, &buf, &seqdatatuple);
274 :
275 32 : pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(seq_relid));
276 32 : if (!HeapTupleIsValid(pgstuple))
277 0 : elog(ERROR, "cache lookup failed for sequence %u", seq_relid);
278 32 : pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
279 32 : startv = pgsform->seqstart;
280 32 : ReleaseSysCache(pgstuple);
281 :
282 : /*
283 : * Copy the existing sequence tuple.
284 : */
285 32 : tuple = heap_copytuple(&seqdatatuple);
286 :
287 : /* Now we're done with the old page */
288 32 : UnlockReleaseBuffer(buf);
289 :
290 : /*
291 : * Modify the copied tuple to execute the restart (compare the RESTART
292 : * action in AlterSequence)
293 : */
294 32 : seq = (Form_pg_sequence_data) GETSTRUCT(tuple);
295 32 : seq->last_value = startv;
296 32 : seq->is_called = false;
297 32 : seq->log_cnt = 0;
298 :
299 : /*
300 : * Create a new storage file for the sequence.
301 : */
302 32 : 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 32 : 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 32 : elm->cached = elm->last;
320 :
321 32 : sequence_close(seq_rel, NoLock);
322 32 : }
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 2174 : fill_seq_with_data(Relation rel, HeapTuple tuple)
332 : {
333 2174 : fill_seq_fork_with_data(rel, tuple, MAIN_FORKNUM);
334 :
335 2174 : if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
336 : {
337 : SMgrRelation srel;
338 :
339 114 : srel = smgropen(rel->rd_locator, INVALID_PROC_NUMBER);
340 114 : smgrcreate(srel, INIT_FORKNUM, false);
341 114 : log_smgrcreate(&rel->rd_locator, INIT_FORKNUM);
342 114 : fill_seq_fork_with_data(rel, tuple, INIT_FORKNUM);
343 114 : FlushRelationBuffers(rel);
344 114 : smgrclose(srel);
345 : }
346 2174 : }
347 :
348 : /*
349 : * Initialize a sequence's relation fork with the specified tuple as content
350 : */
351 : static void
352 2288 : 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 2288 : buf = ExtendBufferedRel(BMR_REL(rel), forkNum, NULL,
362 : EB_LOCK_FIRST | EB_SKIP_EXTENSION_LOCK);
363 : Assert(BufferGetBlockNumber(buf) == 0);
364 :
365 2288 : page = BufferGetPage(buf);
366 :
367 2288 : PageInit(page, BufferGetPageSize(buf), sizeof(sequence_magic));
368 2288 : sm = (sequence_magic *) PageGetSpecialPointer(page);
369 2288 : 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 2288 : HeapTupleHeaderSetXmin(tuple->t_data, FrozenTransactionId);
381 2288 : HeapTupleHeaderSetXminFrozen(tuple->t_data);
382 2288 : HeapTupleHeaderSetCmin(tuple->t_data, FirstCommandId);
383 2288 : HeapTupleHeaderSetXmax(tuple->t_data, InvalidTransactionId);
384 2288 : tuple->t_data->t_infomask |= HEAP_XMAX_INVALID;
385 2288 : ItemPointerSet(&tuple->t_data->t_ctid, 0, FirstOffsetNumber);
386 :
387 : /* check the comment above nextval_internal()'s equivalent call. */
388 2288 : if (RelationNeedsWAL(rel))
389 1220 : GetTopTransactionId();
390 :
391 2288 : START_CRIT_SECTION();
392 :
393 2288 : MarkBufferDirty(buf);
394 :
395 2288 : offnum = PageAddItem(page, tuple->t_data, tuple->t_len, InvalidOffsetNumber, false, false);
396 2288 : if (offnum != FirstOffsetNumber)
397 0 : elog(ERROR, "failed to add sequence tuple to page");
398 :
399 : /* XLOG stuff */
400 2288 : if (RelationNeedsWAL(rel) || forkNum == INIT_FORKNUM)
401 : {
402 : xl_seq_rec xlrec;
403 : XLogRecPtr recptr;
404 :
405 1334 : XLogBeginInsert();
406 1334 : XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
407 :
408 1334 : xlrec.locator = rel->rd_locator;
409 :
410 1334 : XLogRegisterData(&xlrec, sizeof(xl_seq_rec));
411 1334 : XLogRegisterData(tuple->t_data, tuple->t_len);
412 :
413 1334 : recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
414 :
415 1334 : PageSetLSN(page, recptr);
416 : }
417 :
418 2288 : END_CRIT_SECTION();
419 :
420 2288 : UnlockReleaseBuffer(buf);
421 2288 : }
422 :
423 : /*
424 : * AlterSequence
425 : *
426 : * Modify the definition of a sequence relation
427 : */
428 : ObjectAddress
429 1512 : 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 1512 : 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 1512 : relid = RangeVarGetRelidExtended(stmt->sequence,
450 : ShareRowExclusiveLock,
451 1512 : stmt->missing_ok ? RVR_MISSING_OK : 0,
452 : RangeVarCallbackOwnsRelation,
453 : NULL);
454 1506 : if (relid == InvalidOid)
455 : {
456 6 : ereport(NOTICE,
457 : (errmsg("relation \"%s\" does not exist, skipping",
458 : stmt->sequence->relname)));
459 6 : return InvalidObjectAddress;
460 : }
461 :
462 1500 : init_sequence(relid, &elm, &seqrel);
463 :
464 1494 : rel = table_open(SequenceRelationId, RowExclusiveLock);
465 1494 : seqtuple = SearchSysCacheCopy1(SEQRELID,
466 : ObjectIdGetDatum(relid));
467 1494 : if (!HeapTupleIsValid(seqtuple))
468 0 : elog(ERROR, "cache lookup failed for sequence %u",
469 : relid);
470 :
471 1494 : seqform = (Form_pg_sequence) GETSTRUCT(seqtuple);
472 :
473 : /* lock page buffer and read tuple into new sequence structure */
474 1494 : (void) read_seq_tuple(seqrel, &buf, &datatuple);
475 :
476 : /* copy the existing sequence data tuple, so it can be modified locally */
477 1494 : newdatatuple = heap_copytuple(&datatuple);
478 1494 : newdataform = (Form_pg_sequence_data) GETSTRUCT(newdatatuple);
479 1494 : last_value = newdataform->last_value;
480 1494 : is_called = newdataform->is_called;
481 :
482 1494 : UnlockReleaseBuffer(buf);
483 :
484 : /* Check and set new values */
485 1494 : 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 1464 : if (need_seq_rewrite)
491 : {
492 : /* check the comment above nextval_internal()'s equivalent call. */
493 178 : if (RelationNeedsWAL(seqrel))
494 174 : GetTopTransactionId();
495 :
496 : /*
497 : * Create a new storage file for the sequence, making the state
498 : * changes transactional.
499 : */
500 178 : 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 178 : newdataform->last_value = last_value;
514 178 : newdataform->is_called = is_called;
515 178 : if (reset_state)
516 176 : newdataform->log_cnt = 0;
517 178 : 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 1464 : elm->cached = elm->last;
523 :
524 : /* process OWNED BY if given */
525 1464 : if (owned_by)
526 1272 : process_owned_by(seqrel, owned_by, stmt->for_identity);
527 :
528 : /* update the pg_sequence tuple (we could skip this in some cases...) */
529 1458 : CatalogTupleUpdate(rel, &seqtuple->t_self, seqtuple);
530 :
531 1458 : InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
532 :
533 1458 : ObjectAddressSet(address, RelationRelationId, relid);
534 :
535 1458 : table_close(rel, RowExclusiveLock);
536 1458 : sequence_close(seqrel, NoLock);
537 :
538 1458 : return address;
539 : }
540 :
541 : void
542 72 : 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 72 : LockRelationOid(relid, AccessExclusiveLock);
556 72 : init_sequence(relid, &elm, &seqrel);
557 :
558 : /* check the comment above nextval_internal()'s equivalent call. */
559 72 : if (RelationNeedsWAL(seqrel))
560 40 : GetTopTransactionId();
561 :
562 72 : (void) read_seq_tuple(seqrel, &buf, &seqdatatuple);
563 72 : RelationSetNewRelfilenumber(seqrel, newrelpersistence);
564 72 : fill_seq_with_data(seqrel, &seqdatatuple);
565 72 : UnlockReleaseBuffer(buf);
566 :
567 72 : sequence_close(seqrel, NoLock);
568 72 : }
569 :
570 : void
571 1010 : DeleteSequenceTuple(Oid relid)
572 : {
573 : Relation rel;
574 : HeapTuple tuple;
575 :
576 1010 : rel = table_open(SequenceRelationId, RowExclusiveLock);
577 :
578 1010 : tuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
579 1010 : if (!HeapTupleIsValid(tuple))
580 0 : elog(ERROR, "cache lookup failed for sequence %u", relid);
581 :
582 1010 : CatalogTupleDelete(rel, &tuple->t_self);
583 :
584 1010 : ReleaseSysCache(tuple);
585 1010 : table_close(rel, RowExclusiveLock);
586 1010 : }
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 18 : nextval(PG_FUNCTION_ARGS)
595 : {
596 18 : text *seqin = PG_GETARG_TEXT_PP(0);
597 : RangeVar *sequence;
598 : Oid relid;
599 :
600 18 : 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 18 : relid = RangeVarGetRelid(sequence, NoLock, false);
611 :
612 18 : PG_RETURN_INT64(nextval_internal(relid, true));
613 : }
614 :
615 : Datum
616 381134 : nextval_oid(PG_FUNCTION_ARGS)
617 : {
618 381134 : Oid relid = PG_GETARG_OID(0);
619 :
620 381134 : PG_RETURN_INT64(nextval_internal(relid, true));
621 : }
622 :
623 : int64
624 382078 : 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 382078 : rescnt = 0;
644 : bool cycle;
645 382078 : bool logit = false;
646 :
647 : /* open and lock sequence */
648 382078 : init_sequence(relid, &elm, &seqrel);
649 :
650 763230 : if (check_permissions &&
651 381152 : pg_class_aclcheck(elm->relid, GetUserId(),
652 : ACL_USAGE | ACL_UPDATE) != ACLCHECK_OK)
653 6 : 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 382072 : if (!seqrel->rd_islocaltemp)
660 260318 : 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 382066 : PreventCommandIfParallelMode("nextval()");
668 :
669 382066 : if (elm->last != elm->cached) /* some numbers were cached */
670 : {
671 : Assert(elm->last_valid);
672 : Assert(elm->increment != 0);
673 12 : elm->last += elm->increment;
674 12 : sequence_close(seqrel, NoLock);
675 12 : last_used_seq = elm;
676 12 : return elm->last;
677 : }
678 :
679 382054 : pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
680 382054 : if (!HeapTupleIsValid(pgstuple))
681 0 : elog(ERROR, "cache lookup failed for sequence %u", relid);
682 382054 : pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
683 382054 : incby = pgsform->seqincrement;
684 382054 : maxv = pgsform->seqmax;
685 382054 : minv = pgsform->seqmin;
686 382054 : cache = pgsform->seqcache;
687 382054 : cycle = pgsform->seqcycle;
688 382054 : ReleaseSysCache(pgstuple);
689 :
690 : /* lock page buffer and read tuple */
691 382054 : seq = read_seq_tuple(seqrel, &buf, &seqdatatuple);
692 382054 : page = BufferGetPage(buf);
693 :
694 382054 : last = next = result = seq->last_value;
695 382054 : fetch = cache;
696 382054 : log = seq->log_cnt;
697 :
698 382054 : if (!seq->is_called)
699 : {
700 1198 : rescnt++; /* return last_value if not is_called */
701 1198 : 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 382054 : if (log < fetch || !seq->is_called)
715 : {
716 : /* forced log to satisfy local demand for values */
717 8982 : fetch = log = fetch + SEQ_LOG_VALS;
718 8982 : logit = true;
719 : }
720 : else
721 : {
722 373072 : XLogRecPtr redoptr = GetRedoRecPtr();
723 :
724 373072 : if (PageGetLSN(page) <= redoptr)
725 : {
726 : /* last update of seq was before checkpoint */
727 123250 : fetch = log = fetch + SEQ_LOG_VALS;
728 123250 : logit = true;
729 : }
730 : }
731 :
732 4992720 : while (fetch) /* try to fetch cache [+ log ] numbers */
733 : {
734 : /*
735 : * Check MAXVALUE for ascending sequences and MINVALUE for descending
736 : * sequences
737 : */
738 4610724 : if (incby > 0)
739 : {
740 : /* ascending sequence */
741 4610130 : if ((maxv >= 0 && next > maxv - incby) ||
742 0 : (maxv < 0 && next + incby > maxv))
743 : {
744 40 : if (rescnt > 0)
745 24 : break; /* stop fetching */
746 16 : if (!cycle)
747 10 : 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 6 : next = minv;
753 : }
754 : else
755 4610090 : next += incby;
756 : }
757 : else
758 : {
759 : /* descending sequence */
760 594 : if ((minv < 0 && next < minv - incby) ||
761 0 : (minv >= 0 && next + incby < minv))
762 : {
763 30 : if (rescnt > 0)
764 18 : break; /* stop fetching */
765 12 : if (!cycle)
766 6 : 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 6 : next = maxv;
772 : }
773 : else
774 564 : next += incby;
775 : }
776 4610666 : fetch--;
777 4610666 : if (rescnt < cache)
778 : {
779 380894 : log--;
780 380894 : rescnt++;
781 380894 : last = next;
782 380894 : if (rescnt == 1) /* if it's first result - */
783 380840 : result = next; /* it's what to return */
784 : }
785 : }
786 :
787 382038 : log -= fetch; /* adjust for any unfetched numbers */
788 : Assert(log >= 0);
789 :
790 : /* save info in local cache */
791 382038 : elm->increment = incby;
792 382038 : elm->last = result; /* last returned number */
793 382038 : elm->cached = last; /* last fetched number */
794 382038 : elm->last_valid = true;
795 :
796 382038 : 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 382038 : if (logit && RelationNeedsWAL(seqrel))
806 8734 : GetTopTransactionId();
807 :
808 : /* ready to change the on-disk (or really, in-buffer) tuple */
809 382038 : 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 382038 : MarkBufferDirty(buf);
821 :
822 : /* XLOG stuff */
823 382038 : 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 8734 : XLogBeginInsert();
835 8734 : XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
836 :
837 : /* set values that will be saved in xlog */
838 8734 : seq->last_value = next;
839 8734 : seq->is_called = true;
840 8734 : seq->log_cnt = 0;
841 :
842 8734 : xlrec.locator = seqrel->rd_locator;
843 :
844 8734 : XLogRegisterData(&xlrec, sizeof(xl_seq_rec));
845 8734 : XLogRegisterData(seqdatatuple.t_data, seqdatatuple.t_len);
846 :
847 8734 : recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
848 :
849 8734 : PageSetLSN(page, recptr);
850 : }
851 :
852 : /* Now update sequence tuple to the intended final state */
853 382038 : seq->last_value = last; /* last fetched number */
854 382038 : seq->is_called = true;
855 382038 : seq->log_cnt = log; /* how much is logged */
856 :
857 382038 : END_CRIT_SECTION();
858 :
859 382038 : UnlockReleaseBuffer(buf);
860 :
861 382038 : sequence_close(seqrel, NoLock);
862 :
863 382038 : return result;
864 : }
865 :
866 : Datum
867 116 : currval_oid(PG_FUNCTION_ARGS)
868 : {
869 116 : Oid relid = PG_GETARG_OID(0);
870 : int64 result;
871 : SeqTable elm;
872 : Relation seqrel;
873 :
874 : /* open and lock sequence */
875 116 : init_sequence(relid, &elm, &seqrel);
876 :
877 116 : if (pg_class_aclcheck(elm->relid, GetUserId(),
878 : ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
879 6 : ereport(ERROR,
880 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
881 : errmsg("permission denied for sequence %s",
882 : RelationGetRelationName(seqrel))));
883 :
884 110 : if (!elm->last_valid)
885 6 : 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 104 : result = elm->last;
891 :
892 104 : sequence_close(seqrel, NoLock);
893 :
894 104 : PG_RETURN_INT64(result);
895 : }
896 :
897 : Datum
898 48 : lastval(PG_FUNCTION_ARGS)
899 : {
900 : Relation seqrel;
901 : int64 result;
902 :
903 48 : if (last_used_seq == NULL)
904 6 : 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 42 : if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(last_used_seq->relid)))
910 6 : ereport(ERROR,
911 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
912 : errmsg("lastval is not yet defined in this session")));
913 :
914 36 : 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 36 : if (pg_class_aclcheck(last_used_seq->relid, GetUserId(),
920 : ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
921 6 : ereport(ERROR,
922 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
923 : errmsg("permission denied for sequence %s",
924 : RelationGetRelationName(seqrel))));
925 :
926 30 : result = last_used_seq->last;
927 30 : sequence_close(seqrel, NoLock);
928 :
929 30 : 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 566 : 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 566 : init_sequence(relid, &elm, &seqrel);
960 :
961 566 : if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
962 6 : ereport(ERROR,
963 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
964 : errmsg("permission denied for sequence %s",
965 : RelationGetRelationName(seqrel))));
966 :
967 560 : pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
968 560 : if (!HeapTupleIsValid(pgstuple))
969 0 : elog(ERROR, "cache lookup failed for sequence %u", relid);
970 560 : pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
971 560 : maxv = pgsform->seqmax;
972 560 : minv = pgsform->seqmin;
973 560 : ReleaseSysCache(pgstuple);
974 :
975 : /* read-only transactions may only modify temp sequences */
976 560 : if (!seqrel->rd_islocaltemp)
977 302 : 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 554 : PreventCommandIfParallelMode("setval()");
985 :
986 : /* lock page buffer and read tuple */
987 554 : seq = read_seq_tuple(seqrel, &buf, &seqdatatuple);
988 :
989 554 : if ((next < minv) || (next > maxv))
990 12 : 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 542 : if (iscalled)
998 : {
999 210 : elm->last = next; /* last returned number */
1000 210 : elm->last_valid = true;
1001 : }
1002 :
1003 : /* In any case, forget any future cached numbers */
1004 542 : elm->cached = elm->last;
1005 :
1006 : /* check the comment above nextval_internal()'s equivalent call. */
1007 542 : if (RelationNeedsWAL(seqrel))
1008 256 : GetTopTransactionId();
1009 :
1010 : /* ready to change the on-disk (or really, in-buffer) tuple */
1011 542 : START_CRIT_SECTION();
1012 :
1013 542 : seq->last_value = next; /* last fetched number */
1014 542 : seq->is_called = iscalled;
1015 542 : seq->log_cnt = 0;
1016 :
1017 542 : MarkBufferDirty(buf);
1018 :
1019 : /* XLOG stuff */
1020 542 : if (RelationNeedsWAL(seqrel))
1021 : {
1022 : xl_seq_rec xlrec;
1023 : XLogRecPtr recptr;
1024 256 : Page page = BufferGetPage(buf);
1025 :
1026 256 : XLogBeginInsert();
1027 256 : XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
1028 :
1029 256 : xlrec.locator = seqrel->rd_locator;
1030 256 : XLogRegisterData(&xlrec, sizeof(xl_seq_rec));
1031 256 : XLogRegisterData(seqdatatuple.t_data, seqdatatuple.t_len);
1032 :
1033 256 : recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
1034 :
1035 256 : PageSetLSN(page, recptr);
1036 : }
1037 :
1038 542 : END_CRIT_SECTION();
1039 :
1040 542 : UnlockReleaseBuffer(buf);
1041 :
1042 542 : sequence_close(seqrel, NoLock);
1043 542 : }
1044 :
1045 : /*
1046 : * Implement the 2 arg setval procedure.
1047 : * See SetSequence for discussion.
1048 : */
1049 : Datum
1050 170 : setval_oid(PG_FUNCTION_ARGS)
1051 : {
1052 170 : Oid relid = PG_GETARG_OID(0);
1053 170 : int64 next = PG_GETARG_INT64(1);
1054 :
1055 170 : SetSequence(relid, next, true);
1056 :
1057 146 : PG_RETURN_INT64(next);
1058 : }
1059 :
1060 : /*
1061 : * Implement the 3 arg setval procedure.
1062 : * See SetSequence for discussion.
1063 : */
1064 : Datum
1065 378 : setval3_oid(PG_FUNCTION_ARGS)
1066 : {
1067 378 : Oid relid = PG_GETARG_OID(0);
1068 378 : int64 next = PG_GETARG_INT64(1);
1069 378 : bool iscalled = PG_GETARG_BOOL(2);
1070 :
1071 378 : SetSequence(relid, next, iscalled);
1072 :
1073 378 : 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 385792 : lock_and_open_sequence(SeqTable seq)
1087 : {
1088 385792 : LocalTransactionId thislxid = MyProc->vxid.lxid;
1089 :
1090 : /* Get the lock if not already held in this xact */
1091 385792 : if (seq->lxid != thislxid)
1092 : {
1093 : ResourceOwner currentOwner;
1094 :
1095 6310 : currentOwner = CurrentResourceOwner;
1096 6310 : CurrentResourceOwner = TopTransactionResourceOwner;
1097 :
1098 6310 : LockRelationOid(seq->relid, RowExclusiveLock);
1099 :
1100 6310 : CurrentResourceOwner = currentOwner;
1101 :
1102 : /* Flag that we have a lock in the current xact */
1103 6310 : seq->lxid = thislxid;
1104 : }
1105 :
1106 : /* We now know we have the lock, and can safely open the rel */
1107 385792 : return sequence_open(seq->relid, NoLock);
1108 : }
1109 :
1110 : /*
1111 : * Creates the hash table for storing sequence data
1112 : */
1113 : static void
1114 846 : create_seq_hashtable(void)
1115 : {
1116 : HASHCTL ctl;
1117 :
1118 846 : ctl.keysize = sizeof(Oid);
1119 846 : ctl.entrysize = sizeof(SeqTableData);
1120 :
1121 846 : seqhashtab = hash_create("Sequence values", 16, &ctl,
1122 : HASH_ELEM | HASH_BLOBS);
1123 846 : }
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 385756 : 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 385756 : if (seqhashtab == NULL)
1138 846 : create_seq_hashtable();
1139 :
1140 385756 : 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 385756 : if (!found)
1151 : {
1152 : /* relid already filled in */
1153 3364 : elm->filenumber = InvalidRelFileNumber;
1154 3364 : elm->lxid = InvalidLocalTransactionId;
1155 3364 : elm->last_valid = false;
1156 3364 : elm->last = elm->cached = 0;
1157 : }
1158 :
1159 : /*
1160 : * Open the sequence relation.
1161 : */
1162 385756 : 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 385750 : if (seqrel->rd_rel->relfilenode != elm->filenumber)
1170 : {
1171 3490 : elm->filenumber = seqrel->rd_rel->relfilenode;
1172 3490 : elm->cached = elm->last;
1173 : }
1174 :
1175 : /* Return results */
1176 385750 : *p_elm = elm;
1177 385750 : *p_rel = seqrel;
1178 385750 : }
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 385556 : 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 385556 : *buf = ReadBuffer(rel, 0);
1199 385556 : LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
1200 :
1201 385556 : page = BufferGetPage(*buf);
1202 385556 : sm = (sequence_magic *) PageGetSpecialPointer(page);
1203 :
1204 385556 : if (sm->magic != SEQ_MAGIC)
1205 0 : elog(ERROR, "bad magic number in sequence \"%s\": %08X",
1206 : RelationGetRelationName(rel), sm->magic);
1207 :
1208 385556 : lp = PageGetItemId(page, FirstOffsetNumber);
1209 : Assert(ItemIdIsNormal(lp));
1210 :
1211 : /* Note we currently only bother to set these two fields of *seqdatatuple */
1212 385556 : seqdatatuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
1213 385556 : 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 385556 : 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 385556 : seq = (Form_pg_sequence_data) GETSTRUCT(seqdatatuple);
1233 :
1234 385556 : 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 3458 : 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 3458 : DefElem *as_type = NULL;
1270 3458 : DefElem *start_value = NULL;
1271 3458 : DefElem *restart_value = NULL;
1272 3458 : DefElem *increment_by = NULL;
1273 3458 : DefElem *max_value = NULL;
1274 3458 : DefElem *min_value = NULL;
1275 3458 : DefElem *cache_value = NULL;
1276 3458 : DefElem *is_cycled = NULL;
1277 : ListCell *option;
1278 3458 : bool reset_max_value = false;
1279 3458 : bool reset_min_value = false;
1280 :
1281 3458 : *need_seq_rewrite = false;
1282 3458 : *owned_by = NIL;
1283 :
1284 7392 : foreach(option, options)
1285 : {
1286 3934 : DefElem *defel = (DefElem *) lfirst(option);
1287 :
1288 3934 : if (strcmp(defel->defname, "as") == 0)
1289 : {
1290 1494 : if (as_type)
1291 0 : errorConflictingDefElem(defel, pstate);
1292 1494 : as_type = defel;
1293 1494 : *need_seq_rewrite = true;
1294 : }
1295 2440 : else if (strcmp(defel->defname, "increment") == 0)
1296 : {
1297 258 : if (increment_by)
1298 0 : errorConflictingDefElem(defel, pstate);
1299 258 : increment_by = defel;
1300 258 : *need_seq_rewrite = true;
1301 : }
1302 2182 : else if (strcmp(defel->defname, "start") == 0)
1303 : {
1304 246 : if (start_value)
1305 0 : errorConflictingDefElem(defel, pstate);
1306 246 : start_value = defel;
1307 246 : *need_seq_rewrite = true;
1308 : }
1309 1936 : else if (strcmp(defel->defname, "restart") == 0)
1310 : {
1311 84 : if (restart_value)
1312 0 : errorConflictingDefElem(defel, pstate);
1313 84 : restart_value = defel;
1314 84 : *need_seq_rewrite = true;
1315 : }
1316 1852 : else if (strcmp(defel->defname, "maxvalue") == 0)
1317 : {
1318 182 : if (max_value)
1319 0 : errorConflictingDefElem(defel, pstate);
1320 182 : max_value = defel;
1321 182 : *need_seq_rewrite = true;
1322 : }
1323 1670 : else if (strcmp(defel->defname, "minvalue") == 0)
1324 : {
1325 182 : if (min_value)
1326 0 : errorConflictingDefElem(defel, pstate);
1327 182 : min_value = defel;
1328 182 : *need_seq_rewrite = true;
1329 : }
1330 1488 : else if (strcmp(defel->defname, "cache") == 0)
1331 : {
1332 142 : if (cache_value)
1333 0 : errorConflictingDefElem(defel, pstate);
1334 142 : cache_value = defel;
1335 142 : *need_seq_rewrite = true;
1336 : }
1337 1346 : else if (strcmp(defel->defname, "cycle") == 0)
1338 : {
1339 48 : if (is_cycled)
1340 0 : errorConflictingDefElem(defel, pstate);
1341 48 : is_cycled = defel;
1342 48 : *need_seq_rewrite = true;
1343 : }
1344 1298 : else if (strcmp(defel->defname, "owned_by") == 0)
1345 : {
1346 1298 : if (*owned_by)
1347 0 : errorConflictingDefElem(defel, pstate);
1348 1298 : *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 3458 : if (isInit)
1375 1964 : *reset_state = true;
1376 :
1377 : /* AS type */
1378 3458 : if (as_type != NULL)
1379 : {
1380 1494 : Oid newtypid = typenameTypeId(pstate, defGetTypeName(as_type));
1381 :
1382 1488 : if (newtypid != INT2OID &&
1383 136 : newtypid != INT4OID &&
1384 : newtypid != INT8OID)
1385 24 : 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 1464 : 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 90 : if ((seqform->seqtypid == INT2OID && seqform->seqmax == PG_INT16_MAX) ||
1400 66 : (seqform->seqtypid == INT4OID && seqform->seqmax == PG_INT32_MAX) ||
1401 36 : (seqform->seqtypid == INT8OID && seqform->seqmax == PG_INT64_MAX))
1402 66 : reset_max_value = true;
1403 90 : if ((seqform->seqtypid == INT2OID && seqform->seqmin == PG_INT16_MIN) ||
1404 72 : (seqform->seqtypid == INT4OID && seqform->seqmin == PG_INT32_MIN) ||
1405 66 : (seqform->seqtypid == INT8OID && seqform->seqmin == PG_INT64_MIN))
1406 24 : reset_min_value = true;
1407 : }
1408 :
1409 1464 : seqform->seqtypid = newtypid;
1410 : }
1411 1964 : else if (isInit)
1412 : {
1413 566 : seqform->seqtypid = INT8OID;
1414 : }
1415 :
1416 : /* INCREMENT BY */
1417 3428 : if (increment_by != NULL)
1418 : {
1419 258 : seqform->seqincrement = defGetInt64(increment_by);
1420 258 : if (seqform->seqincrement == 0)
1421 6 : ereport(ERROR,
1422 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1423 : errmsg("INCREMENT must not be zero")));
1424 252 : *reset_state = true;
1425 : }
1426 3170 : else if (isInit)
1427 : {
1428 1736 : seqform->seqincrement = 1;
1429 : }
1430 :
1431 : /* CYCLE */
1432 3422 : if (is_cycled != NULL)
1433 : {
1434 48 : seqform->seqcycle = boolVal(is_cycled->arg);
1435 : Assert(BoolIsValid(seqform->seqcycle));
1436 48 : *reset_state = true;
1437 : }
1438 3374 : else if (isInit)
1439 : {
1440 1918 : seqform->seqcycle = false;
1441 : }
1442 :
1443 : /* MAXVALUE (null arg means NO MAXVALUE) */
1444 3422 : if (max_value != NULL && max_value->arg)
1445 : {
1446 74 : seqform->seqmax = defGetInt64(max_value);
1447 74 : *reset_state = true;
1448 : }
1449 3348 : else if (isInit || max_value != NULL || reset_max_value)
1450 : {
1451 1956 : if (seqform->seqincrement > 0 || reset_max_value)
1452 : {
1453 : /* ascending seq */
1454 1920 : if (seqform->seqtypid == INT2OID)
1455 74 : seqform->seqmax = PG_INT16_MAX;
1456 1846 : else if (seqform->seqtypid == INT4OID)
1457 1216 : seqform->seqmax = PG_INT32_MAX;
1458 : else
1459 630 : seqform->seqmax = PG_INT64_MAX;
1460 : }
1461 : else
1462 36 : seqform->seqmax = -1; /* descending seq */
1463 1956 : *reset_state = true;
1464 : }
1465 :
1466 : /* Validate maximum value. No need to check INT8 as seqmax is an int64 */
1467 3422 : if ((seqform->seqtypid == INT2OID && (seqform->seqmax < PG_INT16_MIN || seqform->seqmax > PG_INT16_MAX))
1468 3410 : || (seqform->seqtypid == INT4OID && (seqform->seqmax < PG_INT32_MIN || seqform->seqmax > PG_INT32_MAX)))
1469 12 : 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 3410 : if (min_value != NULL && min_value->arg)
1477 : {
1478 74 : seqform->seqmin = defGetInt64(min_value);
1479 74 : *reset_state = true;
1480 : }
1481 3336 : else if (isInit || min_value != NULL || reset_min_value)
1482 : {
1483 1904 : if (seqform->seqincrement < 0 || reset_min_value)
1484 : {
1485 : /* descending seq */
1486 62 : if (seqform->seqtypid == INT2OID)
1487 20 : seqform->seqmin = PG_INT16_MIN;
1488 42 : else if (seqform->seqtypid == INT4OID)
1489 28 : seqform->seqmin = PG_INT32_MIN;
1490 : else
1491 14 : seqform->seqmin = PG_INT64_MIN;
1492 : }
1493 : else
1494 1842 : seqform->seqmin = 1; /* ascending seq */
1495 1904 : *reset_state = true;
1496 : }
1497 :
1498 : /* Validate minimum value. No need to check INT8 as seqmin is an int64 */
1499 3410 : if ((seqform->seqtypid == INT2OID && (seqform->seqmin < PG_INT16_MIN || seqform->seqmin > PG_INT16_MAX))
1500 3398 : || (seqform->seqtypid == INT4OID && (seqform->seqmin < PG_INT32_MIN || seqform->seqmin > PG_INT32_MAX)))
1501 12 : 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 3398 : if (seqform->seqmin >= seqform->seqmax)
1509 12 : 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 3386 : if (start_value != NULL)
1517 : {
1518 246 : seqform->seqstart = defGetInt64(start_value);
1519 : }
1520 3140 : else if (isInit)
1521 : {
1522 1698 : if (seqform->seqincrement > 0)
1523 1674 : seqform->seqstart = seqform->seqmin; /* ascending seq */
1524 : else
1525 24 : seqform->seqstart = seqform->seqmax; /* descending seq */
1526 : }
1527 :
1528 : /* crosscheck START */
1529 3386 : if (seqform->seqstart < seqform->seqmin)
1530 6 : 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 3380 : if (seqform->seqstart > seqform->seqmax)
1536 6 : 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 3374 : if (restart_value != NULL)
1544 : {
1545 84 : if (restart_value->arg != NULL)
1546 54 : *last_value = defGetInt64(restart_value);
1547 : else
1548 30 : *last_value = seqform->seqstart;
1549 84 : *is_called = false;
1550 84 : *reset_state = true;
1551 : }
1552 3290 : else if (isInit)
1553 : {
1554 1898 : *last_value = seqform->seqstart;
1555 1898 : *is_called = false;
1556 : }
1557 :
1558 : /* crosscheck RESTART (or current value, if changing MIN/MAX) */
1559 3374 : if (*last_value < seqform->seqmin)
1560 6 : 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 3368 : if (*last_value > seqform->seqmax)
1566 6 : 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 3362 : if (cache_value != NULL)
1574 : {
1575 142 : seqform->seqcache = defGetInt64(cache_value);
1576 142 : if (seqform->seqcache <= 0)
1577 6 : ereport(ERROR,
1578 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1579 : errmsg("CACHE (%" PRId64 ") must be greater than zero",
1580 : seqform->seqcache)));
1581 136 : *reset_state = true;
1582 : }
1583 3220 : else if (isInit)
1584 : {
1585 1758 : seqform->seqcache = 1;
1586 : }
1587 3356 : }
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 1298 : 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 1298 : deptype = for_identity ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO;
1606 :
1607 1298 : nnames = list_length(owned_by);
1608 : Assert(nnames > 0);
1609 1298 : if (nnames == 1)
1610 : {
1611 : /* Must be OWNED BY NONE */
1612 12 : if (strcmp(strVal(linitial(owned_by)), "none") != 0)
1613 6 : 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 6 : tablerel = NULL;
1618 6 : attnum = 0;
1619 : }
1620 : else
1621 : {
1622 : List *relname;
1623 : char *attrname;
1624 : RangeVar *rel;
1625 :
1626 : /* Separate relname and attr name */
1627 1286 : relname = list_copy_head(owned_by, nnames - 1);
1628 1286 : attrname = strVal(llast(owned_by));
1629 :
1630 : /* Open and lock rel to ensure it won't go away meanwhile */
1631 1286 : rel = makeRangeVarFromNameList(relname);
1632 1286 : tablerel = relation_openrv(rel, AccessShareLock);
1633 :
1634 : /* Must be a regular or foreign table */
1635 1286 : if (!(tablerel->rd_rel->relkind == RELKIND_RELATION ||
1636 52 : tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
1637 44 : tablerel->rd_rel->relkind == RELKIND_VIEW ||
1638 44 : tablerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
1639 6 : 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 1280 : 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 1280 : if (RelationGetNamespace(seqrel) != RelationGetNamespace(tablerel))
1651 6 : 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 1274 : attnum = get_attnum(RelationGetRelid(tablerel), attrname);
1657 1274 : if (attnum == InvalidAttrNumber)
1658 6 : 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 1274 : if (deptype == DEPENDENCY_AUTO)
1668 : {
1669 : Oid tableId;
1670 : int32 colId;
1671 :
1672 866 : if (sequenceIsOwned(RelationGetRelid(seqrel), DEPENDENCY_INTERNAL, &tableId, &colId))
1673 6 : 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 1268 : deleteDependencyRecordsForClass(RelationRelationId, RelationGetRelid(seqrel),
1686 : RelationRelationId, deptype);
1687 :
1688 1268 : if (tablerel)
1689 : {
1690 : ObjectAddress refobject,
1691 : depobject;
1692 :
1693 1268 : refobject.classId = RelationRelationId;
1694 1268 : refobject.objectId = RelationGetRelid(tablerel);
1695 1268 : refobject.objectSubId = attnum;
1696 1268 : depobject.classId = RelationRelationId;
1697 1268 : depobject.objectId = RelationGetRelid(seqrel);
1698 1268 : depobject.objectSubId = 0;
1699 1268 : recordDependencyOn(&depobject, &refobject, deptype);
1700 : }
1701 :
1702 : /* Done, but hold lock until commit */
1703 1268 : if (tablerel)
1704 1268 : relation_close(tablerel, NoLock);
1705 1268 : }
1706 :
1707 :
1708 : /*
1709 : * Return sequence parameters in a list of the form created by the parser.
1710 : */
1711 : List *
1712 12 : sequence_options(Oid relid)
1713 : {
1714 : HeapTuple pgstuple;
1715 : Form_pg_sequence pgsform;
1716 12 : List *options = NIL;
1717 :
1718 12 : pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
1719 12 : if (!HeapTupleIsValid(pgstuple))
1720 0 : elog(ERROR, "cache lookup failed for sequence %u", relid);
1721 12 : pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
1722 :
1723 : /* Use makeFloat() for 64-bit integers, like gram.y does. */
1724 12 : options = lappend(options,
1725 12 : makeDefElem("cache", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqcache)), -1));
1726 12 : options = lappend(options,
1727 12 : makeDefElem("cycle", (Node *) makeBoolean(pgsform->seqcycle), -1));
1728 12 : options = lappend(options,
1729 12 : makeDefElem("increment", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqincrement)), -1));
1730 12 : options = lappend(options,
1731 12 : makeDefElem("maxvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmax)), -1));
1732 12 : options = lappend(options,
1733 12 : makeDefElem("minvalue", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqmin)), -1));
1734 12 : options = lappend(options,
1735 12 : makeDefElem("start", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqstart)), -1));
1736 :
1737 12 : ReleaseSysCache(pgstuple);
1738 :
1739 12 : return options;
1740 : }
1741 :
1742 : /*
1743 : * Return sequence parameters (formerly for use by information schema)
1744 : */
1745 : Datum
1746 6 : pg_sequence_parameters(PG_FUNCTION_ARGS)
1747 : {
1748 6 : 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 6 : 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 6 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1762 0 : elog(ERROR, "return type must be a row type");
1763 :
1764 6 : memset(isnull, 0, sizeof(isnull));
1765 :
1766 6 : pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
1767 6 : if (!HeapTupleIsValid(pgstuple))
1768 0 : elog(ERROR, "cache lookup failed for sequence %u", relid);
1769 6 : pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
1770 :
1771 6 : values[0] = Int64GetDatum(pgsform->seqstart);
1772 6 : values[1] = Int64GetDatum(pgsform->seqmin);
1773 6 : values[2] = Int64GetDatum(pgsform->seqmax);
1774 6 : values[3] = Int64GetDatum(pgsform->seqincrement);
1775 6 : values[4] = BoolGetDatum(pgsform->seqcycle);
1776 6 : values[5] = Int64GetDatum(pgsform->seqcache);
1777 6 : values[6] = ObjectIdGetDatum(pgsform->seqtypid);
1778 :
1779 6 : ReleaseSysCache(pgstuple);
1780 :
1781 6 : 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 1276 : pg_get_sequence_data(PG_FUNCTION_ARGS)
1794 : {
1795 : #define PG_GET_SEQUENCE_DATA_COLS 3
1796 1276 : Oid relid = PG_GETARG_OID(0);
1797 : SeqTable elm;
1798 : Relation seqrel;
1799 1276 : Datum values[PG_GET_SEQUENCE_DATA_COLS] = {0};
1800 1276 : bool isnull[PG_GET_SEQUENCE_DATA_COLS] = {0};
1801 : TupleDesc resultTupleDesc;
1802 : HeapTuple resultHeapTuple;
1803 : Datum result;
1804 :
1805 1276 : resultTupleDesc = CreateTemplateTupleDesc(PG_GET_SEQUENCE_DATA_COLS);
1806 1276 : TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "last_value",
1807 : INT8OID, -1, 0);
1808 1276 : TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "is_called",
1809 : BOOLOID, -1, 0);
1810 1276 : TupleDescInitEntry(resultTupleDesc, (AttrNumber) 3, "page_lsn",
1811 : LSNOID, -1, 0);
1812 1276 : resultTupleDesc = BlessTupleDesc(resultTupleDesc);
1813 :
1814 1276 : init_sequence(relid, &elm, &seqrel);
1815 :
1816 : /*
1817 : * Return all NULLs for sequences for which we lack privileges, other
1818 : * sessions' temporary sequences, and unlogged sequences on standbys.
1819 : */
1820 1276 : if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT) == ACLCHECK_OK &&
1821 1256 : !RELATION_IS_OTHER_TEMP(seqrel) &&
1822 1256 : (RelationIsPermanent(seqrel) || !RecoveryInProgress()))
1823 1236 : {
1824 : Buffer buf;
1825 : HeapTupleData seqtuple;
1826 : Form_pg_sequence_data seq;
1827 : Page page;
1828 :
1829 1236 : seq = read_seq_tuple(seqrel, &buf, &seqtuple);
1830 1236 : page = BufferGetPage(buf);
1831 :
1832 1236 : values[0] = Int64GetDatum(seq->last_value);
1833 1236 : values[1] = BoolGetDatum(seq->is_called);
1834 1236 : values[2] = LSNGetDatum(PageGetLSN(page));
1835 :
1836 1236 : UnlockReleaseBuffer(buf);
1837 : }
1838 : else
1839 40 : memset(isnull, true, sizeof(isnull));
1840 :
1841 1276 : sequence_close(seqrel, NoLock);
1842 :
1843 1276 : resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
1844 1276 : result = HeapTupleGetDatum(resultHeapTuple);
1845 1276 : PG_RETURN_DATUM(result);
1846 : #undef PG_GET_SEQUENCE_DATA_COLS
1847 : }
1848 :
1849 :
1850 : /*
1851 : * Return the last value from the sequence
1852 : *
1853 : * Note: This has a completely different meaning than lastval().
1854 : */
1855 : Datum
1856 116 : pg_sequence_last_value(PG_FUNCTION_ARGS)
1857 : {
1858 116 : Oid relid = PG_GETARG_OID(0);
1859 : SeqTable elm;
1860 : Relation seqrel;
1861 116 : bool is_called = false;
1862 116 : int64 result = 0;
1863 :
1864 : /* open and lock sequence */
1865 116 : init_sequence(relid, &elm, &seqrel);
1866 :
1867 : /*
1868 : * We return NULL for other sessions' temporary sequences. The
1869 : * pg_sequences system view already filters those out, but this offers a
1870 : * defense against ERRORs in case someone invokes this function directly.
1871 : *
1872 : * Also, for the benefit of the pg_sequences view, we return NULL for
1873 : * unlogged sequences on standbys and for sequences for which the current
1874 : * user lacks privileges instead of throwing an error.
1875 : */
1876 116 : if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_USAGE) == ACLCHECK_OK &&
1877 116 : !RELATION_IS_OTHER_TEMP(seqrel) &&
1878 116 : (RelationIsPermanent(seqrel) || !RecoveryInProgress()))
1879 : {
1880 : Buffer buf;
1881 : HeapTupleData seqtuple;
1882 : Form_pg_sequence_data seq;
1883 :
1884 114 : seq = read_seq_tuple(seqrel, &buf, &seqtuple);
1885 :
1886 114 : is_called = seq->is_called;
1887 114 : result = seq->last_value;
1888 :
1889 114 : UnlockReleaseBuffer(buf);
1890 : }
1891 116 : sequence_close(seqrel, NoLock);
1892 :
1893 116 : if (is_called)
1894 48 : PG_RETURN_INT64(result);
1895 : else
1896 68 : PG_RETURN_NULL();
1897 : }
1898 :
1899 : /*
1900 : * Flush cached sequence information.
1901 : */
1902 : void
1903 18 : ResetSequenceCaches(void)
1904 : {
1905 18 : if (seqhashtab)
1906 : {
1907 12 : hash_destroy(seqhashtab);
1908 12 : seqhashtab = NULL;
1909 : }
1910 :
1911 18 : last_used_seq = NULL;
1912 18 : }
|