sequence.c 38.7 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * sequence.c
4
 *	  PostgreSQL sequences support code.
5
 *
6
 * Portions Copyright (c) 1996-2010, 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"
B
Bruce Momjian 已提交
27
#include "miscadmin.h"
28
#include "nodes/makefuncs.h"
29 30
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
31
#include "storage/proc.h"
32
#include "storage/smgr.h"
33
#include "utils/acl.h"
B
Bruce Momjian 已提交
34
#include "utils/builtins.h"
35
#include "utils/lsyscache.h"
36
#include "utils/resowner.h"
37
#include "utils/syscache.h"
38

39

V
Vadim B. Mikheev 已提交
40
/*
41
 * We don't want to log each fetching of a value from a sequence,
V
Vadim B. Mikheev 已提交
42 43 44
 * 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 已提交
45
#define SEQ_LOG_VALS	32
46

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

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

57 58 59 60 61 62
/*
 * 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 已提交
63
 * XXX We use linear search to find pre-existing SeqTable entries.	This is
64 65 66
 * 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.
 */
67 68
typedef struct SeqTableData
{
69 70
	struct SeqTableData *next;	/* link to next SeqTable object */
	Oid			relid;			/* pg_class OID of this sequence */
71
	Oid			filenode;		/* last seen relfilenode of this sequence */
72
	LocalTransactionId lxid;	/* xact in which we last did a seq op */
73
	bool		last_valid;		/* do we have a valid "last" value? */
74 75 76 77
	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 */
78
	/* note that increment is zero until we first do read_info() */
79
} SeqTableData;
80 81 82

typedef SeqTableData *SeqTable;

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

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

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

101 102

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

121
	/* Check and set all option values */
122
	init_params(seq->options, true, &new, &owned_by);
123 124

	/*
125
	 * Create relation (and fill value[] and null[] for the tuple)
126 127 128
	 */
	stmt->tableElts = NIL;
	for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
129
	{
130
		ColumnDef  *coldef = makeNode(ColumnDef);
131

132 133
		coldef->inhcount = 0;
		coldef->is_local = true;
134
		coldef->is_not_null = true;
135
		coldef->storage = 0;
136 137
		coldef->raw_default = NULL;
		coldef->cooked_default = NULL;
138 139
		coldef->constraints = NIL;

140
		null[i - 1] = false;
141 142 143

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

199 200
	stmt->relation = seq->sequence;
	stmt->inhRelations = NIL;
201
	stmt->constraints = NIL;
202
	stmt->options = list_make1(defWithOids(false));
203
	stmt->oncommit = ONCOMMIT_NOOP;
204
	stmt->tablespacename = NULL;
R
Robert Haas 已提交
205
	stmt->if_not_exists = false;
206

207
	seqoid = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId);
R
Robert Haas 已提交
208
	Assert(seqoid != InvalidOid);
209

210
	rel = heap_open(seqoid, AccessExclusiveLock);
211
	tupDesc = RelationGetDescr(rel);
212

213 214 215 216 217 218 219 220 221 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
	/* 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;

307 308
	/* Initialize first page of relation with special magic number */

309
	buf = ReadBuffer(rel, P_NEW);
310 311
	Assert(BufferGetBlockNumber(buf) == 0);

312
	page = BufferGetPage(buf);
313

314
	PageInit(page, BufferGetPageSize(buf), sizeof(sequence_magic));
315 316 317
	sm = (sequence_magic *) PageGetSpecialPointer(page);
	sm->magic = SEQ_MAGIC;

318
	/* hack: ensure heap_insert will insert on the just-created page */
319
	RelationSetTargetBlock(rel, 0);
320

321
	/* Now insert sequence tuple */
322
	simple_heap_insert(rel, tuple);
323

324 325
	Assert(ItemPointerGetOffsetNumber(&(tuple->t_self)) == FirstOffsetNumber);

326
	/*
327 328
	 * Two special hacks here:
	 *
329 330
	 * 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 已提交
331
	 * invisible to SELECTs after 2G transactions.	It is okay to do this
332 333 334
	 * because if the current transaction aborts, no other xact will ever
	 * examine the sequence tuple anyway.
	 *
B
Bruce Momjian 已提交
335 336 337 338 339
	 * 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 :-(
340
	 */
341
	LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
342

343
	START_CRIT_SECTION();
