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