sequence.c 40.5 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * sequence.c
4
 *	  PostgreSQL sequences support code.
5
 *
B
Bruce Momjian 已提交
6
 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7 8 9 10
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
11
 *	  src/backend/commands/sequence.c
12
 *
13 14
 *-------------------------------------------------------------------------
 */
15
#include "postgres.h"
16

17
#include "access/heapam.h"
18 19
#include "access/transam.h"
#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 "funcapi.h"
B
Bruce Momjian 已提交
28
#include "miscadmin.h"
29
#include "nodes/makefuncs.h"
30 31
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
32
#include "storage/proc.h"
33
#include "storage/smgr.h"
34
#include "utils/acl.h"
B
Bruce Momjian 已提交
35
#include "utils/builtins.h"
36
#include "utils/lsyscache.h"
37
#include "utils/resowner.h"
38
#include "utils/syscache.h"
39

40

V
Vadim B. Mikheev 已提交
41
/*
42
 * We don't want to log each fetching of a value from a sequence,
V
Vadim B. Mikheev 已提交
43 44 45
 * so we pre-log a few fetches in advance. In the event of
 * crash we can lose as much as we pre-logged.
 */
B
Bruce Momjian 已提交
46
#define SEQ_LOG_VALS	32
47

48 49 50 51 52
/*
 * The "special area" of a sequence's buffer page looks like this.
 */
#define SEQ_MAGIC	  0x1717

53 54
typedef struct sequence_magic
{
55
	uint32		magic;
56
} sequence_magic;
57

58 59 60 61 62 63
/*
 * We store a SeqTable item for every sequence we have touched in the current
 * session.  This is needed to hold onto nextval/currval state.  (We can't
 * rely on the relcache, since it's only, well, a cache, and may decide to
 * discard entries.)
 *
B
Bruce Momjian 已提交
64
 * XXX We use linear search to find pre-existing SeqTable entries.	This is
65 66 67
 * good when only a small number of sequences are touched in a session, but
 * would suck with many different sequences.  Perhaps use a hashtable someday.
 */
68 69
typedef struct SeqTableData
{
70 71
	struct SeqTableData *next;	/* link to next SeqTable object */
	Oid			relid;			/* pg_class OID of this sequence */
72
	Oid			filenode;		/* last seen relfilenode of this sequence */
73
	LocalTransactionId lxid;	/* xact in which we last did a seq op */
74
	bool		last_valid;		/* do we have a valid "last" value? */
75 76 77 78
	int64		last;			/* value last returned by nextval */
	int64		cached;			/* last value already cached for nextval */
	/* if last != cached, we have not used up all the cached values */
	int64		increment;		/* copy of sequence's increment field */
79
	/* note that increment is zero until we first do read_info() */
80
} SeqTableData;
81 82 83

typedef SeqTableData *SeqTable;

84
static SeqTable seqtab = NULL;	/* Head of list of SeqTable items */
85

86 87 88 89 90
/*
 * last_used_seq is updated by nextval() to point to the last used
 * sequence.
 */
static SeqTableData *last_used_seq = NULL;
91

92
static void fill_seq_with_data(Relation rel, HeapTuple tuple);
93
static int64 nextval_internal(Oid relid);
94
static Relation open_share_lock(SeqTable seq);
95
static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
96
static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf);
97
static void init_params(List *options, bool isInit,
98
			Form_pg_sequence new, List **owned_by);
99
static void do_setval(Oid relid, int64 next, bool iscalled);
100 101
static void process_owned_by(Relation seqrel, List *owned_by);

102 103

/*
B
Bruce Momjian 已提交
104
 * DefineSequence
105
 *				Creates a new sequence relation
106 107
 */
void
108
DefineSequence(CreateSeqStmt *seq)
109
{
110
	FormData_pg_sequence new;
111
	List	   *owned_by;
112
	CreateStmt *stmt = makeNode(CreateStmt);
113
	Oid			seqoid;
114 115 116 117
	Relation	rel;
	HeapTuple	tuple;
	TupleDesc	tupDesc;
	Datum		value[SEQ_COL_LASTCOL];
118
	bool		null[SEQ_COL_LASTCOL];
119
	int			i;
120
	NameData	name;
121

122 123 124 125 126 127
	/* Unlogged sequences are not implemented -- not clear if useful. */
	if (seq->sequence->relpersistence == RELPERSISTENCE_UNLOGGED)
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("unlogged sequences are not supported")));

128
	/* Check and set all option values */
129
	init_params(seq->options, true, &new, &owned_by);
130 131

	/*
132
	 * Create relation (and fill value[] and null[] for the tuple)
133 134 135
	 */
	stmt->tableElts = NIL;
	for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
136
	{
137
		ColumnDef  *coldef = makeNode(ColumnDef);
138

139 140
		coldef->inhcount = 0;
		coldef->is_local = true;
141
		coldef->is_not_null = true;
142
		coldef->is_from_type = false;
143
		coldef->storage = 0;
144 145
		coldef->raw_default = NULL;
		coldef->cooked_default = NULL;
146 147
		coldef->collClause = NULL;
		coldef->collOid = InvalidOid;
148 149
		coldef->constraints = NIL;

150
		null[i - 1] = false;
151 152 153

		switch (i)
		{
154
			case SEQ_COL_NAME:
155
				coldef->typeName = makeTypeNameFromOid(NAMEOID, -1);
156
				coldef->colname = "sequence_name";
157
				namestrcpy(&name, seq->sequence->relname);
158
				value[i - 1] = NameGetDatum(&name);
159 160
				break;
			case SEQ_COL_LASTVAL:
161
				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
162
				coldef->colname = "last_value";
163
				value[i - 1] = Int64GetDatumFast(new.last_value);
164
				break;
165
			case SEQ_COL_STARTVAL:
166
				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
167 168 169
				coldef->colname = "start_value";
				value[i - 1] = Int64GetDatumFast(new.start_value);
				break;
170
			case SEQ_COL_INCBY:
171
				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
172
				coldef->colname = "increment_by";
173
				value[i - 1] = Int64GetDatumFast(new.increment_by);
174 175
				break;
			case SEQ_COL_MAXVALUE:
176
				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
177
				coldef->colname = "max_value";
178
				value[i - 1] = Int64GetDatumFast(new.max_value);
179 180
				break;
			case SEQ_COL_MINVALUE:
181
				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
182
				coldef->colname = "min_value";
183
				value[i - 1] = Int64GetDatumFast(new.min_value);
184 185
				break;
			case SEQ_COL_CACHE:
186
				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
187
				coldef->colname = "cache_value";
188
				value[i - 1] = Int64GetDatumFast(new.cache_value);
189
				break;
V
Vadim B. Mikheev 已提交
190
			case SEQ_COL_LOG:
191
				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
V
Vadim B. Mikheev 已提交
192
				coldef->colname = "log_cnt";
193
				value[i - 1] = Int64GetDatum((int64) 1);
V
Vadim B. Mikheev 已提交
194
				break;
195
			case SEQ_COL_CYCLE:
196
				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
197
				coldef->colname = "is_cycled";
198
				value[i - 1] = BoolGetDatum(new.is_cycled);
199 200
				break;
			case SEQ_COL_CALLED:
201
				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
202
				coldef->colname = "is_called";
203
				value[i - 1] = BoolGetDatum(false);
204
				break;
205 206 207 208
		}
		stmt->tableElts = lappend(stmt->tableElts, coldef);
	}