344 345 346

	{
		/*
B
Bruce Momjian 已提交
347
		 * Note that the "tuple" structure is still just a local tuple record
348
		 * created by heap_form_tuple; its t_data pointer doesn't point at the
B
Bruce Momjian 已提交
349 350 351
		 * 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.
352 353 354 355 356 357 358
		 */
		ItemId		itemId;
		Item		item;

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

359
		HeapTupleHeaderSetXmin((HeapTupleHeader) item, FrozenTransactionId);
360 361
		((HeapTupleHeader) item)->t_infomask |= HEAP_XMIN_COMMITTED;

362
		HeapTupleHeaderSetXmin(tuple->t_data, FrozenTransactionId);
363 364 365
		tuple->t_data->t_infomask |= HEAP_XMIN_COMMITTED;
	}

366 367
	MarkBufferDirty(buf);

368 369
	/* XLOG stuff */
	if (!rel->rd_istemp)
370
	{
371 372 373 374
		xl_seq_rec	xlrec;
		XLogRecPtr	recptr;
		XLogRecData rdata[2];
		Form_pg_sequence newseq = (Form_pg_sequence) GETSTRUCT(tuple);
375 376

		/* We do not log first nextval call, so "advance" sequence here */
377
		/* Note we are scribbling on local tuple, not the disk buffer */
378
		newseq->is_called = true;
379 380 381 382 383
		newseq->log_cnt = 0;

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

387
		rdata[1].data = (char *) tuple->t_data;
388
		rdata[1].len = tuple->t_len;
389
		rdata[1].buffer = InvalidBuffer;
390 391
		rdata[1].next = NULL;

392
		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
393 394

		PageSetLSN(page, recptr);
395
		PageSetTLI(page, ThisTimeLineID);
396
	}
397

398
	END_CRIT_SECTION();
399

400
	UnlockReleaseBuffer(buf);
401 402
}

B
Bruce Momjian 已提交
403 404 405
/*
 * AlterSequence
 *
406
 * Modify the definition of a sequence relation
B
Bruce Momjian 已提交
407 408
 */
void
409
AlterSequence(AlterSeqStmt *stmt)
B
Bruce Momjian 已提交
410
{
411
	Oid			relid;
B
Bruce Momjian 已提交
412 413 414 415 416 417
	SeqTable	elm;
	Relation	seqrel;
	Buffer		buf;
	Page		page;
	Form_pg_sequence seq;
	FormData_pg_sequence new;
418
	List	   *owned_by;
B
Bruce Momjian 已提交
419 420

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

424 425 426 427 428
	/* 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 已提交
429
	/* lock page' buffer and read tuple into new sequence structure */
430
	seq = read_info(elm, seqrel, &buf);
B
Bruce Momjian 已提交
431 432
	page = BufferGetPage(buf);

433 434 435 436
	/* Copy old values of options into workspace */
	memcpy(&new, seq, sizeof(FormData_pg_sequence));

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

439 440 441 442
	/* 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;

443
	/* Now okay to update the on-disk tuple */
444
	memcpy(seq, &new, sizeof(FormData_pg_sequence));
B
Bruce Momjian 已提交
445 446 447

	START_CRIT_SECTION();

448 449
	MarkBufferDirty(buf);

B
Bruce Momjian 已提交
450 451 452 453 454 455 456 457 458 459
	/* XLOG stuff */
	if (!seqrel->rd_istemp)
	{
		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);
460
		rdata[0].buffer = InvalidBuffer;
B
Bruce Momjian 已提交
461 462 463 464 465
		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;
466
		rdata[1].buffer = InvalidBuffer;
B
Bruce Momjian 已提交
467 468
		rdata[1].next = NULL;

469
		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
B
Bruce Momjian 已提交
470 471

		PageSetLSN(page, recptr);
472
		PageSetTLI(page, ThisTimeLineID);
B
Bruce Momjian 已提交
473 474 475 476
	}

	END_CRIT_SECTION();

477
	UnlockReleaseBuffer(buf);
B
Bruce Momjian 已提交
478

479 480 481 482
	/* process OWNED BY if given */
	if (owned_by)
		process_owned_by(seqrel, owned_by);

B
Bruce Momjian 已提交
483 484 485
	relation_close(seqrel, NoLock);
}

486

487 488 489 490 491
/*
 * 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.
 */
