sequence.c 28.3 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * sequence.c
4
 *	  PostgreSQL sequences support code.
5
 *
B
Bruce Momjian 已提交
6
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 8 9 10
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.97 2003/07/20 21:56:32 tgl Exp $
12
 *
13 14
 *-------------------------------------------------------------------------
 */
15
#include "postgres.h"
16

17
#include "access/heapam.h"
18
#include "catalog/namespace.h"
19
#include "catalog/pg_type.h"
20
#include "commands/defrem.h"
21
#include "commands/tablecmds.h"
22
#include "commands/sequence.h"
B
Bruce Momjian 已提交
23
#include "miscadmin.h"
24
#include "utils/acl.h"
B
Bruce Momjian 已提交
25
#include "utils/builtins.h"
26

V
Vadim B. Mikheev 已提交
27
/*
28
 * We don't want to log each fetching of a value from a sequence,
V
Vadim B. Mikheev 已提交
29 30 31
 * 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 已提交
32
#define SEQ_LOG_VALS	32
33

34 35 36 37 38
/*
 * The "special area" of a sequence's buffer page looks like this.
 */
#define SEQ_MAGIC	  0x1717

39 40
typedef struct sequence_magic
{
41
	uint32		magic;
42
} sequence_magic;
43

44 45 46 47 48 49
/*
 * 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 已提交
50
 * XXX We use linear search to find pre-existing SeqTable entries.	This is
51 52 53
 * 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.
 */
54 55
typedef struct SeqTableData
{
56 57 58 59 60 61 62
	struct SeqTableData *next;	/* link to next SeqTable object */
	Oid			relid;			/* pg_class OID of this sequence */
	TransactionId xid;			/* xact in which we last did a seq op */
	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 */
63
} SeqTableData;
64 65 66

typedef SeqTableData *SeqTable;

67
static SeqTable seqtab = NULL;	/* Head of list of SeqTable items */
68

69

70 71 72 73
static void init_sequence(RangeVar *relation,
						  SeqTable *p_elm, Relation *p_rel);
static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf);
static void init_params(List *options, Form_pg_sequence new);
74
static void do_setval(RangeVar *sequence, int64 next, bool iscalled);
75 76

/*
B
Bruce Momjian 已提交
77
 * DefineSequence
78
 *				Creates a new sequence relation
79 80
 */