209 210
	stmt->relation = seq->sequence;
	stmt->inhRelations = NIL;
211
	stmt->constraints = NIL;
212
	stmt->options = list_make1(defWithOids(false));
213
	stmt->oncommit = ONCOMMIT_NOOP;
214
	stmt->tablespacename = NULL;
R
Robert Haas 已提交
215
	stmt->if_not_exists = false;
216

217
	seqoid = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId);
R
Robert Haas 已提交
218
	Assert(seqoid != InvalidOid);
219

220
	rel = heap_open(seqoid, AccessExclusiveLock);
221
	tupDesc = RelationGetDescr(rel);
222

223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
	/* now initialize the sequence's data */
	tuple = heap_form_tuple(tupDesc, value, null);
	fill_seq_with_data(rel, tuple);

	/* process OWNED BY if given */
	if (owned_by)
		process_owned_by(rel, owned_by);

	heap_close(rel, NoLock);
}

/*
 * Reset a sequence to its initial value.
 *
 * The change is made transactionally, so that on failure of the current
 * transaction, the sequence will be restored to its previous state.
 * We do that by creating a whole new relfilenode for the sequence; so this
 * works much like the rewriting forms of ALTER TABLE.
 *
 * Caller is assumed to have acquired AccessExclusiveLock on the sequence,
 * which must not be released until end of transaction.  Caller is also
 * responsible for permissions checking.
 */
void
ResetSequence(Oid seq_relid)
{
	Relation	seq_rel;
	SeqTable	elm;
	Form_pg_sequence seq;
	Buffer		buf;
	Page		page;
	HeapTuple	tuple;
	HeapTupleData tupledata;
	ItemId		lp;

	/*
	 * Read the old sequence.  This does a bit more work than really
	 * necessary, but it's simple, and we do want to double-check that it's
	 * indeed a sequence.
	 */
	init_sequence(seq_relid, &elm, &seq_rel);
	seq = read_info(elm, seq_rel, &buf);

	/*
	 * Copy the existing sequence tuple.
	 */
	page = BufferGetPage(buf);
	lp = PageGetItemId(page, FirstOffsetNumber);
	Assert(ItemIdIsNormal(lp));

	tupledata.t_data = (HeapTupleHeader) PageGetItem(page, lp);
	tupledata.t_len = ItemIdGetLength(lp);
	tuple = heap_copytuple(&tupledata);

	/* Now we're done with the old page */
	UnlockReleaseBuffer(buf);

	/*
	 * Modify the copied tuple to execute the restart (compare the RESTART
	 * action in AlterSequence)
	 */
	seq = (Form_pg_sequence) GETSTRUCT(tuple);
	seq->last_value = seq->start_value;
	seq->is_called = false;
	seq->log_cnt = 1;

	/*
	 * Create a new storage file for the sequence.  We want to keep the
	 * sequence's relfrozenxid at 0, since it won't contain any unfrozen XIDs.
	 */
	RelationSetNewRelfilenode(seq_rel, InvalidTransactionId);

	/*
	 * Insert the modified tuple into the new storage file.
	 */
	fill_seq_with_data(seq_rel, tuple);

	/* Clear local cache so that we don't think we have cached numbers */
	/* Note that we do not change the currval() state */
	elm->cached = elm->last;

	relation_close(seq_rel, NoLock);
}

/*
 * Initialize a sequence's relation with the specified tuple as content
 */
static void
fill_seq_with_data(Relation rel, HeapTuple tuple)
{
	Buffer		buf;
	Page		page;
	sequence_magic *sm;

317 318
	/* Initialize first page of relation with special magic number */

319
	buf = ReadBuffer(rel, P_NEW);
320 321
	Assert(BufferGetBlockNumber(buf) == 0);

322
	page = BufferGetPage(buf);
323

324
	PageInit(page, BufferGetPageSize(buf), sizeof(sequence_magic));
325 326 327
	sm = (sequence_magic *) PageGetSpecialPointer(page);
	sm->magic = SEQ_MAGIC;

328
	/* hack: ensure heap_insert will insert on the just-created page */
329
	RelationSetTargetBlock(rel, 0);
330

331
	/* Now insert sequence tuple */
332
	simple_heap_insert(rel, tuple);
333

334 335
	Assert(ItemPointerGetOffsetNumber(&(tuple->t_self)) == FirstOffsetNumber);

336
	/*
337 338
	 * Two special hacks here:
	 *
339 340
	 * 1. Since VACUUM does not process sequences, we have to force the tuple
	 * to have xmin = FrozenTransactionId now.	Otherwise it would become
B
Bruce Momjian 已提交
341
	 * invisible to SELECTs after 2G transactions.	It is okay to do this
342 343 344
	 * because if the current transaction aborts, no other xact will ever
	 * examine the sequence tuple anyway.
	 *
B
Bruce Momjian 已提交
345 346 347 348 349
	 * 2. Even though heap_insert emitted a WAL log record, we have to emit an
	 * XLOG_SEQ_LOG record too, since (a) the heap_insert record will not have
	 * the right xmin, and (b) REDO of the heap_insert record would re-init
	 * page and sequence magic number would be lost.  This means two log
	 * records instead of one :-(
350
	 */
351
	LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
352

353
	START_CRIT_SECTION();
354 355 356

	{
		/*
B
Bruce Momjian 已提交
357
		 * Note that the "tuple" structure is still just a local tuple record
358
		 * created by heap_form_tuple; its t_data pointer doesn't point at the
B
Bruce Momjian 已提交
359 360 361
		 * disk buffer.  To scribble on the disk buffer we need to fetch the
		 * item pointer.  But do the same to the local tuple, since that will
		 * be the source for the WAL log record, below.
362 363 364 365 366 367 368
		 */
		ItemId		itemId;
		Item		item;

		itemId = PageGetItemId((Page) page, FirstOffsetNumber);
		item = PageGetItem((Page) page, itemId);

369
		HeapTupleHeaderSetXmin((HeapTupleHeader) item, FrozenTransactionId);
370 371
		((HeapTupleHeader) item)->t_infomask |= HEAP_XMIN_COMMITTED;

372
		HeapTupleHeaderSetXmin(tuple->t_data, FrozenTransactionId);
373 374 375
		tuple->t_data->t_infomask |= HEAP_XMIN_COMMITTED;
	}

376 377
	MarkBufferDirty(buf);

378
	/* XLOG stuff */
379
	if (RelationNeedsWAL(rel))
380
	{
381 382 383 384
		xl_seq_rec	xlrec;
		XLogRecPtr	recptr;
		XLogRecData rdata[2];
		Form_pg_sequence newseq = (Form_pg_sequence) GETSTRUCT(tuple);
385 386

		/* We do not log first nextval call, so "advance" sequence here */
387
		/* Note we are scribbling on local tuple, not the disk buffer */
388
		newseq->is_called = true;
389 390 391 392 393
		newseq->log_cnt = 0;

		xlrec.node = rel->rd_node;
		rdata[0].data = (char *) &xlrec;
		rdata[0].len = sizeof(xl_seq_rec);
394
		rdata[0].buffer = InvalidBuffer;
395 396
		rdata[0].next = &(rdata[1]);

397
		rdata[1].data = (char *) tuple->t_data;
398
		rdata[1].len = tuple->t_len;
399
		rdata[1].buffer = InvalidBuffer;
400 401
		rdata[1].next = NULL;

402
		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
403 404

		PageSetLSN(page, recptr);
405
		PageSetTLI(page, ThisTimeLineID);
406
	}
407

408
	END_CRIT_SECTION();
409

410
	UnlockReleaseBuffer(buf);
411 412
}

