1 /*-------------------------------------------------------------------------
4 * PostgreSQL sequences support code.
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "access/transam.h"
19 #include "access/xact.h"
20 #include "access/xlogutils.h"
21 #include "catalog/dependency.h"
22 #include "catalog/namespace.h"
23 #include "catalog/pg_type.h"
24 #include "commands/defrem.h"
25 #include "commands/sequence.h"
26 #include "commands/tablecmds.h"
27 #include "miscadmin.h"
28 #include "nodes/makefuncs.h"
29 #include "storage/bufmgr.h"
30 #include "storage/lmgr.h"
31 #include "storage/proc.h"
32 #include "utils/acl.h"
33 #include "utils/builtins.h"
34 #include "utils/lsyscache.h"
35 #include "utils/resowner.h"
36 #include "utils/syscache.h"
40 * We don't want to log each fetching of a value from a sequence,
41 * so we pre-log a few fetches in advance. In the event of
42 * crash we can lose as much as we pre-logged.
44 #define SEQ_LOG_VALS 32
47 * The "special area" of a sequence's buffer page looks like this.
49 #define SEQ_MAGIC 0x1717
51 typedef struct sequence_magic
57 * We store a SeqTable item for every sequence we have touched in the current
58 * session. This is needed to hold onto nextval/currval state. (We can't
59 * rely on the relcache, since it's only, well, a cache, and may decide to
62 * XXX We use linear search to find pre-existing SeqTable entries. This is
63 * good when only a small number of sequences are touched in a session, but
64 * would suck with many different sequences. Perhaps use a hashtable someday.
66 typedef struct SeqTableData
68 struct SeqTableData
*next
; /* link to next SeqTable object */
69 Oid relid
; /* pg_class OID of this sequence */
70 LocalTransactionId lxid
; /* xact in which we last did a seq op */
71 bool last_valid
; /* do we have a valid "last" value? */
72 int64 last
; /* value last returned by nextval */
73 int64 cached
; /* last value already cached for nextval */
74 /* if last != cached, we have not used up all the cached values */
75 int64 increment
; /* copy of sequence's increment field */
76 /* note that increment is zero until we first do read_info() */
79 typedef SeqTableData
*SeqTable
;
81 static SeqTable seqtab
= NULL
; /* Head of list of SeqTable items */
84 * last_used_seq is updated by nextval() to point to the last used
87 static SeqTableData
*last_used_seq
= NULL
;
89 static int64
nextval_internal(Oid relid
);
90 static Relation
open_share_lock(SeqTable seq
);
91 static void init_sequence(Oid relid
, SeqTable
*p_elm
, Relation
*p_rel
);
92 static Form_pg_sequence
read_info(SeqTable elm
, Relation rel
, Buffer
*buf
);
93 static void init_params(List
*options
, bool isInit
,
94 Form_pg_sequence
new, List
**owned_by
);
95 static void do_setval(Oid relid
, int64 next
, bool iscalled
);
96 static void process_owned_by(Relation seqrel
, List
*owned_by
);
101 * Creates a new sequence relation
104 DefineSequence(CreateSeqStmt
*seq
)
106 FormData_pg_sequence
new;
108 CreateStmt
*stmt
= makeNode(CreateStmt
);
116 Datum value
[SEQ_COL_LASTCOL
];
117 char null
[SEQ_COL_LASTCOL
];
121 /* Check and set all option values */
122 init_params(seq
->options
, true, &new, &owned_by
);
125 * Create relation (and fill value[] and null[] for the tuple)
127 stmt
->tableElts
= NIL
;
128 for (i
= SEQ_COL_FIRSTCOL
; i
<= SEQ_COL_LASTCOL
; i
++)
130 ColumnDef
*coldef
= makeNode(ColumnDef
);
132 coldef
->inhcount
= 0;
133 coldef
->is_local
= true;
134 coldef
->is_not_null
= true;
135 coldef
->raw_default
= NULL
;
136 coldef
->cooked_default
= NULL
;
137 coldef
->constraints
= NIL
;
144 coldef
->typename
= makeTypeNameFromOid(NAMEOID
, -1);
145 coldef
->colname
= "sequence_name";
146 namestrcpy(&name
, seq
->sequence
->relname
);
147 value
[i
- 1] = NameGetDatum(&name
);
149 case SEQ_COL_LASTVAL
:
150 coldef
->typename
= makeTypeNameFromOid(INT8OID
, -1);
151 coldef
->colname
= "last_value";
152 value
[i
- 1] = Int64GetDatumFast(new.last_value
);
154 case SEQ_COL_STARTVAL
:
155 coldef
->typename
= makeTypeNameFromOid(INT8OID
, -1);
156 coldef
->colname
= "start_value";
157 value
[i
- 1] = Int64GetDatumFast(new.start_value
);
160 coldef
->typename
= makeTypeNameFromOid(INT8OID
, -1);
161 coldef
->colname
= "increment_by";
162 value
[i
- 1] = Int64GetDatumFast(new.increment_by
);
164 case SEQ_COL_MAXVALUE
:
165 coldef
->typename
= makeTypeNameFromOid(INT8OID
, -1);
166 coldef
->colname
= "max_value";
167 value
[i
- 1] = Int64GetDatumFast(new.max_value
);
169 case SEQ_COL_MINVALUE
:
170 coldef
->typename
= makeTypeNameFromOid(INT8OID
, -1);
171 coldef
->colname
= "min_value";
172 value
[i
- 1] = Int64GetDatumFast(new.min_value
);
175 coldef
->typename
= makeTypeNameFromOid(INT8OID
, -1);
176 coldef
->colname
= "cache_value";
177 value
[i
- 1] = Int64GetDatumFast(new.cache_value
);
180 coldef
->typename
= makeTypeNameFromOid(INT8OID
, -1);
181 coldef
->colname
= "log_cnt";
182 value
[i
- 1] = Int64GetDatum((int64
) 1);
185 coldef
->typename
= makeTypeNameFromOid(BOOLOID
, -1);
186 coldef
->colname
= "is_cycled";
187 value
[i
- 1] = BoolGetDatum(new.is_cycled
);
190 coldef
->typename
= makeTypeNameFromOid(BOOLOID
, -1);
191 coldef
->colname
= "is_called";
192 value
[i
- 1] = BoolGetDatum(false);
195 stmt
->tableElts
= lappend(stmt
->tableElts
, coldef
);
198 stmt
->relation
= seq
->sequence
;
199 stmt
->inhRelations
= NIL
;
200 stmt
->constraints
= NIL
;
201 stmt
->options
= list_make1(defWithOids(false));
202 stmt
->oncommit
= ONCOMMIT_NOOP
;
203 stmt
->tablespacename
= NULL
;
205 seqoid
= DefineRelation(stmt
, RELKIND_SEQUENCE
);
207 rel
= heap_open(seqoid
, AccessExclusiveLock
);
208 tupDesc
= RelationGetDescr(rel
);
210 /* Initialize first page of relation with special magic number */
212 buf
= ReadBuffer(rel
, P_NEW
);
213 Assert(BufferGetBlockNumber(buf
) == 0);
215 page
= BufferGetPage(buf
);
217 PageInit(page
, BufferGetPageSize(buf
), sizeof(sequence_magic
));
218 sm
= (sequence_magic
*) PageGetSpecialPointer(page
);
219 sm
->magic
= SEQ_MAGIC
;
221 /* hack: ensure heap_insert will insert on the just-created page */
222 rel
->rd_targblock
= 0;
224 /* Now form & insert sequence tuple */
225 tuple
= heap_formtuple(tupDesc
, value
, null
);
226 simple_heap_insert(rel
, tuple
);
228 Assert(ItemPointerGetOffsetNumber(&(tuple
->t_self
)) == FirstOffsetNumber
);
231 * Two special hacks here:
233 * 1. Since VACUUM does not process sequences, we have to force the tuple
234 * to have xmin = FrozenTransactionId now. Otherwise it would become
235 * invisible to SELECTs after 2G transactions. It is okay to do this
236 * because if the current transaction aborts, no other xact will ever
237 * examine the sequence tuple anyway.
239 * 2. Even though heap_insert emitted a WAL log record, we have to emit an
240 * XLOG_SEQ_LOG record too, since (a) the heap_insert record will not have
241 * the right xmin, and (b) REDO of the heap_insert record would re-init
242 * page and sequence magic number would be lost. This means two log
243 * records instead of one :-(
245 LockBuffer(buf
, BUFFER_LOCK_EXCLUSIVE
);
247 START_CRIT_SECTION();
251 * Note that the "tuple" structure is still just a local tuple record
252 * created by heap_formtuple; its t_data pointer doesn't point at the
253 * disk buffer. To scribble on the disk buffer we need to fetch the
254 * item pointer. But do the same to the local tuple, since that will
255 * be the source for the WAL log record, below.
260 itemId
= PageGetItemId((Page
) page
, FirstOffsetNumber
);
261 item
= PageGetItem((Page
) page
, itemId
);
263 HeapTupleHeaderSetXmin((HeapTupleHeader
) item
, FrozenTransactionId
);
264 ((HeapTupleHeader
) item
)->t_infomask
|= HEAP_XMIN_COMMITTED
;
266 HeapTupleHeaderSetXmin(tuple
->t_data
, FrozenTransactionId
);
267 tuple
->t_data
->t_infomask
|= HEAP_XMIN_COMMITTED
;
270 MarkBufferDirty(buf
);
277 XLogRecData rdata
[2];
278 Form_pg_sequence newseq
= (Form_pg_sequence
) GETSTRUCT(tuple
);
280 /* We do not log first nextval call, so "advance" sequence here */
281 /* Note we are scribbling on local tuple, not the disk buffer */
282 newseq
->is_called
= true;
285 xlrec
.node
= rel
->rd_node
;
286 rdata
[0].data
= (char *) &xlrec
;
287 rdata
[0].len
= sizeof(xl_seq_rec
);
288 rdata
[0].buffer
= InvalidBuffer
;
289 rdata
[0].next
= &(rdata
[1]);
291 rdata
[1].data
= (char *) tuple
->t_data
;
292 rdata
[1].len
= tuple
->t_len
;
293 rdata
[1].buffer
= InvalidBuffer
;
294 rdata
[1].next
= NULL
;
296 recptr
= XLogInsert(RM_SEQ_ID
, XLOG_SEQ_LOG
, rdata
);
298 PageSetLSN(page
, recptr
);
299 PageSetTLI(page
, ThisTimeLineID
);
304 UnlockReleaseBuffer(buf
);
306 /* process OWNED BY if given */
308 process_owned_by(rel
, owned_by
);
310 heap_close(rel
, NoLock
);
316 * Modify the definition of a sequence relation
319 AlterSequence(AlterSeqStmt
*stmt
)
324 relid
= RangeVarGetRelid(stmt
->sequence
, false);
326 /* allow ALTER to sequence owner only */
327 /* if you change this, see also callers of AlterSequenceInternal! */
328 if (!pg_class_ownercheck(relid
, GetUserId()))
329 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_CLASS
,
330 stmt
->sequence
->relname
);
333 AlterSequenceInternal(relid
, stmt
->options
);
337 * AlterSequenceInternal
339 * Same as AlterSequence except that the sequence is specified by OID
340 * and we assume the caller already checked permissions.
343 AlterSequenceInternal(Oid relid
, List
*options
)
349 Form_pg_sequence seq
;
350 FormData_pg_sequence
new;
353 /* open and AccessShareLock sequence */
354 init_sequence(relid
, &elm
, &seqrel
);
356 /* lock page' buffer and read tuple into new sequence structure */
357 seq
= read_info(elm
, seqrel
, &buf
);
358 page
= BufferGetPage(buf
);
360 /* Copy old values of options into workspace */
361 memcpy(&new, seq
, sizeof(FormData_pg_sequence
));
363 /* Check and set new values */
364 init_params(options
, false, &new, &owned_by
);
366 /* Clear local cache so that we don't think we have cached numbers */
367 /* Note that we do not change the currval() state */
368 elm
->cached
= elm
->last
;
370 /* Now okay to update the on-disk tuple */
371 memcpy(seq
, &new, sizeof(FormData_pg_sequence
));
373 START_CRIT_SECTION();
375 MarkBufferDirty(buf
);
378 if (!seqrel
->rd_istemp
)
382 XLogRecData rdata
[2];
384 xlrec
.node
= seqrel
->rd_node
;
385 rdata
[0].data
= (char *) &xlrec
;
386 rdata
[0].len
= sizeof(xl_seq_rec
);
387 rdata
[0].buffer
= InvalidBuffer
;
388 rdata
[0].next
= &(rdata
[1]);
390 rdata
[1].data
= (char *) page
+ ((PageHeader
) page
)->pd_upper
;
391 rdata
[1].len
= ((PageHeader
) page
)->pd_special
-
392 ((PageHeader
) page
)->pd_upper
;
393 rdata
[1].buffer
= InvalidBuffer
;
394 rdata
[1].next
= NULL
;
396 recptr
= XLogInsert(RM_SEQ_ID
, XLOG_SEQ_LOG
, rdata
);
398 PageSetLSN(page
, recptr
);
399 PageSetTLI(page
, ThisTimeLineID
);
404 UnlockReleaseBuffer(buf
);
406 /* process OWNED BY if given */
408 process_owned_by(seqrel
, owned_by
);
410 relation_close(seqrel
, NoLock
);
415 * Note: nextval with a text argument is no longer exported as a pg_proc
416 * entry, but we keep it around to ease porting of C code that may have
417 * called the function directly.
420 nextval(PG_FUNCTION_ARGS
)
422 text
*seqin
= PG_GETARG_TEXT_P(0);
426 sequence
= makeRangeVarFromNameList(textToQualifiedNameList(seqin
));
427 relid
= RangeVarGetRelid(sequence
, false);
429 PG_RETURN_INT64(nextval_internal(relid
));
433 nextval_oid(PG_FUNCTION_ARGS
)
435 Oid relid
= PG_GETARG_OID(0);
437 PG_RETURN_INT64(nextval_internal(relid
));
441 nextval_internal(Oid relid
)
447 Form_pg_sequence seq
;
460 /* open and AccessShareLock sequence */
461 init_sequence(relid
, &elm
, &seqrel
);
463 if (pg_class_aclcheck(elm
->relid
, GetUserId(), ACL_USAGE
) != ACLCHECK_OK
&&
464 pg_class_aclcheck(elm
->relid
, GetUserId(), ACL_UPDATE
) != ACLCHECK_OK
)
466 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
467 errmsg("permission denied for sequence %s",
468 RelationGetRelationName(seqrel
))));
470 if (elm
->last
!= elm
->cached
) /* some numbers were cached */
472 Assert(elm
->last_valid
);
473 Assert(elm
->increment
!= 0);
474 elm
->last
+= elm
->increment
;
475 relation_close(seqrel
, NoLock
);
480 /* lock page' buffer and read tuple */
481 seq
= read_info(elm
, seqrel
, &buf
);
482 page
= BufferGetPage(buf
);
484 last
= next
= result
= seq
->last_value
;
485 incby
= seq
->increment_by
;
486 maxv
= seq
->max_value
;
487 minv
= seq
->min_value
;
488 fetch
= cache
= seq
->cache_value
;
493 rescnt
++; /* last_value if not called */
499 * Decide whether we should emit a WAL log record. If so, force up the
500 * fetch count to grab SEQ_LOG_VALS more values than we actually need to
501 * cache. (These will then be usable without logging.)
503 * If this is the first nextval after a checkpoint, we must force a new
504 * WAL record to be written anyway, else replay starting from the
505 * checkpoint would fail to advance the sequence past the logged values.
506 * In this case we may as well fetch extra values.
510 /* forced log to satisfy local demand for values */
511 fetch
= log
= fetch
+ SEQ_LOG_VALS
;
516 XLogRecPtr redoptr
= GetRedoRecPtr();
518 if (XLByteLE(PageGetLSN(page
), redoptr
))
520 /* last update of seq was before checkpoint */
521 fetch
= log
= fetch
+ SEQ_LOG_VALS
;
526 while (fetch
) /* try to fetch cache [+ log ] numbers */
529 * Check MAXVALUE for ascending sequences and MINVALUE for descending
534 /* ascending sequence */
535 if ((maxv
>= 0 && next
> maxv
- incby
) ||
536 (maxv
< 0 && next
+ incby
> maxv
))
539 break; /* stop fetching */
544 snprintf(buf
, sizeof(buf
), INT64_FORMAT
, maxv
);
546 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
547 errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
548 RelationGetRelationName(seqrel
), buf
)));
557 /* descending sequence */
558 if ((minv
< 0 && next
< minv
- incby
) ||
559 (minv
>= 0 && next
+ incby
< minv
))
562 break; /* stop fetching */
567 snprintf(buf
, sizeof(buf
), INT64_FORMAT
, minv
);
569 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
570 errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
571 RelationGetRelationName(seqrel
), buf
)));
584 if (rescnt
== 1) /* if it's first result - */
585 result
= next
; /* it's what to return */
589 log
-= fetch
; /* adjust for any unfetched numbers */
592 /* save info in local cache */
593 elm
->last
= result
; /* last returned number */
594 elm
->cached
= last
; /* last fetched number */
595 elm
->last_valid
= true;
599 START_CRIT_SECTION();
601 MarkBufferDirty(buf
);
604 if (logit
&& !seqrel
->rd_istemp
)
608 XLogRecData rdata
[2];
610 xlrec
.node
= seqrel
->rd_node
;
611 rdata
[0].data
= (char *) &xlrec
;
612 rdata
[0].len
= sizeof(xl_seq_rec
);
613 rdata
[0].buffer
= InvalidBuffer
;
614 rdata
[0].next
= &(rdata
[1]);
616 /* set values that will be saved in xlog */
617 seq
->last_value
= next
;
618 seq
->is_called
= true;
621 rdata
[1].data
= (char *) page
+ ((PageHeader
) page
)->pd_upper
;
622 rdata
[1].len
= ((PageHeader
) page
)->pd_special
-
623 ((PageHeader
) page
)->pd_upper
;
624 rdata
[1].buffer
= InvalidBuffer
;
625 rdata
[1].next
= NULL
;
627 recptr
= XLogInsert(RM_SEQ_ID
, XLOG_SEQ_LOG
, rdata
);
629 PageSetLSN(page
, recptr
);
630 PageSetTLI(page
, ThisTimeLineID
);
633 /* update on-disk data */
634 seq
->last_value
= last
; /* last fetched number */
635 seq
->is_called
= true;
636 seq
->log_cnt
= log
; /* how much is logged */
640 UnlockReleaseBuffer(buf
);
642 relation_close(seqrel
, NoLock
);
648 currval_oid(PG_FUNCTION_ARGS
)
650 Oid relid
= PG_GETARG_OID(0);
655 /* open and AccessShareLock sequence */
656 init_sequence(relid
, &elm
, &seqrel
);
658 if (pg_class_aclcheck(elm
->relid
, GetUserId(), ACL_SELECT
) != ACLCHECK_OK
&&
659 pg_class_aclcheck(elm
->relid
, GetUserId(), ACL_USAGE
) != ACLCHECK_OK
)
661 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
662 errmsg("permission denied for sequence %s",
663 RelationGetRelationName(seqrel
))));
665 if (!elm
->last_valid
)
667 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
668 errmsg("currval of sequence \"%s\" is not yet defined in this session",
669 RelationGetRelationName(seqrel
))));
673 relation_close(seqrel
, NoLock
);
675 PG_RETURN_INT64(result
);
679 lastval(PG_FUNCTION_ARGS
)
684 if (last_used_seq
== NULL
)
686 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
687 errmsg("lastval is not yet defined in this session")));
689 /* Someone may have dropped the sequence since the last nextval() */
690 if (!SearchSysCacheExists(RELOID
,
691 ObjectIdGetDatum(last_used_seq
->relid
),
694 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
695 errmsg("lastval is not yet defined in this session")));
697 seqrel
= open_share_lock(last_used_seq
);
699 /* nextval() must have already been called for this sequence */
700 Assert(last_used_seq
->last_valid
);
702 if (pg_class_aclcheck(last_used_seq
->relid
, GetUserId(), ACL_SELECT
) != ACLCHECK_OK
&&
703 pg_class_aclcheck(last_used_seq
->relid
, GetUserId(), ACL_USAGE
) != ACLCHECK_OK
)
705 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
706 errmsg("permission denied for sequence %s",
707 RelationGetRelationName(seqrel
))));
709 result
= last_used_seq
->last
;
710 relation_close(seqrel
, NoLock
);
712 PG_RETURN_INT64(result
);
716 * Main internal procedure that handles 2 & 3 arg forms of SETVAL.
718 * Note that the 3 arg version (which sets the is_called flag) is
719 * only for use in pg_dump, and setting the is_called flag may not
720 * work if multiple users are attached to the database and referencing
721 * the sequence (unlikely if pg_dump is restoring it).
723 * It is necessary to have the 3 arg version so that pg_dump can
724 * restore the state of a sequence exactly during data-only restores -
725 * it is the only way to clear the is_called flag in an existing
729 do_setval(Oid relid
, int64 next
, bool iscalled
)
734 Form_pg_sequence seq
;
736 /* open and AccessShareLock sequence */
737 init_sequence(relid
, &elm
, &seqrel
);
739 if (pg_class_aclcheck(elm
->relid
, GetUserId(), ACL_UPDATE
) != ACLCHECK_OK
)
741 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
742 errmsg("permission denied for sequence %s",
743 RelationGetRelationName(seqrel
))));
745 /* lock page' buffer and read tuple */
746 seq
= read_info(elm
, seqrel
, &buf
);
748 if ((next
< seq
->min_value
) || (next
> seq
->max_value
))
754 snprintf(bufv
, sizeof(bufv
), INT64_FORMAT
, next
);
755 snprintf(bufm
, sizeof(bufm
), INT64_FORMAT
, seq
->min_value
);
756 snprintf(bufx
, sizeof(bufx
), INT64_FORMAT
, seq
->max_value
);
758 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
759 errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)",
760 bufv
, RelationGetRelationName(seqrel
),
764 /* Set the currval() state only if iscalled = true */
767 elm
->last
= next
; /* last returned number */
768 elm
->last_valid
= true;
771 /* In any case, forget any future cached numbers */
772 elm
->cached
= elm
->last
;
774 START_CRIT_SECTION();
776 MarkBufferDirty(buf
);
779 if (!seqrel
->rd_istemp
)
783 XLogRecData rdata
[2];
784 Page page
= BufferGetPage(buf
);
786 xlrec
.node
= seqrel
->rd_node
;
787 rdata
[0].data
= (char *) &xlrec
;
788 rdata
[0].len
= sizeof(xl_seq_rec
);
789 rdata
[0].buffer
= InvalidBuffer
;
790 rdata
[0].next
= &(rdata
[1]);
792 /* set values that will be saved in xlog */
793 seq
->last_value
= next
;
794 seq
->is_called
= true;
797 rdata
[1].data
= (char *) page
+ ((PageHeader
) page
)->pd_upper
;
798 rdata
[1].len
= ((PageHeader
) page
)->pd_special
-
799 ((PageHeader
) page
)->pd_upper
;
800 rdata
[1].buffer
= InvalidBuffer
;
801 rdata
[1].next
= NULL
;
803 recptr
= XLogInsert(RM_SEQ_ID
, XLOG_SEQ_LOG
, rdata
);
805 PageSetLSN(page
, recptr
);
806 PageSetTLI(page
, ThisTimeLineID
);
809 /* save info in sequence relation */
810 seq
->last_value
= next
; /* last fetched number */
811 seq
->is_called
= iscalled
;
812 seq
->log_cnt
= (iscalled
) ? 0 : 1;
816 UnlockReleaseBuffer(buf
);
818 relation_close(seqrel
, NoLock
);
822 * Implement the 2 arg setval procedure.
823 * See do_setval for discussion.
826 setval_oid(PG_FUNCTION_ARGS
)
828 Oid relid
= PG_GETARG_OID(0);
829 int64 next
= PG_GETARG_INT64(1);
831 do_setval(relid
, next
, true);
833 PG_RETURN_INT64(next
);
837 * Implement the 3 arg setval procedure.
838 * See do_setval for discussion.
841 setval3_oid(PG_FUNCTION_ARGS
)
843 Oid relid
= PG_GETARG_OID(0);
844 int64 next
= PG_GETARG_INT64(1);
845 bool iscalled
= PG_GETARG_BOOL(2);
847 do_setval(relid
, next
, iscalled
);
849 PG_RETURN_INT64(next
);
854 * Open the sequence and acquire AccessShareLock if needed
856 * If we haven't touched the sequence already in this transaction,
857 * we need to acquire AccessShareLock. We arrange for the lock to
858 * be owned by the top transaction, so that we don't need to do it
859 * more than once per xact.
862 open_share_lock(SeqTable seq
)
864 LocalTransactionId thislxid
= MyProc
->lxid
;
866 /* Get the lock if not already held in this xact */
867 if (seq
->lxid
!= thislxid
)
869 ResourceOwner currentOwner
;
871 currentOwner
= CurrentResourceOwner
;
874 CurrentResourceOwner
= TopTransactionResourceOwner
;
875 LockRelationOid(seq
->relid
, AccessShareLock
);
879 /* Ensure CurrentResourceOwner is restored on error */
880 CurrentResourceOwner
= currentOwner
;
884 CurrentResourceOwner
= currentOwner
;
886 /* Flag that we have a lock in the current xact */
887 seq
->lxid
= thislxid
;
890 /* We now know we have AccessShareLock, and can safely open the rel */
891 return relation_open(seq
->relid
, NoLock
);
895 * Given a relation OID, open and lock the sequence. p_elm and p_rel are
899 init_sequence(Oid relid
, SeqTable
*p_elm
, Relation
*p_rel
)
904 /* Look to see if we already have a seqtable entry for relation */
905 for (elm
= seqtab
; elm
!= NULL
; elm
= elm
->next
)
907 if (elm
->relid
== relid
)
912 * Allocate new seqtable entry if we didn't find one.
914 * NOTE: seqtable entries remain in the list for the life of a backend. If
915 * the sequence itself is deleted then the entry becomes wasted memory,
916 * but it's small enough that this should not matter.
921 * Time to make a new seqtable entry. These entries live as long as
922 * the backend does, so we use plain malloc for them.
924 elm
= (SeqTable
) malloc(sizeof(SeqTableData
));
927 (errcode(ERRCODE_OUT_OF_MEMORY
),
928 errmsg("out of memory")));
930 elm
->lxid
= InvalidLocalTransactionId
;
931 elm
->last_valid
= false;
932 elm
->last
= elm
->cached
= elm
->increment
= 0;
938 * Open the sequence relation.
940 seqrel
= open_share_lock(elm
);
942 if (seqrel
->rd_rel
->relkind
!= RELKIND_SEQUENCE
)
944 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
945 errmsg("\"%s\" is not a sequence",
946 RelationGetRelationName(seqrel
))));
953 /* Given an opened relation, lock the page buffer and find the tuple */
954 static Form_pg_sequence
955 read_info(SeqTable elm
, Relation rel
, Buffer
*buf
)
961 Form_pg_sequence seq
;
963 *buf
= ReadBuffer(rel
, 0);
964 LockBuffer(*buf
, BUFFER_LOCK_EXCLUSIVE
);
966 page
= BufferGetPage(*buf
);
967 sm
= (sequence_magic
*) PageGetSpecialPointer(page
);
969 if (sm
->magic
!= SEQ_MAGIC
)
970 elog(ERROR
, "bad magic number in sequence \"%s\": %08X",
971 RelationGetRelationName(rel
), sm
->magic
);
973 lp
= PageGetItemId(page
, FirstOffsetNumber
);
974 Assert(ItemIdIsNormal(lp
));
975 tuple
.t_data
= (HeapTupleHeader
) PageGetItem(page
, lp
);
977 seq
= (Form_pg_sequence
) GETSTRUCT(&tuple
);
979 /* this is a handy place to update our copy of the increment */
980 elm
->increment
= seq
->increment_by
;
986 * init_params: process the options list of CREATE or ALTER SEQUENCE,
987 * and store the values into appropriate fields of *new. Also set
988 * *owned_by to any OWNED BY option, or to NIL if there is none.
990 * If isInit is true, fill any unspecified options with default values;
991 * otherwise, do not change existing options that aren't explicitly overridden.
994 init_params(List
*options
, bool isInit
,
995 Form_pg_sequence
new, List
**owned_by
)
997 DefElem
*start_value
= NULL
;
998 DefElem
*restart_value
= NULL
;
999 DefElem
*increment_by
= NULL
;
1000 DefElem
*max_value
= NULL
;
1001 DefElem
*min_value
= NULL
;
1002 DefElem
*cache_value
= NULL
;
1003 DefElem
*is_cycled
= NULL
;
1008 foreach(option
, options
)
1010 DefElem
*defel
= (DefElem
*) lfirst(option
);
1012 if (strcmp(defel
->defname
, "increment") == 0)
1016 (errcode(ERRCODE_SYNTAX_ERROR
),
1017 errmsg("conflicting or redundant options")));
1018 increment_by
= defel
;
1020 else if (strcmp(defel
->defname
, "start") == 0)
1024 (errcode(ERRCODE_SYNTAX_ERROR
),
1025 errmsg("conflicting or redundant options")));
1026 start_value
= defel
;
1028 else if (strcmp(defel
->defname
, "restart") == 0)
1032 (errcode(ERRCODE_SYNTAX_ERROR
),
1033 errmsg("conflicting or redundant options")));
1034 restart_value
= defel
;
1036 else if (strcmp(defel
->defname
, "maxvalue") == 0)
1040 (errcode(ERRCODE_SYNTAX_ERROR
),
1041 errmsg("conflicting or redundant options")));
1044 else if (strcmp(defel
->defname
, "minvalue") == 0)
1048 (errcode(ERRCODE_SYNTAX_ERROR
),
1049 errmsg("conflicting or redundant options")));
1052 else if (strcmp(defel
->defname
, "cache") == 0)
1056 (errcode(ERRCODE_SYNTAX_ERROR
),
1057 errmsg("conflicting or redundant options")));
1058 cache_value
= defel
;
1060 else if (strcmp(defel
->defname
, "cycle") == 0)
1064 (errcode(ERRCODE_SYNTAX_ERROR
),
1065 errmsg("conflicting or redundant options")));
1068 else if (strcmp(defel
->defname
, "owned_by") == 0)
1072 (errcode(ERRCODE_SYNTAX_ERROR
),
1073 errmsg("conflicting or redundant options")));
1074 *owned_by
= defGetQualifiedName(defel
);
1077 elog(ERROR
, "option \"%s\" not recognized",
1082 if (increment_by
!= NULL
)
1084 new->increment_by
= defGetInt64(increment_by
);
1085 if (new->increment_by
== 0)
1087 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1088 errmsg("INCREMENT must not be zero")));
1091 new->increment_by
= 1;
1094 if (is_cycled
!= NULL
)
1096 new->is_cycled
= intVal(is_cycled
->arg
);
1097 Assert(new->is_cycled
== false || new->is_cycled
== true);
1100 new->is_cycled
= false;
1102 /* MAXVALUE (null arg means NO MAXVALUE) */
1103 if (max_value
!= NULL
&& max_value
->arg
)
1104 new->max_value
= defGetInt64(max_value
);
1105 else if (isInit
|| max_value
!= NULL
)
1107 if (new->increment_by
> 0)
1108 new->max_value
= SEQ_MAXVALUE
; /* ascending seq */
1110 new->max_value
= -1; /* descending seq */
1113 /* MINVALUE (null arg means NO MINVALUE) */
1114 if (min_value
!= NULL
&& min_value
->arg
)
1115 new->min_value
= defGetInt64(min_value
);
1116 else if (isInit
|| min_value
!= NULL
)
1118 if (new->increment_by
> 0)
1119 new->min_value
= 1; /* ascending seq */
1121 new->min_value
= SEQ_MINVALUE
; /* descending seq */
1124 /* crosscheck min/max */
1125 if (new->min_value
>= new->max_value
)
1130 snprintf(bufm
, sizeof(bufm
), INT64_FORMAT
, new->min_value
);
1131 snprintf(bufx
, sizeof(bufx
), INT64_FORMAT
, new->max_value
);
1133 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1134 errmsg("MINVALUE (%s) must be less than MAXVALUE (%s)",
1139 if (start_value
!= NULL
)
1140 new->start_value
= defGetInt64(start_value
);
1143 if (new->increment_by
> 0)
1144 new->start_value
= new->min_value
; /* ascending seq */
1146 new->start_value
= new->max_value
; /* descending seq */
1149 /* crosscheck START */
1150 if (new->start_value
< new->min_value
)
1155 snprintf(bufs
, sizeof(bufs
), INT64_FORMAT
, new->start_value
);
1156 snprintf(bufm
, sizeof(bufm
), INT64_FORMAT
, new->min_value
);
1158 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1159 errmsg("START value (%s) cannot be less than MINVALUE (%s)",
1162 if (new->start_value
> new->max_value
)
1167 snprintf(bufs
, sizeof(bufs
), INT64_FORMAT
, new->start_value
);
1168 snprintf(bufm
, sizeof(bufm
), INT64_FORMAT
, new->max_value
);
1170 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1171 errmsg("START value (%s) cannot be greater than MAXVALUE (%s)",
1175 /* RESTART [WITH] */
1176 if (restart_value
!= NULL
)
1178 if (restart_value
->arg
!= NULL
)
1179 new->last_value
= defGetInt64(restart_value
);
1181 new->last_value
= new->start_value
;
1182 new->is_called
= false;
1187 new->last_value
= new->start_value
;
1188 new->is_called
= false;
1192 /* crosscheck RESTART (or current value, if changing MIN/MAX) */
1193 if (new->last_value
< new->min_value
)
1198 snprintf(bufs
, sizeof(bufs
), INT64_FORMAT
, new->last_value
);
1199 snprintf(bufm
, sizeof(bufm
), INT64_FORMAT
, new->min_value
);
1201 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1202 errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)",
1205 if (new->last_value
> new->max_value
)
1210 snprintf(bufs
, sizeof(bufs
), INT64_FORMAT
, new->last_value
);
1211 snprintf(bufm
, sizeof(bufm
), INT64_FORMAT
, new->max_value
);
1213 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1214 errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)",
1219 if (cache_value
!= NULL
)
1221 new->cache_value
= defGetInt64(cache_value
);
1222 if (new->cache_value
<= 0)
1226 snprintf(buf
, sizeof(buf
), INT64_FORMAT
, new->cache_value
);
1228 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1229 errmsg("CACHE (%s) must be greater than zero",
1234 new->cache_value
= 1;
1238 * Process an OWNED BY option for CREATE/ALTER SEQUENCE
1240 * Ownership permissions on the sequence are already checked,
1241 * but if we are establishing a new owned-by dependency, we must
1242 * enforce that the referenced table has the same owner and namespace
1246 process_owned_by(Relation seqrel
, List
*owned_by
)
1252 nnames
= list_length(owned_by
);
1256 /* Must be OWNED BY NONE */
1257 if (strcmp(strVal(linitial(owned_by
)), "none") != 0)
1259 (errcode(ERRCODE_SYNTAX_ERROR
),
1260 errmsg("invalid OWNED BY option"),
1261 errhint("Specify OWNED BY table.column or OWNED BY NONE.")));
1271 /* Separate relname and attr name */
1272 relname
= list_truncate(list_copy(owned_by
), nnames
- 1);
1273 attrname
= strVal(lfirst(list_tail(owned_by
)));
1275 /* Open and lock rel to ensure it won't go away meanwhile */
1276 rel
= makeRangeVarFromNameList(relname
);
1277 tablerel
= relation_openrv(rel
, AccessShareLock
);
1279 /* Must be a regular table */
1280 if (tablerel
->rd_rel
->relkind
!= RELKIND_RELATION
)
1282 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1283 errmsg("referenced relation \"%s\" is not a table",
1284 RelationGetRelationName(tablerel
))));
1286 /* We insist on same owner and schema */
1287 if (seqrel
->rd_rel
->relowner
!= tablerel
->rd_rel
->relowner
)
1289 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
1290 errmsg("sequence must have same owner as table it is linked to")));
1291 if (RelationGetNamespace(seqrel
) != RelationGetNamespace(tablerel
))
1293 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
1294 errmsg("sequence must be in same schema as table it is linked to")));
1296 /* Now, fetch the attribute number from the system cache */
1297 attnum
= get_attnum(RelationGetRelid(tablerel
), attrname
);
1298 if (attnum
== InvalidAttrNumber
)
1300 (errcode(ERRCODE_UNDEFINED_COLUMN
),
1301 errmsg("column \"%s\" of relation \"%s\" does not exist",
1302 attrname
, RelationGetRelationName(tablerel
))));
1306 * OK, we are ready to update pg_depend. First remove any existing AUTO
1307 * dependencies for the sequence, then optionally add a new one.
1309 markSequenceUnowned(RelationGetRelid(seqrel
));
1313 ObjectAddress refobject
,
1316 refobject
.classId
= RelationRelationId
;
1317 refobject
.objectId
= RelationGetRelid(tablerel
);
1318 refobject
.objectSubId
= attnum
;
1319 depobject
.classId
= RelationRelationId
;
1320 depobject
.objectId
= RelationGetRelid(seqrel
);
1321 depobject
.objectSubId
= 0;
1322 recordDependencyOn(&depobject
, &refobject
, DEPENDENCY_AUTO
);
1325 /* Done, but hold lock until commit */
1327 relation_close(tablerel
, NoLock
);
1332 seq_redo(XLogRecPtr lsn
, XLogRecord
*record
)
1334 uint8 info
= record
->xl_info
& ~XLR_INFO_MASK
;
1339 xl_seq_rec
*xlrec
= (xl_seq_rec
*) XLogRecGetData(record
);
1342 if (info
!= XLOG_SEQ_LOG
)
1343 elog(PANIC
, "seq_redo: unknown op code %u", info
);
1345 buffer
= XLogReadBuffer(xlrec
->node
, 0, true);
1346 Assert(BufferIsValid(buffer
));
1347 page
= (Page
) BufferGetPage(buffer
);
1349 /* Always reinit the page and reinstall the magic number */
1350 /* See comments in DefineSequence */
1351 PageInit((Page
) page
, BufferGetPageSize(buffer
), sizeof(sequence_magic
));
1352 sm
= (sequence_magic
*) PageGetSpecialPointer(page
);
1353 sm
->magic
= SEQ_MAGIC
;
1355 item
= (char *) xlrec
+ sizeof(xl_seq_rec
);
1356 itemsz
= record
->xl_len
- sizeof(xl_seq_rec
);
1357 itemsz
= MAXALIGN(itemsz
);
1358 if (PageAddItem(page
, (Item
) item
, itemsz
,
1359 FirstOffsetNumber
, false, false) == InvalidOffsetNumber
)
1360 elog(PANIC
, "seq_redo: failed to add item to page");
1362 PageSetLSN(page
, lsn
);
1363 PageSetTLI(page
, ThisTimeLineID
);
1364 MarkBufferDirty(buffer
);
1365 UnlockReleaseBuffer(buffer
);
1369 seq_desc(StringInfo buf
, uint8 xl_info
, char *rec
)
1371 uint8 info
= xl_info
& ~XLR_INFO_MASK
;
1372 xl_seq_rec
*xlrec
= (xl_seq_rec
*) rec
;
1374 if (info
== XLOG_SEQ_LOG
)
1375 appendStringInfo(buf
, "log: ");
1378 appendStringInfo(buf
, "UNKNOWN");
1382 appendStringInfo(buf
, "rel %u/%u/%u",
1383 xlrec
->node
.spcNode
, xlrec
->node
.dbNode
, xlrec
->node
.relNode
);