sequence.c 13.4 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * sequence.c
4
 *	  PostgreSQL sequences support code.
5 6 7 8 9 10 11
 *
 *-------------------------------------------------------------------------
 */
#include <stdio.h>
#include <string.h>

#include <postgres.h>
M
 
Marc G. Fournier 已提交
12
#include <miscadmin.h>
13 14 15 16 17

#include <access/heapam.h>
#include <commands/creatinh.h>
#include <commands/sequence.h>
#include <utils/builtins.h>
M
 
Marc G. Fournier 已提交
18
#include <utils/acl.h>
19

20
#define SEQ_MAGIC	  0x1717
21 22 23 24

#define SEQ_MAXVALUE	((int4)0x7FFFFFFF)
#define SEQ_MINVALUE	-(SEQ_MAXVALUE)

25 26
typedef struct FormData_pg_sequence
{
27 28 29 30 31 32 33 34
	NameData	sequence_name;
	int4		last_value;
	int4		increment_by;
	int4		max_value;
	int4		min_value;
	int4		cache_value;
	char		is_cycled;
	char		is_called;
35
} FormData_pg_sequence;
36

37
typedef FormData_pg_sequence *Form_pg_sequence;
38 39 40

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

44 45
typedef struct SeqTableData
{
46 47 48 49 50 51
	char	   *name;
	Oid			relid;
	Relation	rel;
	int4		cached;
	int4		last;
	int4		increment;
52
	struct SeqTableData *next;
53
} SeqTableData;
54 55 56 57 58

typedef SeqTableData *SeqTable;

static SeqTable seqtab = NULL;

59
static SeqTable init_sequence(char *caller, char *name);
60 61
static Form_pg_sequence read_info(char *caller, SeqTable elm, Buffer *buf);
static void init_params(CreateSeqStmt *seq, Form_pg_sequence new);
62
static int	get_param(DefElem *def);
63 64

/*
B
Bruce Momjian 已提交
65
 * DefineSequence
66
 *				Creates a new sequence relation
67 68
 */