B
Bruce Momjian 已提交
413 414 415
/*
 * AlterSequence
 *
416
 * Modify the definition of a sequence relation
B
Bruce Momjian 已提交
417 418
 */
void
419
AlterSequence(AlterSeqStmt *stmt)
B
Bruce Momjian 已提交
420
{
421
	Oid			relid;
B
Bruce Momjian 已提交
422 423 424 425 426 427
	SeqTable	elm;
	Relation	seqrel;
	Buffer		buf;
	Page		page;
	Form_pg_sequence seq;
	FormData_pg_sequence new;
428
	List	   *owned_by;
B
Bruce Momjian 已提交
429 430

	/* open and AccessShareLock sequence */
431
	relid = RangeVarGetRelid(stmt->sequence, false);
432
	init_sequence(relid, &elm, &seqrel);
B
Bruce Momjian 已提交
433

434 435 436 437 438
	/* allow ALTER to sequence owner only */
	if (!pg_class_ownercheck(relid, GetUserId()))
		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
					   stmt->sequence->relname);

B
Bruce Momjian 已提交
439
	/* lock page' buffer and read tuple into new sequence structure */
440
	seq = read_info(elm, seqrel, &buf);
B
Bruce Momjian 已提交
441 442
	page = BufferGetPage(buf);

443 444 445 446
	/* Copy old values of options into workspace */
	memcpy(&new, seq, sizeof(FormData_pg_sequence));

	/* Check and set new values */
447
	init_params(stmt->options, false, &new, &owned_by);
B
Bruce Momjian 已提交
448

449 450 451 452
	/* Clear local cache so that we don't think we have cached numbers */
	/* Note that we do not change the currval() state */
	elm->cached = elm->last;

453
	/* Now okay to update the on-disk tuple */
454
	memcpy(seq, &new, sizeof(FormData_pg_sequence));
B
Bruce Momjian 已提交
455 456 457

	START_CRIT_SECTION();

458 459
	MarkBufferDirty(buf);

B
Bruce Momjian 已提交
460
	/* XLOG stuff */
461
	if (RelationNeedsWAL(seqrel))
B
Bruce Momjian 已提交
462 463 464 465 466 467 468 469
	{
		xl_seq_rec	xlrec;
		XLogRecPtr	recptr;
		XLogRecData rdata[2];

		xlrec.node = seqrel->rd_node;
		rdata[0].data = (char *) &xlrec;
		rdata[0].len = sizeof(xl_seq_rec);
470
		rdata[0].buffer = InvalidBuffer;
B
Bruce Momjian 已提交
471 472 473 474 475
		rdata[0].next = &(rdata[1]);

		rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
		rdata[1].len = ((PageHeader) page)->pd_special -
			((PageHeader) page)->pd_upper;
476
		rdata[1].buffer = InvalidBuffer;
B
Bruce Momjian 已提交
477 478
		rdata[1].next = NULL;

479
		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
B
Bruce Momjian 已提交
480 481

		PageSetLSN(page, recptr);
482
		PageSetTLI(page, ThisTimeLineID);
B
Bruce Momjian 已提交
483 484 485 486
	}

	END_CRIT_SECTION();

487
	UnlockReleaseBuffer(buf);
B
Bruce Momjian 已提交
488

489 490 491 492
	/* process OWNED BY if given */
	if (owned_by)
		process_owned_by(seqrel, owned_by);

B
Bruce Momjian 已提交
493 494 495
	relation_close(seqrel, NoLock);
}

496

497 498 499 500 501
/*
 * Note: nextval with a text argument is no longer exported as a pg_proc
 * entry, but we keep it around to ease porting of C code that may have
 * called the function directly.
 */
502 503
Datum
nextval(PG_FUNCTION_ARGS)
504
{
505
	text	   *seqin = PG_GETARG_TEXT_P(0);
506
	RangeVar   *sequence;
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
	Oid			relid;

	sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin));
	relid = RangeVarGetRelid(sequence, false);

	PG_RETURN_INT64(nextval_internal(relid));
}

Datum
nextval_oid(PG_FUNCTION_ARGS)
{
	Oid			relid = PG_GETARG_OID(0);

	PG_RETURN_INT64(nextval_internal(relid));
}

static int64
nextval_internal(Oid relid)
{
526
	SeqTable	elm;
527
	Relation	seqrel;
528
	Buffer		buf;
529
	Page		page;
530
	Form_pg_sequence seq;
531
	int64		incby,
532 533
				maxv,
				minv,
V
Vadim B. Mikheev 已提交
534 535 536 537
				cache,
				log,
				fetch,
				last;
538
	int64		result,
539 540
				next,
				rescnt = 0;
V
Vadim B. Mikheev 已提交
541
	bool		logit = false;
542

V
Vadim B. Mikheev 已提交
543
	/* open and AccessShareLock sequence */
544
	init_sequence(relid, &elm, &seqrel);
545

546 547
	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK &&
		pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
548 549
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
550
				 errmsg("permission denied for sequence %s",
551
						RelationGetRelationName(seqrel))));
552

553
	/* read-only transactions may only modify temp sequences */
554
	if (seqrel->rd_backend != MyBackendId)
555 556
		PreventCommandIfReadOnly("nextval()");

557 558
	if (elm->last != elm->cached)		/* some numbers were cached */
	{
559 560
		Assert(elm->last_valid);
		Assert(elm->increment != 0);
561
		elm->last += elm->increment;
562
		relation_close(seqrel, NoLock);
563
		last_used_seq = elm;
564
		return elm->last;
565
	}
566

567
	/* lock page' buffer and read tuple */
568
	seq = read_info(elm, seqrel, &buf);