492 493
Datum
nextval(PG_FUNCTION_ARGS)
494
{
495
	text	   *seqin = PG_GETARG_TEXT_P(0);
496
	RangeVar   *sequence;
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
	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)
{
516
	SeqTable	elm;
517
	Relation	seqrel;
518
	Buffer		buf;
519
	Page		page;
520
	Form_pg_sequence seq;
521
	int64		incby,
522 523
				maxv,
				minv,
V
Vadim B. Mikheev 已提交
524 525 526 527
				cache,
				log,
				fetch,
				last;
528
	int64		result,
529 530
				next,
				rescnt = 0;
V
Vadim B. Mikheev 已提交
531
	bool		logit = false;
532

V
Vadim B. Mikheev 已提交
533
	/* open and AccessShareLock sequence */
534
	init_sequence(relid, &elm, &seqrel);
535

536 537
	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK &&
		pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
538 539
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
540
				 errmsg("permission denied for sequence %s",
541
						RelationGetRelationName(seqrel))));
542

543
	/* read-only transactions may only modify temp sequences */
544
	if (seqrel->rd_backend != MyBackendId)
545 546
		PreventCommandIfReadOnly("nextval()");

547 548
	if (elm->last != elm->cached)		/* some numbers were cached */
	{
549 550
		Assert(elm->last_valid);
		Assert(elm->increment != 0);
551
		elm->last += elm->increment;
552
		relation_close(seqrel, NoLock);
553
		last_used_seq = elm;
554
		return elm->last;
555
	}
556

557
	/* lock page' buffer and read tuple */
558
	seq = read_info(elm, seqrel, &buf);
559
	page = BufferGetPage(buf);
560

V
Vadim B. Mikheev 已提交
561
	last = next = result = seq->last_value;
562 563 564
	incby = seq->increment_by;
	maxv = seq->max_value;
	minv = seq->min_value;
V
Vadim B. Mikheev 已提交
565 566
	fetch = cache = seq->cache_value;
	log = seq->log_cnt;
567

568
	if (!seq->is_called)
V
Vadim B. Mikheev 已提交
569
	{
570
		rescnt++;				/* last_value if not called */
V
Vadim B. Mikheev 已提交
571 572 573
		fetch--;
		log--;
	}
574

575
	/*
B
Bruce Momjian 已提交
576 577 578
	 * 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.)
579
	 *
580 581 582 583
	 * 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.
584
	 */
V
Vadim B. Mikheev 已提交
585 586
	if (log < fetch)
	{
587 588
		/* forced log to satisfy local demand for values */
		fetch = log = fetch + SEQ_LOG_VALS;
V
Vadim B. Mikheev 已提交
589 590
		logit = true;
	}
591 592 593 594 595 596 597 598 599 600 601
	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 已提交
602

B
Bruce Momjian 已提交
603
	while (fetch)				/* try to fetch cache [+ log ] numbers */
604
	{
605
		/*
B
Bruce Momjian 已提交
606 607
		 * Check MAXVALUE for ascending sequences and MINVALUE for descending
		 * sequences
608
		 */
609
		if (incby > 0)
610
		{
611
			/* ascending sequence */
612 613 614 615
			if ((maxv >= 0 && next > maxv - incby) ||
				(maxv < 0 && next + incby > maxv))
			{
				if (rescnt > 0)
V
Vadim B. Mikheev 已提交
616
					break;		/* stop fetching */
617
				if (!seq->is_cycled)
618
				{
B
Bruce Momjian 已提交
619 620
					char		buf[100];

621
					snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
622
					ereport(ERROR,
B
Bruce Momjian 已提交
623 624 625
						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
						   errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
								  RelationGetRelationName(seqrel), buf)));
626
				}
627 628 629 630 631 632 633
				next = minv;
			}
			else
				next += incby;
		}
		else
		{
634
			/* descending sequence */
635 636 637 638
			if ((minv < 0 && next < minv - incby) ||
				(minv >= 0 && next + incby < minv))
			{
				if (rescnt > 0)
V
Vadim B. Mikheev 已提交
639
					break;		/* stop fetching */
640
				if (!seq->is_cycled)
641
				{
B
Bruce Momjian 已提交
642 643
					char		buf[100];

644
					snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
645
					ereport(ERROR,
B
Bruce Momjian 已提交
646 647 648
						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
						   errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
								  RelationGetRelationName(seqrel), buf)));
649
				}
650 651 652 653 654
				next = maxv;
			}
			else
				next += incby;
		}
V
Vadim B. Mikheev 已提交
655 656 657 658 659 660
		fetch--;
		if (rescnt < cache)
		{
			log--;
			rescnt++;
			last = next;
B
Bruce Momjian 已提交
661 662
			if (rescnt == 1)	/* if it's first result - */
				result = next;	/* it's what to return */
V
Vadim B. Mikheev 已提交
663
		}
664 665
	}

666 667 668
	log -= fetch;				/* adjust for any unfetched numbers */
	Assert(log >= 0);

669 670
	/* save info in local cache */
	elm->last = result;			/* last returned number */
V
Vadim B. Mikheev 已提交
671
	elm->cached = last;			/* last fetched number */
672
	elm->last_valid = true;
V
Vadim B. Mikheev 已提交
673

674 675
	last_used_seq = elm;

676
	START_CRIT_SECTION();
677

678 679
	MarkBufferDirty(buf);

680 681
	/* XLOG stuff */
	if (logit && !seqrel->rd_istemp)
V
Vadim B. Mikheev 已提交
682 683 684
	{
		xl_seq_rec	xlrec;
		XLogRecPtr	recptr;
B
Bruce Momjian 已提交
685
		XLogRecData rdata[2];
V
Vadim B. Mikheev 已提交
686

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

693
		/* set values that will be saved in xlog */
694
		seq->last_value = next;
695
		seq->is_called = true;
696
		seq->log_cnt = 0;
697

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

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

706
		PageSetLSN(page, recptr);
707
		PageSetTLI(page, ThisTimeLineID);
V
Vadim B. Mikheev 已提交
708
	}
709

710
	/* update on-disk data */
V
Vadim B. Mikheev 已提交
711
	seq->last_value = last;		/* last fetched number */
712
	seq->is_called = true;
V
Vadim B. Mikheev 已提交
713
	seq->log_cnt = log;			/* how much is logged */
714

715
	END_CRIT_SECTION();
716

717
	UnlockReleaseBuffer(buf);
718

719 720
	relation_close(seqrel, NoLock);

721
	return result;
722 723
}

724
Datum
725
currval_oid(PG_FUNCTION_ARGS)
726
{
727 728
	Oid			relid = PG_GETARG_OID(0);
	int64		result;
729
	SeqTable	elm;
730
	Relation	seqrel;
731

V
Vadim B. Mikheev 已提交
732
	/* open and AccessShareLock sequence */
733
	init_sequence(relid, &elm, &seqrel);
734

735 736
	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK &&
		pg_class_aclcheck(elm->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
737 738
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
739
				 errmsg("permission denied for sequence %s",
740
						RelationGetRelationName(seqrel))));
741

742
	if (!elm->last_valid)
743 744
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
745
				 errmsg("currval of sequence \"%s\" is not yet defined in this session",
746
						RelationGetRelationName(seqrel))));
747 748 749

	result = elm->last;

750 751
	relation_close(seqrel, NoLock);

752
	PG_RETURN_INT64(result);
753 754
}

755 756 757 758 759 760 761 762 763 764 765 766
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() */
767
	if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(last_used_seq->relid)))
768 769 770 771
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				 errmsg("lastval is not yet defined in this session")));

772
	seqrel = open_share_lock(last_used_seq);
773 774

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

777 778
	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)
779 780 781 782 783 784 785
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("permission denied for sequence %s",
						RelationGetRelationName(seqrel))));

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

787 788 789
	PG_RETURN_INT64(result);
}

B
Bruce Momjian 已提交
790
/*
791 792 793 794
 * 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 已提交
795
 * work if multiple users are attached to the database and referencing
796 797
 * the sequence (unlikely if pg_dump is restoring it).
 *
B
Bruce Momjian 已提交
798
 * It is necessary to have the 3 arg version so that pg_dump can
799 800 801 802
 * 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 已提交
803
static void
804
do_setval(Oid relid, int64 next, bool iscalled)
M
 
Marc G. Fournier 已提交
805 806
{
	SeqTable	elm;
807
	Relation	seqrel;
808
	Buffer		buf;
809
	Form_pg_sequence seq;
M
 
Marc G. Fournier 已提交
810

811
	/* open and AccessShareLock sequence */