void
81
DefineSequence(CreateSeqStmt *seq)
82
{
83
	FormData_pg_sequence new;
84
	CreateStmt *stmt = makeNode(CreateStmt);
85
	Oid			seqoid;
86 87 88
	Relation	rel;
	Buffer		buf;
	PageHeader	page;
89
	sequence_magic *sm;
90 91 92 93 94
	HeapTuple	tuple;
	TupleDesc	tupDesc;
	Datum		value[SEQ_COL_LASTCOL];
	char		null[SEQ_COL_LASTCOL];
	int			i;
95
	NameData	name;
96

B
Bruce Momjian 已提交
97
	/* Values are NULL (or false) by default */
B
Bruce Momjian 已提交
98 99 100 101 102
	new.last_value = 0;
	new.increment_by = 0;
	new.max_value = 0; 
	new.min_value = 0;
	new.cache_value = 0;
B
Bruce Momjian 已提交
103 104
	new.is_cycled = false; 

105
	/* Check and set values */
106
	init_params(seq->options, &new);
107 108

	/*
109
	 * Create relation (and fill *null & *value)
110 111 112
	 */
	stmt->tableElts = NIL;
	for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
113
	{
114 115 116
		ColumnDef  *coldef;
		TypeName   *typnam;

117 118
		typnam = makeNode(TypeName);
		typnam->setof = FALSE;
119
		typnam->arrayBounds = NIL;
B
Bruce Momjian 已提交
120
		typnam->typmod = -1;
121

122 123
		coldef = makeNode(ColumnDef);
		coldef->typename = typnam;
124 125
		coldef->inhcount = 0;
		coldef->is_local = true;
126
		coldef->is_not_null = true;
127 128
		coldef->raw_default = NULL;
		coldef->cooked_default = NULL;
129 130 131
		coldef->constraints = NIL;
		coldef->support = NULL;

132 133 134 135
		null[i - 1] = ' ';

		switch (i)
		{
136
			case SEQ_COL_NAME:
137
				typnam->typeid = NAMEOID;
138
				coldef->colname = "sequence_name";
139
				namestrcpy(&name, seq->sequence->relname);
140
				value[i - 1] = NameGetDatum(&name);
141 142
				break;
			case SEQ_COL_LASTVAL:
143
				typnam->typeid = INT8OID;
144
				coldef->colname = "last_value";
145
				value[i - 1] = Int64GetDatumFast(new.last_value);
146 147
				break;
			case SEQ_COL_INCBY:
148
				typnam->typeid = INT8OID;
149
				coldef->colname = "increment_by";
150
				value[i - 1] = Int64GetDatumFast(new.increment_by);
151 152
				break;
			case SEQ_COL_MAXVALUE:
153
				typnam->typeid = INT8OID;
154
				coldef->colname = "max_value";
155
				value[i - 1] = Int64GetDatumFast(new.max_value);
156 157
				break;
			case SEQ_COL_MINVALUE:
158
				typnam->typeid = INT8OID;
159
				coldef->colname = "min_value";
160
				value[i - 1] = Int64GetDatumFast(new.min_value);
161 162
				break;
			case SEQ_COL_CACHE:
163
				typnam->typeid = INT8OID;
164
				coldef->colname = "cache_value";
165
				value[i - 1] = Int64GetDatumFast(new.cache_value);
166
				break;
V
Vadim B. Mikheev 已提交
167
			case SEQ_COL_LOG:
168
				typnam->typeid = INT8OID;
V
Vadim B. Mikheev 已提交
169
				coldef->colname = "log_cnt";
170
				value[i - 1] = Int64GetDatum((int64) 1);
V
Vadim B. Mikheev 已提交
171
				break;
172
			case SEQ_COL_CYCLE:
173
				typnam->typeid = BOOLOID;
174
				coldef->colname = "is_cycled";
175
				value[i - 1] = BoolGetDatum(new.is_cycled);
176 177
				break;
			case SEQ_COL_CALLED:
178
				typnam->typeid = BOOLOID;
179
				coldef->colname = "is_called";
180
				value[i - 1] = BoolGetDatum(false);
181
				break;
182 183 184 185
		}
		stmt->tableElts = lappend(stmt->tableElts, coldef);
	}

186 187
	stmt->relation = seq->sequence;
	stmt->inhRelations = NIL;
188
	stmt->constraints = NIL;
189
	stmt->hasoids = false;
190
	stmt->oncommit = ONCOMMIT_NOOP;
191

192
	seqoid = DefineRelation(stmt, RELKIND_SEQUENCE);
193

194
	rel = heap_open(seqoid, AccessExclusiveLock);
195
	tupDesc = RelationGetDescr(rel);
196

197 198
	/* Initialize first page of relation with special magic number */

199 200 201
	buf = ReadBuffer(rel, P_NEW);

	if (!BufferIsValid(buf))
202
		elog(ERROR, "ReadBuffer failed");
203

204 205
	Assert(BufferGetBlockNumber(buf) == 0);

206 207 208 209 210 211
	page = (PageHeader) BufferGetPage(buf);

	PageInit((Page) page, BufferGetPageSize(buf), sizeof(sequence_magic));
	sm = (sequence_magic *) PageGetSpecialPointer(page);
	sm->magic = SEQ_MAGIC;

212 213 214
	/* hack: ensure heap_insert will insert on the just-created page */
	rel->rd_targblock = 0;

215
	/* Now form & insert sequence tuple */
216
	tuple = heap_formtuple(tupDesc, value, null);
217
	simple_heap_insert(rel, tuple);
218

219 220
	Assert(ItemPointerGetOffsetNumber(&(tuple->t_self)) == FirstOffsetNumber);

221
	/*
222 223 224
	 * Two special hacks here:
	 *
	 * 1. Since VACUUM does not process sequences, we have to force the tuple
B
Bruce Momjian 已提交
225 226
	 * to have xmin = FrozenTransactionId now.	Otherwise it would become
	 * invisible to SELECTs after 2G transactions.	It is okay to do this
227 228 229 230 231 232
	 * because if the current transaction aborts, no other xact will ever
	 * examine the sequence tuple anyway.
	 *
	 * 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
B
Bruce Momjian 已提交
233
	 * would re-init page and sequence magic number would be lost.	This
234
	 * means two log records instead of one :-(
235
	 */
236
	LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
237

238
	START_CRIT_SECTION();
239 240 241

	{
		/*
B
Bruce Momjian 已提交
242 243 244 245 246 247
		 * Note that the "tuple" structure is still just a local tuple
		 * record created by heap_formtuple; its t_data pointer doesn't
		 * point at the 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.
248 249 250 251 252 253 254
		 */
		ItemId		itemId;
		Item		item;

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

255
		HeapTupleHeaderSetXmin((HeapTupleHeader) item, FrozenTransactionId);
256 257
		((HeapTupleHeader) item)->t_infomask |= HEAP_XMIN_COMMITTED;

258
		HeapTupleHeaderSetXmin(tuple->t_data, FrozenTransactionId);
259 260 261
		tuple->t_data->t_infomask |= HEAP_XMIN_COMMITTED;
	}

262 263
	/* XLOG stuff */
	if (!rel->rd_istemp)
264
	{
265 266 267 268
		xl_seq_rec	xlrec;
		XLogRecPtr	recptr;
		XLogRecData rdata[2];
		Form_pg_sequence newseq = (Form_pg_sequence) GETSTRUCT(tuple);
269 270

		/* We do not log first nextval call, so "advance" sequence here */
271
		/* Note we are scribbling on local tuple, not the disk buffer */
272
		newseq->is_called = true;
273 274 275 276 277 278 279 280 281
		newseq->log_cnt = 0;

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

		rdata[1].buffer = InvalidBuffer;
282
		rdata[1].data = (char *) tuple->t_data;
283 284 285 286 287 288 289 290
		rdata[1].len = tuple->t_len;
		rdata[1].next = NULL;

		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);

		PageSetLSN(page, recptr);
		PageSetSUI(page, ThisStartUpID);
	}
