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