812
	init_sequence(relid, &elm, &seqrel);
813 814

	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
815 816
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
817
				 errmsg("permission denied for sequence %s",
818
						RelationGetRelationName(seqrel))));
M
 
Marc G. Fournier 已提交
819

820
	/* read-only transactions may only modify temp sequences */
821
	if (seqrel->rd_backend != MyBackendId)
822 823
		PreventCommandIfReadOnly("setval()");

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

827
	if ((next < seq->min_value) || (next > seq->max_value))
828
	{
B
Bruce Momjian 已提交
829 830 831 832
		char		bufv[100],
					bufm[100],
					bufx[100];

833 834 835
		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);
836 837
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
838
				 errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)",
839 840
						bufv, RelationGetRelationName(seqrel),
						bufm, bufx)));
841
	}
M
 
Marc G. Fournier 已提交
842

843 844 845 846 847 848 849 850 851
	/* 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 已提交
852

853
	START_CRIT_SECTION();
854

855 856
	MarkBufferDirty(buf);

857 858
	/* XLOG stuff */
	if (!seqrel->rd_istemp)
V
Vadim B. Mikheev 已提交
859 860 861
	{
		xl_seq_rec	xlrec;
		XLogRecPtr	recptr;
B
Bruce Momjian 已提交
862
		XLogRecData rdata[2];
863
		Page		page = BufferGetPage(buf);
V
Vadim B. Mikheev 已提交
864

865
		xlrec.node = seqrel->rd_node;
B
Bruce Momjian 已提交
866
		rdata[0].data = (char *) &xlrec;
867
		rdata[0].len = sizeof(xl_seq_rec);
868
		rdata[0].buffer = InvalidBuffer;
869 870
		rdata[0].next = &(rdata[1]);

871
		/* set values that will be saved in xlog */
872
		seq->last_value = next;
873
		seq->is_called = true;
874
		seq->log_cnt = 0;
875

B
Bruce Momjian 已提交
876 877 878
		rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
		rdata[1].len = ((PageHeader) page)->pd_special -
			((PageHeader) page)->pd_upper;
879
		rdata[1].buffer = InvalidBuffer;
880 881
		rdata[1].next = NULL;

882
		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
883 884

		PageSetLSN(page, recptr);
885
		PageSetTLI(page, ThisTimeLineID);
V
Vadim B. Mikheev 已提交
886
	}
887

888 889
	/* save info in sequence relation */
	seq->last_value = next;		/* last fetched number */
890
	seq->is_called = iscalled;
891
	seq->log_cnt = (iscalled) ? 0 : 1;
892

893
	END_CRIT_SECTION();
M
 
Marc G. Fournier 已提交
894

895
	UnlockReleaseBuffer(buf);
896 897

	relation_close(seqrel, NoLock);
898 899
}

900 901 902 903
/*
 * Implement the 2 arg setval procedure.
 * See do_setval for discussion.
 */
904
Datum
905
setval_oid(PG_FUNCTION_ARGS)
906
{
907
	Oid			relid = PG_GETARG_OID(0);
908
	int64		next = PG_GETARG_INT64(1);
909

910
	do_setval(relid, next, true);
911

912
	PG_RETURN_INT64(next);
913 914
}

915 916 917 918
/*
 * Implement the 3 arg setval procedure.
 * See do_setval for discussion.
 */
919
Datum
920
setval3_oid(PG_FUNCTION_ARGS)
921
{
922
	Oid			relid = PG_GETARG_OID(0);
923
	int64		next = PG_GETARG_INT64(1);
924 925
	bool		iscalled = PG_GETARG_BOOL(2);

926
	do_setval(relid, next, iscalled);
927

928
	PG_RETURN_INT64(next);
M
 
Marc G. Fournier 已提交
929 930
}

931

932
/*
933 934
 * Open the sequence and acquire AccessShareLock if needed
 *
935
 * If we haven't touched the sequence already in this transaction,
B
Bruce Momjian 已提交
936
 * we need to acquire AccessShareLock.	We arrange for the lock to
937 938 939
 * be owned by the top transaction, so that we don't need to do it
 * more than once per xact.
 */