569
	page = BufferGetPage(buf);
570

V
Vadim B. Mikheev 已提交
571
	last = next = result = seq->last_value;
572 573 574
	incby = seq->increment_by;
	maxv = seq->max_value;
	minv = seq->min_value;
V
Vadim B. Mikheev 已提交
575 576
	fetch = cache = seq->cache_value;
	log = seq->log_cnt;
577

578
	if (!seq->is_called)
V
Vadim B. Mikheev 已提交
579
	{
580
		rescnt++;				/* last_value if not called */
V
Vadim B. Mikheev 已提交
581 582 583
		fetch--;
		log--;
	}
584

585
	/*
B
Bruce Momjian 已提交
586 587 588
	 * Decide whether we should emit a WAL log record.	If so, force up the
	 * fetch count to grab SEQ_LOG_VALS more values than we actually need to
	 * cache.  (These will then be usable without logging.)
589
	 *
590 591 592 593
	 * If this is the first nextval after a checkpoint, we must force a new
	 * WAL record to be written anyway, else replay starting from the
	 * checkpoint would fail to advance the sequence past the logged values.
	 * In this case we may as well fetch extra values.
594
	 */
V
Vadim B. Mikheev 已提交
595 596
	if (log < fetch)
	{
597 598
		/* forced log to satisfy local demand for values */
		fetch = log = fetch + SEQ_LOG_VALS;
V
Vadim B. Mikheev 已提交
599 600
		logit = true;
	}
601 602 603 604 605 606 607 608 609 610 611
	else
	{
		XLogRecPtr	redoptr = GetRedoRecPtr();

		if (XLByteLE(PageGetLSN(page), redoptr))
		{
			/* last update of seq was before checkpoint */
			fetch = log = fetch + SEQ_LOG_VALS;
			logit = true;
		}
	}
V
Vadim B. Mikheev 已提交
612

B
Bruce Momjian 已提交
613
	while (fetch)				/* try to fetch cache [+ log ] numbers */
614
	{
615
		/*
B
Bruce Momjian 已提交
616 617
		 * Check MAXVALUE for ascending sequences and MINVALUE for descending
		 * sequences
618
		 */
619
		if (incby > 0)
620
		{
621
			/* ascending sequence */
622 623 624 625
			if ((maxv >= 0 && next > maxv - incby) ||
				(maxv < 0 && next + incby > maxv))
			{
				if (rescnt > 0)
V
Vadim B. Mikheev 已提交
626
					break;		/* stop fetching */
627
				if (!seq->is_cycled)
628
				{
B
Bruce Momjian 已提交
629 630
					char		buf[100];

631
					snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
632
					ereport(ERROR,
B
Bruce Momjian 已提交
633 634 635
						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
						   errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
								  RelationGetRelationName(seqrel), buf)));
636
				}
637 638 639 640 641 642 643
				next = minv;
			}
			else
				next += incby;
		}
		else
		{
644
			/* descending sequence */
645 646 647 648
			if ((minv < 0 && next < minv - incby) ||
				(minv >= 0 && next + incby < minv))
			{
				if (rescnt > 0)
V
Vadim B. Mikheev 已提交
649
					break;		/* stop fetching */
650
				if (!seq->is_cycled)
651
				{
B
Bruce Momjian 已提交
652 653
					char		buf[100];

654
					snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
655
					ereport(ERROR,
B
Bruce Momjian 已提交
656 657 658
						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
						   errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
								  RelationGetRelationName(seqrel), buf)));
659
				}
660 661 662 663 664
				next = maxv;
			}
			else
				next += incby;
		}
V
Vadim B. Mikheev 已提交
665 666 667 668 669 670
		fetch--;
		if (rescnt < cache)
		{
			log--;
			rescnt++;
			last = next;
B
Bruce Momjian 已提交
671 672
			if (rescnt == 1)	/* if it's first result - */
				result = next;	/* it's what to return */
V
Vadim B. Mikheev 已提交
673
		}
674 675
	}

676 677 678
	log -= fetch;				/* adjust for any unfetched numbers */
	Assert(log >= 0);

679 680
	/* save info in local cache */
	elm->last = result;			/* last returned number */
V
Vadim B. Mikheev 已提交
681
	elm->cached = last;			/* last fetched number */
682
	elm->last_valid = true;
V
Vadim B. Mikheev 已提交
683

684 685
	last_used_seq = elm;

686
	START_CRIT_SECTION();
687

688 689
	MarkBufferDirty(buf);

690
	/* XLOG stuff */
691
	if (logit && RelationNeedsWAL(seqrel))
V
Vadim B. Mikheev 已提交
692 693 694
	{
		xl_seq_rec	xlrec;
		XLogRecPtr	recptr;
B
Bruce Momjian 已提交
695
		XLogRecData rdata[2];
V
Vadim B. Mikheev 已提交
696

697
		xlrec.node = seqrel->rd_node;
B
Bruce Momjian 已提交
698
		rdata[0].data = (char *) &xlrec;
699
		rdata[0].len = sizeof(xl_seq_rec);
700
		rdata[0].buffer = InvalidBuffer;
701 702
		rdata[0].next = &(rdata[1]);

703
		/* set values that will be saved in xlog */
704
		seq->last_value = next;
705
		seq->is_called = true;
706
		seq->log_cnt = 0;
707

B
Bruce Momjian 已提交
708 709 710
		rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
		rdata[1].len = ((PageHeader) page)->pd_special -
			((PageHeader) page)->pd_upper;
711
		rdata[1].buffer = InvalidBuffer;
712 713
		rdata[1].next = NULL;

714
		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
V
Vadim B. Mikheev 已提交
715

716
		PageSetLSN(page, recptr);
717
		PageSetTLI(page, ThisTimeLineID);
V
Vadim B. Mikheev 已提交
718
	}
719

720
	/* update on-disk data */
V
Vadim B. Mikheev 已提交
721
	seq->last_value = last;		/* last fetched number */
722
	seq->is_called = true;
V
Vadim B. Mikheev 已提交
723
	seq->log_cnt = log;			/* how much is logged */
724

725
	END_CRIT_SECTION();
726

727
	UnlockReleaseBuffer(buf);
728

729 730
	relation_close(seqrel, NoLock);

731
	return result;
732 733
}

734
Datum
735
currval_oid(PG_FUNCTION_ARGS)
736
{
737 738
	Oid			relid = PG_GETARG_OID(0);
	int64		result;
739
	SeqTable	elm;
740
	Relation	seqrel;
741

V
Vadim B. Mikheev 已提交
742
	/* open and AccessShareLock sequence */
743
	init_sequence(relid, &elm, &seqrel);
744

745 746
	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK &&
		pg_class_aclcheck(elm->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
747 748
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
749
				 errmsg("permission denied for sequence %s",
750
						RelationGetRelationName(seqrel))));
751

752
	if (!elm->last_valid)
