⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sequence.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * sequence.c *	  PostgreSQL sequences support code. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.125.2.1 2005/11/22 18:23:07 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/namespace.h"#include "catalog/pg_type.h"#include "commands/defrem.h"#include "commands/tablecmds.h"#include "commands/sequence.h"#include "miscadmin.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/resowner.h"#include "utils/syscache.h"/* * We don't want to log each fetching of a value from a sequence, * so we pre-log a few fetches in advance. In the event of * crash we can lose as much as we pre-logged. */#define SEQ_LOG_VALS	32/* * The "special area" of a sequence's buffer page looks like this. */#define SEQ_MAGIC	  0x1717typedef struct sequence_magic{	uint32		magic;} sequence_magic;/* * 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.) * * XXX We use linear search to find pre-existing SeqTable entries.	This is * 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. */typedef struct SeqTableData{	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 */} SeqTableData;typedef SeqTableData *SeqTable;static SeqTable seqtab = NULL;	/* Head of list of SeqTable items *//* * last_used_seq is updated by nextval() to point to the last used * sequence. */static SeqTableData *last_used_seq = NULL;static int64 nextval_internal(Oid relid);static void acquire_share_lock(Relation seqrel, SeqTable seq);static void init_sequence(Oid relid, 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, bool isInit);static void do_setval(Oid relid, int64 next, bool iscalled);/* * DefineSequence *				Creates a new sequence relation */voidDefineSequence(CreateSeqStmt *seq){	FormData_pg_sequence new;	CreateStmt *stmt = makeNode(CreateStmt);	Oid			seqoid;	Relation	rel;	Buffer		buf;	PageHeader	page;	sequence_magic *sm;	HeapTuple	tuple;	TupleDesc	tupDesc;	Datum		value[SEQ_COL_LASTCOL];	char		null[SEQ_COL_LASTCOL];	int			i;	NameData	name;	/* Check and set all option values */	init_params(seq->options, &new, true);	/*	 * Create relation (and fill *null & *value)	 */	stmt->tableElts = NIL;	for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)	{		ColumnDef  *coldef;		TypeName   *typnam;		typnam = makeNode(TypeName);		typnam->setof = FALSE;		typnam->arrayBounds = NIL;		typnam->typmod = -1;		coldef = makeNode(ColumnDef);		coldef->typename = typnam;		coldef->inhcount = 0;		coldef->is_local = true;		coldef->is_not_null = true;		coldef->raw_default = NULL;		coldef->cooked_default = NULL;		coldef->constraints = NIL;		coldef->support = NULL;		null[i - 1] = ' ';		switch (i)		{			case SEQ_COL_NAME:				typnam->typeid = NAMEOID;				coldef->colname = "sequence_name";				namestrcpy(&name, seq->sequence->relname);				value[i - 1] = NameGetDatum(&name);				break;			case SEQ_COL_LASTVAL:				typnam->typeid = INT8OID;				coldef->colname = "last_value";				value[i - 1] = Int64GetDatumFast(new.last_value);				break;			case SEQ_COL_INCBY:				typnam->typeid = INT8OID;				coldef->colname = "increment_by";				value[i - 1] = Int64GetDatumFast(new.increment_by);				break;			case SEQ_COL_MAXVALUE:				typnam->typeid = INT8OID;				coldef->colname = "max_value";				value[i - 1] = Int64GetDatumFast(new.max_value);				break;			case SEQ_COL_MINVALUE:				typnam->typeid = INT8OID;				coldef->colname = "min_value";				value[i - 1] = Int64GetDatumFast(new.min_value);				break;			case SEQ_COL_CACHE:				typnam->typeid = INT8OID;				coldef->colname = "cache_value";				value[i - 1] = Int64GetDatumFast(new.cache_value);				break;			case SEQ_COL_LOG:				typnam->typeid = INT8OID;				coldef->colname = "log_cnt";				value[i - 1] = Int64GetDatum((int64) 1);				break;			case SEQ_COL_CYCLE:				typnam->typeid = BOOLOID;				coldef->colname = "is_cycled";				value[i - 1] = BoolGetDatum(new.is_cycled);				break;			case SEQ_COL_CALLED:				typnam->typeid = BOOLOID;				coldef->colname = "is_called";				value[i - 1] = BoolGetDatum(false);				break;		}		stmt->tableElts = lappend(stmt->tableElts, coldef);	}	stmt->relation = seq->sequence;	stmt->inhRelations = NIL;	stmt->constraints = NIL;	stmt->hasoids = MUST_NOT_HAVE_OIDS;	stmt->oncommit = ONCOMMIT_NOOP;	stmt->tablespacename = NULL;	seqoid = DefineRelation(stmt, RELKIND_SEQUENCE);	rel = heap_open(seqoid, AccessExclusiveLock);	tupDesc = RelationGetDescr(rel);	/* Initialize first page of relation with special magic number */	buf = ReadBuffer(rel, P_NEW);	Assert(BufferGetBlockNumber(buf) == 0);	page = (PageHeader) BufferGetPage(buf);	PageInit((Page) page, BufferGetPageSize(buf), sizeof(sequence_magic));	sm = (sequence_magic *) PageGetSpecialPointer(page);	sm->magic = SEQ_MAGIC;	/* hack: ensure heap_insert will insert on the just-created page */	rel->rd_targblock = 0;	/* Now form & insert sequence tuple */	tuple = heap_formtuple(tupDesc, value, null);	simple_heap_insert(rel, tuple);	Assert(ItemPointerGetOffsetNumber(&(tuple->t_self)) == FirstOffsetNumber);	/*	 * Two special hacks here:	 *	 * 1. Since VACUUM does not process sequences, we have to force the tuple	 * to have xmin = FrozenTransactionId now.	Otherwise it would become	 * invisible to SELECTs after 2G transactions.	It is okay to do this	 * 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 would re-init	 * page and sequence magic number would be lost.  This means two log	 * records instead of one :-(	 */	LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);	START_CRIT_SECTION();	{		/*		 * 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.		 */		ItemId		itemId;		Item		item;		itemId = PageGetItemId((Page) page, FirstOffsetNumber);		item = PageGetItem((Page) page, itemId);		HeapTupleHeaderSetXmin((HeapTupleHeader) item, FrozenTransactionId);		((HeapTupleHeader) item)->t_infomask |= HEAP_XMIN_COMMITTED;		HeapTupleHeaderSetXmin(tuple->t_data, FrozenTransactionId);		tuple->t_data->t_infomask |= HEAP_XMIN_COMMITTED;	}	/* XLOG stuff */	if (!rel->rd_istemp)	{		xl_seq_rec	xlrec;		XLogRecPtr	recptr;		XLogRecData rdata[2];		Form_pg_sequence newseq = (Form_pg_sequence) GETSTRUCT(tuple);		/* We do not log first nextval call, so "advance" sequence here */		/* Note we are scribbling on local tuple, not the disk buffer */		newseq->is_called = true;		newseq->log_cnt = 0;		xlrec.node = rel->rd_node;		rdata[0].data = (char *) &xlrec;		rdata[0].len = sizeof(xl_seq_rec);		rdata[0].buffer = InvalidBuffer;		rdata[0].next = &(rdata[1]);		rdata[1].data = (char *) tuple->t_data;		rdata[1].len = tuple->t_len;		rdata[1].buffer = InvalidBuffer;		rdata[1].next = NULL;		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);		PageSetLSN(page, recptr);		PageSetTLI(page, ThisTimeLineID);	}	END_CRIT_SECTION();	LockBuffer(buf, BUFFER_LOCK_UNLOCK);	WriteBuffer(buf);	heap_close(rel, NoLock);}/* * AlterSequence * * Modify the definition of a sequence relation */voidAlterSequence(AlterSeqStmt *stmt){	Oid			relid;	SeqTable	elm;	Relation	seqrel;	Buffer		buf;	Page		page;	Form_pg_sequence seq;	FormData_pg_sequence new;	/* open and AccessShareLock sequence */	relid = RangeVarGetRelid(stmt->sequence, false);	init_sequence(relid, &elm, &seqrel);	/* allow ALTER to sequence owner only */	if (!pg_class_ownercheck(elm->relid, GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,					   stmt->sequence->relname);	/* lock page' buffer and read tuple into new sequence structure */	seq = read_info(elm, seqrel, &buf);	page = BufferGetPage(buf);	/* Copy old values of options into workspace */	memcpy(&new, seq, sizeof(FormData_pg_sequence));	/* Check and set new values */	init_params(stmt->options, &new, false);	/* Now okay to update the on-disk tuple */	memcpy(seq, &new, sizeof(FormData_pg_sequence));	/* Clear local cache so that we don't think we have cached numbers */	elm->last = new.last_value; /* last returned number */	elm->cached = new.last_value;		/* last cached number (forget cached										 * values) */	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].data = (char *) &xlrec;		rdata[0].len = sizeof(xl_seq_rec);		rdata[0].buffer = InvalidBuffer;		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;		rdata[1].buffer = InvalidBuffer;		rdata[1].next = NULL;		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);		PageSetLSN(page, recptr);		PageSetTLI(page, ThisTimeLineID);	}	END_CRIT_SECTION();	LockBuffer(buf, BUFFER_LOCK_UNLOCK);	WriteBuffer(buf);	relation_close(seqrel, NoLock);}/* * 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. */Datumnextval(PG_FUNCTION_ARGS){	text	   *seqin = PG_GETARG_TEXT_P(0);	RangeVar   *sequence;	Oid			relid;	sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin));	relid = RangeVarGetRelid(sequence, false);	PG_RETURN_INT64(nextval_internal(relid));}Datumnextval_oid(PG_FUNCTION_ARGS){	Oid			relid = PG_GETARG_OID(0);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -