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