940 941
static Relation
open_share_lock(SeqTable seq)
942
{
943
	LocalTransactionId thislxid = MyProc->lxid;
944

945
	/* Get the lock if not already held in this xact */
946
	if (seq->lxid != thislxid)
947 948 949 950 951 952 953
	{
		ResourceOwner currentOwner;

		currentOwner = CurrentResourceOwner;
		PG_TRY();
		{
			CurrentResourceOwner = TopTransactionResourceOwner;
954
			LockRelationOid(seq->relid, AccessShareLock);
955 956 957 958 959 960 961 962 963 964
		}
		PG_CATCH();
		{
			/* Ensure CurrentResourceOwner is restored on error */
			CurrentResourceOwner = currentOwner;
			PG_RE_THROW();
		}
		PG_END_TRY();
		CurrentResourceOwner = currentOwner;

965
		/* Flag that we have a lock in the current xact */
966
		seq->lxid = thislxid;
967
	}
968 969 970

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

973
/*
974
 * Given a relation OID, open and lock the sequence.  p_elm and p_rel are
975 976 977
 * output parameters.
 */
static void
978
init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
979
{
B
Bruce Momjian 已提交
980
	SeqTable	elm;
981
	Relation	seqrel;
982

983 984 985 986 987 988 989
	/* 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;
	}

990
	/*
991
	 * Allocate new seqtable entry if we didn't find one.
992
	 *
B
Bruce Momjian 已提交
993 994 995
	 * 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 已提交
996
	 */
997
	if (elm == NULL)
998
	{
999
		/*
B
Bruce Momjian 已提交
1000 1001
		 * Time to make a new seqtable entry.  These entries live as long as
		 * the backend does, so we use plain malloc for them.
1002 1003
		 */
		elm = (SeqTable) malloc(sizeof(SeqTableData));
T
Tom Lane 已提交
1004
		if (elm == NULL)
1005 1006 1007
			ereport(ERROR,
					(errcode(ERRCODE_OUT_OF_MEMORY),
					 errmsg("out of memory")));
1008
		elm->relid = relid;
1009
		elm->filenode = InvalidOid;
1010
		elm->lxid = InvalidLocalTransactionId;
1011
		elm->last_valid = false;
1012 1013 1014
		elm->last = elm->cached = elm->increment = 0;
		elm->next = seqtab;
		seqtab = elm;
1015 1016
	}

1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
	/*
	 * 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))));
1027

1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
	/*
	 * 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 */
1040 1041
	*p_elm = elm;
	*p_rel = seqrel;
1042 1043 1044
}


1045 1046
/* Given an opened relation, lock the page buffer and find the tuple */
static Form_pg_sequence
1047
read_info(SeqTable elm, Relation rel, Buffer *buf)
1048
{
1049
	Page		page;
1050 1051 1052 1053
	ItemId		lp;
	HeapTupleData tuple;
	sequence_magic *sm;
	Form_pg_sequence seq;
1054

1055 1056 1057
	*buf = ReadBuffer(rel, 0);
	LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);

1058
	page = BufferGetPage(*buf);
1059 1060 1061
	sm = (sequence_magic *) PageGetSpecialPointer(page);

	if (sm->magic != SEQ_MAGIC)
1062 1063
		elog(ERROR, "bad magic number in sequence \"%s\": %08X",
			 RelationGetRelationName(rel), sm->magic);
1064 1065

	lp = PageGetItemId(page, FirstOffsetNumber);
1066
	Assert(ItemIdIsNormal(lp));
1067
	tuple.t_data = (HeapTupleHeader) PageGetItem(page, lp);
1068 1069 1070

	seq = (Form_pg_sequence) GETSTRUCT(&tuple);

1071
	/* this is a handy place to update our copy of the increment */
1072 1073 1074
	elm->increment = seq->increment_by;

	return seq;
1075 1076
}

1077 1078
/*
 * init_params: process the options list of CREATE or ALTER SEQUENCE,
1079 1080
 * 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.
1081 1082 1083 1084
 *
 * If isInit is true, fill any unspecified options with default values;
 * otherwise, do not change existing options that aren't explicitly overridden.
 */
1085
static void
1086
init_params(List *options, bool isInit,
1087
			Form_pg_sequence new, List **owned_by)