void
69
DefineSequence(CreateSeqStmt *seq)
70
{
71
	FormData_pg_sequence new;
72 73 74 75 76 77
	CreateStmt *stmt = makeNode(CreateStmt);
	ColumnDef  *coldef;
	TypeName   *typnam;
	Relation	rel;
	Buffer		buf;
	PageHeader	page;
78
	sequence_magic *sm;
79 80 81 82 83
	HeapTuple	tuple;
	TupleDesc	tupDesc;
	Datum		value[SEQ_COL_LASTCOL];
	char		null[SEQ_COL_LASTCOL];
	int			i;
84
	NameData	name;
85 86 87 88 89

	/* Check and set values */
	init_params(seq, &new);

	/*
90
	 * Create relation (and fill *null & *value)
91 92 93
	 */
	stmt->tableElts = NIL;
	for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
94
	{
95 96 97
		typnam = makeNode(TypeName);
		typnam->setof = FALSE;
		typnam->arrayBounds = NULL;
B
Bruce Momjian 已提交
98
		typnam->typmod = -1;
99 100 101 102 103 104 105 106
		coldef = makeNode(ColumnDef);
		coldef->typename = typnam;
		coldef->defval = NULL;
		coldef->is_not_null = false;
		null[i - 1] = ' ';

		switch (i)
		{
107 108 109
			case SEQ_COL_NAME:
				typnam->name = "name";
				coldef->colname = "sequence_name";
110 111
				namestrcpy(&name, seq->seqname);
				value[i - 1] = NameGetDatum(&name);
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
				break;
			case SEQ_COL_LASTVAL:
				typnam->name = "int4";
				coldef->colname = "last_value";
				value[i - 1] = Int32GetDatum(new.last_value);
				break;
			case SEQ_COL_INCBY:
				typnam->name = "int4";
				coldef->colname = "increment_by";
				value[i - 1] = Int32GetDatum(new.increment_by);
				break;
			case SEQ_COL_MAXVALUE:
				typnam->name = "int4";
				coldef->colname = "max_value";
				value[i - 1] = Int32GetDatum(new.max_value);
				break;
			case SEQ_COL_MINVALUE:
				typnam->name = "int4";
				coldef->colname = "min_value";
				value[i - 1] = Int32GetDatum(new.min_value);
				break;
			case SEQ_COL_CACHE:
				typnam->name = "int4";
				coldef->colname = "cache_value";
				value[i - 1] = Int32GetDatum(new.cache_value);
				break;
			case SEQ_COL_CYCLE:
				typnam->name = "char";
				coldef->colname = "is_cycled";
				value[i - 1] = CharGetDatum(new.is_cycled);
				break;
			case SEQ_COL_CALLED:
				typnam->name = "char";
				coldef->colname = "is_called";
				value[i - 1] = CharGetDatum('f');
				break;
148 149 150 151 152 153 154 155
		}
		stmt->tableElts = lappend(stmt->tableElts, coldef);
	}

	stmt->relname = seq->seqname;
	stmt->inhRelnames = NIL;
	stmt->constraints = NIL;

156
	DefineRelation(stmt, RELKIND_SEQUENCE);
157 158 159 160

	rel = heap_openr(seq->seqname);
	Assert(RelationIsValid(rel));

V
Vadim B. Mikheev 已提交
161
	LockRelation(rel, AccessExclusiveLock);
162

163
	tupDesc = RelationGetDescr(rel);
164 165 166 167 168

	Assert(RelationGetNumberOfBlocks(rel) == 0);
	buf = ReadBuffer(rel, P_NEW);

	if (!BufferIsValid(buf))
169
		elog(ERROR, "DefineSequence: ReadBuffer failed");
170 171 172 173 174 175 176 177 178 179 180 181

	page = (PageHeader) BufferGetPage(buf);

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

	/* Now - form & insert sequence tuple */
	tuple = heap_formtuple(tupDesc, value, null);
	heap_insert(rel, tuple);

	if (WriteBuffer(buf) == STATUS_ERROR)
182
		elog(ERROR, "DefineSequence: WriteBuffer failed");
183

V
Vadim B. Mikheev 已提交
184
	UnlockRelation(rel, AccessExclusiveLock);
185 186 187
	heap_close(rel);

	return;
188 189 190 191 192

}


int4
193
nextval(struct varlena * seqin)
194
{
195 196 197
	char	   *seqname = textout(seqin);
	SeqTable	elm;
	Buffer		buf;
198
	Form_pg_sequence seq;
199 200 201 202 203 204 205
	int4		incby,
				maxv,
				minv,
				cache;
	int4		result,
				next,
				rescnt = 0;
206

V
Vadim B. Mikheev 已提交
207
	/* open and AccessShareLock sequence */
208 209 210 211 212 213
	elm = init_sequence("nextval", seqname);
	pfree(seqname);

	if (elm->last != elm->cached)		/* some numbers were cached */
	{
		elm->last += elm->increment;
214
		return elm->last;
215
	}
216

B
Bruce Momjian 已提交
217 218
	seq = read_info("nextval", elm, &buf);		/* lock page' buffer and
												 * read tuple */
219 220 221 222 223 224 225 226 227 228 229

	next = result = seq->last_value;
	incby = seq->increment_by;
	maxv = seq->max_value;
	minv = seq->min_value;
	cache = seq->cache_value;

	if (seq->is_called != 't')
		rescnt++;				/* last_value if not called */

	while (rescnt < cache)		/* try to fetch cache numbers */
230
	{
231 232 233 234 235 236 237 238 239 240 241 242 243

		/*
		 * Check MAXVALUE for ascending sequences and MINVALUE for
		 * descending sequences
		 */
		if (incby > 0)			/* ascending sequence */
		{
			if ((maxv >= 0 && next > maxv - incby) ||
				(maxv < 0 && next + incby > maxv))
			{
				if (rescnt > 0)
					break;		/* stop caching */
				if (seq->is_cycled != 't')
244
					elog(ERROR, "%s.nextval: got MAXVALUE (%d)",
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
						 elm->name, maxv);
				next = minv;
			}
			else
				next += incby;
		}
		else
/* descending sequence */
		{
			if ((minv < 0 && next < minv - incby) ||
				(minv >= 0 && next + incby < minv))
			{
				if (rescnt > 0)
					break;		/* stop caching */
				if (seq->is_cycled != 't')
260
					elog(ERROR, "%s.nextval: got MINVALUE (%d)",
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
						 elm->name, minv);
				next = maxv;
			}
			else
				next += incby;
		}
		rescnt++;				/* got result */
		if (rescnt == 1)		/* if it's first one - */
			result = next;		/* it's what to return */
	}

	/* save info in local cache */
	elm->last = result;			/* last returned number */
	elm->cached = next;			/* last cached number */

	/* save info in sequence relation */
	seq->last_value = next;		/* last fetched number */
	seq->is_called = 't';

V
Vadim B. Mikheev 已提交
280 281
	LockBuffer(buf, BUFFER_LOCK_UNLOCK);

282
	if (WriteBuffer(buf) == STATUS_ERROR)
283
		elog(ERROR, "%s.nextval: WriteBuffer failed", elm->name);
284

285
	return result;
286

287 288 289 290
}