753 754
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
755
				 errmsg("currval of sequence \"%s\" is not yet defined in this session",
756
						RelationGetRelationName(seqrel))));
757 758 759

	result = elm->last;

760 761
	relation_close(seqrel, NoLock);

762
	PG_RETURN_INT64(result);
763 764
}

765 766 767 768 769 770 771 772 773 774 775 776
Datum
lastval(PG_FUNCTION_ARGS)
{
	Relation	seqrel;
	int64		result;

	if (last_used_seq == NULL)
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				 errmsg("lastval is not yet defined in this session")));

	/* Someone may have dropped the sequence since the last nextval() */
777
	if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(last_used_seq->relid)))
778 779 780 781
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				 errmsg("lastval is not yet defined in this session")));

782
	seqrel = open_share_lock(last_used_seq);
783 784

	/* nextval() must have already been called for this sequence */
785
	Assert(last_used_seq->last_valid);
786

787 788
	if (pg_class_aclcheck(last_used_seq->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK &&
		pg_class_aclcheck(last_used_seq->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
789 790 791 792 793 794 795
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("permission denied for sequence %s",
						RelationGetRelationName(seqrel))));

	result = last_used_seq->last;
	relation_close(seqrel, NoLock);
796

797 798 799
	PG_RETURN_INT64(result);
}

B
Bruce Momjian 已提交
800
/*
801 802 803 804
 * Main internal procedure that handles 2 & 3 arg forms of SETVAL.
 *
 * Note that the 3 arg version (which sets the is_called flag) is
 * only for use in pg_dump, and setting the is_called flag may not
B
Bruce Momjian 已提交
805
 * work if multiple users are attached to the database and referencing
806 807
 * the sequence (unlikely if pg_dump is restoring it).
 *
B
Bruce Momjian 已提交
808
 * It is necessary to have the 3 arg version so that pg_dump can
809 810 811 812
 * restore the state of a sequence exactly during data-only restores -
 * it is the only way to clear the is_called flag in an existing
 * sequence.
 */
B
Bruce Momjian 已提交
813
static void
814
do_setval(Oid relid, int64 next, bool iscalled)
M
 
Marc G. Fournier 已提交
815 816
{
	SeqTable	elm;
817
	Relation	seqrel;
818
	Buffer		buf;
819
	Form_pg_sequence seq;
M
 
Marc G. Fournier 已提交
820

821
	/* open and AccessShareLock sequence */
822
	init_sequence(relid, &elm, &seqrel);
823 824

	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
825 826
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
827
				 errmsg("permission denied for sequence %s",
828
						RelationGetRelationName(seqrel))));
M
 
Marc G. Fournier 已提交
829

830
	/* read-only transactions may only modify temp sequences */
831
	if (seqrel->rd_backend != MyBackendId)
832 833
		PreventCommandIfReadOnly("setval()");

834
	/* lock page' buffer and read tuple */
835
	seq = read_info(elm, seqrel, &buf);
M
 
Marc G. Fournier 已提交
836

837
	if ((next < seq->min_value) || (next > seq->max_value))
838
	{
B
Bruce Momjian 已提交
839 840 841 842
		char		bufv[100],
					bufm[100],
					bufx[100];

843 844 845
		snprintf(bufv, sizeof(bufv), INT64_FORMAT, next);
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, seq->min_value);
		snprintf(bufx, sizeof(bufx), INT64_FORMAT, seq->max_value);
846 847
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
848
				 errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)",
849 850
						bufv, RelationGetRelationName(seqrel),
						bufm, bufx)));
851
	}
M
 
Marc G. Fournier 已提交
852

853 854 855 856 857 858 859 860 861
	/* Set the currval() state only if iscalled = true */
	if (iscalled)
	{
		elm->last = next;		/* last returned number */
		elm->last_valid = true;
	}

	/* In any case, forget any future cached numbers */
	elm->cached = elm->last;
M
 
Marc G. Fournier 已提交
862

863
	START_CRIT_SECTION();
864

865 866
	MarkBufferDirty(buf);

867
	/* XLOG stuff */
868
	if (RelationNeedsWAL(seqrel))
V
Vadim B. Mikheev 已提交
869 870 871
	{
		xl_seq_rec	xlrec;
		XLogRecPtr	recptr;
B
Bruce Momjian 已提交
872
		XLogRecData rdata[2];
873
		Page		page = BufferGetPage(buf);
V
Vadim B. Mikheev 已提交
874

875
		xlrec.node = seqrel->rd_node;
B
Bruce Momjian 已提交
876
		rdata[0].data = (char *) &xlrec;
877
		rdata[0].len = sizeof(xl_seq_rec);
878
		rdata[0].buffer = InvalidBuffer;
879 880
		rdata[0].next = &(rdata[1]);

881
		/* set values that will be saved in xlog */
882
		seq->last_value = next;
883
		seq->is_called = true;
884
		seq->log_cnt = 0;
885

B
Bruce Momjian 已提交
886 887 888
		rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
		rdata[1].len = ((PageHeader) page)->pd_special -
			((PageHeader) page)->pd_upper;
889
		rdata[1].buffer = InvalidBuffer;
890 891
		rdata[1].next = NULL;

892
		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
893 894

		PageSetLSN(page, recptr);
895
		PageSetTLI(page, ThisTimeLineID);
V
Vadim B. Mikheev 已提交
896
	}
897

898 899
	/* save info in sequence relation */
	seq->last_value = next;		/* last fetched number */
900
	seq->is_called = iscalled;
901
	seq->log_cnt = (iscalled) ? 0 : 1;
902

903
	END_CRIT_SECTION();
M
 
Marc G. Fournier 已提交
904

905
	UnlockReleaseBuffer(buf);
906 907

	relation_close(seqrel, NoLock);
908 909
}

910 911 912 913
/*
 * Implement the 2 arg setval procedure.
 * See do_setval for discussion.
 */
914
Datum
915
setval_oid(PG_FUNCTION_ARGS)
916
{
917
	Oid			relid = PG_GETARG_OID(0);
918
	int64		next = PG_GETARG_INT64(1);
919

920
	do_setval(relid, next, true);
921

922
	PG_RETURN_INT64(next);
923 924
}

925 926 927 928
/*
 * Implement the 3 arg setval procedure.
 * See do_setval for discussion.
 */
929
Datum
930
setval3_oid(PG_FUNCTION_ARGS)
931
{
932
	Oid			relid = PG_GETARG_OID(0);
933
	int64		next = PG_GETARG_INT64(1);
934 935
	bool		iscalled = PG_GETARG_BOOL(2);

936
	do_setval(relid, next, iscalled);
937

938
	PG_RETURN_INT64(next);
M
 
Marc G. Fournier 已提交
939 940
}

941

942
/*
943 944
 * Open the sequence and acquire AccessShareLock if needed
 *
945
 * If we haven't touched the sequence already in this transaction,
B
Bruce Momjian 已提交
946
 * we need to acquire AccessShareLock.	We arrange for the lock to
947 948 949
 * be owned by the top transaction, so that we don't need to do it
 * more than once per xact.
 */
