00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/htup_details.h"
00018 #include "access/multixact.h"
00019 #include "access/transam.h"
00020 #include "access/xlogutils.h"
00021 #include "catalog/dependency.h"
00022 #include "catalog/namespace.h"
00023 #include "catalog/objectaccess.h"
00024 #include "catalog/pg_type.h"
00025 #include "commands/defrem.h"
00026 #include "commands/sequence.h"
00027 #include "commands/tablecmds.h"
00028 #include "funcapi.h"
00029 #include "miscadmin.h"
00030 #include "nodes/makefuncs.h"
00031 #include "storage/lmgr.h"
00032 #include "storage/proc.h"
00033 #include "storage/smgr.h"
00034 #include "utils/acl.h"
00035 #include "utils/builtins.h"
00036 #include "utils/lsyscache.h"
00037 #include "utils/resowner.h"
00038 #include "utils/syscache.h"
00039
00040
00041
00042
00043
00044
00045
00046 #define SEQ_LOG_VALS 32
00047
00048
00049
00050
00051 #define SEQ_MAGIC 0x1717
00052
00053 typedef struct sequence_magic
00054 {
00055 uint32 magic;
00056 } sequence_magic;
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 typedef struct SeqTableData
00069 {
00070 struct SeqTableData *next;
00071 Oid relid;
00072 Oid filenode;
00073 LocalTransactionId lxid;
00074 bool last_valid;
00075 int64 last;
00076 int64 cached;
00077
00078 int64 increment;
00079
00080 } SeqTableData;
00081
00082 typedef SeqTableData *SeqTable;
00083
00084 static SeqTable seqtab = NULL;
00085
00086
00087
00088
00089
00090 static SeqTableData *last_used_seq = NULL;
00091
00092 static void fill_seq_with_data(Relation rel, HeapTuple tuple);
00093 static int64 nextval_internal(Oid relid);
00094 static Relation open_share_lock(SeqTable seq);
00095 static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
00096 static Form_pg_sequence read_seq_tuple(SeqTable elm, Relation rel,
00097 Buffer *buf, HeapTuple seqtuple);
00098 static void init_params(List *options, bool isInit,
00099 Form_pg_sequence new, List **owned_by);
00100 static void do_setval(Oid relid, int64 next, bool iscalled);
00101 static void process_owned_by(Relation seqrel, List *owned_by);
00102
00103
00104
00105
00106
00107
00108 Oid
00109 DefineSequence(CreateSeqStmt *seq)
00110 {
00111 FormData_pg_sequence new;
00112 List *owned_by;
00113 CreateStmt *stmt = makeNode(CreateStmt);
00114 Oid seqoid;
00115 Relation rel;
00116 HeapTuple tuple;
00117 TupleDesc tupDesc;
00118 Datum value[SEQ_COL_LASTCOL];
00119 bool null[SEQ_COL_LASTCOL];
00120 int i;
00121 NameData name;
00122
00123
00124 if (seq->sequence->relpersistence == RELPERSISTENCE_UNLOGGED)
00125 ereport(ERROR,
00126 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00127 errmsg("unlogged sequences are not supported")));
00128
00129
00130 init_params(seq->options, true, &new, &owned_by);
00131
00132
00133
00134
00135 stmt->tableElts = NIL;
00136 for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
00137 {
00138 ColumnDef *coldef = makeNode(ColumnDef);
00139
00140 coldef->inhcount = 0;
00141 coldef->is_local = true;
00142 coldef->is_not_null = true;
00143 coldef->is_from_type = false;
00144 coldef->storage = 0;
00145 coldef->raw_default = NULL;
00146 coldef->cooked_default = NULL;
00147 coldef->collClause = NULL;
00148 coldef->collOid = InvalidOid;
00149 coldef->constraints = NIL;
00150
00151 null[i - 1] = false;
00152
00153 switch (i)
00154 {
00155 case SEQ_COL_NAME:
00156 coldef->typeName = makeTypeNameFromOid(NAMEOID, -1);
00157 coldef->colname = "sequence_name";
00158 namestrcpy(&name, seq->sequence->relname);
00159 value[i - 1] = NameGetDatum(&name);
00160 break;
00161 case SEQ_COL_LASTVAL:
00162 coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
00163 coldef->colname = "last_value";
00164 value[i - 1] = Int64GetDatumFast(new.last_value);
00165 break;
00166 case SEQ_COL_STARTVAL:
00167 coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
00168 coldef->colname = "start_value";
00169 value[i - 1] = Int64GetDatumFast(new.start_value);
00170 break;
00171 case SEQ_COL_INCBY:
00172 coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
00173 coldef->colname = "increment_by";
00174 value[i - 1] = Int64GetDatumFast(new.increment_by);
00175 break;
00176 case SEQ_COL_MAXVALUE:
00177 coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
00178 coldef->colname = "max_value";
00179 value[i - 1] = Int64GetDatumFast(new.max_value);
00180 break;
00181 case SEQ_COL_MINVALUE:
00182 coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
00183 coldef->colname = "min_value";
00184 value[i - 1] = Int64GetDatumFast(new.min_value);
00185 break;
00186 case SEQ_COL_CACHE:
00187 coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
00188 coldef->colname = "cache_value";
00189 value[i - 1] = Int64GetDatumFast(new.cache_value);
00190 break;
00191 case SEQ_COL_LOG:
00192 coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
00193 coldef->colname = "log_cnt";
00194 value[i - 1] = Int64GetDatum((int64) 0);
00195 break;
00196 case SEQ_COL_CYCLE:
00197 coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
00198 coldef->colname = "is_cycled";
00199 value[i - 1] = BoolGetDatum(new.is_cycled);
00200 break;
00201 case SEQ_COL_CALLED:
00202 coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
00203 coldef->colname = "is_called";
00204 value[i - 1] = BoolGetDatum(false);
00205 break;
00206 }
00207 stmt->tableElts = lappend(stmt->tableElts, coldef);
00208 }
00209
00210 stmt->relation = seq->sequence;
00211 stmt->inhRelations = NIL;
00212 stmt->constraints = NIL;
00213 stmt->options = NIL;
00214 stmt->oncommit = ONCOMMIT_NOOP;
00215 stmt->tablespacename = NULL;
00216 stmt->if_not_exists = false;
00217
00218 seqoid = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId);
00219 Assert(seqoid != InvalidOid);
00220
00221 rel = heap_open(seqoid, AccessExclusiveLock);
00222 tupDesc = RelationGetDescr(rel);
00223
00224
00225 tuple = heap_form_tuple(tupDesc, value, null);
00226 fill_seq_with_data(rel, tuple);
00227
00228
00229 if (owned_by)
00230 process_owned_by(rel, owned_by);
00231
00232 heap_close(rel, NoLock);
00233
00234 return seqoid;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 void
00250 ResetSequence(Oid seq_relid)
00251 {
00252 Relation seq_rel;
00253 SeqTable elm;
00254 Form_pg_sequence seq;
00255 Buffer buf;
00256 HeapTupleData seqtuple;
00257 HeapTuple tuple;
00258
00259
00260
00261
00262
00263
00264 init_sequence(seq_relid, &elm, &seq_rel);
00265 (void) read_seq_tuple(elm, seq_rel, &buf, &seqtuple);
00266
00267
00268
00269
00270 tuple = heap_copytuple(&seqtuple);
00271
00272
00273 UnlockReleaseBuffer(buf);
00274
00275
00276
00277
00278
00279 seq = (Form_pg_sequence) GETSTRUCT(tuple);
00280 seq->last_value = seq->start_value;
00281 seq->is_called = false;
00282 seq->log_cnt = 0;
00283
00284
00285
00286
00287
00288
00289 RelationSetNewRelfilenode(seq_rel, InvalidTransactionId,
00290 InvalidMultiXactId);
00291
00292
00293
00294
00295 fill_seq_with_data(seq_rel, tuple);
00296
00297
00298
00299 elm->cached = elm->last;
00300
00301 relation_close(seq_rel, NoLock);
00302 }
00303
00304
00305
00306
00307 static void
00308 fill_seq_with_data(Relation rel, HeapTuple tuple)
00309 {
00310 Buffer buf;
00311 Page page;
00312 sequence_magic *sm;
00313
00314
00315
00316 buf = ReadBuffer(rel, P_NEW);
00317 Assert(BufferGetBlockNumber(buf) == 0);
00318
00319 page = BufferGetPage(buf);
00320
00321 PageInit(page, BufferGetPageSize(buf), sizeof(sequence_magic));
00322 sm = (sequence_magic *) PageGetSpecialPointer(page);
00323 sm->magic = SEQ_MAGIC;
00324
00325
00326 RelationSetTargetBlock(rel, 0);
00327
00328
00329 simple_heap_insert(rel, tuple);
00330
00331 Assert(ItemPointerGetOffsetNumber(&(tuple->t_self)) == FirstOffsetNumber);
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
00349
00350 START_CRIT_SECTION();
00351
00352 {
00353
00354
00355
00356
00357
00358
00359
00360 ItemId itemId;
00361 Item item;
00362
00363 itemId = PageGetItemId((Page) page, FirstOffsetNumber);
00364 item = PageGetItem((Page) page, itemId);
00365
00366 HeapTupleHeaderSetXmin((HeapTupleHeader) item, FrozenTransactionId);
00367 ((HeapTupleHeader) item)->t_infomask |= HEAP_XMIN_COMMITTED;
00368
00369 HeapTupleHeaderSetXmin(tuple->t_data, FrozenTransactionId);
00370 tuple->t_data->t_infomask |= HEAP_XMIN_COMMITTED;
00371 }
00372
00373 MarkBufferDirty(buf);
00374
00375
00376 if (RelationNeedsWAL(rel))
00377 {
00378 xl_seq_rec xlrec;
00379 XLogRecPtr recptr;
00380 XLogRecData rdata[2];
00381
00382 xlrec.node = rel->rd_node;
00383 rdata[0].data = (char *) &xlrec;
00384 rdata[0].len = sizeof(xl_seq_rec);
00385 rdata[0].buffer = InvalidBuffer;
00386 rdata[0].next = &(rdata[1]);
00387
00388 rdata[1].data = (char *) tuple->t_data;
00389 rdata[1].len = tuple->t_len;
00390 rdata[1].buffer = InvalidBuffer;
00391 rdata[1].next = NULL;
00392
00393 recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
00394
00395 PageSetLSN(page, recptr);
00396 }
00397
00398 END_CRIT_SECTION();
00399
00400 UnlockReleaseBuffer(buf);
00401 }
00402
00403
00404
00405
00406
00407
00408 Oid
00409 AlterSequence(AlterSeqStmt *stmt)
00410 {
00411 Oid relid;
00412 SeqTable elm;
00413 Relation seqrel;
00414 Buffer buf;
00415 HeapTupleData seqtuple;
00416 Form_pg_sequence seq;
00417 FormData_pg_sequence new;
00418 List *owned_by;
00419
00420
00421 relid = RangeVarGetRelid(stmt->sequence, AccessShareLock, stmt->missing_ok);
00422 if (relid == InvalidOid)
00423 {
00424 ereport(NOTICE,
00425 (errmsg("relation \"%s\" does not exist, skipping",
00426 stmt->sequence->relname)));
00427 return InvalidOid;
00428 }
00429
00430 init_sequence(relid, &elm, &seqrel);
00431
00432
00433 if (!pg_class_ownercheck(relid, GetUserId()))
00434 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
00435 stmt->sequence->relname);
00436
00437
00438 seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
00439
00440
00441 memcpy(&new, seq, sizeof(FormData_pg_sequence));
00442
00443
00444 init_params(stmt->options, false, &new, &owned_by);
00445
00446
00447
00448 elm->cached = elm->last;
00449
00450
00451 START_CRIT_SECTION();
00452
00453 memcpy(seq, &new, sizeof(FormData_pg_sequence));
00454
00455 MarkBufferDirty(buf);
00456
00457
00458 if (RelationNeedsWAL(seqrel))
00459 {
00460 xl_seq_rec xlrec;
00461 XLogRecPtr recptr;
00462 XLogRecData rdata[2];
00463 Page page = BufferGetPage(buf);
00464
00465 xlrec.node = seqrel->rd_node;
00466 rdata[0].data = (char *) &xlrec;
00467 rdata[0].len = sizeof(xl_seq_rec);
00468 rdata[0].buffer = InvalidBuffer;
00469 rdata[0].next = &(rdata[1]);
00470
00471 rdata[1].data = (char *) seqtuple.t_data;
00472 rdata[1].len = seqtuple.t_len;
00473 rdata[1].buffer = InvalidBuffer;
00474 rdata[1].next = NULL;
00475
00476 recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
00477
00478 PageSetLSN(page, recptr);
00479 }
00480
00481 END_CRIT_SECTION();
00482
00483 UnlockReleaseBuffer(buf);
00484
00485
00486 if (owned_by)
00487 process_owned_by(seqrel, owned_by);
00488
00489 InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
00490
00491 relation_close(seqrel, NoLock);
00492
00493 return relid;
00494 }
00495
00496
00497
00498
00499
00500
00501
00502 Datum
00503 nextval(PG_FUNCTION_ARGS)
00504 {
00505 text *seqin = PG_GETARG_TEXT_P(0);
00506 RangeVar *sequence;
00507 Oid relid;
00508
00509 sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin));
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 relid = RangeVarGetRelid(sequence, NoLock, false);
00520
00521 PG_RETURN_INT64(nextval_internal(relid));
00522 }
00523
00524 Datum
00525 nextval_oid(PG_FUNCTION_ARGS)
00526 {
00527 Oid relid = PG_GETARG_OID(0);
00528
00529 PG_RETURN_INT64(nextval_internal(relid));
00530 }
00531
00532 static int64
00533 nextval_internal(Oid relid)
00534 {
00535 SeqTable elm;
00536 Relation seqrel;
00537 Buffer buf;
00538 Page page;
00539 HeapTupleData seqtuple;
00540 Form_pg_sequence seq;
00541 int64 incby,
00542 maxv,
00543 minv,
00544 cache,
00545 log,
00546 fetch,
00547 last;
00548 int64 result,
00549 next,
00550 rescnt = 0;
00551 bool logit = false;
00552
00553
00554 init_sequence(relid, &elm, &seqrel);
00555
00556 if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK &&
00557 pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
00558 ereport(ERROR,
00559 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00560 errmsg("permission denied for sequence %s",
00561 RelationGetRelationName(seqrel))));
00562
00563
00564 if (!seqrel->rd_islocaltemp)
00565 PreventCommandIfReadOnly("nextval()");
00566
00567 if (elm->last != elm->cached)
00568 {
00569 Assert(elm->last_valid);
00570 Assert(elm->increment != 0);
00571 elm->last += elm->increment;
00572 relation_close(seqrel, NoLock);
00573 last_used_seq = elm;
00574 return elm->last;
00575 }
00576
00577
00578 seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
00579 page = BufferGetPage(buf);
00580
00581 last = next = result = seq->last_value;
00582 incby = seq->increment_by;
00583 maxv = seq->max_value;
00584 minv = seq->min_value;
00585 fetch = cache = seq->cache_value;
00586 log = seq->log_cnt;
00587
00588 if (!seq->is_called)
00589 {
00590 rescnt++;
00591 fetch--;
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 if (log < fetch || !seq->is_called)
00605 {
00606
00607 fetch = log = fetch + SEQ_LOG_VALS;
00608 logit = true;
00609 }
00610 else
00611 {
00612 XLogRecPtr redoptr = GetRedoRecPtr();
00613
00614 if (PageGetLSN(page) <= redoptr)
00615 {
00616
00617 fetch = log = fetch + SEQ_LOG_VALS;
00618 logit = true;
00619 }
00620 }
00621
00622 while (fetch)
00623 {
00624
00625
00626
00627
00628 if (incby > 0)
00629 {
00630
00631 if ((maxv >= 0 && next > maxv - incby) ||
00632 (maxv < 0 && next + incby > maxv))
00633 {
00634 if (rescnt > 0)
00635 break;
00636 if (!seq->is_cycled)
00637 {
00638 char buf[100];
00639
00640 snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
00641 ereport(ERROR,
00642 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00643 errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
00644 RelationGetRelationName(seqrel), buf)));
00645 }
00646 next = minv;
00647 }
00648 else
00649 next += incby;
00650 }
00651 else
00652 {
00653
00654 if ((minv < 0 && next < minv - incby) ||
00655 (minv >= 0 && next + incby < minv))
00656 {
00657 if (rescnt > 0)
00658 break;
00659 if (!seq->is_cycled)
00660 {
00661 char buf[100];
00662
00663 snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
00664 ereport(ERROR,
00665 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00666 errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
00667 RelationGetRelationName(seqrel), buf)));
00668 }
00669 next = maxv;
00670 }
00671 else
00672 next += incby;
00673 }
00674 fetch--;
00675 if (rescnt < cache)
00676 {
00677 log--;
00678 rescnt++;
00679 last = next;
00680 if (rescnt == 1)
00681 result = next;
00682 }
00683 }
00684
00685 log -= fetch;
00686 Assert(log >= 0);
00687
00688
00689 elm->last = result;
00690 elm->cached = last;
00691 elm->last_valid = true;
00692
00693 last_used_seq = elm;
00694
00695
00696 START_CRIT_SECTION();
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707 MarkBufferDirty(buf);
00708
00709
00710 if (logit && RelationNeedsWAL(seqrel))
00711 {
00712 xl_seq_rec xlrec;
00713 XLogRecPtr recptr;
00714 XLogRecData rdata[2];
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724 seq->last_value = next;
00725 seq->is_called = true;
00726 seq->log_cnt = 0;
00727
00728 xlrec.node = seqrel->rd_node;
00729 rdata[0].data = (char *) &xlrec;
00730 rdata[0].len = sizeof(xl_seq_rec);
00731 rdata[0].buffer = InvalidBuffer;
00732 rdata[0].next = &(rdata[1]);
00733
00734 rdata[1].data = (char *) seqtuple.t_data;
00735 rdata[1].len = seqtuple.t_len;
00736 rdata[1].buffer = InvalidBuffer;
00737 rdata[1].next = NULL;
00738
00739 recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
00740
00741 PageSetLSN(page, recptr);
00742 }
00743
00744
00745 seq->last_value = last;
00746 seq->is_called = true;
00747 seq->log_cnt = log;
00748
00749 END_CRIT_SECTION();
00750
00751 UnlockReleaseBuffer(buf);
00752
00753 relation_close(seqrel, NoLock);
00754
00755 return result;
00756 }
00757
00758 Datum
00759 currval_oid(PG_FUNCTION_ARGS)
00760 {
00761 Oid relid = PG_GETARG_OID(0);
00762 int64 result;
00763 SeqTable elm;
00764 Relation seqrel;
00765
00766
00767 init_sequence(relid, &elm, &seqrel);
00768
00769 if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK &&
00770 pg_class_aclcheck(elm->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
00771 ereport(ERROR,
00772 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00773 errmsg("permission denied for sequence %s",
00774 RelationGetRelationName(seqrel))));
00775
00776 if (!elm->last_valid)
00777 ereport(ERROR,
00778 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00779 errmsg("currval of sequence \"%s\" is not yet defined in this session",
00780 RelationGetRelationName(seqrel))));
00781
00782 result = elm->last;
00783
00784 relation_close(seqrel, NoLock);
00785
00786 PG_RETURN_INT64(result);
00787 }
00788
00789 Datum
00790 lastval(PG_FUNCTION_ARGS)
00791 {
00792 Relation seqrel;
00793 int64 result;
00794
00795 if (last_used_seq == NULL)
00796 ereport(ERROR,
00797 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00798 errmsg("lastval is not yet defined in this session")));
00799
00800
00801 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(last_used_seq->relid)))
00802 ereport(ERROR,
00803 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00804 errmsg("lastval is not yet defined in this session")));
00805
00806 seqrel = open_share_lock(last_used_seq);
00807
00808
00809 Assert(last_used_seq->last_valid);
00810
00811 if (pg_class_aclcheck(last_used_seq->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK &&
00812 pg_class_aclcheck(last_used_seq->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
00813 ereport(ERROR,
00814 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00815 errmsg("permission denied for sequence %s",
00816 RelationGetRelationName(seqrel))));
00817
00818 result = last_used_seq->last;
00819 relation_close(seqrel, NoLock);
00820
00821 PG_RETURN_INT64(result);
00822 }
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837 static void
00838 do_setval(Oid relid, int64 next, bool iscalled)
00839 {
00840 SeqTable elm;
00841 Relation seqrel;
00842 Buffer buf;
00843 HeapTupleData seqtuple;
00844 Form_pg_sequence seq;
00845
00846
00847 init_sequence(relid, &elm, &seqrel);
00848
00849 if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
00850 ereport(ERROR,
00851 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00852 errmsg("permission denied for sequence %s",
00853 RelationGetRelationName(seqrel))));
00854
00855
00856 if (!seqrel->rd_islocaltemp)
00857 PreventCommandIfReadOnly("setval()");
00858
00859
00860 seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
00861
00862 if ((next < seq->min_value) || (next > seq->max_value))
00863 {
00864 char bufv[100],
00865 bufm[100],
00866 bufx[100];
00867
00868 snprintf(bufv, sizeof(bufv), INT64_FORMAT, next);
00869 snprintf(bufm, sizeof(bufm), INT64_FORMAT, seq->min_value);
00870 snprintf(bufx, sizeof(bufx), INT64_FORMAT, seq->max_value);
00871 ereport(ERROR,
00872 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
00873 errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)",
00874 bufv, RelationGetRelationName(seqrel),
00875 bufm, bufx)));
00876 }
00877
00878
00879 if (iscalled)
00880 {
00881 elm->last = next;
00882 elm->last_valid = true;
00883 }
00884
00885
00886 elm->cached = elm->last;
00887
00888
00889 START_CRIT_SECTION();
00890
00891 seq->last_value = next;
00892 seq->is_called = iscalled;
00893 seq->log_cnt = 0;
00894
00895 MarkBufferDirty(buf);
00896
00897
00898 if (RelationNeedsWAL(seqrel))
00899 {
00900 xl_seq_rec xlrec;
00901 XLogRecPtr recptr;
00902 XLogRecData rdata[2];
00903 Page page = BufferGetPage(buf);
00904
00905 xlrec.node = seqrel->rd_node;
00906 rdata[0].data = (char *) &xlrec;
00907 rdata[0].len = sizeof(xl_seq_rec);
00908 rdata[0].buffer = InvalidBuffer;
00909 rdata[0].next = &(rdata[1]);
00910
00911 rdata[1].data = (char *) seqtuple.t_data;
00912 rdata[1].len = seqtuple.t_len;
00913 rdata[1].buffer = InvalidBuffer;
00914 rdata[1].next = NULL;
00915
00916 recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
00917
00918 PageSetLSN(page, recptr);
00919 }
00920
00921 END_CRIT_SECTION();
00922
00923 UnlockReleaseBuffer(buf);
00924
00925 relation_close(seqrel, NoLock);
00926 }
00927
00928
00929
00930
00931
00932 Datum
00933 setval_oid(PG_FUNCTION_ARGS)
00934 {
00935 Oid relid = PG_GETARG_OID(0);
00936 int64 next = PG_GETARG_INT64(1);
00937
00938 do_setval(relid, next, true);
00939
00940 PG_RETURN_INT64(next);
00941 }
00942
00943
00944
00945
00946
00947 Datum
00948 setval3_oid(PG_FUNCTION_ARGS)
00949 {
00950 Oid relid = PG_GETARG_OID(0);
00951 int64 next = PG_GETARG_INT64(1);
00952 bool iscalled = PG_GETARG_BOOL(2);
00953
00954 do_setval(relid, next, iscalled);
00955
00956 PG_RETURN_INT64(next);
00957 }
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968 static Relation
00969 open_share_lock(SeqTable seq)
00970 {
00971 LocalTransactionId thislxid = MyProc->lxid;
00972
00973
00974 if (seq->lxid != thislxid)
00975 {
00976 ResourceOwner currentOwner;
00977
00978 currentOwner = CurrentResourceOwner;
00979 PG_TRY();
00980 {
00981 CurrentResourceOwner = TopTransactionResourceOwner;
00982 LockRelationOid(seq->relid, AccessShareLock);
00983 }
00984 PG_CATCH();
00985 {
00986
00987 CurrentResourceOwner = currentOwner;
00988 PG_RE_THROW();
00989 }
00990 PG_END_TRY();
00991 CurrentResourceOwner = currentOwner;
00992
00993
00994 seq->lxid = thislxid;
00995 }
00996
00997
00998 return relation_open(seq->relid, NoLock);
00999 }
01000
01001
01002
01003
01004
01005 static void
01006 init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
01007 {
01008 SeqTable elm;
01009 Relation seqrel;
01010
01011
01012 for (elm = seqtab; elm != NULL; elm = elm->next)
01013 {
01014 if (elm->relid == relid)
01015 break;
01016 }
01017
01018
01019
01020
01021
01022
01023
01024
01025 if (elm == NULL)
01026 {
01027
01028
01029
01030
01031 elm = (SeqTable) malloc(sizeof(SeqTableData));
01032 if (elm == NULL)
01033 ereport(ERROR,
01034 (errcode(ERRCODE_OUT_OF_MEMORY),
01035 errmsg("out of memory")));
01036 elm->relid = relid;
01037 elm->filenode = InvalidOid;
01038 elm->lxid = InvalidLocalTransactionId;
01039 elm->last_valid = false;
01040 elm->last = elm->cached = elm->increment = 0;
01041 elm->next = seqtab;
01042 seqtab = elm;
01043 }
01044
01045
01046
01047
01048 seqrel = open_share_lock(elm);
01049
01050 if (seqrel->rd_rel->relkind != RELKIND_SEQUENCE)
01051 ereport(ERROR,
01052 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01053 errmsg("\"%s\" is not a sequence",
01054 RelationGetRelationName(seqrel))));
01055
01056
01057
01058
01059
01060
01061 if (seqrel->rd_rel->relfilenode != elm->filenode)
01062 {
01063 elm->filenode = seqrel->rd_rel->relfilenode;
01064 elm->cached = elm->last;
01065 }
01066
01067
01068 *p_elm = elm;
01069 *p_rel = seqrel;
01070 }
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082 static Form_pg_sequence
01083 read_seq_tuple(SeqTable elm, Relation rel, Buffer *buf, HeapTuple seqtuple)
01084 {
01085 Page page;
01086 ItemId lp;
01087 sequence_magic *sm;
01088 Form_pg_sequence seq;
01089
01090 *buf = ReadBuffer(rel, 0);
01091 LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
01092
01093 page = BufferGetPage(*buf);
01094 sm = (sequence_magic *) PageGetSpecialPointer(page);
01095
01096 if (sm->magic != SEQ_MAGIC)
01097 elog(ERROR, "bad magic number in sequence \"%s\": %08X",
01098 RelationGetRelationName(rel), sm->magic);
01099
01100 lp = PageGetItemId(page, FirstOffsetNumber);
01101 Assert(ItemIdIsNormal(lp));
01102
01103
01104 seqtuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
01105 seqtuple->t_len = ItemIdGetLength(lp);
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115 Assert(!(seqtuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI));
01116 if (HeapTupleHeaderGetRawXmax(seqtuple->t_data) != InvalidTransactionId)
01117 {
01118 HeapTupleHeaderSetXmax(seqtuple->t_data, InvalidTransactionId);
01119 seqtuple->t_data->t_infomask &= ~HEAP_XMAX_COMMITTED;
01120 seqtuple->t_data->t_infomask |= HEAP_XMAX_INVALID;
01121 MarkBufferDirtyHint(*buf);
01122 }
01123
01124 seq = (Form_pg_sequence) GETSTRUCT(seqtuple);
01125
01126
01127 elm->increment = seq->increment_by;
01128
01129 return seq;
01130 }
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140 static void
01141 init_params(List *options, bool isInit,
01142 Form_pg_sequence new, List **owned_by)
01143 {
01144 DefElem *start_value = NULL;
01145 DefElem *restart_value = NULL;
01146 DefElem *increment_by = NULL;
01147 DefElem *max_value = NULL;
01148 DefElem *min_value = NULL;
01149 DefElem *cache_value = NULL;
01150 DefElem *is_cycled = NULL;
01151 ListCell *option;
01152
01153 *owned_by = NIL;
01154
01155 foreach(option, options)
01156 {
01157 DefElem *defel = (DefElem *) lfirst(option);
01158
01159 if (strcmp(defel->defname, "increment") == 0)
01160 {
01161 if (increment_by)
01162 ereport(ERROR,
01163 (errcode(ERRCODE_SYNTAX_ERROR),
01164 errmsg("conflicting or redundant options")));
01165 increment_by = defel;
01166 }
01167 else if (strcmp(defel->defname, "start") == 0)
01168 {
01169 if (start_value)
01170 ereport(ERROR,
01171 (errcode(ERRCODE_SYNTAX_ERROR),
01172 errmsg("conflicting or redundant options")));
01173 start_value = defel;
01174 }
01175 else if (strcmp(defel->defname, "restart") == 0)
01176 {
01177 if (restart_value)
01178 ereport(ERROR,
01179 (errcode(ERRCODE_SYNTAX_ERROR),
01180 errmsg("conflicting or redundant options")));
01181 restart_value = defel;
01182 }
01183 else if (strcmp(defel->defname, "maxvalue") == 0)
01184 {
01185 if (max_value)
01186 ereport(ERROR,
01187 (errcode(ERRCODE_SYNTAX_ERROR),
01188 errmsg("conflicting or redundant options")));
01189 max_value = defel;
01190 }
01191 else if (strcmp(defel->defname, "minvalue") == 0)
01192 {
01193 if (min_value)
01194 ereport(ERROR,
01195 (errcode(ERRCODE_SYNTAX_ERROR),
01196 errmsg("conflicting or redundant options")));
01197 min_value = defel;
01198 }
01199 else if (strcmp(defel->defname, "cache") == 0)
01200 {
01201 if (cache_value)
01202 ereport(ERROR,
01203 (errcode(ERRCODE_SYNTAX_ERROR),
01204 errmsg("conflicting or redundant options")));
01205 cache_value = defel;
01206 }
01207 else if (strcmp(defel->defname, "cycle") == 0)
01208 {
01209 if (is_cycled)
01210 ereport(ERROR,
01211 (errcode(ERRCODE_SYNTAX_ERROR),
01212 errmsg("conflicting or redundant options")));
01213 is_cycled = defel;
01214 }
01215 else if (strcmp(defel->defname, "owned_by") == 0)
01216 {
01217 if (*owned_by)
01218 ereport(ERROR,
01219 (errcode(ERRCODE_SYNTAX_ERROR),
01220 errmsg("conflicting or redundant options")));
01221 *owned_by = defGetQualifiedName(defel);
01222 }
01223 else
01224 elog(ERROR, "option \"%s\" not recognized",
01225 defel->defname);
01226 }
01227
01228
01229
01230
01231
01232 if (isInit)
01233 new->log_cnt = 0;
01234
01235
01236 if (increment_by != NULL)
01237 {
01238 new->increment_by = defGetInt64(increment_by);
01239 if (new->increment_by == 0)
01240 ereport(ERROR,
01241 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01242 errmsg("INCREMENT must not be zero")));
01243 new->log_cnt = 0;
01244 }
01245 else if (isInit)
01246 new->increment_by = 1;
01247
01248
01249 if (is_cycled != NULL)
01250 {
01251 new->is_cycled = intVal(is_cycled->arg);
01252 Assert(BoolIsValid(new->is_cycled));
01253 new->log_cnt = 0;
01254 }
01255 else if (isInit)
01256 new->is_cycled = false;
01257
01258
01259 if (max_value != NULL && max_value->arg)
01260 {
01261 new->max_value = defGetInt64(max_value);
01262 new->log_cnt = 0;
01263 }
01264 else if (isInit || max_value != NULL)
01265 {
01266 if (new->increment_by > 0)
01267 new->max_value = SEQ_MAXVALUE;
01268 else
01269 new->max_value = -1;
01270 new->log_cnt = 0;
01271 }
01272
01273
01274 if (min_value != NULL && min_value->arg)
01275 {
01276 new->min_value = defGetInt64(min_value);
01277 new->log_cnt = 0;
01278 }
01279 else if (isInit || min_value != NULL)
01280 {
01281 if (new->increment_by > 0)
01282 new->min_value = 1;
01283 else
01284 new->min_value = SEQ_MINVALUE;
01285 new->log_cnt = 0;
01286 }
01287
01288
01289 if (new->min_value >= new->max_value)
01290 {
01291 char bufm[100],
01292 bufx[100];
01293
01294 snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
01295 snprintf(bufx, sizeof(bufx), INT64_FORMAT, new->max_value);
01296 ereport(ERROR,
01297 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01298 errmsg("MINVALUE (%s) must be less than MAXVALUE (%s)",
01299 bufm, bufx)));
01300 }
01301
01302
01303 if (start_value != NULL)
01304 new->start_value = defGetInt64(start_value);
01305 else if (isInit)
01306 {
01307 if (new->increment_by > 0)
01308 new->start_value = new->min_value;
01309 else
01310 new->start_value = new->max_value;
01311 }
01312
01313
01314 if (new->start_value < new->min_value)
01315 {
01316 char bufs[100],
01317 bufm[100];
01318
01319 snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->start_value);
01320 snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
01321 ereport(ERROR,
01322 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01323 errmsg("START value (%s) cannot be less than MINVALUE (%s)",
01324 bufs, bufm)));
01325 }
01326 if (new->start_value > new->max_value)
01327 {
01328 char bufs[100],
01329 bufm[100];
01330
01331 snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->start_value);
01332 snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
01333 ereport(ERROR,
01334 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01335 errmsg("START value (%s) cannot be greater than MAXVALUE (%s)",
01336 bufs, bufm)));
01337 }
01338
01339
01340 if (restart_value != NULL)
01341 {
01342 if (restart_value->arg != NULL)
01343 new->last_value = defGetInt64(restart_value);
01344 else
01345 new->last_value = new->start_value;
01346 new->is_called = false;
01347 new->log_cnt = 0;
01348 }
01349 else if (isInit)
01350 {
01351 new->last_value = new->start_value;
01352 new->is_called = false;
01353 }
01354
01355
01356 if (new->last_value < new->min_value)
01357 {
01358 char bufs[100],
01359 bufm[100];
01360
01361 snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
01362 snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
01363 ereport(ERROR,
01364 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01365 errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)",
01366 bufs, bufm)));
01367 }
01368 if (new->last_value > new->max_value)
01369 {
01370 char bufs[100],
01371 bufm[100];
01372
01373 snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
01374 snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
01375 ereport(ERROR,
01376 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01377 errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)",
01378 bufs, bufm)));
01379 }
01380
01381
01382 if (cache_value != NULL)
01383 {
01384 new->cache_value = defGetInt64(cache_value);
01385 if (new->cache_value <= 0)
01386 {
01387 char buf[100];
01388
01389 snprintf(buf, sizeof(buf), INT64_FORMAT, new->cache_value);
01390 ereport(ERROR,
01391 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01392 errmsg("CACHE (%s) must be greater than zero",
01393 buf)));
01394 }
01395 new->log_cnt = 0;
01396 }
01397 else if (isInit)
01398 new->cache_value = 1;
01399 }
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409 static void
01410 process_owned_by(Relation seqrel, List *owned_by)
01411 {
01412 int nnames;
01413 Relation tablerel;
01414 AttrNumber attnum;
01415
01416 nnames = list_length(owned_by);
01417 Assert(nnames > 0);
01418 if (nnames == 1)
01419 {
01420
01421 if (strcmp(strVal(linitial(owned_by)), "none") != 0)
01422 ereport(ERROR,
01423 (errcode(ERRCODE_SYNTAX_ERROR),
01424 errmsg("invalid OWNED BY option"),
01425 errhint("Specify OWNED BY table.column or OWNED BY NONE.")));
01426 tablerel = NULL;
01427 attnum = 0;
01428 }
01429 else
01430 {
01431 List *relname;
01432 char *attrname;
01433 RangeVar *rel;
01434
01435
01436 relname = list_truncate(list_copy(owned_by), nnames - 1);
01437 attrname = strVal(lfirst(list_tail(owned_by)));
01438
01439
01440 rel = makeRangeVarFromNameList(relname);
01441 tablerel = relation_openrv(rel, AccessShareLock);
01442
01443
01444 if (tablerel->rd_rel->relkind != RELKIND_RELATION)
01445 ereport(ERROR,
01446 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01447 errmsg("referenced relation \"%s\" is not a table",
01448 RelationGetRelationName(tablerel))));
01449
01450
01451 if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
01452 ereport(ERROR,
01453 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
01454 errmsg("sequence must have same owner as table it is linked to")));
01455 if (RelationGetNamespace(seqrel) != RelationGetNamespace(tablerel))
01456 ereport(ERROR,
01457 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
01458 errmsg("sequence must be in same schema as table it is linked to")));
01459
01460
01461 attnum = get_attnum(RelationGetRelid(tablerel), attrname);
01462 if (attnum == InvalidAttrNumber)
01463 ereport(ERROR,
01464 (errcode(ERRCODE_UNDEFINED_COLUMN),
01465 errmsg("column \"%s\" of relation \"%s\" does not exist",
01466 attrname, RelationGetRelationName(tablerel))));
01467 }
01468
01469
01470
01471
01472
01473 markSequenceUnowned(RelationGetRelid(seqrel));
01474
01475 if (tablerel)
01476 {
01477 ObjectAddress refobject,
01478 depobject;
01479
01480 refobject.classId = RelationRelationId;
01481 refobject.objectId = RelationGetRelid(tablerel);
01482 refobject.objectSubId = attnum;
01483 depobject.classId = RelationRelationId;
01484 depobject.objectId = RelationGetRelid(seqrel);
01485 depobject.objectSubId = 0;
01486 recordDependencyOn(&depobject, &refobject, DEPENDENCY_AUTO);
01487 }
01488
01489
01490 if (tablerel)
01491 relation_close(tablerel, NoLock);
01492 }
01493
01494
01495
01496
01497
01498 Datum
01499 pg_sequence_parameters(PG_FUNCTION_ARGS)
01500 {
01501 Oid relid = PG_GETARG_OID(0);
01502 TupleDesc tupdesc;
01503 Datum values[5];
01504 bool isnull[5];
01505 SeqTable elm;
01506 Relation seqrel;
01507 Buffer buf;
01508 HeapTupleData seqtuple;
01509 Form_pg_sequence seq;
01510
01511
01512 init_sequence(relid, &elm, &seqrel);
01513
01514 if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_UPDATE | ACL_USAGE) != ACLCHECK_OK)
01515 ereport(ERROR,
01516 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
01517 errmsg("permission denied for sequence %s",
01518 RelationGetRelationName(seqrel))));
01519
01520 tupdesc = CreateTemplateTupleDesc(5, false);
01521 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "start_value",
01522 INT8OID, -1, 0);
01523 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "minimum_value",
01524 INT8OID, -1, 0);
01525 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "maximum_value",
01526 INT8OID, -1, 0);
01527 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "increment",
01528 INT8OID, -1, 0);
01529 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "cycle_option",
01530 BOOLOID, -1, 0);
01531
01532 BlessTupleDesc(tupdesc);
01533
01534 memset(isnull, 0, sizeof(isnull));
01535
01536 seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
01537
01538 values[0] = Int64GetDatum(seq->start_value);
01539 values[1] = Int64GetDatum(seq->min_value);
01540 values[2] = Int64GetDatum(seq->max_value);
01541 values[3] = Int64GetDatum(seq->increment_by);
01542 values[4] = BoolGetDatum(seq->is_cycled);
01543
01544 UnlockReleaseBuffer(buf);
01545 relation_close(seqrel, NoLock);
01546
01547 return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
01548 }
01549
01550
01551 void
01552 seq_redo(XLogRecPtr lsn, XLogRecord *record)
01553 {
01554 uint8 info = record->xl_info & ~XLR_INFO_MASK;
01555 Buffer buffer;
01556 Page page;
01557 Page localpage;
01558 char *item;
01559 Size itemsz;
01560 xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
01561 sequence_magic *sm;
01562
01563
01564 Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
01565
01566 if (info != XLOG_SEQ_LOG)
01567 elog(PANIC, "seq_redo: unknown op code %u", info);
01568
01569 buffer = XLogReadBuffer(xlrec->node, 0, true);
01570 Assert(BufferIsValid(buffer));
01571 page = (Page) BufferGetPage(buffer);
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583 localpage = (Page) palloc(BufferGetPageSize(buffer));
01584
01585 PageInit(localpage, BufferGetPageSize(buffer), sizeof(sequence_magic));
01586 sm = (sequence_magic *) PageGetSpecialPointer(localpage);
01587 sm->magic = SEQ_MAGIC;
01588
01589 item = (char *) xlrec + sizeof(xl_seq_rec);
01590 itemsz = record->xl_len - sizeof(xl_seq_rec);
01591
01592 if (PageAddItem(localpage, (Item) item, itemsz,
01593 FirstOffsetNumber, false, false) == InvalidOffsetNumber)
01594 elog(PANIC, "seq_redo: failed to add item to page");
01595
01596 PageSetLSN(localpage, lsn);
01597
01598 memcpy(page, localpage, BufferGetPageSize(buffer));
01599 MarkBufferDirty(buffer);
01600 UnlockReleaseBuffer(buffer);
01601
01602 pfree(localpage);
01603 }