1 /*-------------------------------------------------------------------------
4 * PostgreSQL sequences support code.
6 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.102 2003/08/08 21:41:32 momjian Exp $
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "catalog/namespace.h"
19 #include "catalog/pg_type.h"
20 #include "commands/defrem.h"
21 #include "commands/tablecmds.h"
22 #include "commands/sequence.h"
23 #include "miscadmin.h"
24 #include "utils/acl.h"
25 #include "utils/builtins.h"
28 * We don't want to log each fetching of a value from a sequence,
29 * so we pre-log a few fetches in advance. In the event of
30 * crash we can lose as much as we pre-logged.
32 #define SEQ_LOG_VALS 32
35 * The "special area" of a sequence's buffer page looks like this.
37 #define SEQ_MAGIC 0x1717
39 typedef struct sequence_magic
45 * We store a SeqTable item for every sequence we have touched in the current
46 * session. This is needed to hold onto nextval/currval state. (We can't
47 * rely on the relcache, since it's only, well, a cache, and may decide to
50 * XXX We use linear search to find pre-existing SeqTable entries. This is
51 * good when only a small number of sequences are touched in a session, but
52 * would suck with many different sequences. Perhaps use a hashtable someday.
54 typedef struct SeqTableData
56 struct SeqTableData *next; /* link to next SeqTable object */
57 Oid relid; /* pg_class OID of this sequence */
58 TransactionId xid; /* xact in which we last did a seq op */
59 int64 last; /* value last returned by nextval */
60 int64 cached; /* last value already cached for nextval */
61 /* if last != cached, we have not used up all the cached values */
62 int64 increment; /* copy of sequence's increment field */
65 typedef SeqTableData *SeqTable;
67 static SeqTable seqtab = NULL; /* Head of list of SeqTable items */
70 static void init_sequence(RangeVar *relation,
71 SeqTable *p_elm, Relation *p_rel);
72 static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf);
73 static void init_params(List *options, Form_pg_sequence new);
74 static void do_setval(RangeVar *sequence, int64 next, bool iscalled);
78 * Creates a new sequence relation
81 DefineSequence(CreateSeqStmt *seq)
83 FormData_pg_sequence new;
84 CreateStmt *stmt = makeNode(CreateStmt);
92 Datum value[SEQ_COL_LASTCOL];
93 char null[SEQ_COL_LASTCOL];
97 /* Values are NULL (or false) by default */
103 new.is_cycled = false;
105 /* Check and set values */
106 init_params(seq->options, &new);
109 * Create relation (and fill *null & *value)
111 stmt->tableElts = NIL;
112 for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
117 typnam = makeNode(TypeName);
118 typnam->setof = FALSE;
119 typnam->arrayBounds = NIL;
122 coldef = makeNode(ColumnDef);
123 coldef->typename = typnam;
124 coldef->inhcount = 0;
125 coldef->is_local = true;
126 coldef->is_not_null = true;
127 coldef->raw_default = NULL;
128 coldef->cooked_default = NULL;
129 coldef->constraints = NIL;
130 coldef->support = NULL;
137 typnam->typeid = NAMEOID;
138 coldef->colname = "sequence_name";
139 namestrcpy(&name, seq->sequence->relname);
140 value[i - 1] = NameGetDatum(&name);
142 case SEQ_COL_LASTVAL:
143 typnam->typeid = INT8OID;
144 coldef->colname = "last_value";
145 value[i - 1] = Int64GetDatumFast(new.last_value);
148 typnam->typeid = INT8OID;
149 coldef->colname = "increment_by";
150 value[i - 1] = Int64GetDatumFast(new.increment_by);
152 case SEQ_COL_MAXVALUE:
153 typnam->typeid = INT8OID;
154 coldef->colname = "max_value";
155 value[i - 1] = Int64GetDatumFast(new.max_value);
157 case SEQ_COL_MINVALUE:
158 typnam->typeid = INT8OID;
159 coldef->colname = "min_value";
160 value[i - 1] = Int64GetDatumFast(new.min_value);
163 typnam->typeid = INT8OID;
164 coldef->colname = "cache_value";
165 value[i - 1] = Int64GetDatumFast(new.cache_value);
168 typnam->typeid = INT8OID;
169 coldef->colname = "log_cnt";
170 value[i - 1] = Int64GetDatum((int64) 1);
173 typnam->typeid = BOOLOID;
174 coldef->colname = "is_cycled";
175 value[i - 1] = BoolGetDatum(new.is_cycled);
178 typnam->typeid = BOOLOID;
179 coldef->colname = "is_called";
180 value[i - 1] = BoolGetDatum(false);
183 stmt->tableElts = lappend(stmt->tableElts, coldef);
186 stmt->relation = seq->sequence;
187 stmt->inhRelations = NIL;
188 stmt->constraints = NIL;
189 stmt->hasoids = false;
190 stmt->oncommit = ONCOMMIT_NOOP;
192 seqoid = DefineRelation(stmt, RELKIND_SEQUENCE);
194 rel = heap_open(seqoid, AccessExclusiveLock);
195 tupDesc = RelationGetDescr(rel);
197 /* Initialize first page of relation with special magic number */
199 buf = ReadBuffer(rel, P_NEW);
201 if (!BufferIsValid(buf))
202 elog(ERROR, "ReadBuffer failed");
204 Assert(BufferGetBlockNumber(buf) == 0);
206 page = (PageHeader) BufferGetPage(buf);
208 PageInit((Page) page, BufferGetPageSize(buf), sizeof(sequence_magic));
209 sm = (sequence_magic *) PageGetSpecialPointer(page);
210 sm->magic = SEQ_MAGIC;
212 /* hack: ensure heap_insert will insert on the just-created page */
213 rel->rd_targblock = 0;
215 /* Now form & insert sequence tuple */
216 tuple = heap_formtuple(tupDesc, value, null);
217 simple_heap_insert(rel, tuple);
219 Assert(ItemPointerGetOffsetNumber(&(tuple->t_self)) == FirstOffsetNumber);
222 * Two special hacks here:
224 * 1. Since VACUUM does not process sequences, we have to force the tuple
225 * to have xmin = FrozenTransactionId now. Otherwise it would become
226 * invisible to SELECTs after 2G transactions. It is okay to do this
227 * because if the current transaction aborts, no other xact will ever
228 * examine the sequence tuple anyway.
230 * 2. Even though heap_insert emitted a WAL log record, we have to emit
231 * an XLOG_SEQ_LOG record too, since (a) the heap_insert record will
232 * not have the right xmin, and (b) REDO of the heap_insert record
233 * would re-init page and sequence magic number would be lost. This
234 * means two log records instead of one :-(
236 LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
238 START_CRIT_SECTION();
242 * Note that the "tuple" structure is still just a local tuple
243 * record created by heap_formtuple; its t_data pointer doesn't
244 * point at the disk buffer. To scribble on the disk buffer we
245 * need to fetch the item pointer. But do the same to the local
246 * tuple, since that will be the source for the WAL log record,
252 itemId = PageGetItemId((Page) page, FirstOffsetNumber);
253 item = PageGetItem((Page) page, itemId);
255 HeapTupleHeaderSetXmin((HeapTupleHeader) item, FrozenTransactionId);
256 ((HeapTupleHeader) item)->t_infomask |= HEAP_XMIN_COMMITTED;
258 HeapTupleHeaderSetXmin(tuple->t_data, FrozenTransactionId);
259 tuple->t_data->t_infomask |= HEAP_XMIN_COMMITTED;
267 XLogRecData rdata[2];
268 Form_pg_sequence newseq = (Form_pg_sequence) GETSTRUCT(tuple);
270 /* We do not log first nextval call, so "advance" sequence here */
271 /* Note we are scribbling on local tuple, not the disk buffer */
272 newseq->is_called = true;
275 xlrec.node = rel->rd_node;
276 rdata[0].buffer = InvalidBuffer;
277 rdata[0].data = (char *) &xlrec;
278 rdata[0].len = sizeof(xl_seq_rec);
279 rdata[0].next = &(rdata[1]);
281 rdata[1].buffer = InvalidBuffer;
282 rdata[1].data = (char *) tuple->t_data;
283 rdata[1].len = tuple->t_len;
284 rdata[1].next = NULL;
286 recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
288 PageSetLSN(page, recptr);
289 PageSetSUI(page, ThisStartUpID);
294 LockBuffer(buf, BUFFER_LOCK_UNLOCK);
296 heap_close(rel, NoLock);
302 * Modify the defition of a sequence relation
305 AlterSequence(AlterSeqStmt *stmt)
311 Form_pg_sequence seq;
312 FormData_pg_sequence new;
314 /* open and AccessShareLock sequence */
315 init_sequence(stmt->sequence, &elm, &seqrel);
317 /* allow DROP to sequence owner only */
318 if (!pg_class_ownercheck(elm->relid, GetUserId()))
319 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
320 stmt->sequence->relname);
322 /* lock page' buffer and read tuple into new sequence structure */
323 seq = read_info(elm, seqrel, &buf);
324 page = BufferGetPage(buf);
326 new.increment_by = seq->increment_by;
327 new.max_value = seq->max_value;
328 new.min_value = seq->min_value;
329 new.cache_value = seq->cache_value;
330 new.is_cycled = seq->is_cycled;
331 new.last_value = seq->last_value;
333 /* Check and set values */
334 init_params(stmt->options, &new);
336 seq->increment_by = new.increment_by;
337 seq->max_value = new.max_value;
338 seq->min_value = new.min_value;
339 seq->cache_value = new.cache_value;
340 seq->is_cycled = new.is_cycled;
341 if (seq->last_value != new.last_value)
343 seq->last_value = new.last_value;
344 seq->is_called = false;
348 /* save info in local cache */
349 elm->last = new.last_value; /* last returned number */
350 elm->cached = new.last_value; /* last cached number (forget
353 START_CRIT_SECTION();
356 if (!seqrel->rd_istemp)
360 XLogRecData rdata[2];
362 xlrec.node = seqrel->rd_node;
363 rdata[0].buffer = InvalidBuffer;
364 rdata[0].data = (char *) &xlrec;
365 rdata[0].len = sizeof(xl_seq_rec);
366 rdata[0].next = &(rdata[1]);
368 rdata[1].buffer = InvalidBuffer;
369 rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
370 rdata[1].len = ((PageHeader) page)->pd_special -
371 ((PageHeader) page)->pd_upper;
372 rdata[1].next = NULL;
374 recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
376 PageSetLSN(page, recptr);
377 PageSetSUI(page, ThisStartUpID);
382 LockBuffer(buf, BUFFER_LOCK_UNLOCK);
386 relation_close(seqrel, NoLock);
391 nextval(PG_FUNCTION_ARGS)
393 text *seqin = PG_GETARG_TEXT_P(0);
399 Form_pg_sequence seq;
412 sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
415 /* open and AccessShareLock sequence */
416 init_sequence(sequence, &elm, &seqrel);
418 if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
420 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
421 errmsg("permission denied for sequence %s",
422 sequence->relname)));
424 if (elm->last != elm->cached) /* some numbers were cached */
426 elm->last += elm->increment;
427 relation_close(seqrel, NoLock);
428 PG_RETURN_INT64(elm->last);
431 /* lock page' buffer and read tuple */
432 seq = read_info(elm, seqrel, &buf);
433 page = BufferGetPage(buf);
435 last = next = result = seq->last_value;
436 incby = seq->increment_by;
437 maxv = seq->max_value;
438 minv = seq->min_value;
439 fetch = cache = seq->cache_value;
444 rescnt++; /* last_value if not called */
450 * Decide whether we should emit a WAL log record. If so, force up
451 * the fetch count to grab SEQ_LOG_VALS more values than we actually
452 * need to cache. (These will then be usable without logging.)
454 * If this is the first nextval after a checkpoint, we must force a new
455 * WAL record to be written anyway, else replay starting from the
456 * checkpoint would fail to advance the sequence past the logged
457 * values. In this case we may as well fetch extra values.
461 /* forced log to satisfy local demand for values */
462 fetch = log = fetch + SEQ_LOG_VALS;
467 XLogRecPtr redoptr = GetRedoRecPtr();
469 if (XLByteLE(PageGetLSN(page), redoptr))
471 /* last update of seq was before checkpoint */
472 fetch = log = fetch + SEQ_LOG_VALS;
477 while (fetch) /* try to fetch cache [+ log ] numbers */
480 * Check MAXVALUE for ascending sequences and MINVALUE for
481 * descending sequences
485 /* ascending sequence */
486 if ((maxv >= 0 && next > maxv - incby) ||
487 (maxv < 0 && next + incby > maxv))
490 break; /* stop fetching */
495 snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
497 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
498 errmsg("%s.nextval: reached MAXVALUE (%s)",
499 sequence->relname, buf)));
508 /* descending sequence */
509 if ((minv < 0 && next < minv - incby) ||
510 (minv >= 0 && next + incby < minv))
513 break; /* stop fetching */
518 snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
520 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
521 errmsg("%s.nextval: reached MINVALUE (%s)",
522 sequence->relname, buf)));
535 if (rescnt == 1) /* if it's first result - */
536 result = next; /* it's what to return */
540 log -= fetch; /* adjust for any unfetched numbers */
543 /* save info in local cache */
544 elm->last = result; /* last returned number */
545 elm->cached = last; /* last fetched number */
547 START_CRIT_SECTION();
550 if (logit && !seqrel->rd_istemp)
554 XLogRecData rdata[2];
556 xlrec.node = seqrel->rd_node;
557 rdata[0].buffer = InvalidBuffer;
558 rdata[0].data = (char *) &xlrec;
559 rdata[0].len = sizeof(xl_seq_rec);
560 rdata[0].next = &(rdata[1]);
562 /* set values that will be saved in xlog */
563 seq->last_value = next;
564 seq->is_called = true;
567 rdata[1].buffer = InvalidBuffer;
568 rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
569 rdata[1].len = ((PageHeader) page)->pd_special -
570 ((PageHeader) page)->pd_upper;
571 rdata[1].next = NULL;
573 recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
575 PageSetLSN(page, recptr);
576 PageSetSUI(page, ThisStartUpID);
579 /* update on-disk data */
580 seq->last_value = last; /* last fetched number */
581 seq->is_called = true;
582 seq->log_cnt = log; /* how much is logged */
586 LockBuffer(buf, BUFFER_LOCK_UNLOCK);
590 relation_close(seqrel, NoLock);
592 PG_RETURN_INT64(result);
596 currval(PG_FUNCTION_ARGS)
598 text *seqin = PG_GETARG_TEXT_P(0);
604 sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
607 /* open and AccessShareLock sequence */
608 init_sequence(sequence, &elm, &seqrel);
610 if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK)
612 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
613 errmsg("permission denied for sequence %s",
614 sequence->relname)));
616 if (elm->increment == 0) /* nextval/read_info were not called */
618 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
619 errmsg("%s.currval is not yet defined in this session",
620 sequence->relname)));
624 relation_close(seqrel, NoLock);
626 PG_RETURN_INT64(result);
630 * Main internal procedure that handles 2 & 3 arg forms of SETVAL.
632 * Note that the 3 arg version (which sets the is_called flag) is
633 * only for use in pg_dump, and setting the is_called flag may not
634 * work if multiple users are attached to the database and referencing
635 * the sequence (unlikely if pg_dump is restoring it).
637 * It is necessary to have the 3 arg version so that pg_dump can
638 * restore the state of a sequence exactly during data-only restores -
639 * it is the only way to clear the is_called flag in an existing
643 do_setval(RangeVar *sequence, int64 next, bool iscalled)
648 Form_pg_sequence seq;
650 /* open and AccessShareLock sequence */
651 init_sequence(sequence, &elm, &seqrel);
653 if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
655 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
656 errmsg("permission denied for sequence %s",
657 sequence->relname)));
659 /* lock page' buffer and read tuple */
660 seq = read_info(elm, seqrel, &buf);
662 if ((next < seq->min_value) || (next > seq->max_value))
668 snprintf(bufv, sizeof(bufv), INT64_FORMAT, next);
669 snprintf(bufm, sizeof(bufm), INT64_FORMAT, seq->min_value);
670 snprintf(bufx, sizeof(bufx), INT64_FORMAT, seq->max_value);
672 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
673 errmsg("%s.setval: value %s is out of bounds (%s..%s)",
674 sequence->relname, bufv, bufm, bufx)));
677 /* save info in local cache */
678 elm->last = next; /* last returned number */
679 elm->cached = next; /* last cached number (forget cached
682 START_CRIT_SECTION();
685 if (!seqrel->rd_istemp)
689 XLogRecData rdata[2];
690 Page page = BufferGetPage(buf);
692 xlrec.node = seqrel->rd_node;
693 rdata[0].buffer = InvalidBuffer;
694 rdata[0].data = (char *) &xlrec;
695 rdata[0].len = sizeof(xl_seq_rec);
696 rdata[0].next = &(rdata[1]);
698 /* set values that will be saved in xlog */
699 seq->last_value = next;
700 seq->is_called = true;
703 rdata[1].buffer = InvalidBuffer;
704 rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
705 rdata[1].len = ((PageHeader) page)->pd_special -
706 ((PageHeader) page)->pd_upper;
707 rdata[1].next = NULL;
709 recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
711 PageSetLSN(page, recptr);
712 PageSetSUI(page, ThisStartUpID);
715 /* save info in sequence relation */
716 seq->last_value = next; /* last fetched number */
717 seq->is_called = iscalled;
718 seq->log_cnt = (iscalled) ? 0 : 1;
722 LockBuffer(buf, BUFFER_LOCK_UNLOCK);
726 relation_close(seqrel, NoLock);
730 * Implement the 2 arg setval procedure.
731 * See do_setval for discussion.
734 setval(PG_FUNCTION_ARGS)
736 text *seqin = PG_GETARG_TEXT_P(0);
737 int64 next = PG_GETARG_INT64(1);
740 sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
743 do_setval(sequence, next, true);
745 PG_RETURN_INT64(next);
749 * Implement the 3 arg setval procedure.
750 * See do_setval for discussion.
753 setval_and_iscalled(PG_FUNCTION_ARGS)
755 text *seqin = PG_GETARG_TEXT_P(0);
756 int64 next = PG_GETARG_INT64(1);
757 bool iscalled = PG_GETARG_BOOL(2);
760 sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
763 do_setval(sequence, next, iscalled);
765 PG_RETURN_INT64(next);
770 * Given a relation name, open and lock the sequence. p_elm and p_rel are
774 init_sequence(RangeVar *relation, SeqTable *p_elm, Relation *p_rel)
776 Oid relid = RangeVarGetRelid(relation, false);
777 TransactionId thisxid = GetCurrentTransactionId();
781 /* Look to see if we already have a seqtable entry for relation */
782 for (elm = seqtab; elm != NULL; elm = elm->next)
784 if (elm->relid == relid)
789 * Open the sequence relation, acquiring AccessShareLock if we don't
790 * already have a lock in the current xact.
792 if (elm == NULL || elm->xid != thisxid)
793 seqrel = relation_open(relid, AccessShareLock);
795 seqrel = relation_open(relid, NoLock);
797 if (seqrel->rd_rel->relkind != RELKIND_SEQUENCE)
799 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
800 errmsg("\"%s\" is not a sequence",
801 relation->relname)));
804 * Allocate new seqtable entry if we didn't find one.
806 * NOTE: seqtable entries remain in the list for the life of a backend.
807 * If the sequence itself is deleted then the entry becomes wasted
808 * memory, but it's small enough that this should not matter.
813 * Time to make a new seqtable entry. These entries live as long
814 * as the backend does, so we use plain malloc for them.
816 elm = (SeqTable) malloc(sizeof(SeqTableData));
819 (errcode(ERRCODE_OUT_OF_MEMORY),
820 errmsg("out of memory")));
822 /* increment is set to 0 until we do read_info (see currval) */
823 elm->last = elm->cached = elm->increment = 0;
828 /* Flag that we have a lock in the current xact. */
836 /* Given an opened relation, lock the page buffer and find the tuple */
837 static Form_pg_sequence
838 read_info(SeqTable elm, Relation rel, Buffer *buf)
844 Form_pg_sequence seq;
846 if (rel->rd_nblocks > 1)
847 elog(ERROR, "invalid number of blocks in sequence \"%s\"",
848 RelationGetRelationName(rel));
850 *buf = ReadBuffer(rel, 0);
851 if (!BufferIsValid(*buf))
852 elog(ERROR, "ReadBuffer failed");
854 LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
856 page = (PageHeader) BufferGetPage(*buf);
857 sm = (sequence_magic *) PageGetSpecialPointer(page);
859 if (sm->magic != SEQ_MAGIC)
860 elog(ERROR, "bad magic number in sequence \"%s\": %08X",
861 RelationGetRelationName(rel), sm->magic);
863 lp = PageGetItemId(page, FirstOffsetNumber);
864 Assert(ItemIdIsUsed(lp));
865 tuple.t_data = (HeapTupleHeader) PageGetItem((Page) page, lp);
867 seq = (Form_pg_sequence) GETSTRUCT(&tuple);
869 elm->increment = seq->increment_by;
876 init_params(List *options, Form_pg_sequence new)
878 DefElem *last_value = NULL;
879 DefElem *increment_by = NULL;
880 DefElem *max_value = NULL;
881 DefElem *min_value = NULL;
882 DefElem *cache_value = NULL;
883 bool is_cycled_set = false;
886 foreach(option, options)
888 DefElem *defel = (DefElem *) lfirst(option);
890 if (strcmp(defel->defname, "increment") == 0)
894 (errcode(ERRCODE_SYNTAX_ERROR),
895 errmsg("conflicting or redundant options")));
896 increment_by = defel;
900 * start is for a new sequence restart is for alter
902 else if (strcmp(defel->defname, "start") == 0 ||
903 strcmp(defel->defname, "restart") == 0)
907 (errcode(ERRCODE_SYNTAX_ERROR),
908 errmsg("conflicting or redundant options")));
911 else if (strcmp(defel->defname, "maxvalue") == 0)
915 (errcode(ERRCODE_SYNTAX_ERROR),
916 errmsg("conflicting or redundant options")));
919 else if (strcmp(defel->defname, "minvalue") == 0)
923 (errcode(ERRCODE_SYNTAX_ERROR),
924 errmsg("conflicting or redundant options")));
927 else if (strcmp(defel->defname, "cache") == 0)
931 (errcode(ERRCODE_SYNTAX_ERROR),
932 errmsg("conflicting or redundant options")));
935 else if (strcmp(defel->defname, "cycle") == 0)
939 (errcode(ERRCODE_SYNTAX_ERROR),
940 errmsg("conflicting or redundant options")));
941 is_cycled_set = true;
942 new->is_cycled = (defel->arg != NULL);
945 elog(ERROR, "option \"%s\" not recognized",
950 if (new->increment_by == 0 && increment_by == (DefElem *) NULL)
951 new->increment_by = 1;
952 else if (increment_by != (DefElem *) NULL)
954 new->increment_by = defGetInt64(increment_by);
955 if (new->increment_by == 0)
957 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
958 errmsg("cannot increment by zero")));
962 if ((new->max_value == 0 && max_value == (DefElem *) NULL)
963 || (max_value != (DefElem *) NULL && !max_value->arg))
965 if (new->increment_by > 0)
966 new->max_value = SEQ_MAXVALUE; /* ascending seq */
968 new->max_value = -1; /* descending seq */
970 else if (max_value != (DefElem *) NULL)
971 new->max_value = defGetInt64(max_value);
974 if ((new->min_value == 0 && min_value == (DefElem *) NULL)
975 || (min_value != (DefElem *) NULL && !min_value->arg))
977 if (new->increment_by > 0)
978 new->min_value = 1; /* ascending seq */
980 new->min_value = SEQ_MINVALUE; /* descending seq */
982 else if (min_value != (DefElem *) NULL)
983 new->min_value = defGetInt64(min_value);
985 if (new->min_value >= new->max_value)
990 snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
991 snprintf(bufx, sizeof(bufx), INT64_FORMAT, new->max_value);
993 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
994 errmsg("MINVALUE (%s) must be less than MAXVALUE (%s)",
999 if (new->last_value == 0 && last_value == (DefElem *) NULL)
1001 if (new->increment_by > 0)
1002 new->last_value = new->min_value; /* ascending seq */
1004 new->last_value = new->max_value; /* descending seq */
1006 else if (last_value != (DefElem *) NULL)
1007 new->last_value = defGetInt64(last_value);
1009 if (new->last_value < new->min_value)
1014 snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
1015 snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
1017 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1018 errmsg("START value (%s) can't be less than MINVALUE (%s)",
1021 if (new->last_value > new->max_value)
1026 snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
1027 snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
1029 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1030 errmsg("START value (%s) can't be greater than MAXVALUE (%s)",
1035 if (cache_value == (DefElem *) NULL)
1036 new->cache_value = 1;
1037 else if ((new->cache_value = defGetInt64(cache_value)) <= 0)
1041 snprintf(buf, sizeof(buf), INT64_FORMAT, new->cache_value);
1043 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1044 errmsg("CACHE (%s) must be greater than zero", buf)));
1050 seq_redo(XLogRecPtr lsn, XLogRecord *record)
1052 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1058 xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
1061 if (info != XLOG_SEQ_LOG)
1062 elog(PANIC, "seq_redo: unknown op code %u", info);
1064 reln = XLogOpenRelation(true, RM_SEQ_ID, xlrec->node);
1065 if (!RelationIsValid(reln))
1068 buffer = XLogReadBuffer(true, reln, 0);
1069 if (!BufferIsValid(buffer))
1070 elog(PANIC, "seq_redo: can't read block of %u/%u",
1071 xlrec->node.tblNode, xlrec->node.relNode);
1073 page = (Page) BufferGetPage(buffer);
1075 /* Always reinit the page and reinstall the magic number */
1076 /* See comments in DefineSequence */
1077 PageInit((Page) page, BufferGetPageSize(buffer), sizeof(sequence_magic));
1078 sm = (sequence_magic *) PageGetSpecialPointer(page);
1079 sm->magic = SEQ_MAGIC;
1081 item = (char *) xlrec + sizeof(xl_seq_rec);
1082 itemsz = record->xl_len - sizeof(xl_seq_rec);
1083 itemsz = MAXALIGN(itemsz);
1084 if (PageAddItem(page, (Item) item, itemsz,
1085 FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
1086 elog(PANIC, "seq_redo: failed to add item to page");
1088 PageSetLSN(page, lsn);
1089 PageSetSUI(page, ThisStartUpID);
1090 UnlockAndWriteBuffer(buffer);
1094 seq_undo(XLogRecPtr lsn, XLogRecord *record)
1099 seq_desc(char *buf, uint8 xl_info, char *rec)
1101 uint8 info = xl_info & ~XLR_INFO_MASK;
1102 xl_seq_rec *xlrec = (xl_seq_rec *) rec;
1104 if (info == XLOG_SEQ_LOG)
1105 strcat(buf, "log: ");
1108 strcat(buf, "UNKNOWN");
1112 sprintf(buf + strlen(buf), "node %u/%u",
1113 xlrec->node.tblNode, xlrec->node.relNode);