950 951
static Relation
open_share_lock(SeqTable seq)
952
{
953
	LocalTransactionId thislxid = MyProc->lxid;
954

955
	/* Get the lock if not already held in this xact */
956
	if (seq->lxid != thislxid)
957 958 959 960 961 962 963
	{
		ResourceOwner currentOwner;

		currentOwner = CurrentResourceOwner;
		PG_TRY();
		{
			CurrentResourceOwner = TopTransactionResourceOwner;
964
			LockRelationOid(seq->relid, AccessShareLock);
965 966 967 968 969 970 971 972 973 974
		}
		PG_CATCH();
		{
			/* Ensure CurrentResourceOwner is restored on error */
			CurrentResourceOwner = currentOwner;
			PG_RE_THROW();
		}
		PG_END_TRY();
		CurrentResourceOwner = currentOwner;

975
		/* Flag that we have a lock in the current xact */
976
		seq->lxid = thislxid;
977
	}
978 979 980

	/* We now know we have AccessShareLock, and can safely open the rel */
	return relation_open(seq->relid, NoLock);
981 982
}

983
/*
984
 * Given a relation OID, open and lock the sequence.  p_elm and p_rel are
985 986 987
 * output parameters.
 */
static void
988
init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
989
{
B
Bruce Momjian 已提交
990
	SeqTable	elm;
991
	Relation	seqrel;
992

993 994 995 996 997 998 999
	/* Look to see if we already have a seqtable entry for relation */
	for (elm = seqtab; elm != NULL; elm = elm->next)
	{
		if (elm->relid == relid)
			break;
	}

1000
	/*
1001
	 * Allocate new seqtable entry if we didn't find one.
1002
	 *
B
Bruce Momjian 已提交
1003 1004 1005
	 * NOTE: seqtable entries remain in the list for the life of a backend. If
	 * the sequence itself is deleted then the entry becomes wasted memory,
	 * but it's small enough that this should not matter.
B
Bruce Momjian 已提交
1006
	 */
1007
	if (elm == NULL)
1008
	{
1009
		/*
B
Bruce Momjian 已提交
1010 1011
		 * Time to make a new seqtable entry.  These entries live as long as
		 * the backend does, so we use plain malloc for them.
1012 1013
		 */
		elm = (SeqTable) malloc(sizeof(SeqTableData));
T
Tom Lane 已提交
1014
		if (elm == NULL)
1015 1016 1017
			ereport(ERROR,
					(errcode(ERRCODE_OUT_OF_MEMORY),
					 errmsg("out of memory")));
1018
		elm->relid = relid;
1019
		elm->filenode = InvalidOid;
1020
		elm->lxid = InvalidLocalTransactionId;
1021
		elm->last_valid = false;
1022 1023 1024
		elm->last = elm->cached = elm->increment = 0;
		elm->next = seqtab;
		seqtab = elm;
1025 1026
	}

1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
	/*
	 * Open the sequence relation.
	 */
	seqrel = open_share_lock(elm);

	if (seqrel->rd_rel->relkind != RELKIND_SEQUENCE)
		ereport(ERROR,
				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
				 errmsg("\"%s\" is not a sequence",
						RelationGetRelationName(seqrel))));
1037

1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
	/*
	 * If the sequence has been transactionally replaced since we last saw it,
	 * discard any cached-but-unissued values.  We do not touch the currval()
	 * state, however.
	 */
	if (seqrel->rd_rel->relfilenode != elm->filenode)
	{
		elm->filenode = seqrel->rd_rel->relfilenode;
		elm->cached = elm->last;
	}

	/* Return results */
1050 1051
	*p_elm = elm;
	*p_rel = seqrel;
1052 1053 1054
}


1055 1056
/* Given an opened relation, lock the page buffer and find the tuple */
static Form_pg_sequence
1057
read_info(SeqTable elm, Relation rel, Buffer *buf)
1058
{
1059
	Page		page;
1060 1061 1062 1063
	ItemId		lp;
	HeapTupleData tuple;
	sequence_magic *sm;
	Form_pg_sequence seq;
1064

1065 1066 1067
	*buf = ReadBuffer(rel, 0);
	LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);

1068
	page = BufferGetPage(*buf);
1069 1070 1071
	sm = (sequence_magic *) PageGetSpecialPointer(page);

	if (sm->magic != SEQ_MAGIC)
1072 1073
		elog(ERROR, "bad magic number in sequence \"%s\": %08X",
			 RelationGetRelationName(rel), sm->magic);
1074 1075

	lp = PageGetItemId(page, FirstOffsetNumber);
1076
	Assert(ItemIdIsNormal(lp));
1077
	tuple.t_data = (HeapTupleHeader) PageGetItem(page, lp);
1078 1079 1080

	seq = (Form_pg_sequence) GETSTRUCT(&tuple);

1081
	/* this is a handy place to update our copy of the increment */
1082 1083 1084
	elm->increment = seq->increment_by;

	return seq;
1085 1086
}

1087 1088
/*
 * init_params: process the options list of CREATE or ALTER SEQUENCE,
1089 1090
 * and store the values into appropriate fields of *new.  Also set
 * *owned_by to any OWNED BY option, or to NIL if there is none.
1091 1092 1093 1094
 *
 * If isInit is true, fill any unspecified options with default values;
 * otherwise, do not change existing options that aren't explicitly overridden.
 */
1095
static void
1096
init_params(List *options, bool isInit,
1097
			Form_pg_sequence new, List **owned_by)
1098
{
1099 1100
	DefElem    *start_value = NULL;
	DefElem    *restart_value = NULL;
1101 1102 1103 1104
	DefElem    *increment_by = NULL;
	DefElem    *max_value = NULL;
	DefElem    *min_value = NULL;
	DefElem    *cache_value = NULL;
1105
	DefElem    *is_cycled = NULL;
1106
	ListCell   *option;
1107

1108 1109
	*owned_by = NIL;

B
Bruce Momjian 已提交
1110
	foreach(option, options)
1111
	{
1112
		DefElem    *defel = (DefElem *) lfirst(option);
1113

1114
		if (strcmp(defel->defname, "increment") == 0)
1115 1116
		{
			if (increment_by)
1117 1118 1119
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1120
			increment_by = defel;
1121
		}
1122 1123
		else if (strcmp(defel->defname, "start") == 0)
		{
1124
			if (start_value)
1125 1126 1127
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1128
			start_value = defel;
1129 1130
		}
		else if (strcmp(defel->defname, "restart") == 0)
1131
		{
1132
			if (restart_value)
1133 1134 1135
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1136
			restart_value = defel;
1137
		}
1138
		else if (strcmp(defel->defname, "maxvalue") == 0)
1139 1140
		{
			if (max_value)
1141 1142 1143
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1144
			max_value = defel;
1145
		}
1146
		else if (strcmp(defel->defname, "minvalue") == 0)
1147 1148
		{
			if (min_value)
1149 1150 1151
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1152
			min_value = defel;
1153
		}
1154
		else if (strcmp(defel->defname, "cache") == 0)
1155 1156
		{
			if (cache_value)
1157 1158 1159
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1160
			cache_value = defel;
1161
		}
1162
		else if (strcmp(defel->defname, "cycle") == 0)
1163
		{
1164
			if (is_cycled)
1165 1166 1167
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1168
			is_cycled = defel;
1169
		}
1170 1171 1172 1173 1174 1175 1176 1177
		else if (strcmp(defel->defname, "owned_by") == 0)
		{
			if (*owned_by)
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
			*owned_by = defGetQualifiedName(defel);
		}
1178
		else
1179
			elog(ERROR, "option \"%s\" not recognized",
1180 1181 1182
				 defel->defname);
	}

B
Bruce Momjian 已提交
1183
	/* INCREMENT BY */
1184
	if (increment_by != NULL)
B
Bruce Momjian 已提交
1185 1186
	{
		new->increment_by = defGetInt64(increment_by);
1187 1188 1189
		if (new->increment_by == 0)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1190
					 errmsg("INCREMENT must not be zero")));