291

292
	END_CRIT_SECTION();
293

294
	LockBuffer(buf, BUFFER_LOCK_UNLOCK);
295 296
	WriteBuffer(buf);
	heap_close(rel, NoLock);
297 298
}

B
Bruce Momjian 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
/*
 * AlterSequence
 *
 * Modify the defition of a sequence relation 
 */
void
AlterSequence(AlterSeqStmt *stmt)
{
	SeqTable	elm;
	Relation	seqrel;
	Buffer		buf;
	Page		page;
	Form_pg_sequence seq;
	FormData_pg_sequence new;

	/* open and AccessShareLock sequence */
315
	init_sequence(stmt->sequence, &elm, &seqrel);
B
Bruce Momjian 已提交
316 317 318 319 320 321

	/* Allow DROP to sequence owner only*/
	if (!pg_class_ownercheck(elm->relid, GetUserId()))
		aclcheck_error(ACLCHECK_NOT_OWNER, stmt->sequence->relname);

	/* lock page' buffer and read tuple into new sequence structure */
322
	seq = read_info(elm, seqrel, &buf);
B
Bruce Momjian 已提交
323 324 325 326 327 328 329 330 331 332
	page = BufferGetPage(buf);

	new.increment_by = seq->increment_by;
	new.max_value = seq->max_value; 
	new.min_value = seq->min_value;
	new.cache_value = seq->cache_value;
	new.is_cycled = seq->is_cycled;
	new.last_value = seq->last_value;

	/* Check and set values */
333
	init_params(stmt->options, &new);
B
Bruce Momjian 已提交
334 335 336 337 338 339 340 341 342 343 344 345 346

	seq->increment_by = new.increment_by;
	seq->max_value = new.max_value;
	seq->min_value = new.min_value;
	seq->cache_value = new.cache_value;
	seq->is_cycled = new.is_cycled;
	if (seq->last_value != new.last_value)
	{
		seq->last_value = new.last_value;
		seq->is_called = false;
		seq->log_cnt = 1;
	}

347 348 349 350 351
	/* save info in local cache */
	elm->last = new.last_value;		/* last returned number */
	elm->cached = new.last_value;	/* last cached number (forget cached
									 * values) */

B
Bruce Momjian 已提交
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
	START_CRIT_SECTION();

	/* XLOG stuff */
	if (!seqrel->rd_istemp)
	{
		xl_seq_rec	xlrec;
		XLogRecPtr	recptr;
		XLogRecData rdata[2];

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

		rdata[1].buffer = InvalidBuffer;
		rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
		rdata[1].len = ((PageHeader) page)->pd_special -
			((PageHeader) page)->pd_upper;
		rdata[1].next = NULL;

		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);

		PageSetLSN(page, recptr);
		PageSetSUI(page, ThisStartUpID);
	}

	END_CRIT_SECTION();

	LockBuffer(buf, BUFFER_LOCK_UNLOCK);

	WriteBuffer(buf);

	relation_close(seqrel, NoLock);
}

388

389 390
Datum
nextval(PG_FUNCTION_ARGS)
391
{
392
	text	   *seqin = PG_GETARG_TEXT_P(0);
393
	RangeVar   *sequence;
394
	SeqTable	elm;
395
	Relation	seqrel;
396
	Buffer		buf;
397
	Page		page;
398
	Form_pg_sequence seq;
399
	int64		incby,
400 401
				maxv,
				minv,
V
Vadim B. Mikheev 已提交
402 403 404 405
				cache,
				log,
				fetch,
				last;
406
	int64		result,
407 408
				next,
				rescnt = 0;
V
Vadim B. Mikheev 已提交
409
	bool		logit = false;
410

411
	sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
B
Bruce Momjian 已提交
412
															 "nextval"));
413

V
Vadim B. Mikheev 已提交
414
	/* open and AccessShareLock sequence */
415
	init_sequence(sequence, &elm, &seqrel);
416

417
	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
418 419 420 421
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("%s.nextval: permission denied",
						sequence->relname)));
422 423 424 425

	if (elm->last != elm->cached)		/* some numbers were cached */
	{
		elm->last += elm->increment;
426
		relation_close(seqrel, NoLock);
427
		PG_RETURN_INT64(elm->last);
428
	}
429

430
	/* lock page' buffer and read tuple */
431
	seq = read_info(elm, seqrel, &buf);
432
	page = BufferGetPage(buf);
433

V
Vadim B. Mikheev 已提交
434
	last = next = result = seq->last_value;
435 436 437
	incby = seq->increment_by;
	maxv = seq->max_value;
	minv = seq->min_value;
V
Vadim B. Mikheev 已提交
438 439
	fetch = cache = seq->cache_value;
	log = seq->log_cnt;
