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