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