440

441
	if (!seq->is_called)
V
Vadim B. Mikheev 已提交
442
	{
443
		rescnt++;				/* last_value if not called */
V
Vadim B. Mikheev 已提交
444 445 446
		fetch--;
		log--;
	}
447

448
	/*
B
Bruce Momjian 已提交
449
	 * Decide whether we should emit a WAL log record.	If so, force up
450 451 452
	 * the fetch count to grab SEQ_LOG_VALS more values than we actually
	 * need to cache.  (These will then be usable without logging.)
	 *
B
Bruce Momjian 已提交
453 454
	 * 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
455
	 * checkpoint would fail to advance the sequence past the logged
B
Bruce Momjian 已提交
456
	 * values.	In this case we may as well fetch extra values.
457
	 */
V
Vadim B. Mikheev 已提交
458 459
	if (log < fetch)
	{
460 461
		/* forced log to satisfy local demand for values */
		fetch = log = fetch + SEQ_LOG_VALS;
V
Vadim B. Mikheev 已提交
462 463
		logit = true;
	}
464 465 466 467 468 469 470 471 472 473 474
	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 已提交
475

B
Bruce Momjian 已提交
476
	while (fetch)				/* try to fetch cache [+ log ] numbers */
477
	{
478 479 480 481
		/*
		 * Check MAXVALUE for ascending sequences and MINVALUE for
		 * descending sequences
		 */
482
		if (incby > 0)
483
		{
484
			/* ascending sequence */
485 486 487 488
			if ((maxv >= 0 && next > maxv - incby) ||
				(maxv < 0 && next + incby > maxv))
			{
				if (rescnt > 0)
V
Vadim B. Mikheev 已提交
489
					break;		/* stop fetching */
490
				if (!seq->is_cycled)
491
				{
B
Bruce Momjian 已提交
492 493
					char		buf[100];

494
					snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
495 496 497 498
					ereport(ERROR,
							(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
							 errmsg("%s.nextval: reached MAXVALUE (%s)",
									sequence->relname, buf)));
499
				}
500 501 502 503 504 505 506
				next = minv;
			}
			else
				next += incby;
		}
		else
		{
507
			/* descending sequence */
508 509 510 511
			if ((minv < 0 && next < minv - incby) ||
				(minv >= 0 && next + incby < minv))
			{
				if (rescnt > 0)
V
Vadim B. Mikheev 已提交
512
					break;		/* stop fetching */
513
				if (!seq->is_cycled)
514
				{
B
Bruce Momjian 已提交
515 516
					char		buf[100];

517
					snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
518 519 520 521
					ereport(ERROR,
							(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
							 errmsg("%s.nextval: reached MINVALUE (%s)",
									sequence->relname, buf)));
522
				}
523 524 525 526 527
				next = maxv;
			}
			else
				next += incby;
		}
V
Vadim B. Mikheev 已提交
528 529 530 531 532 533
		fetch--;
		if (rescnt < cache)
		{
			log--;
			rescnt++;
			last = next;
B
Bruce Momjian 已提交
534 535
			if (rescnt == 1)	/* if it's first result - */
				result = next;	/* it's what to return */
V
Vadim B. Mikheev 已提交
536
		}
537 538
	}

539 540 541
	log -= fetch;				/* adjust for any unfetched numbers */
	Assert(log >= 0);

542 543
	/* save info in local cache */
	elm->last = result;			/* last returned number */
V
Vadim B. Mikheev 已提交
544 545
	elm->cached = last;			/* last fetched number */

546
	START_CRIT_SECTION();
547 548 549

	/* XLOG stuff */
	if (logit && !seqrel->rd_istemp)
V
Vadim B. Mikheev 已提交
550 551 552
	{
		xl_seq_rec	xlrec;
		XLogRecPtr	recptr;
B
Bruce Momjian 已提交
553
		XLogRecData rdata[2];
V
Vadim B. Mikheev 已提交
554

555
		xlrec.node = seqrel->rd_node;
556
		rdata[0].buffer = InvalidBuffer;
B
Bruce Momjian 已提交
557
		rdata[0].data = (char *) &xlrec;
558 559 560
		rdata[0].len = sizeof(xl_seq_rec);
		rdata[0].next = &(rdata[1]);

561
		/* set values that will be saved in xlog */
562
		seq->last_value = next;
563
		seq->is_called = true;
564
		seq->log_cnt = 0;
565

566
		rdata[1].buffer = InvalidBuffer;
B
Bruce Momjian 已提交
567 568 569
		rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
		rdata[1].len = ((PageHeader) page)->pd_special -
			((PageHeader) page)->pd_upper;
570 571
		rdata[1].next = NULL;

B
Bruce Momjian 已提交
572
		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
V
Vadim B. Mikheev 已提交
573

574 575
		PageSetLSN(page, recptr);
		PageSetSUI(page, ThisStartUpID);
V
Vadim B. Mikheev 已提交
576
	}
577

578
	/* update on-disk data */
V
Vadim B. Mikheev 已提交
579
	seq->last_value = last;		/* last fetched number */