1088
{
1089 1090
	DefElem    *start_value = NULL;
	DefElem    *restart_value = NULL;
1091 1092 1093 1094
	DefElem    *increment_by = NULL;
	DefElem    *max_value = NULL;
	DefElem    *min_value = NULL;
	DefElem    *cache_value = NULL;
1095
	DefElem    *is_cycled = NULL;
1096
	ListCell   *option;
1097

1098 1099
	*owned_by = NIL;

B
Bruce Momjian 已提交
1100
	foreach(option, options)
1101
	{
1102
		DefElem    *defel = (DefElem *) lfirst(option);
1103

1104
		if (strcmp(defel->defname, "increment") == 0)
1105 1106
		{
			if (increment_by)
1107 1108 1109
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1110
			increment_by = defel;
1111
		}
1112 1113
		else if (strcmp(defel->defname, "start") == 0)
		{
1114
			if (start_value)
1115 1116 1117
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1118
			start_value = defel;
1119 1120
		}
		else if (strcmp(defel->defname, "restart") == 0)
1121
		{
1122
			if (restart_value)
1123 1124 1125
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1126
			restart_value = defel;
1127
		}
1128
		else if (strcmp(defel->defname, "maxvalue") == 0)
1129 1130
		{
			if (max_value)
1131 1132 1133
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1134
			max_value = defel;
1135
		}
1136
		else if (strcmp(defel->defname, "minvalue") == 0)
1137 1138
		{
			if (min_value)
1139 1140 1141
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1142
			min_value = defel;
1143
		}
1144
		else if (strcmp(defel->defname, "cache") == 0)
1145 1146
		{
			if (cache_value)
1147 1148 1149
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1150
			cache_value = defel;
1151
		}
1152
		else if (strcmp(defel->defname, "cycle") == 0)
1153
		{
1154
			if (is_cycled)
1155 1156 1157
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
1158
			is_cycled = defel;
1159
		}
1160 1161 1162 1163 1164 1165 1166 1167
		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);
		}
1168
		else
1169
			elog(ERROR, "option \"%s\" not recognized",
1170 1171 1172
				 defel->defname);
	}

B
Bruce Momjian 已提交
1173
	/* INCREMENT BY */
1174
	if (increment_by != NULL)
B
Bruce Momjian 已提交
1175 1176
	{
		new->increment_by = defGetInt64(increment_by);
1177 1178 1179
		if (new->increment_by == 0)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1180
					 errmsg("INCREMENT must not be zero")));
B
Bruce Momjian 已提交
1181
	}
1182 1183 1184 1185
	else if (isInit)
		new->increment_by = 1;

	/* CYCLE */
1186
	if (is_cycled != NULL)
1187 1188
	{
		new->is_cycled = intVal(is_cycled->arg);
1189
		Assert(BoolIsValid(new->is_cycled));
1190 1191 1192
	}
	else if (isInit)
		new->is_cycled = false;
1193

1194
	/* MAXVALUE (null arg means NO MAXVALUE) */
1195
	if (max_value != NULL && max_value->arg)
1196
		new->max_value = defGetInt64(max_value);
1197
	else if (isInit || max_value != NULL)
1198
	{
1199
		if (new->increment_by > 0)
B
Bruce Momjian 已提交
1200
			new->max_value = SEQ_MAXVALUE;		/* ascending seq */
1201
		else
B
Bruce Momjian 已提交
1202
			new->max_value = -1;	/* descending seq */
1203
	}
1204

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

1216
	/* crosscheck min/max */
1217
	if (new->min_value >= new->max_value)
1218
	{
B
Bruce Momjian 已提交
1219 1220 1221
		char		bufm[100],
					bufx[100];

1222 1223
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
		snprintf(bufx, sizeof(bufx), INT64_FORMAT, new->max_value);
1224 1225 1226 1227
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("MINVALUE (%s) must be less than MAXVALUE (%s)",
						bufm, bufx)));
1228
	}
1229

1230 1231 1232
	/* START WITH */
	if (start_value != NULL)
		new->start_value = defGetInt64(start_value);
1233
	else if (isInit)
1234
	{
1235
		if (new->increment_by > 0)
1236
			new->start_value = new->min_value;	/* ascending seq */
1237
		else
1238
			new->start_value = new->max_value;	/* descending seq */
1239
	}
1240

1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
	/* 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)));
	}

1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
	/* 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) */
1285
	if (new->last_value < new->min_value)