int4
291
currval(struct varlena * seqin)
292
{
293 294 295
	char	   *seqname = textout(seqin);
	SeqTable	elm;
	int4		result;
296

V
Vadim B. Mikheev 已提交
297
	/* open and AccessShareLock sequence */
298 299 300 301
	elm = init_sequence("currval", seqname);
	pfree(seqname);

	if (elm->increment == 0)	/* nextval/read_info were not called */
302
		elog(ERROR, "%s.currval is not yet defined in this session", elm->name);
303 304 305

	result = elm->last;

306
	return result;
307

308 309
}

M
 
Marc G. Fournier 已提交
310 311 312
int4
setval(struct varlena * seqin, int4 next)
{
313
	char	   *seqname = textout(seqin);
M
 
Marc G. Fournier 已提交
314
	SeqTable	elm;
315
	Buffer		buf;
316
	Form_pg_sequence seq;
M
 
Marc G. Fournier 已提交
317 318 319 320 321 322 323

#ifndef NO_SECURITY
	if (pg_aclcheck(seqname, getpgusername(), ACL_WR) != ACLCHECK_OK)
		elog(ERROR, "%s.setval: you don't have permissions to set sequence %s",
			 seqname, seqname);
#endif

V
Vadim B. Mikheev 已提交
324
	/* open and AccessShareLock sequence */
325
	elm = init_sequence("setval", seqname);
B
Bruce Momjian 已提交
326 327
	seq = read_info("setval", elm, &buf);		/* lock page' buffer and
												 * read tuple */
M
 
Marc G. Fournier 已提交
328

329 330 331 332
	if (seq->cache_value != 1)
	{
		elog(ERROR, "%s.setval: can't set value of sequence %s, cache != 1",
			 seqname, seqname);
M
 
Marc G. Fournier 已提交
333 334
	}

335 336 337 338
	if ((next < seq->min_value) || (next > seq->max_value))
	{
		elog(ERROR, "%s.setval: value %d is of of bounds (%d,%d)",
			 seqname, next, seq->min_value, seq->max_value);
M
 
Marc G. Fournier 已提交
339 340 341 342 343 344 345 346 347 348
	}

	/* save info in local cache */
	elm->last = next;			/* last returned number */
	elm->cached = next;			/* last cached number */

	/* save info in sequence relation */
	seq->last_value = next;		/* last fetched number */
	seq->is_called = 't';

V
Vadim B. Mikheev 已提交
349 350
	LockBuffer(buf, BUFFER_LOCK_UNLOCK);

351 352
	if (WriteBuffer(buf) == STATUS_ERROR)
		elog(ERROR, "%s.settval: WriteBuffer failed", seqname);
M
 
Marc G. Fournier 已提交
353

354
	return next;
M
 
Marc G. Fournier 已提交
355 356
}