580
	seq->is_called = true;
V
Vadim B. Mikheev 已提交
581
	seq->log_cnt = log;			/* how much is logged */
582

583
	END_CRIT_SECTION();
584

V
Vadim B. Mikheev 已提交
585 586
	LockBuffer(buf, BUFFER_LOCK_UNLOCK);

B
Bruce Momjian 已提交
587
	WriteBuffer(buf);
588

589 590
	relation_close(seqrel, NoLock);

591
	PG_RETURN_INT64(result);
592 593
}

594 595
Datum
currval(PG_FUNCTION_ARGS)
596
{
597
	text	   *seqin = PG_GETARG_TEXT_P(0);
598
	RangeVar   *sequence;
599
	SeqTable	elm;
600
	Relation	seqrel;
601
	int64		result;
602

603
	sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
B
Bruce Momjian 已提交
604
															 "currval"));
605

V
Vadim B. Mikheev 已提交
606
	/* open and AccessShareLock sequence */
607
	init_sequence(sequence, &elm, &seqrel);
608

609
	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK)
610 611 612 613
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("%s.currval: permission denied",
						sequence->relname)));
614

615
	if (elm->increment == 0)	/* nextval/read_info were not called */
616 617 618 619
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				 errmsg("%s.currval is not yet defined in this session",
						sequence->relname)));
620 621 622

	result = elm->last;

623 624
	relation_close(seqrel, NoLock);

625
	PG_RETURN_INT64(result);
626 627
}

B
Bruce Momjian 已提交
628
/*
629 630 631 632
 * 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 已提交
633
 * work if multiple users are attached to the database and referencing
634 635
 * the sequence (unlikely if pg_dump is restoring it).
 *
B
Bruce Momjian 已提交
636
 * It is necessary to have the 3 arg version so that pg_dump can
637 638 639 640
 * 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 已提交
641
static void
642
do_setval(RangeVar *sequence, int64 next, bool iscalled)
M
 
Marc G. Fournier 已提交
643 644
{
	SeqTable	elm;
645
	Relation	seqrel;
646
	Buffer		buf;
647
	Form_pg_sequence seq;
M
 
Marc G. Fournier 已提交
648

649
	/* open and AccessShareLock sequence */
650
	init_sequence(sequence, &elm, &seqrel);
651 652

	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
653 654 655 656
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("%s.setval: permission denied",
						sequence->relname)));
M
 
Marc G. Fournier 已提交
657

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

661
	if ((next < seq->min_value) || (next > seq->max_value))
662
	{
B
Bruce Momjian 已提交
663 664 665 666
		char		bufv[100],
					bufm[100],
					bufx[100];

667 668 669
		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);
670 671 672 673
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("%s.setval: value %s is out of bounds (%s..%s)",
						sequence->relname, bufv, bufm, bufx)));
674
	}
M
 
Marc G. Fournier 已提交
675 676 677

	/* save info in local cache */
	elm->last = next;			/* last returned number */
B
Bruce Momjian 已提交
678 679
	elm->cached = next;			/* last cached number (forget cached
								 * values) */
M
 
Marc G. Fournier 已提交
680

681
	START_CRIT_SECTION();
682 683 684

	/* XLOG stuff */
	if (!seqrel->rd_istemp)
V
Vadim B. Mikheev 已提交
685 686 687
	{
		xl_seq_rec	xlrec;
		XLogRecPtr	recptr;
B
Bruce Momjian 已提交
688
		XLogRecData rdata[2];
689
		Page		page = BufferGetPage(buf);
V
Vadim B. Mikheev 已提交
690

691
		xlrec.node = seqrel->rd_node;
692
		rdata[0].buffer = InvalidBuffer;
B
Bruce Momjian 已提交
693
		rdata[0].data = (char *) &xlrec;
694 695 696
		rdata[0].len = sizeof(xl_seq_rec);
		rdata[0].next = &(rdata[1]);

697
		/* set values that will be saved in xlog */
698
		seq->last_value = next;
699
		seq->is_called = true;
700
		seq->log_cnt = 0;
701

702
		rdata[1].buffer = InvalidBuffer;
B
Bruce Momjian 已提交
703 704 705
		rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
		rdata[1].len = ((PageHeader) page)->pd_special -
			((PageHeader) page)->pd_upper;
706 707
		rdata[1].next = NULL;

B
Bruce Momjian 已提交
708
		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
709 710 711

		PageSetLSN(page, recptr);
		PageSetSUI(page, ThisStartUpID);
V
Vadim B. Mikheev 已提交
712
	}
713

714 715
	/* save info in sequence relation */
	seq->last_value = next;		/* last fetched number */
716
	seq->is_called = iscalled;
717
	seq->log_cnt = (iscalled) ? 0 : 1;
718

719
	END_CRIT_SECTION();
M
 
Marc G. Fournier 已提交
720

V
Vadim B. Mikheev 已提交
721 722
	LockBuffer(buf, BUFFER_LOCK_UNLOCK);

