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