357
static Form_pg_sequence
B
Bruce Momjian 已提交
358
read_info(char *caller, SeqTable elm, Buffer *buf)
359
{
B
Bruce Momjian 已提交
360 361 362
	PageHeader	page;
	ItemId		lp;
	HeapTupleData tuple;
363
	sequence_magic *sm;
B
Bruce Momjian 已提交
364
	Form_pg_sequence seq;
365 366

	if (RelationGetNumberOfBlocks(elm->rel) != 1)
367
		elog(ERROR, "%s.%s: invalid number of blocks in sequence",
368 369 370 371
			 elm->name, caller);

	*buf = ReadBuffer(elm->rel, 0);
	if (!BufferIsValid(*buf))
372
		elog(ERROR, "%s.%s: ReadBuffer failed", elm->name, caller);
373

V
Vadim B. Mikheev 已提交
374 375
	LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);

376 377 378 379
	page = (PageHeader) BufferGetPage(*buf);
	sm = (sequence_magic *) PageGetSpecialPointer(page);

	if (sm->magic != SEQ_MAGIC)
380
		elog(ERROR, "%s.%s: bad magic (%08X)", elm->name, caller, sm->magic);
381 382 383

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

386
	seq = (Form_pg_sequence) GETSTRUCT(&tuple);
387 388 389

	elm->increment = seq->increment_by;

390
	return seq;
391 392 393 394

}


395
static SeqTable
396
init_sequence(char *caller, char *name)
397
{
398 399 400
	SeqTable	elm,
				priv = (SeqTable) NULL;
	SeqTable	temp;
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422

	for (elm = seqtab; elm != (SeqTable) NULL;)
	{
		if (strcmp(elm->name, name) == 0)
			break;
		priv = elm;
		elm = elm->next;
	}

	if (elm == (SeqTable) NULL) /* not found */
	{
		temp = (SeqTable) malloc(sizeof(SeqTableData));
		temp->name = malloc(strlen(name) + 1);
		strcpy(temp->name, name);
		temp->rel = (Relation) NULL;
		temp->cached = temp->last = temp->increment = 0;
		temp->next = (SeqTable) NULL;
	}
	else
/* found */
	{
		if (elm->rel != (Relation) NULL)		/* already opened */
423
			return elm;
424 425 426 427 428 429
		temp = elm;
	}

	temp->rel = heap_openr(name);

	if (!RelationIsValid(temp->rel))
430
		elog(ERROR, "%s.%s: sequence does not exist", name, caller);
431

V
Vadim B. Mikheev 已提交
432
	LockRelation(temp->rel, AccessShareLock);
433 434

	if (temp->rel->rd_rel->relkind != RELKIND_SEQUENCE)
435
		elog(ERROR, "%s.%s: %s is not sequence !", name, caller, name);
436 437 438

	if (elm != (SeqTable) NULL) /* we opened sequence from our */
	{							/* SeqTable - check relid ! */
439
		if (RelationGetRelid(elm->rel) != elm->relid)
440 441 442 443
		{
			elog(NOTICE, "%s.%s: sequence was re-created",
				 name, caller, name);
			elm->cached = elm->last = elm->increment = 0;
444
			elm->relid = RelationGetRelid(elm->rel);
445 446 447 448 449
		}
	}
	else
	{
		elm = temp;
450
		elm->relid = RelationGetRelid(elm->rel);
451 452 453 454 455 456
		if (seqtab == (SeqTable) NULL)
			seqtab = elm;
		else
			priv->next = elm;
	}

457
	return elm;
458

459 460 461 462
}


/*
B
Bruce Momjian 已提交
463
 * CloseSequences
464
 *				is calling by xact mgr at commit/abort.
465 466
 */
void
467
CloseSequences(void)
468
{
469 470
	SeqTable	elm;
	Relation	rel;
471 472

	for (elm = seqtab; elm != (SeqTable) NULL;)
473
	{
474 475 476 477
		if (elm->rel != (Relation) NULL)		/* opened in current xact */
		{
			rel = elm->rel;
			elm->rel = (Relation) NULL;
V
Vadim B. Mikheev 已提交
478
			UnlockRelation(rel, AccessShareLock);
479 480 481 482 483 484 485
			heap_close(rel);
		}
		elm = elm->next;
	}

	return;

486 487 488
}