B
Bruce Momjian 已提交
723
	WriteBuffer(buf);
724 725

	relation_close(seqrel, NoLock);
726 727
}

728 729 730 731
/*
 * Implement the 2 arg setval procedure.
 * See do_setval for discussion.
 */
732 733 734 735
Datum
setval(PG_FUNCTION_ARGS)
{
	text	   *seqin = PG_GETARG_TEXT_P(0);
736
	int64		next = PG_GETARG_INT64(1);
737 738 739
	RangeVar   *sequence;

	sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
B
Bruce Momjian 已提交
740
															  "setval"));
741

742
	do_setval(sequence, next, true);
743

744
	PG_RETURN_INT64(next);
745 746
}

747 748 749 750
/*
 * Implement the 3 arg setval procedure.
 * See do_setval for discussion.
 */
751 752 753 754
Datum
setval_and_iscalled(PG_FUNCTION_ARGS)
{
	text	   *seqin = PG_GETARG_TEXT_P(0);
755
	int64		next = PG_GETARG_INT64(1);
756
	bool		iscalled = PG_GETARG_BOOL(2);
757
	RangeVar   *sequence;
758

759
	sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
B
Bruce Momjian 已提交
760
															  "setval"));
761

762
	do_setval(sequence, next, iscalled);
763

764
	PG_RETURN_INT64(next);
M
 
Marc G. Fournier 已提交
765 766
}

767

768 769 770 771 772
/*
 * Given a relation name, open and lock the sequence.  p_elm and p_rel are
 * output parameters.
 */
static void
773
init_sequence(RangeVar *relation, SeqTable *p_elm, Relation *p_rel)
774
{
775
	Oid			relid = RangeVarGetRelid(relation, false);
776 777
	TransactionId thisxid = GetCurrentTransactionId();
	SeqTable	elm;
778
	Relation	seqrel;
B
Bruce Momjian 已提交
779

780
	/* Look to see if we already have a seqtable entry for relation */
781
	for (elm = seqtab; elm != NULL; elm = elm->next)
782
	{
783
		if (elm->relid == relid)
784 785 786
			break;
	}

787 788 789 790 791 792 793 794
	/*
	 * Open the sequence relation, acquiring AccessShareLock if we don't
	 * already have a lock in the current xact.
	 */
	if (elm == NULL || elm->xid != thisxid)
		seqrel = relation_open(relid, AccessShareLock);
	else
		seqrel = relation_open(relid, NoLock);
795

796
	if (seqrel->rd_rel->relkind != RELKIND_SEQUENCE)
797 798 799 800
		ereport(ERROR,
				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
				 errmsg("\"%s\" is not a sequence",
						relation->relname)));
801

802
	/*
803
	 * Allocate new seqtable entry if we didn't find one.
804 805
	 *
	 * NOTE: seqtable entries remain in the list for the life of a backend.
B
Bruce Momjian 已提交
806 807 808
	 * If the sequence itself is deleted then the entry becomes wasted
	 * memory, but it's small enough that this should not matter.
	 */
809
	if (elm == NULL)
810
	{
811 812
		/*
		 * Time to make a new seqtable entry.  These entries live as long
813 814 815
		 * as the backend does, so we use plain malloc for them.
		 */
		elm = (SeqTable) malloc(sizeof(SeqTableData));
T
Tom Lane 已提交
816
		if (elm == NULL)
817 818 819
			ereport(ERROR,
					(errcode(ERRCODE_OUT_OF_MEMORY),
					 errmsg("out of memory")));
820
		elm->relid = relid;
821 822 823 824
		/* increment is set to 0 until we do read_info (see currval) */
		elm->last = elm->cached = elm->increment = 0;
		elm->next = seqtab;
		seqtab = elm;
825 826
	}

827 828 829 830 831
	/* Flag that we have a lock in the current xact. */
	elm->xid = thisxid;

	*p_elm = elm;
	*p_rel = seqrel;
832 833 834
}


835 836
/* Given an opened relation, lock the page buffer and find the tuple */
static Form_pg_sequence
837
read_info(SeqTable elm, Relation rel, Buffer *buf)
838
{
839 840 841 842 843
	PageHeader	page;
	ItemId		lp;
	HeapTupleData tuple;
	sequence_magic *sm;
	Form_pg_sequence seq;
844

845
	if (rel->rd_nblocks > 1)
846 847
		elog(ERROR, "invalid number of blocks in sequence \"%s\"",
			 RelationGetRelationName(rel));
848 849 850

	*buf = ReadBuffer(rel, 0);
	if (!BufferIsValid(*buf))
851
		elog(ERROR, "ReadBuffer failed");
852 853 854 855 856 857 858

	LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);

	page = (PageHeader) BufferGetPage(*buf);
	sm = (sequence_magic *) PageGetSpecialPointer(page);

	if (sm->magic != SEQ_MAGIC)
859 860
		elog(ERROR, "bad magic number (%08X) in sequence \"%s\"",
			 sm->magic, RelationGetRelationName(rel));