B
Bruce Momjian 已提交
1191
	}
1192 1193 1194 1195
	else if (isInit)
		new->increment_by = 1;

	/* CYCLE */
1196
	if (is_cycled != NULL)
1197 1198
	{
		new->is_cycled = intVal(is_cycled->arg);
1199
		Assert(BoolIsValid(new->is_cycled));
1200 1201 1202
	}
	else if (isInit)
		new->is_cycled = false;
1203

1204
	/* MAXVALUE (null arg means NO MAXVALUE) */
1205
	if (max_value != NULL && max_value->arg)
1206
		new->max_value = defGetInt64(max_value);
1207
	else if (isInit || max_value != NULL)
1208
	{
1209
		if (new->increment_by > 0)
B
Bruce Momjian 已提交
1210
			new->max_value = SEQ_MAXVALUE;		/* ascending seq */
1211
		else
B
Bruce Momjian 已提交
1212
			new->max_value = -1;	/* descending seq */
1213
	}
1214

1215
	/* MINVALUE (null arg means NO MINVALUE) */
1216
	if (min_value != NULL && min_value->arg)
1217
		new->min_value = defGetInt64(min_value);
1218
	else if (isInit || min_value != NULL)
1219
	{
1220
		if (new->increment_by > 0)
B
Bruce Momjian 已提交
1221
			new->min_value = 1; /* ascending seq */
1222
		else
B
Bruce Momjian 已提交
1223
			new->min_value = SEQ_MINVALUE;		/* descending seq */
1224
	}
1225

1226
	/* crosscheck min/max */
1227
	if (new->min_value >= new->max_value)
1228
	{
B
Bruce Momjian 已提交
1229 1230 1231
		char		bufm[100],
					bufx[100];

1232 1233
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
		snprintf(bufx, sizeof(bufx), INT64_FORMAT, new->max_value);
1234 1235 1236 1237
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("MINVALUE (%s) must be less than MAXVALUE (%s)",
						bufm, bufx)));
1238
	}
1239

1240 1241 1242
	/* START WITH */
	if (start_value != NULL)
		new->start_value = defGetInt64(start_value);
1243
	else if (isInit)
1244
	{
1245
		if (new->increment_by > 0)
1246
			new->start_value = new->min_value;	/* ascending seq */
1247
		else
1248
			new->start_value = new->max_value;	/* descending seq */
1249
	}
1250

1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
	/* crosscheck START */
	if (new->start_value < new->min_value)
	{
		char		bufs[100],
					bufm[100];

		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->start_value);
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("START value (%s) cannot be less than MINVALUE (%s)",
						bufs, bufm)));
	}
	if (new->start_value > new->max_value)
	{
		char		bufs[100],
					bufm[100];

		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->start_value);
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
			  errmsg("START value (%s) cannot be greater than MAXVALUE (%s)",
					 bufs, bufm)));
	}

1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294
	/* RESTART [WITH] */
	if (restart_value != NULL)
	{
		if (restart_value->arg != NULL)
			new->last_value = defGetInt64(restart_value);
		else
			new->last_value = new->start_value;
		new->is_called = false;
		new->log_cnt = 1;
	}
	else if (isInit)
	{
		new->last_value = new->start_value;
		new->is_called = false;
		new->log_cnt = 1;
	}

	/* crosscheck RESTART (or current value, if changing MIN/MAX) */
1295
	if (new->last_value < new->min_value)
1296
	{
B
Bruce Momjian 已提交
1297 1298 1299
		char		bufs[100],
					bufm[100];

1300 1301
		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
1302 1303
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1304 1305
			   errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)",
					  bufs, bufm)));
1306
	}
1307
	if (new->last_value > new->max_value)
1308
	{
B
Bruce Momjian 已提交
1309 1310 1311
		char		bufs[100],
					bufm[100];

1312 1313
		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
1314 1315
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1316 1317
			errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)",
				   bufs, bufm)));
1318
	}
1319

B
Bruce Momjian 已提交
1320
	/* CACHE */
1321
	if (cache_value != NULL)
1322
	{
1323 1324 1325 1326
		new->cache_value = defGetInt64(cache_value);
		if (new->cache_value <= 0)
		{
			char		buf[100];
B
Bruce Momjian 已提交
1327

1328 1329 1330 1331 1332 1333
			snprintf(buf, sizeof(buf), INT64_FORMAT, new->cache_value);
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("CACHE (%s) must be greater than zero",
							buf)));
		}
1334
	}
1335 1336
	else if (isInit)
		new->cache_value = 1;
1337 1338
}

1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
/*
 * Process an OWNED BY option for CREATE/ALTER SEQUENCE
 *
 * Ownership permissions on the sequence are already checked,
 * but if we are establishing a new owned-by dependency, we must
 * enforce that the referenced table has the same owner and namespace
 * as the sequence.
 */
static void
process_owned_by(Relation seqrel, List *owned_by)
{
	int			nnames;
	Relation	tablerel;
	AttrNumber	attnum;

	nnames = list_length(owned_by);
	Assert(nnames > 0);
	if (nnames == 1)
	{
		/* Must be OWNED BY NONE */
		if (strcmp(strVal(linitial(owned_by)), "none") != 0)
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("invalid OWNED BY option"),
B
Bruce Momjian 已提交
1363
				errhint("Specify OWNED BY table.column or OWNED BY NONE.")));