489
static void
490
init_params(CreateSeqStmt *seq, Form_pg_sequence new)
491
{
492 493 494 495 496 497
	DefElem    *last_value = NULL;
	DefElem    *increment_by = NULL;
	DefElem    *max_value = NULL;
	DefElem    *min_value = NULL;
	DefElem    *cache_value = NULL;
	List	   *option;
498 499 500 501

	new->is_cycled = 'f';
	foreach(option, seq->options)
	{
502
		DefElem    *defel = (DefElem *) lfirst(option);
503 504 505 506 507 508 509 510 511 512 513 514 515 516

		if (!strcasecmp(defel->defname, "increment"))
			increment_by = defel;
		else if (!strcasecmp(defel->defname, "start"))
			last_value = defel;
		else if (!strcasecmp(defel->defname, "maxvalue"))
			max_value = defel;
		else if (!strcasecmp(defel->defname, "minvalue"))
			min_value = defel;
		else if (!strcasecmp(defel->defname, "cache"))
			cache_value = defel;
		else if (!strcasecmp(defel->defname, "cycle"))
		{
			if (defel->arg != (Node *) NULL)
517
				elog(ERROR, "DefineSequence: CYCLE ??");
518 519 520
			new->is_cycled = 't';
		}
		else
521
			elog(ERROR, "DefineSequence: option \"%s\" not recognized",
522 523 524 525 526 527
				 defel->defname);
	}

	if (increment_by == (DefElem *) NULL)		/* INCREMENT BY */
		new->increment_by = 1;
	else if ((new->increment_by = get_param(increment_by)) == 0)
528
		elog(ERROR, "DefineSequence: can't INCREMENT by 0");
529 530

	if (max_value == (DefElem *) NULL)	/* MAXVALUE */
531
	{
532 533 534 535
		if (new->increment_by > 0)
			new->max_value = SEQ_MAXVALUE;		/* ascending seq */
		else
			new->max_value = -1;/* descending seq */
536
	}
537
	else
538
		new->max_value = get_param(max_value);
539

540
	if (min_value == (DefElem *) NULL)	/* MINVALUE */
541
	{
542 543 544 545
		if (new->increment_by > 0)
			new->min_value = 1; /* ascending seq */
		else
			new->min_value = SEQ_MINVALUE;		/* descending seq */
546
	}
547
	else
548 549 550
		new->min_value = get_param(min_value);

	if (new->min_value >= new->max_value)
551
		elog(ERROR, "DefineSequence: MINVALUE (%d) can't be >= MAXVALUE (%d)",
552 553 554
			 new->min_value, new->max_value);

	if (last_value == (DefElem *) NULL) /* START WITH */
555
	{
556 557 558 559
		if (new->increment_by > 0)
			new->last_value = new->min_value;	/* ascending seq */
		else
			new->last_value = new->max_value;	/* descending seq */
560
	}
561
	else
562 563 564
		new->last_value = get_param(last_value);

	if (new->last_value < new->min_value)
565
		elog(ERROR, "DefineSequence: START value (%d) can't be < MINVALUE (%d)",
566 567
			 new->last_value, new->min_value);
	if (new->last_value > new->max_value)
568
		elog(ERROR, "DefineSequence: START value (%d) can't be > MAXVALUE (%d)",
569 570 571 572 573
			 new->last_value, new->max_value);

	if (cache_value == (DefElem *) NULL)		/* CACHE */
		new->cache_value = 1;
	else if ((new->cache_value = get_param(cache_value)) <= 0)
574
		elog(ERROR, "DefineSequence: CACHE (%d) can't be <= 0",
575
			 new->cache_value);
576 577 578 579 580

}


static int
581
get_param(DefElem *def)
582
{
583
	if (def->arg == (Node *) NULL)
584
		elog(ERROR, "DefineSequence: \"%s\" value unspecified", def->defname);
585 586

	if (nodeTag(def->arg) == T_Integer)
587
		return intVal(def->arg);
588

589
	elog(ERROR, "DefineSequence: \"%s\" is to be integer", def->defname);
590
	return -1;
591
}