861 862 863 864 865 866 867 868 869 870

	lp = PageGetItemId(page, FirstOffsetNumber);
	Assert(ItemIdIsUsed(lp));
	tuple.t_data = (HeapTupleHeader) PageGetItem((Page) page, lp);

	seq = (Form_pg_sequence) GETSTRUCT(&tuple);

	elm->increment = seq->increment_by;

	return seq;
871 872 873
}


874
static void
875
init_params(List *options, Form_pg_sequence new)
876
{
877 878 879 880 881
	DefElem    *last_value = NULL;
	DefElem    *increment_by = NULL;
	DefElem    *max_value = NULL;
	DefElem    *min_value = NULL;
	DefElem    *cache_value = NULL;
882
	bool		is_cycled_set = false;
883
	List	   *option;
884

B
Bruce Momjian 已提交
885
	foreach(option, options)
886
	{
887
		DefElem    *defel = (DefElem *) lfirst(option);
888

889
		if (strcmp(defel->defname, "increment") == 0)
890 891
		{
			if (increment_by)
892 893 894
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
895
			increment_by = defel;
896
		}
B
Bruce Momjian 已提交
897 898 899 900
		/*
		 * start is for a new sequence
		 * restart is for alter
		 */
901 902
		else if (strcmp(defel->defname, "start") == 0 ||
				 strcmp(defel->defname, "restart") == 0)
903 904
		{
			if (last_value)
905 906 907
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
908
			last_value = defel;
909
		}
910
		else if (strcmp(defel->defname, "maxvalue") == 0)
911 912
		{
			if (max_value)
913 914 915
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
916
			max_value = defel;
917
		}
918
		else if (strcmp(defel->defname, "minvalue") == 0)
919 920
		{
			if (min_value)
921 922 923
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
924
			min_value = defel;
925
		}
926
		else if (strcmp(defel->defname, "cache") == 0)
927 928
		{
			if (cache_value)
929 930 931
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
932
			cache_value = defel;
933
		}
934
		else if (strcmp(defel->defname, "cycle") == 0)
935 936
		{
			if (is_cycled_set)
937 938 939
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
940
			is_cycled_set = true;
941
			new->is_cycled = (defel->arg != NULL);
942
		}
943
		else
944
			elog(ERROR, "option \"%s\" not recognized",
945 946 947
				 defel->defname);
	}

B
Bruce Momjian 已提交
948
	/* INCREMENT BY */
B
Bruce Momjian 已提交
949
	if (new->increment_by == 0 && increment_by == (DefElem *) NULL)
950
		new->increment_by = 1;
B
Bruce Momjian 已提交
951 952 953
	else if (increment_by != (DefElem *) NULL)
	{
		new->increment_by = defGetInt64(increment_by);
954 955 956 957
		if (new->increment_by == 0)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("can't INCREMENT by zero")));
B
Bruce Momjian 已提交
958
	}
959

B
Bruce Momjian 已提交
960
	/* MAXVALUE */
B
Bruce Momjian 已提交
961
	if ((new->max_value == 0 && max_value == (DefElem *) NULL)
B
Bruce Momjian 已提交
962
		|| (max_value != (DefElem *) NULL && !max_value->arg))
963
	{
964
		if (new->increment_by > 0)
B
Bruce Momjian 已提交
965
			new->max_value = SEQ_MAXVALUE;	/* ascending seq */
966
		else
B
Bruce Momjian 已提交
967
			new->max_value = -1;			/* descending seq */
968
	}
B
Bruce Momjian 已提交
969
	else if (max_value != (DefElem *) NULL)
970
		new->max_value = defGetInt64(max_value);
971

B
Bruce Momjian 已提交
972
	/* MINVALUE */
B
Bruce Momjian 已提交
973
	if ((new->min_value == 0 && min_value == (DefElem *) NULL)
B
Bruce Momjian 已提交
974
		|| (min_value != (DefElem *) NULL && !min_value->arg))
975
	{
976
		if (new->increment_by > 0)
B
Bruce Momjian 已提交
977
			new->min_value = 1;				/* ascending seq */
978
		else
B
Bruce Momjian 已提交
979
			new->min_value = SEQ_MINVALUE;	/* descending seq */
980
	}
B
Bruce Momjian 已提交
981
	else if (min_value != (DefElem *) NULL)
982
		new->min_value = defGetInt64(min_value);
983 984

	if (new->min_value >= new->max_value)
985
	{
B
Bruce Momjian 已提交
986 987 988
		char		bufm[100],
					bufx[100];

989 990
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
		snprintf(bufx, sizeof(bufx), INT64_FORMAT, new->max_value);
991 992 993 994
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("MINVALUE (%s) must be less than MAXVALUE (%s)",
						bufm, bufx)));
995
	}
996

B
Bruce Momjian 已提交
997
	/* START WITH */
B
Bruce Momjian 已提交
998
	if (new->last_value == 0 && last_value == (DefElem *) NULL) 
999
	{
1000 1001 1002 1003
		if (new->increment_by > 0)
			new->last_value = new->min_value;	/* ascending seq */
		else
			new->last_value = new->max_value;	/* descending seq */
1004
	}
B
Bruce Momjian 已提交
1005
	else if (last_value != (DefElem *) NULL)
1006
		new->last_value = defGetInt64(last_value);
1007 1008

	if (new->last_value < new->min_value)
1009
	{
B
Bruce Momjian 已提交
1010 1011 1012
		char		bufs[100],
					bufm[100];

1013 1014
		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
1015 1016 1017 1018
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("START value (%s) can't be less than MINVALUE (%s)",
						bufs, bufm)));
1019
	}
1020
	if (new->last_value > new->max_value)
1021
	{
B
Bruce Momjian 已提交
1022 1023 1024
		char		bufs[100],
					bufm[100];

1025 1026
		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
1027 1028 1029 1030
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("START value (%s) can't be greater than MAXVALUE (%s)",
						bufs, bufm)));
1031
	}
1032

B
Bruce Momjian 已提交
1033 1034
	/* CACHE */
	if (cache_value == (DefElem *) NULL)
1035
		new->cache_value = 1;
1036
	else if ((new->cache_value = defGetInt64(cache_value)) <= 0)
1037
	{
B
Bruce Momjian 已提交
1038 1039
		char		buf[100];

1040
		snprintf(buf, sizeof(buf), INT64_FORMAT, new->cache_value);
1041 1042 1043
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("CACHE (%s) must be greater than zero", buf)));
1044
	}
1045 1046
}

V
Vadim B. Mikheev 已提交
1047

B
Bruce Momjian 已提交
1048 1049
void
seq_redo(XLogRecPtr lsn, XLogRecord *record)
V
Vadim B. Mikheev 已提交
1050
{
B
Bruce Momjian 已提交
1051 1052 1053 1054 1055 1056 1057
	uint8		info = record->xl_info & ~XLR_INFO_MASK;
	Relation	reln;
	Buffer		buffer;
	Page		page;
	char	   *item;
	Size		itemsz;
	xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
1058
	sequence_magic *sm;
V
Vadim B. Mikheev 已提交
1059

1060
	if (info != XLOG_SEQ_LOG)
1061
		elog(PANIC, "seq_redo: unknown op code %u", info);
V
Vadim B. Mikheev 已提交
1062 1063 1064 1065 1066

	reln = XLogOpenRelation(true, RM_SEQ_ID, xlrec->node);
	if (!RelationIsValid(reln))
		return;

1067
	buffer = XLogReadBuffer(true, reln, 0);
V
Vadim B. Mikheev 已提交
1068
	if (!BufferIsValid(buffer))
1069
		elog(PANIC, "seq_redo: can't read block of %u/%u",
B
Bruce Momjian 已提交
1070
			 xlrec->node.tblNode, xlrec->node.relNode);
V
Vadim B. Mikheev 已提交
1071 1072 1073

	page = (Page) BufferGetPage(buffer);

1074 1075
	/* Always reinit the page and reinstall the magic number */
	/* See comments in DefineSequence */
1076 1077 1078
	PageInit((Page) page, BufferGetPageSize(buffer), sizeof(sequence_magic));
	sm = (sequence_magic *) PageGetSpecialPointer(page);
	sm->magic = SEQ_MAGIC;
V
Vadim B. Mikheev 已提交
1079

B
Bruce Momjian 已提交
1080
	item = (char *) xlrec + sizeof(xl_seq_rec);
1081 1082
	itemsz = record->xl_len - sizeof(xl_seq_rec);
	itemsz = MAXALIGN(itemsz);
B
Bruce Momjian 已提交
1083
	if (PageAddItem(page, (Item) item, itemsz,
1084
					FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
1085
		elog(PANIC, "seq_redo: failed to add item to page");
V
Vadim B. Mikheev 已提交
1086 1087 1088 1089 1090 1091

	PageSetLSN(page, lsn);
	PageSetSUI(page, ThisStartUpID);
	UnlockAndWriteBuffer(buffer);
}

B
Bruce Momjian 已提交
1092 1093
void
seq_undo(XLogRecPtr lsn, XLogRecord *record)
V
Vadim B. Mikheev 已提交
1094 1095 1096
{
}

B
Bruce Momjian 已提交
1097 1098
void
seq_desc(char *buf, uint8 xl_info, char *rec)
V
Vadim B. Mikheev 已提交
1099
{
B
Bruce Momjian 已提交
1100 1101
	uint8		info = xl_info & ~XLR_INFO_MASK;
	xl_seq_rec *xlrec = (xl_seq_rec *) rec;
V
Vadim B. Mikheev 已提交
1102 1103 1104 1105 1106 1107 1108 1109 1110

	if (info == XLOG_SEQ_LOG)
		strcat(buf, "log: ");
	else
	{
		strcat(buf, "UNKNOWN");
		return;
	}

1111
	sprintf(buf + strlen(buf), "node %u/%u",
B
Bruce Momjian 已提交
1112
			xlrec->node.tblNode, xlrec->node.relNode);
V
Vadim B. Mikheev 已提交
1113
}