1286
	{
B
Bruce Momjian 已提交
1287 1288 1289
		char		bufs[100],
					bufm[100];

1290 1291
		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
1292 1293
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1294 1295
			   errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)",
					  bufs, bufm)));
1296
	}
1297
	if (new->last_value > new->max_value)
1298
	{
B
Bruce Momjian 已提交
1299 1300 1301
		char		bufs[100],
					bufm[100];

1302 1303
		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
1304 1305
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1306 1307
			errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)",
				   bufs, bufm)));
1308
	}
1309

B
Bruce Momjian 已提交
1310
	/* CACHE */
1311
	if (cache_value != NULL)
1312
	{
1313 1314 1315 1316
		new->cache_value = defGetInt64(cache_value);
		if (new->cache_value <= 0)
		{
			char		buf[100];
B
Bruce Momjian 已提交
1317

1318 1319 1320 1321 1322 1323
			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)));
		}
1324
	}
1325 1326
	else if (isInit)
		new->cache_value = 1;
1327 1328
}

1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
/*
 * 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 已提交
1353
				errhint("Specify OWNED BY table.column or OWNED BY NONE.")));
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
		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 已提交
1382
					 errmsg("sequence must have same owner as table it is linked to")));
1383 1384 1385
		if (RelationGetNamespace(seqrel) != RelationGetNamespace(tablerel))
			ereport(ERROR,
					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
P
Peter Eisentraut 已提交
1386
					 errmsg("sequence must be in same schema as table it is linked to")));
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397

		/* 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 已提交
1398 1399
	 * OK, we are ready to update pg_depend.  First remove any existing AUTO
	 * dependencies for the sequence, then optionally add a new one.
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
	 */
	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 已提交
1422

B
Bruce Momjian 已提交
1423 1424
void
seq_redo(XLogRecPtr lsn, XLogRecord *record)
V
Vadim B. Mikheev 已提交
1425
{
B
Bruce Momjian 已提交
1426 1427 1428 1429 1430 1431
	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);
1432
	sequence_magic *sm;
V
Vadim B. Mikheev 已提交
1433

1434 1435 1436
	/* Backup blocks are not used in seq records */
	Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));

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

1440
	buffer = XLogReadBuffer(xlrec->node, 0, true);
1441
	Assert(BufferIsValid(buffer));
V
Vadim B. Mikheev 已提交
1442 1443
	page = (Page) BufferGetPage(buffer);

1444 1445
	/* Always reinit the page and reinstall the magic number */
	/* See comments in DefineSequence */
1446 1447 1448
	PageInit((Page) page, BufferGetPageSize(buffer), sizeof(sequence_magic));
	sm = (sequence_magic *) PageGetSpecialPointer(page);
	sm->magic = SEQ_MAGIC;
V
Vadim B. Mikheev 已提交
1449

B
Bruce Momjian 已提交
1450
	item = (char *) xlrec + sizeof(xl_seq_rec);
1451 1452
	itemsz = record->xl_len - sizeof(xl_seq_rec);
	itemsz = MAXALIGN(itemsz);
B
Bruce Momjian 已提交
1453
	if (PageAddItem(page, (Item) item, itemsz,
1454
					FirstOffsetNumber, false, false) == InvalidOffsetNumber)
1455
		elog(PANIC, "seq_redo: failed to add item to page");
V
Vadim B. Mikheev 已提交
1456 1457

	PageSetLSN(page, lsn);
1458
	PageSetTLI(page, ThisTimeLineID);
1459 1460
	MarkBufferDirty(buffer);
	UnlockReleaseBuffer(buffer);
V
Vadim B. Mikheev 已提交
1461 1462
}

B
Bruce Momjian 已提交
1463
void
1464
seq_desc(StringInfo buf, uint8 xl_info, char *rec)
V
Vadim B. Mikheev 已提交
1465
{
B
Bruce Momjian 已提交
1466 1467
	uint8		info = xl_info & ~XLR_INFO_MASK;
	xl_seq_rec *xlrec = (xl_seq_rec *) rec;
V
Vadim B. Mikheev 已提交
1468 1469

	if (info == XLOG_SEQ_LOG)
1470
		appendStringInfo(buf, "log: ");
V
Vadim B. Mikheev 已提交
1471 1472
	else
	{
1473
		appendStringInfo(buf, "UNKNOWN");
V
Vadim B. Mikheev 已提交
1474 1475 1476
		return;
	}

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