1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
		tablerel = NULL;
		attnum = 0;
	}
	else
	{
		List	   *relname;
		char	   *attrname;
		RangeVar   *rel;

		/* Separate relname and attr name */
		relname = list_truncate(list_copy(owned_by), nnames - 1);
		attrname = strVal(lfirst(list_tail(owned_by)));

		/* Open and lock rel to ensure it won't go away meanwhile */
		rel = makeRangeVarFromNameList(relname);
		tablerel = relation_openrv(rel, AccessShareLock);

		/* Must be a regular table */
		if (tablerel->rd_rel->relkind != RELKIND_RELATION)
			ereport(ERROR,
					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
					 errmsg("referenced relation \"%s\" is not a table",
							RelationGetRelationName(tablerel))));

		/* We insist on same owner and schema */
		if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
			ereport(ERROR,
					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
B
Bruce Momjian 已提交
1392
					 errmsg("sequence must have same owner as table it is linked to")));
1393 1394 1395
		if (RelationGetNamespace(seqrel) != RelationGetNamespace(tablerel))
			ereport(ERROR,
					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
P
Peter Eisentraut 已提交
1396
					 errmsg("sequence must be in same schema as table it is linked to")));
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407

		/* Now, fetch the attribute number from the system cache */
		attnum = get_attnum(RelationGetRelid(tablerel), attrname);
		if (attnum == InvalidAttrNumber)
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_COLUMN),
					 errmsg("column \"%s\" of relation \"%s\" does not exist",
							attrname, RelationGetRelationName(tablerel))));
	}

	/*
B
Bruce Momjian 已提交
1408 1409
	 * OK, we are ready to update pg_depend.  First remove any existing AUTO
	 * dependencies for the sequence, then optionally add a new one.
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
	 */
	markSequenceUnowned(RelationGetRelid(seqrel));

	if (tablerel)
	{
		ObjectAddress refobject,
					depobject;

		refobject.classId = RelationRelationId;
		refobject.objectId = RelationGetRelid(tablerel);
		refobject.objectSubId = attnum;
		depobject.classId = RelationRelationId;
		depobject.objectId = RelationGetRelid(seqrel);
		depobject.objectSubId = 0;
		recordDependencyOn(&depobject, &refobject, DEPENDENCY_AUTO);
	}

	/* Done, but hold lock until commit */
	if (tablerel)
		relation_close(tablerel, NoLock);
}

V
Vadim B. Mikheev 已提交
1432

1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
/*
 * Return sequence parameters, for use by information schema
 */
Datum
pg_sequence_parameters(PG_FUNCTION_ARGS)
{
	Oid			relid = PG_GETARG_OID(0);
	TupleDesc	tupdesc;
	Datum		values[5];
	bool		isnull[5];
	SeqTable	elm;
	Relation	seqrel;
	Buffer		buf;
	Form_pg_sequence seq;

	/* open and AccessShareLock sequence */
	init_sequence(relid, &elm, &seqrel);

	if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_UPDATE | ACL_USAGE) != ACLCHECK_OK)
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("permission denied for sequence %s",
						RelationGetRelationName(seqrel))));

	tupdesc = CreateTemplateTupleDesc(5, false);
	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "start_value", INT8OID, -1, 0);
	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "minimum_value", INT8OID, -1, 0);
	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "maximum_value", INT8OID, -1, 0);
	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "increment", INT8OID, -1, 0);
	TupleDescInitEntry(tupdesc, (AttrNumber) 5, "cycle_option", BOOLOID, -1, 0);

	BlessTupleDesc(tupdesc);

	memset(isnull, 0, sizeof(isnull));

	seq = read_info(elm, seqrel, &buf);

	values[0] = Int64GetDatum(seq->start_value);
	values[1] = Int64GetDatum(seq->min_value);
	values[2] = Int64GetDatum(seq->max_value);
	values[3] = Int64GetDatum(seq->increment_by);
	values[4] = BoolGetDatum(seq->is_cycled);

	UnlockReleaseBuffer(buf);
	relation_close(seqrel, NoLock);

	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
}


B
Bruce Momjian 已提交
1483 1484
void
seq_redo(XLogRecPtr lsn, XLogRecord *record)
V
Vadim B. Mikheev 已提交
1485
{
B
Bruce Momjian 已提交
1486 1487 1488 1489 1490 1491
	uint8		info = record->xl_info & ~XLR_INFO_MASK;
	Buffer		buffer;
	Page		page;
	char	   *item;
	Size		itemsz;
	xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
1492
	sequence_magic *sm;
V
Vadim B. Mikheev 已提交
1493

1494 1495 1496
	/* Backup blocks are not used in seq records */
	Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));

1497
	if (info != XLOG_SEQ_LOG)
1498
		elog(PANIC, "seq_redo: unknown op code %u", info);
V
Vadim B. Mikheev 已提交
1499

1500
	buffer = XLogReadBuffer(xlrec->node, 0, true);
1501
	Assert(BufferIsValid(buffer));
V
Vadim B. Mikheev 已提交
1502 1503
	page = (Page) BufferGetPage(buffer);

1504 1505
	/* Always reinit the page and reinstall the magic number */
	/* See comments in DefineSequence */
1506 1507 1508
	PageInit((Page) page, BufferGetPageSize(buffer), sizeof(sequence_magic));
	sm = (sequence_magic *) PageGetSpecialPointer(page);
	sm->magic = SEQ_MAGIC;
V
Vadim B. Mikheev 已提交
1509

B
Bruce Momjian 已提交
1510
	item = (char *) xlrec + sizeof(xl_seq_rec);
1511 1512
	itemsz = record->xl_len - sizeof(xl_seq_rec);
	itemsz = MAXALIGN(itemsz);
B
Bruce Momjian 已提交
1513
	if (PageAddItem(page, (Item) item, itemsz,
1514
					FirstOffsetNumber, false, false) == InvalidOffsetNumber)
1515
		elog(PANIC, "seq_redo: failed to add item to page");
V
Vadim B. Mikheev 已提交
1516 1517

	PageSetLSN(page, lsn);
1518
	PageSetTLI(page, ThisTimeLineID);
1519 1520
	MarkBufferDirty(buffer);
	UnlockReleaseBuffer(buffer);
V
Vadim B. Mikheev 已提交
1521 1522
}

B
Bruce Momjian 已提交
1523
void
1524
seq_desc(StringInfo buf, uint8 xl_info, char *rec)
V
Vadim B. Mikheev 已提交
1525
{
B
Bruce Momjian 已提交
1526 1527
	uint8		info = xl_info & ~XLR_INFO_MASK;
	xl_seq_rec *xlrec = (xl_seq_rec *) rec;
V
Vadim B. Mikheev 已提交
1528 1529

	if (info == XLOG_SEQ_LOG)
1530
		appendStringInfo(buf, "log: ");
V
Vadim B. Mikheev 已提交
1531 1532
	else
	{
1533
		appendStringInfo(buf, "UNKNOWN");
V
Vadim B. Mikheev 已提交
1534 1535 1536
		return;
	}

1537
	appendStringInfo(buf, "rel %u/%u/%u",
B
Bruce Momjian 已提交
1538
			   xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
V
Vadim B. Mikheev 已提交
1539
}