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

📄 inv_api.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * inv_api.c *	  routines for manipulating inversion fs large objects. This file *	  contains the user-level large object application interface routines. * * * Note: many of these routines leak memory in CurrentMemoryContext, as indeed * does most of the backend code.  We expect that CurrentMemoryContext will * be a short-lived context.  Data that must persist across function calls * is kept either in CacheMemoryContext (the Relation structs) or in the * memory context given to inv_open (for LargeObjectDesc structs). * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.113.2.1 2006/04/26 00:35:31 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "access/tuptoaster.h"#include "catalog/catalog.h"#include "catalog/indexing.h"#include "catalog/pg_largeobject.h"#include "commands/comment.h"#include "libpq/libpq-fs.h"#include "storage/large_object.h"#include "utils/fmgroids.h"#include "utils/lsyscache.h"#include "utils/resowner.h"/* * All accesses to pg_largeobject and its index make use of a single Relation * reference, so that we only need to open pg_relation once per transaction. * To avoid problems when the first such reference occurs inside a * subtransaction, we execute a slightly klugy maneuver to assign ownership of * the Relation reference to TopTransactionResourceOwner. */static Relation lo_heap_r = NULL;static Relation lo_index_r = NULL;/* * Open pg_largeobject and its index, if not already done in current xact */static voidopen_lo_relation(void){	ResourceOwner currentOwner;	if (lo_heap_r && lo_index_r)		return;					/* already open in current xact */	/* Arrange for the top xact to own these relation references */	currentOwner = CurrentResourceOwner;	PG_TRY();	{		CurrentResourceOwner = TopTransactionResourceOwner;		/* Use RowExclusiveLock since we might either read or write */		if (lo_heap_r == NULL)			lo_heap_r = heap_open(LargeObjectRelationId, RowExclusiveLock);		if (lo_index_r == NULL)			lo_index_r = index_open(LargeObjectLOidPNIndexId);	}	PG_CATCH();	{		/* Ensure CurrentResourceOwner is restored on error */		CurrentResourceOwner = currentOwner;		PG_RE_THROW();	}	PG_END_TRY();	CurrentResourceOwner = currentOwner;}/* * Clean up at main transaction end */voidclose_lo_relation(bool isCommit){	if (lo_heap_r || lo_index_r)	{		/*		 * Only bother to close if committing; else abort cleanup will handle		 * it		 */		if (isCommit)		{			ResourceOwner currentOwner;			currentOwner = CurrentResourceOwner;			PG_TRY();			{				CurrentResourceOwner = TopTransactionResourceOwner;				if (lo_index_r)					index_close(lo_index_r);				if (lo_heap_r)					heap_close(lo_heap_r, NoLock);			}			PG_CATCH();			{				/* Ensure CurrentResourceOwner is restored on error */				CurrentResourceOwner = currentOwner;				PG_RE_THROW();			}			PG_END_TRY();			CurrentResourceOwner = currentOwner;		}		lo_heap_r = NULL;		lo_index_r = NULL;	}}/* * Same as pg_largeobject.c's LargeObjectExists(), except snapshot to * read with can be specified. */static boolmyLargeObjectExists(Oid loid, Snapshot snapshot){	bool		retval = false;	Relation	pg_largeobject;	ScanKeyData skey[1];	SysScanDesc sd;	/*	 * See if we can find any tuples belonging to the specified LO	 */	ScanKeyInit(&skey[0],				Anum_pg_largeobject_loid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(loid));	pg_largeobject = heap_open(LargeObjectRelationId, AccessShareLock);	sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndexId, true,							snapshot, 1, skey);	if (systable_getnext(sd) != NULL)		retval = true;	systable_endscan(sd);	heap_close(pg_largeobject, AccessShareLock);	return retval;}static int32getbytealen(bytea *data){	Assert(!VARATT_IS_EXTENDED(data));	if (VARSIZE(data) < VARHDRSZ)		elog(ERROR, "invalid VARSIZE(data)");	return (VARSIZE(data) - VARHDRSZ);}/* *	inv_create -- create a new large object * *	Arguments: *	  lobjId - OID to use for new large object, or InvalidOid to pick one * *	Returns: *	  OID of new object * * If lobjId is not InvalidOid, then an error occurs if the OID is already * in use. */Oidinv_create(Oid lobjId){	/*	 * Allocate an OID to be the LO's identifier, unless we were told what to	 * use.  We can use the index on pg_largeobject for checking OID	 * uniqueness, even though it has additional columns besides OID.	 */	if (!OidIsValid(lobjId))	{		open_lo_relation();		lobjId = GetNewOidWithIndex(lo_heap_r, lo_index_r);	}	/*	 * Create the LO by writing an empty first page for it in pg_largeobject	 * (will fail if duplicate)	 */	LargeObjectCreate(lobjId);	/*	 * Advance command counter to make new tuple visible to later operations.	 */	CommandCounterIncrement();	return lobjId;}/* *	inv_open -- access an existing large object. * *		Returns: *		  Large object descriptor, appropriately filled in.  The descriptor *		  and subsidiary data are allocated in the specified memory context, *		  which must be suitably long-lived for the caller's purposes. */LargeObjectDesc *inv_open(Oid lobjId, int flags, MemoryContext mcxt){	LargeObjectDesc *retval;	retval = (LargeObjectDesc *) MemoryContextAlloc(mcxt,													sizeof(LargeObjectDesc));	retval->id = lobjId;	retval->subid = GetCurrentSubTransactionId();	retval->offset = 0;	if (flags & INV_WRITE)	{		retval->snapshot = SnapshotNow;		retval->flags = IFS_WRLOCK | IFS_RDLOCK;	}	else if (flags & INV_READ)	{		/* be sure to copy snap into mcxt */		MemoryContext oldContext = MemoryContextSwitchTo(mcxt);		retval->snapshot = CopySnapshot(ActiveSnapshot);		retval->flags = IFS_RDLOCK;		MemoryContextSwitchTo(oldContext);	}	else		elog(ERROR, "invalid flags: %d", flags);	/* Can't use LargeObjectExists here because it always uses SnapshotNow */	if (!myLargeObjectExists(lobjId, retval->snapshot))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("large object %u does not exist", lobjId)));	return retval;}/* * Closes a large object descriptor previously made by inv_open(), and * releases the long-term memory used by it. */voidinv_close(LargeObjectDesc *obj_desc){	Assert(PointerIsValid(obj_desc));	if (obj_desc->snapshot != SnapshotNow)		FreeSnapshot(obj_desc->snapshot);	pfree(obj_desc);}/* * Destroys an existing large object (not to be confused with a descriptor!) * * returns -1 if failed */intinv_drop(Oid lobjId){	LargeObjectDrop(lobjId);	/* Delete any comments on the large object */	DeleteComments(lobjId, LargeObjectRelationId, 0);	/*	 * Advance command counter so that tuple removal will be seen by later	 * large-object operations in this transaction.	 */	CommandCounterIncrement();	return 1;}/* * Determine size of a large object * * NOTE: LOs can contain gaps, just like Unix files.  We actually return * the offset of the last byte + 1. */static uint32inv_getsize(LargeObjectDesc *obj_desc){	bool		found = false;	uint32		lastbyte = 0;	ScanKeyData skey[1];	IndexScanDesc sd;	HeapTuple	tuple;	Assert(PointerIsValid(obj_desc));	open_lo_relation();	ScanKeyInit(&skey[0],				Anum_pg_largeobject_loid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(obj_desc->id));	sd = index_beginscan(lo_heap_r, lo_index_r,						 obj_desc->snapshot, 1, skey);	/*	 * Because the pg_largeobject index is on both loid and pageno, but we	 * constrain only loid, a backwards scan should visit all pages of the	 * large object in reverse pageno order.  So, it's sufficient to examine	 * the first valid tuple (== last valid page).	 */	while ((tuple = index_getnext(sd, BackwardScanDirection)) != NULL)	{		Form_pg_largeobject data;		bytea	   *datafield;		bool		pfreeit;		found = true;		data = (Form_pg_largeobject) GETSTRUCT(tuple);		datafield = &(data->data);		pfreeit = false;		if (VARATT_IS_EXTENDED(datafield))		{			datafield = (bytea *)				heap_tuple_untoast_attr((varattrib *) datafield);			pfreeit = true;		}		lastbyte = data->pageno * LOBLKSIZE + getbytealen(datafield);

⌨️ 快捷键说明

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