mirror of
https://github.com/postgres/postgres.git
synced 2025-06-11 20:28:21 +03:00
Postgres95 1.01 Distribution - Virgin Sources
This commit is contained in:
15
src/backend/utils/cache/Makefile.inc
vendored
Normal file
15
src/backend/utils/cache/Makefile.inc
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile.inc--
|
||||
# Makefile for utils/cache
|
||||
#
|
||||
# Copyright (c) 1994, Regents of the University of California
|
||||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/Makefile.inc,v 1.1.1.1 1996/07/09 06:22:06 scrappy Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
SUBSRCS+= catcache.c inval.c rel.c relcache.c syscache.c lsyscache.c fcache.c
|
||||
|
1023
src/backend/utils/cache/catcache.c
vendored
Normal file
1023
src/backend/utils/cache/catcache.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
297
src/backend/utils/cache/fcache.c
vendored
Normal file
297
src/backend/utils/cache/fcache.c
vendored
Normal file
@ -0,0 +1,297 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* fcache.c--
|
||||
* Code for the 'function cache' used in Oper and Func nodes....
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.1.1.1 1996/07/09 06:22:06 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "c.h"
|
||||
#include "access/htup.h"
|
||||
#include "utils/catcache.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_language.h"
|
||||
#include "catalog/pg_class.h"
|
||||
#include "parser/parsetree.h" /* for getrelname() */
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fcache.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/palloc.h"
|
||||
#include "nodes/primnodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
static Oid GetDynamicFuncArgType(Var *arg, ExprContext *econtext);
|
||||
static FunctionCachePtr init_fcache(Oid foid,
|
||||
bool use_syscache,
|
||||
List *argList,
|
||||
ExprContext *econtext);
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
*
|
||||
* Initialize the 'FunctionCache' given the PG_PROC oid.
|
||||
*
|
||||
*
|
||||
* NOTE: This function can be called when the system cache is being
|
||||
* initialized. Therefore, use_syscache should ONLY be true
|
||||
* when the function return type is interesting (ie: set_fcache).
|
||||
*-----------------------------------------------------------------
|
||||
*/
|
||||
#define FuncArgTypeIsDynamic(arg) \
|
||||
(IsA(arg,Var) && ((Var*)arg)->varattno == InvalidAttrNumber)
|
||||
|
||||
static Oid
|
||||
GetDynamicFuncArgType(Var *arg, ExprContext *econtext)
|
||||
{
|
||||
char *relname;
|
||||
int rtid;
|
||||
HeapTuple tup;
|
||||
|
||||
Assert(IsA(arg,Var));
|
||||
|
||||
rtid = ((Var*)arg)->varno;
|
||||
relname = (char*)getrelname(rtid, econtext->ecxt_range_table);
|
||||
|
||||
|
||||
tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(relname),
|
||||
0,0,0);
|
||||
if (!tup)
|
||||
elog(WARN, "Lookup failed on type tuple for class %s",
|
||||
relname);
|
||||
|
||||
return tup->t_oid;
|
||||
}
|
||||
|
||||
static FunctionCachePtr
|
||||
init_fcache(Oid foid,
|
||||
bool use_syscache,
|
||||
List *argList,
|
||||
ExprContext *econtext)
|
||||
{
|
||||
HeapTuple procedureTuple;
|
||||
HeapTuple typeTuple;
|
||||
Form_pg_proc procedureStruct;
|
||||
TypeTupleForm typeStruct;
|
||||
FunctionCachePtr retval;
|
||||
text *tmp;
|
||||
int nargs;
|
||||
|
||||
/* ----------------
|
||||
* get the procedure tuple corresponding to the given
|
||||
* functionOid. If this fails, returnValue has been
|
||||
* pre-initialized to "null" so we just return it.
|
||||
* ----------------
|
||||
*/
|
||||
retval = (FunctionCachePtr) palloc(sizeof(FunctionCache));
|
||||
|
||||
if (!use_syscache)
|
||||
elog(WARN, "what the ????, init the fcache without the catalogs?");
|
||||
|
||||
procedureTuple = SearchSysCacheTuple(PROOID,
|
||||
ObjectIdGetDatum(foid),
|
||||
0,0,0);
|
||||
|
||||
if (!HeapTupleIsValid(procedureTuple))
|
||||
elog(WARN,
|
||||
"init_fcache: %s %d",
|
||||
"Cache lookup failed for procedure", foid);
|
||||
|
||||
/* ----------------
|
||||
* get the return type from the procedure tuple
|
||||
* ----------------
|
||||
*/
|
||||
procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
|
||||
|
||||
/* ----------------
|
||||
* get the type tuple corresponding to the return type
|
||||
* If this fails, returnValue has been pre-initialized
|
||||
* to "null" so we just return it.
|
||||
* ----------------
|
||||
*/
|
||||
typeTuple = SearchSysCacheTuple(TYPOID,
|
||||
ObjectIdGetDatum(procedureStruct->prorettype),
|
||||
0,0,0);
|
||||
|
||||
if (!HeapTupleIsValid(typeTuple))
|
||||
elog(WARN,
|
||||
"init_fcache: %s %d",
|
||||
"Cache lookup failed for type",
|
||||
(procedureStruct)->prorettype);
|
||||
|
||||
/* ----------------
|
||||
* get the type length and by-value from the type tuple and
|
||||
* save the information in our one element cache.
|
||||
* ----------------
|
||||
*/
|
||||
typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
|
||||
|
||||
retval->typlen = (typeStruct)->typlen;
|
||||
if ((typeStruct)->typrelid == InvalidOid) {
|
||||
/* The return type is not a relation, so just use byval */
|
||||
retval->typbyval = (typeStruct)->typbyval ? true : false ;
|
||||
} else {
|
||||
/* This is a hack. We assume here that any function returning
|
||||
* a relation returns it by reference. This needs to be
|
||||
* fixed.
|
||||
*/
|
||||
retval->typbyval = false;
|
||||
}
|
||||
retval->foid = foid;
|
||||
retval->language = procedureStruct->prolang;
|
||||
retval->func_state = (char *)NULL;
|
||||
retval->setArg = NULL;
|
||||
retval->hasSetArg = false;
|
||||
retval->oneResult = ! procedureStruct->proretset;
|
||||
retval->istrusted = procedureStruct->proistrusted;
|
||||
|
||||
/*
|
||||
* If we are returning exactly one result then we have to copy
|
||||
* tuples and by reference results because we have to end the execution
|
||||
* before we return the results. When you do this everything allocated
|
||||
* by the executor (i.e. slots and tuples) is freed.
|
||||
*/
|
||||
if ((retval->language == SQLlanguageId) &&
|
||||
(retval->oneResult) &&
|
||||
!(retval->typbyval))
|
||||
{
|
||||
Form_pg_class relationStruct;
|
||||
HeapTuple relationTuple;
|
||||
TupleDesc td;
|
||||
TupleTableSlot *slot;
|
||||
|
||||
slot = makeNode(TupleTableSlot);
|
||||
slot->ttc_shouldFree = true;
|
||||
slot->ttc_descIsNew = true;
|
||||
slot->ttc_tupleDescriptor = (TupleDesc) NULL;
|
||||
slot->ttc_buffer = InvalidBuffer;
|
||||
slot->ttc_whichplan = -1;
|
||||
retval->funcSlot = (Pointer)slot;
|
||||
|
||||
relationTuple = (HeapTuple)
|
||||
SearchSysCacheTuple(RELNAME,
|
||||
PointerGetDatum(&typeStruct->typname),
|
||||
0,0,0);
|
||||
|
||||
if (relationTuple)
|
||||
{
|
||||
relationStruct = (Form_pg_class)GETSTRUCT(relationTuple);
|
||||
td = CreateTemplateTupleDesc(relationStruct->relnatts);
|
||||
}
|
||||
else
|
||||
td = CreateTemplateTupleDesc(1);
|
||||
|
||||
((TupleTableSlot*)retval->funcSlot)->ttc_tupleDescriptor = td;
|
||||
}
|
||||
else
|
||||
retval->funcSlot = (char *)NULL;
|
||||
|
||||
nargs = procedureStruct->pronargs;
|
||||
retval->nargs = nargs;
|
||||
|
||||
if (nargs > 0)
|
||||
{
|
||||
Oid *argTypes;
|
||||
|
||||
retval->nullVect = (bool *)palloc((retval->nargs)*sizeof(bool));
|
||||
|
||||
if (retval->language == SQLlanguageId)
|
||||
{
|
||||
int i;
|
||||
List *oneArg;
|
||||
|
||||
retval->argOidVect =
|
||||
(Oid *)palloc(retval->nargs*sizeof(Oid));
|
||||
argTypes = procedureStruct->proargtypes;
|
||||
memmove(retval->argOidVect,
|
||||
argTypes,
|
||||
(retval->nargs)*sizeof(Oid));
|
||||
|
||||
for (i=0;
|
||||
argList;
|
||||
i++, argList = lnext(argList))
|
||||
{
|
||||
oneArg = lfirst(argList);
|
||||
if (FuncArgTypeIsDynamic(oneArg))
|
||||
retval->argOidVect[i] = GetDynamicFuncArgType((Var*)oneArg,
|
||||
econtext);
|
||||
}
|
||||
}
|
||||
else
|
||||
retval->argOidVect = (Oid *)NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval->argOidVect = (Oid *)NULL;
|
||||
retval->nullVect = (BoolPtr)NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX this is the first varlena in the struct. If the order
|
||||
* changes for some reason this will fail.
|
||||
*/
|
||||
if (procedureStruct->prolang == SQLlanguageId)
|
||||
{
|
||||
retval->src = textout(&(procedureStruct->prosrc));
|
||||
retval->bin = (char *) NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* I'm not sure that we even need to do this at all.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We do for untrusted functions.
|
||||
*/
|
||||
|
||||
if (procedureStruct->proistrusted)
|
||||
retval->bin = (char *) NULL;
|
||||
else {
|
||||
tmp = (text *)
|
||||
SearchSysCacheGetAttribute(PROOID,
|
||||
Anum_pg_proc_probin,
|
||||
ObjectIdGetDatum(foid),
|
||||
0,0,0);
|
||||
retval->bin = textout(tmp);
|
||||
}
|
||||
retval->src = (char *) NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (retval->language != SQLlanguageId)
|
||||
fmgr_info(foid, &(retval->func), &(retval->nargs));
|
||||
else
|
||||
retval->func = (func_ptr)NULL;
|
||||
|
||||
|
||||
return(retval);
|
||||
}
|
||||
|
||||
void
|
||||
setFcache(Node *node, Oid foid, List *argList, ExprContext *econtext)
|
||||
{
|
||||
Func *fnode;
|
||||
Oper *onode;
|
||||
FunctionCachePtr fcache;
|
||||
|
||||
fcache = init_fcache(foid, true, argList, econtext);
|
||||
|
||||
if (IsA(node,Oper)) {
|
||||
onode = (Oper*) node;
|
||||
onode->op_fcache = fcache;
|
||||
}else if (IsA(node,Func)) {
|
||||
fnode = (Func*) node;
|
||||
fnode->func_fcache = fcache;
|
||||
}else {
|
||||
elog(WARN, "init_fcache: node must be Oper or Func!");
|
||||
}
|
||||
}
|
612
src/backend/utils/cache/inval.c
vendored
Normal file
612
src/backend/utils/cache/inval.c
vendored
Normal file
@ -0,0 +1,612 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* inval.c--
|
||||
* POSTGRES cache invalidation dispatcher code.
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.1.1.1 1996/07/09 06:22:06 scrappy Exp $
|
||||
*
|
||||
* Note - this code is real crufty...
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
#include "access/heapam.h" /* XXX to support hacks below */
|
||||
#include "access/htup.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "storage/bufpage.h"
|
||||
#include "storage/buf.h" /* XXX for InvalidBuffer */
|
||||
#include "storage/ipc.h"
|
||||
#include "storage/sinval.h"
|
||||
#include "utils/catcache.h"
|
||||
#include "utils/inval.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/relcache.h"
|
||||
#include "catalog/catname.h" /* XXX to support hacks below */
|
||||
#include "utils/syscache.h" /* XXX to support the hacks below */
|
||||
|
||||
/* ----------------
|
||||
* private invalidation structures
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct CatalogInvalidationData {
|
||||
Index cacheId;
|
||||
Index hashIndex;
|
||||
ItemPointerData pointerData;
|
||||
} CatalogInvalidationData;
|
||||
|
||||
typedef struct RelationInvalidationData {
|
||||
Oid relationId;
|
||||
Oid objectId;
|
||||
} RelationInvalidationData;
|
||||
|
||||
typedef union AnyInvalidation {
|
||||
CatalogInvalidationData catalog;
|
||||
RelationInvalidationData relation;
|
||||
} AnyInvalidation;
|
||||
|
||||
typedef struct InvalidationMessageData {
|
||||
char kind;
|
||||
AnyInvalidation any;
|
||||
} InvalidationMessageData;
|
||||
|
||||
typedef InvalidationMessageData *InvalidationMessage;
|
||||
|
||||
/* ----------------
|
||||
* variables and macros
|
||||
* ----------------
|
||||
*/
|
||||
static LocalInvalid Invalid = EmptyLocalInvalid; /* XXX global */
|
||||
static bool RefreshWhenInvalidate = false;
|
||||
|
||||
Oid MyRelationRelationId = InvalidOid;
|
||||
Oid MyAttributeRelationId = InvalidOid;
|
||||
Oid MyAMRelationId = InvalidOid;
|
||||
Oid MyAMOPRelationId = InvalidOid;
|
||||
|
||||
#define ValidateHacks() \
|
||||
if (!OidIsValid(MyRelationRelationId)) getmyrelids()
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* "local" invalidation support functions
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* --------------------------------
|
||||
* InvalidationEntryAllocate--
|
||||
* Allocates an invalidation entry.
|
||||
* --------------------------------
|
||||
*/
|
||||
InvalidationEntry
|
||||
InvalidationEntryAllocate(uint16 size)
|
||||
{
|
||||
InvalidationEntryData *entryDataP;
|
||||
entryDataP = (InvalidationEntryData *)
|
||||
malloc(sizeof (char *) + size); /* XXX alignment */
|
||||
entryDataP->nextP = NULL;
|
||||
return ((Pointer) &entryDataP->userData);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* LocalInvalidRegister --
|
||||
* Returns a new local cache invalidation state containing a new entry.
|
||||
* --------------------------------
|
||||
*/
|
||||
LocalInvalid
|
||||
LocalInvalidRegister(LocalInvalid invalid,
|
||||
InvalidationEntry entry)
|
||||
{
|
||||
Assert(PointerIsValid(entry));
|
||||
|
||||
((InvalidationUserData *)entry)->dataP[-1] =
|
||||
(InvalidationUserData *)invalid;
|
||||
|
||||
return (entry);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* LocalInvalidInvalidate--
|
||||
* Processes, then frees all entries in a local cache
|
||||
* invalidation state.
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
LocalInvalidInvalidate(LocalInvalid invalid, void (*function)())
|
||||
{
|
||||
InvalidationEntryData *entryDataP;
|
||||
|
||||
while (PointerIsValid(invalid)) {
|
||||
entryDataP = (InvalidationEntryData *)
|
||||
&((InvalidationUserData *)invalid)->dataP[-1];
|
||||
|
||||
if (PointerIsValid(function)) {
|
||||
(*function)((Pointer) &entryDataP->userData);
|
||||
}
|
||||
|
||||
invalid = (Pointer) entryDataP->nextP;
|
||||
|
||||
/* help catch errors */
|
||||
entryDataP->nextP = (InvalidationUserData *) NULL;
|
||||
|
||||
free((Pointer)entryDataP);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* private support functions
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
/* --------------------------------
|
||||
* CacheIdRegisterLocalInvalid
|
||||
* --------------------------------
|
||||
*/
|
||||
#ifdef INVALIDDEBUG
|
||||
#define CacheIdRegisterLocalInvalid_DEBUG1 \
|
||||
elog(DEBUG, "CacheIdRegisterLocalInvalid(%d, %d, [%d, %d])", \
|
||||
cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
|
||||
ItemPointerGetOffsetNumber(pointer))
|
||||
#else
|
||||
#define CacheIdRegisterLocalInvalid_DEBUG1
|
||||
#endif /* INVALIDDEBUG */
|
||||
|
||||
static void
|
||||
CacheIdRegisterLocalInvalid(Index cacheId,
|
||||
Index hashIndex,
|
||||
ItemPointer pointer)
|
||||
{
|
||||
InvalidationMessage message;
|
||||
|
||||
/* ----------------
|
||||
* debugging stuff
|
||||
* ----------------
|
||||
*/
|
||||
CacheIdRegisterLocalInvalid_DEBUG1;
|
||||
|
||||
/* ----------------
|
||||
* create a message describing the system catalog tuple
|
||||
* we wish to invalidate.
|
||||
* ----------------
|
||||
*/
|
||||
message = (InvalidationMessage)
|
||||
InvalidationEntryAllocate(sizeof (InvalidationMessageData));
|
||||
|
||||
message->kind = 'c';
|
||||
message->any.catalog.cacheId = cacheId;
|
||||
message->any.catalog.hashIndex = hashIndex;
|
||||
|
||||
ItemPointerCopy(pointer, &message->any.catalog.pointerData);
|
||||
|
||||
/* ----------------
|
||||
* Note: Invalid is a global variable
|
||||
* ----------------
|
||||
*/
|
||||
Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry)message);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* RelationIdRegisterLocalInvalid
|
||||
* --------------------------------
|
||||
*/
|
||||
static void
|
||||
RelationIdRegisterLocalInvalid(Oid relationId, Oid objectId)
|
||||
{
|
||||
InvalidationMessage message;
|
||||
|
||||
/* ----------------
|
||||
* debugging stuff
|
||||
* ----------------
|
||||
*/
|
||||
#ifdef INVALIDDEBUG
|
||||
elog(DEBUG, "RelationRegisterLocalInvalid(%d, %d)", relationId,
|
||||
objectId);
|
||||
#endif /* defined(INVALIDDEBUG) */
|
||||
|
||||
/* ----------------
|
||||
* create a message describing the relation descriptor
|
||||
* we wish to invalidate.
|
||||
* ----------------
|
||||
*/
|
||||
message = (InvalidationMessage)
|
||||
InvalidationEntryAllocate(sizeof (InvalidationMessageData));
|
||||
|
||||
message->kind = 'r';
|
||||
message->any.relation.relationId = relationId;
|
||||
message->any.relation.objectId = objectId;
|
||||
|
||||
/* ----------------
|
||||
* Note: Invalid is a global variable
|
||||
* ----------------
|
||||
*/
|
||||
Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry)message);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* getmyrelids
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
getmyrelids()
|
||||
{
|
||||
HeapTuple tuple;
|
||||
|
||||
tuple = SearchSysCacheTuple(RELNAME,
|
||||
PointerGetDatum(RelationRelationName),
|
||||
0,0,0);
|
||||
Assert(HeapTupleIsValid(tuple));
|
||||
MyRelationRelationId = tuple->t_oid;
|
||||
|
||||
tuple = SearchSysCacheTuple(RELNAME,
|
||||
PointerGetDatum(AttributeRelationName),
|
||||
0,0,0);
|
||||
Assert(HeapTupleIsValid(tuple));
|
||||
MyAttributeRelationId = tuple->t_oid;
|
||||
|
||||
tuple = SearchSysCacheTuple(RELNAME,
|
||||
PointerGetDatum(AccessMethodRelationName),
|
||||
0,0,0);
|
||||
Assert(HeapTupleIsValid(tuple));
|
||||
MyAMRelationId = tuple->t_oid;
|
||||
|
||||
tuple = SearchSysCacheTuple(RELNAME,
|
||||
PointerGetDatum(AccessMethodOperatorRelationName),
|
||||
0,0,0);
|
||||
Assert(HeapTupleIsValid(tuple));
|
||||
MyAMOPRelationId = tuple->t_oid;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* CacheIdInvalidate
|
||||
*
|
||||
* This routine can invalidate an tuple in a system catalog cache
|
||||
* or a cached relation descriptor. You pay your money and you
|
||||
* take your chances...
|
||||
* --------------------------------
|
||||
*/
|
||||
#ifdef INVALIDDEBUG
|
||||
#define CacheIdInvalidate_DEBUG1 \
|
||||
elog(DEBUG, "CacheIdInvalidate(%d, %d, 0x%x[%d])", cacheId, hashIndex,\
|
||||
pointer, ItemPointerIsValid(pointer))
|
||||
#else
|
||||
#define CacheIdInvalidate_DEBUG1
|
||||
#endif /* defined(INVALIDDEBUG) */
|
||||
|
||||
static void
|
||||
CacheIdInvalidate(Index cacheId,
|
||||
Index hashIndex,
|
||||
ItemPointer pointer)
|
||||
{
|
||||
/* ----------------
|
||||
* assume that if the item pointer is valid, then we are
|
||||
* invalidating an item in the specified system catalog cache.
|
||||
* ----------------
|
||||
*/
|
||||
if (ItemPointerIsValid(pointer)) {
|
||||
CatalogCacheIdInvalidate(cacheId, hashIndex, pointer);
|
||||
return;
|
||||
}
|
||||
|
||||
CacheIdInvalidate_DEBUG1;
|
||||
|
||||
ValidateHacks(); /* XXX */
|
||||
|
||||
/* ----------------
|
||||
* if the cacheId is the oid of any of the tuples in the
|
||||
* following system relations, then assume we are invalidating
|
||||
* a relation descriptor
|
||||
* ----------------
|
||||
*/
|
||||
if (cacheId == MyRelationRelationId) {
|
||||
RelationIdInvalidateRelationCacheByRelationId(hashIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cacheId == MyAttributeRelationId) {
|
||||
RelationIdInvalidateRelationCacheByRelationId(hashIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cacheId == MyAMRelationId) {
|
||||
RelationIdInvalidateRelationCacheByAccessMethodId(hashIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cacheId == MyAMOPRelationId) {
|
||||
RelationIdInvalidateRelationCacheByAccessMethodId(InvalidOid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* Yow! the caller asked us to invalidate something else.
|
||||
* ----------------
|
||||
*/
|
||||
elog(FATAL, "CacheIdInvalidate: cacheId=%d relation id?", cacheId);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* ResetSystemCaches
|
||||
*
|
||||
* this blows away all tuples in the system catalog caches and
|
||||
* all the cached relation descriptors (and closes the files too).
|
||||
* --------------------------------
|
||||
*/
|
||||
static void
|
||||
ResetSystemCaches()
|
||||
{
|
||||
ResetSystemCache();
|
||||
RelationCacheInvalidate(false);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* InvalidationMessageRegisterSharedInvalid
|
||||
* --------------------------------
|
||||
*/
|
||||
#ifdef INVALIDDEBUG
|
||||
#define InvalidationMessageRegisterSharedInvalid_DEBUG1 \
|
||||
elog(DEBUG,\
|
||||
"InvalidationMessageRegisterSharedInvalid(c, %d, %d, [%d, %d])",\
|
||||
message->any.catalog.cacheId,\
|
||||
message->any.catalog.hashIndex,\
|
||||
ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\
|
||||
ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))
|
||||
#define InvalidationMessageRegisterSharedInvalid_DEBUG2 \
|
||||
elog(DEBUG, \
|
||||
"InvalidationMessageRegisterSharedInvalid(r, %d, %d)", \
|
||||
message->any.relation.relationId, \
|
||||
message->any.relation.objectId)
|
||||
#else
|
||||
#define InvalidationMessageRegisterSharedInvalid_DEBUG1
|
||||
#define InvalidationMessageRegisterSharedInvalid_DEBUG2
|
||||
#endif /* INVALIDDEBUG */
|
||||
|
||||
static void
|
||||
InvalidationMessageRegisterSharedInvalid(InvalidationMessage message)
|
||||
{
|
||||
Assert(PointerIsValid(message));
|
||||
|
||||
switch (message->kind) {
|
||||
case 'c': /* cached system catalog tuple */
|
||||
InvalidationMessageRegisterSharedInvalid_DEBUG1;
|
||||
|
||||
RegisterSharedInvalid(message->any.catalog.cacheId,
|
||||
message->any.catalog.hashIndex,
|
||||
&message->any.catalog.pointerData);
|
||||
break;
|
||||
|
||||
case 'r': /* cached relation descriptor */
|
||||
InvalidationMessageRegisterSharedInvalid_DEBUG2;
|
||||
|
||||
RegisterSharedInvalid(message->any.relation.relationId,
|
||||
message->any.relation.objectId,
|
||||
(ItemPointer) NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(FATAL,
|
||||
"InvalidationMessageRegisterSharedInvalid: `%c' kind",
|
||||
message->kind);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* InvalidationMessageCacheInvalidate
|
||||
* --------------------------------
|
||||
*/
|
||||
#ifdef INVALIDDEBUG
|
||||
#define InvalidationMessageCacheInvalidate_DEBUG1 \
|
||||
elog(DEBUG, "InvalidationMessageCacheInvalidate(c, %d, %d, [%d, %d])",\
|
||||
message->any.catalog.cacheId,\
|
||||
message->any.catalog.hashIndex,\
|
||||
ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\
|
||||
ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))
|
||||
#define InvalidationMessageCacheInvalidate_DEBUG2 \
|
||||
elog(DEBUG, "InvalidationMessageCacheInvalidate(r, %d, %d)", \
|
||||
message->any.relation.relationId, \
|
||||
message->any.relation.objectId)
|
||||
#else
|
||||
#define InvalidationMessageCacheInvalidate_DEBUG1
|
||||
#define InvalidationMessageCacheInvalidate_DEBUG2
|
||||
#endif /* defined(INVALIDDEBUG) */
|
||||
|
||||
static void
|
||||
InvalidationMessageCacheInvalidate(InvalidationMessage message)
|
||||
{
|
||||
Assert(PointerIsValid(message));
|
||||
|
||||
switch (message->kind) {
|
||||
case 'c': /* cached system catalog tuple */
|
||||
InvalidationMessageCacheInvalidate_DEBUG1;
|
||||
|
||||
CatalogCacheIdInvalidate(message->any.catalog.cacheId,
|
||||
message->any.catalog.hashIndex,
|
||||
&message->any.catalog.pointerData);
|
||||
break;
|
||||
|
||||
case 'r': /* cached relation descriptor */
|
||||
InvalidationMessageCacheInvalidate_DEBUG2;
|
||||
|
||||
/* XXX ignore this--is this correct ??? */
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(FATAL, "InvalidationMessageCacheInvalidate: `%c' kind",
|
||||
message->kind);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* RelationInvalidateRelationCache
|
||||
* --------------------------------
|
||||
*/
|
||||
static void
|
||||
RelationInvalidateRelationCache(Relation relation,
|
||||
HeapTuple tuple,
|
||||
void (*function)())
|
||||
{
|
||||
Oid relationId;
|
||||
Oid objectId;
|
||||
|
||||
/* ----------------
|
||||
* get the relation object id
|
||||
* ----------------
|
||||
*/
|
||||
ValidateHacks(); /* XXX */
|
||||
relationId = RelationGetRelationId(relation);
|
||||
|
||||
/* ----------------
|
||||
*
|
||||
* ----------------
|
||||
*/
|
||||
if (relationId == MyRelationRelationId) {
|
||||
objectId = tuple->t_oid;
|
||||
} else if (relationId == MyAttributeRelationId) {
|
||||
objectId = ((AttributeTupleForm)GETSTRUCT(tuple))->attrelid;
|
||||
} else if (relationId == MyAMRelationId) {
|
||||
objectId = tuple->t_oid;
|
||||
} else if (relationId == MyAMOPRelationId) {
|
||||
; /* objectId is unused */
|
||||
} else
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* can't handle immediate relation descriptor invalidation
|
||||
* ----------------
|
||||
*/
|
||||
Assert(PointerIsValid(function));
|
||||
|
||||
(*function)(relationId, objectId);
|
||||
}
|
||||
|
||||
/*
|
||||
* DiscardInvalid --
|
||||
* Causes the invalidated cache state to be discarded.
|
||||
*
|
||||
* Note:
|
||||
* This should be called as the first step in processing a transaction.
|
||||
* This should be called while waiting for a query from the front end
|
||||
* when other backends are active.
|
||||
*/
|
||||
void
|
||||
DiscardInvalid()
|
||||
{
|
||||
/* ----------------
|
||||
* debugging stuff
|
||||
* ----------------
|
||||
*/
|
||||
#ifdef INVALIDDEBUG
|
||||
elog(DEBUG, "DiscardInvalid called");
|
||||
#endif /* defined(INVALIDDEBUG) */
|
||||
|
||||
InvalidateSharedInvalid(CacheIdInvalidate, ResetSystemCaches);
|
||||
}
|
||||
|
||||
/*
|
||||
* RegisterInvalid --
|
||||
* Causes registration of invalidated state with other backends iff true.
|
||||
*
|
||||
* Note:
|
||||
* This should be called as the last step in processing a transaction.
|
||||
*/
|
||||
void
|
||||
RegisterInvalid(bool send)
|
||||
{
|
||||
/* ----------------
|
||||
* debugging stuff
|
||||
* ----------------
|
||||
*/
|
||||
#ifdef INVALIDDEBUG
|
||||
elog(DEBUG, "RegisterInvalid(%d) called", send);
|
||||
#endif /* defined(INVALIDDEBUG) */
|
||||
|
||||
/* ----------------
|
||||
* Note: Invalid is a global variable
|
||||
* ----------------
|
||||
*/
|
||||
if (send)
|
||||
LocalInvalidInvalidate(Invalid,
|
||||
InvalidationMessageRegisterSharedInvalid);
|
||||
else
|
||||
LocalInvalidInvalidate(Invalid,
|
||||
InvalidationMessageCacheInvalidate);
|
||||
|
||||
Invalid = EmptyLocalInvalid;
|
||||
}
|
||||
|
||||
/*
|
||||
* SetRefreshWhenInvalidate --
|
||||
* Causes the local caches to be immediately refreshed iff true.
|
||||
*/
|
||||
void
|
||||
SetRefreshWhenInvalidate(bool on)
|
||||
{
|
||||
#ifdef INVALIDDEBUG
|
||||
elog(DEBUG, "RefreshWhenInvalidate(%d) called", on);
|
||||
#endif /* defined(INVALIDDEBUG) */
|
||||
|
||||
RefreshWhenInvalidate = on;
|
||||
}
|
||||
|
||||
/*
|
||||
* RelationIdInvalidateHeapTuple --
|
||||
* Causes the given tuple in a relation to be invalidated.
|
||||
*
|
||||
* Note:
|
||||
* Assumes object id is valid.
|
||||
* Assumes tuple is valid.
|
||||
*/
|
||||
#ifdef INVALIDDEBUG
|
||||
#define RelationInvalidateHeapTuple_DEBUG1 \
|
||||
elog(DEBUG, "RelationInvalidateHeapTuple(%.16s, [%d,%d])", \
|
||||
RelationGetRelationName(relation), \
|
||||
ItemPointerGetBlockNumber(&tuple->t_ctid), \
|
||||
ItemPointerGetOffsetNumber(&tuple->t_ctid))
|
||||
#else
|
||||
#define RelationInvalidateHeapTuple_DEBUG1
|
||||
#endif /* defined(INVALIDDEBUG) */
|
||||
|
||||
void
|
||||
RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple)
|
||||
{
|
||||
/* ----------------
|
||||
* sanity checks
|
||||
* ----------------
|
||||
*/
|
||||
Assert(RelationIsValid(relation));
|
||||
Assert(HeapTupleIsValid(tuple));
|
||||
|
||||
if (IsBootstrapProcessingMode())
|
||||
return;
|
||||
/* ----------------
|
||||
* this only works for system relations now
|
||||
* ----------------
|
||||
*/
|
||||
if (! IsSystemRelationName(RelationGetRelationTupleForm(relation)->relname.data))
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* debugging stuff
|
||||
* ----------------
|
||||
*/
|
||||
RelationInvalidateHeapTuple_DEBUG1;
|
||||
|
||||
/* ----------------
|
||||
*
|
||||
* ----------------
|
||||
*/
|
||||
RelationInvalidateCatalogCacheTuple(relation,
|
||||
tuple,
|
||||
CacheIdRegisterLocalInvalid);
|
||||
|
||||
RelationInvalidateRelationCache(relation,
|
||||
tuple,
|
||||
RelationIdRegisterLocalInvalid);
|
||||
|
||||
if (RefreshWhenInvalidate)
|
||||
RelationInvalidateCatalogCacheTuple(relation,
|
||||
tuple,
|
||||
(void (*)()) NULL);
|
||||
}
|
||||
|
484
src/backend/utils/cache/lsyscache.c
vendored
Normal file
484
src/backend/utils/cache/lsyscache.c
vendored
Normal file
@ -0,0 +1,484 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* lsyscache.c--
|
||||
* Routines to access information within system caches
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.1.1.1 1996/07/09 06:22:06 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Eventually, the index information should go through here, too.
|
||||
*
|
||||
* Most of these routines call SearchSysCacheStruct() and thus simply
|
||||
* (1) allocate some space for the return struct and (2) call it.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "postgres.h"
|
||||
|
||||
#include "nodes/pg_list.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "access/tupmacs.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/palloc.h"
|
||||
#include "utils/elog.h"
|
||||
#include "access/attnum.h"
|
||||
#include "access/heapam.h"
|
||||
|
||||
#include "catalog/pg_amop.h"
|
||||
#include "catalog/pg_type.h"
|
||||
|
||||
/* ---------- AMOP CACHES ---------- */
|
||||
|
||||
/*
|
||||
* op_class -
|
||||
*
|
||||
* Return t iff operator 'opno' is in operator class 'opclass'.
|
||||
*
|
||||
*/
|
||||
bool
|
||||
op_class(Oid opno, int32 opclass, Oid amopid)
|
||||
{
|
||||
FormData_pg_amop amoptup;
|
||||
|
||||
if (SearchSysCacheStruct(AMOPOPID,
|
||||
(char *) &amoptup,
|
||||
ObjectIdGetDatum(opclass),
|
||||
ObjectIdGetDatum(opno),
|
||||
ObjectIdGetDatum(amopid),
|
||||
0))
|
||||
return(true);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
|
||||
/* ---------- ATTRIBUTE CACHES ---------- */
|
||||
|
||||
/*
|
||||
* get_attname -
|
||||
*
|
||||
* Given the relation id and the attribute number,
|
||||
* return the "attname" field from the attribute relation.
|
||||
*
|
||||
*/
|
||||
char*
|
||||
get_attname(Oid relid, AttrNumber attnum)
|
||||
{
|
||||
FormData_pg_attribute att_tup;
|
||||
char *retval;
|
||||
|
||||
if (SearchSysCacheStruct(ATTNUM,
|
||||
(char*)&att_tup,
|
||||
ObjectIdGetDatum(relid),
|
||||
UInt16GetDatum(attnum),
|
||||
0,0)) {
|
||||
retval = pstrdup(att_tup.attname.data);
|
||||
|
||||
return(retval);
|
||||
}
|
||||
else
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_attnum -
|
||||
*
|
||||
* Given the relation id and the attribute name,
|
||||
* return the "attnum" field from the attribute relation.
|
||||
*
|
||||
*/
|
||||
AttrNumber
|
||||
get_attnum(Oid relid, char *attname)
|
||||
{
|
||||
FormData_pg_attribute att_tup;
|
||||
|
||||
if (SearchSysCacheStruct(ATTNAME, (char *) &att_tup,
|
||||
ObjectIdGetDatum(relid),
|
||||
PointerGetDatum(attname),
|
||||
0,0))
|
||||
return(att_tup.attnum);
|
||||
else
|
||||
return(InvalidAttrNumber);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_atttype -
|
||||
*
|
||||
* Given the relation OID and the attribute number with the relation,
|
||||
* return the attribute type OID.
|
||||
*
|
||||
*/
|
||||
Oid
|
||||
get_atttype(Oid relid, AttrNumber attnum)
|
||||
{
|
||||
AttributeTupleForm att_tup = (AttributeTupleForm)palloc(sizeof(*att_tup));
|
||||
|
||||
if (SearchSysCacheStruct(ATTNUM,
|
||||
(char *) att_tup,
|
||||
ObjectIdGetDatum(relid),
|
||||
UInt16GetDatum(attnum),
|
||||
0,0))
|
||||
return(att_tup->atttypid);
|
||||
else
|
||||
return((Oid)NULL);
|
||||
}
|
||||
|
||||
/* This routine uses the attname instead of the attnum because it
|
||||
* replaces the routine find_atttype, which is called sometimes when
|
||||
* only the attname, not the attno, is available.
|
||||
*/
|
||||
bool
|
||||
get_attisset(Oid relid, char *attname)
|
||||
{
|
||||
HeapTuple htup;
|
||||
AttrNumber attno;
|
||||
AttributeTupleForm att_tup;
|
||||
|
||||
attno = get_attnum(relid, attname);
|
||||
|
||||
htup = SearchSysCacheTuple(ATTNAME,
|
||||
ObjectIdGetDatum(relid),
|
||||
PointerGetDatum(attname),
|
||||
0,0);
|
||||
if (!HeapTupleIsValid(htup))
|
||||
elog(WARN, "get_attisset: no attribute %.16s in relation %d",
|
||||
attname, relid);
|
||||
if (heap_attisnull(htup, attno))
|
||||
return(false);
|
||||
else {
|
||||
att_tup = (AttributeTupleForm)GETSTRUCT(htup);
|
||||
return(att_tup->attisset);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- INDEX CACHE ---------- */
|
||||
|
||||
/* watch this space...
|
||||
*/
|
||||
|
||||
/* ---------- OPERATOR CACHE ---------- */
|
||||
|
||||
/*
|
||||
* get_opcode -
|
||||
*
|
||||
* Returns the regproc id of the routine used to implement an
|
||||
* operator given the operator uid.
|
||||
*
|
||||
*/
|
||||
RegProcedure
|
||||
get_opcode(Oid opno)
|
||||
{
|
||||
FormData_pg_operator optup;
|
||||
|
||||
if (SearchSysCacheStruct(OPROID, (char *) &optup,
|
||||
ObjectIdGetDatum(opno),
|
||||
0,0,0))
|
||||
return(optup.oprcode);
|
||||
else
|
||||
return((RegProcedure)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_opname -
|
||||
* returns the name of the operator with the given opno
|
||||
*
|
||||
* Note: return the struct so that it gets copied.
|
||||
*/
|
||||
char*
|
||||
get_opname(Oid opno)
|
||||
{
|
||||
FormData_pg_operator optup;
|
||||
|
||||
if (SearchSysCacheStruct(OPROID, (char *) &optup,
|
||||
ObjectIdGetDatum(opno),
|
||||
0,0,0))
|
||||
return (pstrdup(optup.oprname.data));
|
||||
else {
|
||||
elog(WARN, "can't look up operator %d\n", opno);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* op_mergesortable -
|
||||
*
|
||||
* Returns the left and right sort operators and types corresponding to a
|
||||
* mergesortable operator, or nil if the operator is not mergesortable.
|
||||
*
|
||||
*/
|
||||
bool
|
||||
op_mergesortable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
|
||||
{
|
||||
FormData_pg_operator optup;
|
||||
|
||||
if (SearchSysCacheStruct(OPROID, (char *) &optup,
|
||||
ObjectIdGetDatum(opno),
|
||||
0,0,0) &&
|
||||
optup.oprlsortop &&
|
||||
optup.oprrsortop &&
|
||||
optup.oprleft == ltype &&
|
||||
optup.oprright == rtype) {
|
||||
|
||||
*leftOp = ObjectIdGetDatum(optup.oprlsortop);
|
||||
*rightOp = ObjectIdGetDatum(optup.oprrsortop);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* op_hashjoinable--
|
||||
*
|
||||
* Returns the hash operator corresponding to a hashjoinable operator,
|
||||
* or nil if the operator is not hashjoinable.
|
||||
*
|
||||
*/
|
||||
Oid
|
||||
op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
|
||||
{
|
||||
FormData_pg_operator optup;
|
||||
|
||||
if (SearchSysCacheStruct(OPROID, (char *) &optup,
|
||||
ObjectIdGetDatum(opno),
|
||||
0,0,0) &&
|
||||
optup.oprcanhash &&
|
||||
optup.oprleft == ltype &&
|
||||
optup.oprright == rtype)
|
||||
return(opno);
|
||||
else
|
||||
return(InvalidOid);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_commutator -
|
||||
*
|
||||
* Returns the corresponding commutator of an operator.
|
||||
*
|
||||
*/
|
||||
Oid
|
||||
get_commutator(Oid opno)
|
||||
{
|
||||
FormData_pg_operator optup;
|
||||
|
||||
if (SearchSysCacheStruct(OPROID, (char *) &optup,
|
||||
ObjectIdGetDatum(opno),
|
||||
0,0,0))
|
||||
return(optup.oprcom);
|
||||
else
|
||||
return((Oid)NULL);
|
||||
}
|
||||
|
||||
HeapTuple
|
||||
get_operator_tuple(Oid opno)
|
||||
{
|
||||
HeapTuple optup;
|
||||
|
||||
if ((optup = SearchSysCacheTuple(OPROID,
|
||||
ObjectIdGetDatum(opno),
|
||||
0,0,0)))
|
||||
return(optup);
|
||||
else
|
||||
return((HeapTuple)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_negator -
|
||||
*
|
||||
* Returns the corresponding negator of an operator.
|
||||
*
|
||||
*/
|
||||
Oid
|
||||
get_negator(Oid opno)
|
||||
{
|
||||
FormData_pg_operator optup;
|
||||
|
||||
if (SearchSysCacheStruct(OPROID, (char *) &optup,
|
||||
ObjectIdGetDatum(opno),
|
||||
0,0,0))
|
||||
return(optup.oprnegate);
|
||||
else
|
||||
return((Oid)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_oprrest -
|
||||
*
|
||||
* Returns procedure id for computing selectivity of an operator.
|
||||
*
|
||||
*/
|
||||
RegProcedure
|
||||
get_oprrest(Oid opno)
|
||||
{
|
||||
FormData_pg_operator optup;
|
||||
|
||||
if (SearchSysCacheStruct(OPROID, (char *) &optup,
|
||||
ObjectIdGetDatum(opno),
|
||||
0,0,0))
|
||||
return(optup.oprrest );
|
||||
else
|
||||
return((RegProcedure) NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_oprjoin -
|
||||
*
|
||||
* Returns procedure id for computing selectivity of a join.
|
||||
*
|
||||
*/
|
||||
RegProcedure
|
||||
get_oprjoin(Oid opno)
|
||||
{
|
||||
FormData_pg_operator optup;
|
||||
|
||||
if (SearchSysCacheStruct(OPROID, (char *) &optup,
|
||||
ObjectIdGetDatum(opno),
|
||||
0,0,0))
|
||||
return(optup.oprjoin);
|
||||
else
|
||||
return((RegProcedure)NULL);
|
||||
}
|
||||
|
||||
/* ---------- RELATION CACHE ---------- */
|
||||
|
||||
/*
|
||||
* get_relnatts -
|
||||
*
|
||||
* Returns the number of attributes for a given relation.
|
||||
*
|
||||
*/
|
||||
int
|
||||
get_relnatts(Oid relid)
|
||||
{
|
||||
FormData_pg_class reltup;
|
||||
|
||||
if (SearchSysCacheStruct(RELOID, (char *) &reltup,
|
||||
ObjectIdGetDatum(relid),
|
||||
0,0,0))
|
||||
return(reltup.relnatts);
|
||||
else
|
||||
return(InvalidAttrNumber);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_rel_name -
|
||||
*
|
||||
* Returns the name of a given relation.
|
||||
*
|
||||
*/
|
||||
char*
|
||||
get_rel_name(Oid relid)
|
||||
{
|
||||
FormData_pg_class reltup;
|
||||
|
||||
if ((SearchSysCacheStruct(RELOID,
|
||||
(char*)&reltup,
|
||||
ObjectIdGetDatum(relid),
|
||||
0,0,0))) {
|
||||
return (pstrdup(reltup.relname.data));
|
||||
} else
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* ---------- TYPE CACHE ---------- */
|
||||
|
||||
/*
|
||||
* get_typlen -
|
||||
*
|
||||
* Given the type OID, return the length of the type.
|
||||
*
|
||||
*/
|
||||
int16
|
||||
get_typlen(Oid typid)
|
||||
{
|
||||
TypeTupleFormData typtup;
|
||||
|
||||
if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
|
||||
ObjectIdGetDatum(typid),
|
||||
0,0,0))
|
||||
return(typtup.typlen);
|
||||
else
|
||||
return((int16)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_typbyval -
|
||||
*
|
||||
* Given the type OID, determine whether the type is returned by value or
|
||||
* not. Returns 1 if by value, 0 if by reference.
|
||||
*
|
||||
*/
|
||||
bool
|
||||
get_typbyval(Oid typid)
|
||||
{
|
||||
TypeTupleFormData typtup;
|
||||
|
||||
if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
|
||||
ObjectIdGetDatum(typid),
|
||||
0,0,0))
|
||||
return((bool)typtup.typbyval);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_typbyval -
|
||||
*
|
||||
* Given the type OID, determine whether the type is returned by value or
|
||||
* not. Returns 1 if by value, 0 if by reference.
|
||||
*
|
||||
*/
|
||||
char
|
||||
get_typalign(Oid typid)
|
||||
{
|
||||
TypeTupleFormData typtup;
|
||||
|
||||
if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
|
||||
ObjectIdGetDatum(typid),
|
||||
0,0,0))
|
||||
return(typtup.typalign);
|
||||
else
|
||||
return ('i');
|
||||
}
|
||||
|
||||
/*
|
||||
* get_typdefault -
|
||||
*
|
||||
* Given the type OID, return the default value of the ADT.
|
||||
*
|
||||
*/
|
||||
struct varlena *
|
||||
get_typdefault(Oid typid)
|
||||
{
|
||||
struct varlena *typdefault =
|
||||
(struct varlena *)TypeDefaultRetrieve (typid);
|
||||
return(typdefault);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_typtype -
|
||||
*
|
||||
* Given the type OID, find if it is a basic type, a named relation
|
||||
* or the generic type 'relation'.
|
||||
* It returns the null char if the cache lookup fails...
|
||||
*
|
||||
*/
|
||||
char
|
||||
get_typtype(Oid typid)
|
||||
{
|
||||
TypeTupleFormData typtup;
|
||||
|
||||
if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
|
||||
ObjectIdGetDatum(typid),
|
||||
0,0,0)) {
|
||||
return(typtup.typtype);
|
||||
} else {
|
||||
return('\0');
|
||||
}
|
||||
}
|
||||
|
77
src/backend/utils/cache/rel.c
vendored
Normal file
77
src/backend/utils/cache/rel.c
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* rel.c--
|
||||
* POSTGRES relation descriptor code.
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/rel.c,v 1.1.1.1 1996/07/09 06:22:06 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/* #define RELREFDEBUG 1 */
|
||||
|
||||
#include "postgres.h"
|
||||
#include "miscadmin.h"
|
||||
#include "access/istrat.h"
|
||||
#include "access/tupdesc.h"
|
||||
#include "utils/rel.h"
|
||||
#include "storage/fd.h"
|
||||
|
||||
|
||||
/*
|
||||
* RelationIsValid is now a macro in rel.h -cim 4/27/91
|
||||
*
|
||||
* Many of the RelationGet...() functions are now macros in rel.h
|
||||
* -mer 3/2/92
|
||||
*/
|
||||
|
||||
/*
|
||||
* RelationGetIndexStrategy --
|
||||
* Returns index strategy for a relation.
|
||||
*
|
||||
* Note:
|
||||
* Assumes relation descriptor is valid.
|
||||
* Assumes relation descriptor is for an index relation.
|
||||
*/
|
||||
IndexStrategy
|
||||
RelationGetIndexStrategy(Relation relation)
|
||||
{
|
||||
return relation->rd_istrat;
|
||||
}
|
||||
|
||||
/*
|
||||
* RelationSetIndexSupport --
|
||||
* Sets index strategy and support info for a relation.
|
||||
*
|
||||
* Note:
|
||||
* Assumes relation descriptor is a valid pointer to sufficient space.
|
||||
* Assumes index strategy is valid. Assumes support is valid if non-
|
||||
* NULL.
|
||||
*/
|
||||
/* ----------------
|
||||
* RelationSetIndexSupport
|
||||
*
|
||||
* This routine saves two pointers -- one to the IndexStrategy, and
|
||||
* one to the RegProcs that support the indexed access method. These
|
||||
* pointers are stored in the space following the attribute data in the
|
||||
* reldesc.
|
||||
*
|
||||
* NEW: the index strategy and support are now stored in real fields
|
||||
* at the end of the structure - jolly
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
RelationSetIndexSupport(Relation relation,
|
||||
IndexStrategy strategy,
|
||||
RegProcedure *support)
|
||||
{
|
||||
Assert(PointerIsValid(relation));
|
||||
Assert(IndexStrategyIsValid(strategy));
|
||||
|
||||
relation->rd_istrat = strategy;
|
||||
relation->rd_support = support;
|
||||
}
|
||||
|
1795
src/backend/utils/cache/relcache.c
vendored
Normal file
1795
src/backend/utils/cache/relcache.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
630
src/backend/utils/cache/syscache.c
vendored
Normal file
630
src/backend/utils/cache/syscache.c
vendored
Normal file
@ -0,0 +1,630 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* syscache.c--
|
||||
* System cache management routines
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.1.1.1 1996/07/09 06:22:07 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
* These routines allow the parser/planner/executor to perform
|
||||
* rapid lookups on the contents of the system catalogs.
|
||||
*
|
||||
* see catalog/syscache.h for a list of the cache id's
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "c.h"
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "access/htup.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "utils/catcache.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/palloc.h"
|
||||
#include "nodes/pg_list.h"
|
||||
|
||||
/* ----------------
|
||||
* hardwired attribute information comes from system catalog files.
|
||||
* ----------------
|
||||
*/
|
||||
#include "catalog/pg_am.h"
|
||||
#include "catalog/pg_amop.h"
|
||||
#include "catalog/pg_attribute.h"
|
||||
#include "catalog/pg_group.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "catalog/pg_inherits.h"
|
||||
#include "catalog/pg_language.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_class.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "catalog/pg_rewrite.h"
|
||||
#include "catalog/pg_aggregate.h"
|
||||
#include "catalog/pg_user.h"
|
||||
#include "storage/large_object.h"
|
||||
#include "catalog/pg_listener.h"
|
||||
|
||||
extern bool AMI_OVERRIDE; /* XXX style */
|
||||
|
||||
#include "utils/syscache.h"
|
||||
#include "catalog/indexing.h"
|
||||
|
||||
typedef HeapTuple (*ScanFunc)();
|
||||
|
||||
/* ----------------
|
||||
* Warning: cacheinfo[] below is changed, then be sure and
|
||||
* update the magic constants in syscache.h!
|
||||
* ----------------
|
||||
*/
|
||||
static struct cachedesc cacheinfo[] = {
|
||||
{ AccessMethodOperatorRelationName, /* AMOPOPID */
|
||||
3,
|
||||
{ Anum_pg_amop_amopclaid,
|
||||
Anum_pg_amop_amopopr,
|
||||
Anum_pg_amop_amopid,
|
||||
0 },
|
||||
sizeof(FormData_pg_amop),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
|
||||
3,
|
||||
{ Anum_pg_amop_amopid,
|
||||
Anum_pg_amop_amopclaid,
|
||||
Anum_pg_amop_amopstrategy,
|
||||
0 },
|
||||
sizeof(FormData_pg_amop),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ AttributeRelationName, /* ATTNAME */
|
||||
2,
|
||||
{ Anum_pg_attribute_attrelid,
|
||||
Anum_pg_attribute_attname,
|
||||
0,
|
||||
0 },
|
||||
ATTRIBUTE_TUPLE_SIZE,
|
||||
AttributeNameIndex,
|
||||
(ScanFunc) AttributeNameIndexScan },
|
||||
{ AttributeRelationName, /* ATTNUM */
|
||||
2,
|
||||
{ Anum_pg_attribute_attrelid,
|
||||
Anum_pg_attribute_attnum,
|
||||
0,
|
||||
0 },
|
||||
ATTRIBUTE_TUPLE_SIZE,
|
||||
AttributeNumIndex,
|
||||
(ScanFunc) AttributeNumIndexScan },
|
||||
{ IndexRelationName, /* INDEXRELID */
|
||||
1,
|
||||
{ Anum_pg_index_indexrelid,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
offsetof(FormData_pg_index, indpred),
|
||||
NULL,
|
||||
NULL },
|
||||
{ LanguageRelationName, /* LANNAME */
|
||||
1,
|
||||
{ Anum_pg_language_lanname,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
offsetof(FormData_pg_language, lancompiler),
|
||||
NULL,
|
||||
NULL },
|
||||
{ OperatorRelationName, /* OPRNAME */
|
||||
4,
|
||||
{ Anum_pg_operator_oprname,
|
||||
Anum_pg_operator_oprleft,
|
||||
Anum_pg_operator_oprright,
|
||||
Anum_pg_operator_oprkind },
|
||||
sizeof(FormData_pg_operator),
|
||||
NULL,
|
||||
NULL },
|
||||
{ OperatorRelationName, /* OPROID */
|
||||
1,
|
||||
{ ObjectIdAttributeNumber,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
sizeof(FormData_pg_operator),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ ProcedureRelationName, /* PRONAME */
|
||||
3,
|
||||
{ Anum_pg_proc_proname,
|
||||
Anum_pg_proc_pronargs,
|
||||
Anum_pg_proc_proargtypes,
|
||||
0 },
|
||||
offsetof(FormData_pg_proc, prosrc),
|
||||
ProcedureNameIndex,
|
||||
(ScanFunc) ProcedureNameIndexScan },
|
||||
{ ProcedureRelationName, /* PROOID */
|
||||
1,
|
||||
{ ObjectIdAttributeNumber,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
offsetof(FormData_pg_proc, prosrc),
|
||||
ProcedureOidIndex,
|
||||
(ScanFunc) ProcedureOidIndexScan },
|
||||
{ RelationRelationName, /* RELNAME */
|
||||
1,
|
||||
{ Anum_pg_class_relname,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
CLASS_TUPLE_SIZE,
|
||||
ClassNameIndex,
|
||||
(ScanFunc) ClassNameIndexScan },
|
||||
{ RelationRelationName, /* RELOID */
|
||||
1,
|
||||
{ ObjectIdAttributeNumber,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
CLASS_TUPLE_SIZE,
|
||||
ClassOidIndex,
|
||||
(ScanFunc) ClassOidIndexScan },
|
||||
{ TypeRelationName, /* TYPNAME */
|
||||
1,
|
||||
{ Anum_pg_type_typname,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
offsetof(TypeTupleFormData,typalign)+sizeof(char),
|
||||
TypeNameIndex,
|
||||
TypeNameIndexScan },
|
||||
{ TypeRelationName, /* TYPOID */
|
||||
1,
|
||||
{ ObjectIdAttributeNumber,
|
||||
0,
|
||||
0,
|
||||
0},
|
||||
offsetof(TypeTupleFormData,typalign)+sizeof(char),
|
||||
TypeOidIndex,
|
||||
TypeOidIndexScan },
|
||||
{ AccessMethodRelationName, /* AMNAME */
|
||||
1,
|
||||
{ Anum_pg_am_amname,
|
||||
0,
|
||||
0,
|
||||
0},
|
||||
sizeof(FormData_pg_am),
|
||||
NULL,
|
||||
NULL },
|
||||
{ OperatorClassRelationName, /* CLANAME */
|
||||
1,
|
||||
{ Anum_pg_opclass_opcname,
|
||||
0,
|
||||
0,
|
||||
0},
|
||||
sizeof(FormData_pg_opclass),
|
||||
NULL,
|
||||
NULL },
|
||||
{ IndexRelationName, /* INDRELIDKEY */
|
||||
2,
|
||||
{ Anum_pg_index_indrelid,
|
||||
Anum_pg_index_indkey,
|
||||
0,
|
||||
0},
|
||||
offsetof(FormData_pg_index, indpred),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ InheritsRelationName, /* INHRELID */
|
||||
2,
|
||||
{ Anum_pg_inherits_inhrel,
|
||||
Anum_pg_inherits_inhseqno,
|
||||
0,
|
||||
0},
|
||||
sizeof(FormData_pg_inherits),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ RewriteRelationName, /* RULOID */
|
||||
1,
|
||||
{ ObjectIdAttributeNumber,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
offsetof(FormData_pg_rewrite, ev_qual),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ AggregateRelationName, /*AGGNAME*/
|
||||
2,
|
||||
{ Anum_pg_aggregate_aggname,
|
||||
Anum_pg_aggregate_aggbasetype,
|
||||
0,
|
||||
0 },
|
||||
offsetof(FormData_pg_aggregate, agginitval1),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ ListenerRelationName, /* LISTENREL */
|
||||
2,
|
||||
{ Anum_pg_listener_relname,
|
||||
Anum_pg_listener_pid,
|
||||
0,
|
||||
0 },
|
||||
sizeof(FormData_pg_listener),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ UserRelationName, /* USENAME */
|
||||
1,
|
||||
{ Anum_pg_user_usename,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
sizeof(FormData_pg_user),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ UserRelationName, /* USESYSID */
|
||||
1,
|
||||
{ Anum_pg_user_usesysid,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
sizeof(FormData_pg_user),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ GroupRelationName, /* GRONAME */
|
||||
1,
|
||||
{ Anum_pg_group_groname,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
offsetof(FormData_pg_group, grolist[0]),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ GroupRelationName, /* GROSYSID */
|
||||
1,
|
||||
{ Anum_pg_group_grosysid,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
offsetof(FormData_pg_group, grolist[0]),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ RewriteRelationName, /* REWRITENAME */
|
||||
1,
|
||||
{ Anum_pg_rewrite_rulename,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
offsetof(FormData_pg_rewrite, ev_qual),
|
||||
NULL,
|
||||
(ScanFunc) NULL },
|
||||
{ ProcedureRelationName, /* PROSRC */
|
||||
1,
|
||||
{ Anum_pg_proc_prosrc,
|
||||
0,
|
||||
0,
|
||||
0 },
|
||||
offsetof(FormData_pg_proc, prosrc),
|
||||
ProcedureSrcIndex,
|
||||
(ScanFunc) ProcedureSrcIndexScan }
|
||||
};
|
||||
|
||||
static struct catcache *SysCache[lengthof(cacheinfo)];
|
||||
static int32 SysCacheSize = lengthof(cacheinfo);
|
||||
|
||||
|
||||
/*
|
||||
* zerocaches--
|
||||
*
|
||||
* Make sure the SysCache structure is zero'd.
|
||||
*/
|
||||
void
|
||||
zerocaches()
|
||||
{
|
||||
memset((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
|
||||
}
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* This function was written because the initialized catalog caches
|
||||
* are used to determine which caches may contain tuples which need
|
||||
* to be invalidated in other backends.
|
||||
*/
|
||||
void
|
||||
InitCatalogCache()
|
||||
{
|
||||
int cacheId; /* XXX type */
|
||||
|
||||
if (!AMI_OVERRIDE) {
|
||||
for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1) {
|
||||
|
||||
Assert(!PointerIsValid((Pointer)SysCache[cacheId]));
|
||||
|
||||
SysCache[cacheId] =
|
||||
InitSysCache(cacheinfo[cacheId].name,
|
||||
cacheinfo[cacheId].indname,
|
||||
cacheId,
|
||||
cacheinfo[cacheId].nkeys,
|
||||
cacheinfo[cacheId].key,
|
||||
cacheinfo[cacheId].iScanFunc);
|
||||
if (!PointerIsValid((char *)SysCache[cacheId])) {
|
||||
elog(WARN,
|
||||
"InitCatalogCache: Can't init cache %.16s(%d)",
|
||||
cacheinfo[cacheId].name,
|
||||
cacheId);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SearchSysCacheTuple--
|
||||
*
|
||||
* A layer on top of SearchSysCache that does the initialization and
|
||||
* key-setting for you.
|
||||
*
|
||||
* Returns the tuple if one is found, NULL if not.
|
||||
*
|
||||
* XXX The tuple that is returned is NOT supposed to be pfree'd!
|
||||
*/
|
||||
HeapTuple
|
||||
SearchSysCacheTuple(int cacheId, /* cache selection code */
|
||||
Datum key1,
|
||||
Datum key2,
|
||||
Datum key3,
|
||||
Datum key4)
|
||||
{
|
||||
register HeapTuple tp;
|
||||
|
||||
if (cacheId < 0 || cacheId >= SysCacheSize) {
|
||||
elog(WARN, "SearchSysCacheTuple: Bad cache id %d", cacheId);
|
||||
return((HeapTuple) NULL);
|
||||
}
|
||||
|
||||
if (!AMI_OVERRIDE) {
|
||||
Assert(PointerIsValid(SysCache[cacheId]));
|
||||
} else {
|
||||
if (!PointerIsValid(SysCache[cacheId])) {
|
||||
SysCache[cacheId] =
|
||||
InitSysCache(cacheinfo[cacheId].name,
|
||||
cacheinfo[cacheId].indname,
|
||||
cacheId,
|
||||
cacheinfo[cacheId].nkeys,
|
||||
cacheinfo[cacheId].key,
|
||||
cacheinfo[cacheId].iScanFunc);
|
||||
if (!PointerIsValid(SysCache[cacheId])) {
|
||||
elog(WARN,
|
||||
"InitCatalogCache: Can't init cache %.16s(%d)",
|
||||
cacheinfo[cacheId].name,
|
||||
cacheId);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
|
||||
if (!HeapTupleIsValid(tp)) {
|
||||
#ifdef CACHEDEBUG
|
||||
elog(DEBUG,
|
||||
"SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
|
||||
(*cacheinfo[cacheId].name)->data,
|
||||
cacheId, key1, key2, key3, key4);
|
||||
#endif
|
||||
return((HeapTuple) NULL);
|
||||
}
|
||||
return(tp);
|
||||
}
|
||||
|
||||
/*
|
||||
* SearchSysCacheStruct--
|
||||
* Fills 's' with the information retrieved by calling SearchSysCache()
|
||||
* with arguments key1...key4. Retrieves only the portion of the tuple
|
||||
* which is not variable-length.
|
||||
*
|
||||
* NOTE: we are assuming that non-variable-length fields in the system
|
||||
* catalogs will always be defined!
|
||||
*
|
||||
* Returns 1L if a tuple was found, 0L if not.
|
||||
*/
|
||||
int32
|
||||
SearchSysCacheStruct(int cacheId, /* cache selection code */
|
||||
char *returnStruct, /* (preallocated!) */
|
||||
Datum key1,
|
||||
Datum key2,
|
||||
Datum key3,
|
||||
Datum key4)
|
||||
{
|
||||
HeapTuple tp;
|
||||
|
||||
if (!PointerIsValid(returnStruct)) {
|
||||
elog(WARN, "SearchSysCacheStruct: No receiving struct");
|
||||
return(0);
|
||||
}
|
||||
tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
|
||||
if (!HeapTupleIsValid(tp))
|
||||
return(0);
|
||||
memmove(returnStruct, (char *) GETSTRUCT(tp), cacheinfo[cacheId].size);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SearchSysCacheGetAttribute--
|
||||
* Returns the attribute corresponding to 'attributeNumber' for
|
||||
* a given cached tuple.
|
||||
*
|
||||
* XXX This re-opens a relation, so this is slower.
|
||||
*
|
||||
* [callers all assume this returns a (struct varlena *). -ay 10/94]
|
||||
*/
|
||||
void *
|
||||
SearchSysCacheGetAttribute(int cacheId,
|
||||
AttrNumber attributeNumber,
|
||||
Datum key1,
|
||||
Datum key2,
|
||||
Datum key3,
|
||||
Datum key4)
|
||||
{
|
||||
HeapTuple tp;
|
||||
char *cacheName;
|
||||
Relation relation;
|
||||
int32 attributeLength, attributeByValue;
|
||||
bool isNull;
|
||||
char *attributeValue;
|
||||
void *returnValue;
|
||||
|
||||
tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
|
||||
cacheName = cacheinfo[cacheId].name;
|
||||
|
||||
if (!HeapTupleIsValid(tp)) {
|
||||
#ifdef CACHEDEBUG
|
||||
elog(DEBUG,
|
||||
"SearchSysCacheGetAttribute: Lookup in %s(%d) failed",
|
||||
cacheName, cacheId);
|
||||
#endif /* defined(CACHEDEBUG) */
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
relation = heap_openr(cacheName);
|
||||
|
||||
if (attributeNumber < 0 &&
|
||||
attributeNumber > FirstLowInvalidHeapAttributeNumber) {
|
||||
attributeLength = heap_sysattrlen(attributeNumber);
|
||||
attributeByValue = heap_sysattrbyval(attributeNumber);
|
||||
} else if (attributeNumber > 0 &&
|
||||
attributeNumber <= relation->rd_rel->relnatts) {
|
||||
attributeLength =
|
||||
relation->rd_att->attrs[attributeNumber-1]->attlen;
|
||||
attributeByValue =
|
||||
relation->rd_att->attrs[attributeNumber-1]->attbyval;
|
||||
} else {
|
||||
elog(WARN,
|
||||
"SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)",
|
||||
attributeNumber, cacheName, cacheId);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
attributeValue = heap_getattr(tp,
|
||||
(Buffer) 0,
|
||||
attributeNumber,
|
||||
RelationGetTupleDescriptor(relation),
|
||||
&isNull);
|
||||
|
||||
if (isNull) {
|
||||
/*
|
||||
* Used to be an elog(DEBUG, ...) here and a claim that it should
|
||||
* be a FATAL error, I don't think either is warranted -mer 6/9/92
|
||||
*/
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if (attributeByValue) {
|
||||
returnValue = (void *)attributeValue;
|
||||
} else {
|
||||
char *tmp;
|
||||
int size = (attributeLength < 0)
|
||||
? VARSIZE((struct varlena *) attributeValue) /* variable length */
|
||||
: attributeLength; /* fixed length */
|
||||
|
||||
tmp = (char *) palloc(size);
|
||||
memmove(tmp, attributeValue, size);
|
||||
returnValue = (void *)tmp;
|
||||
}
|
||||
|
||||
heap_close(relation);
|
||||
return(returnValue);
|
||||
}
|
||||
|
||||
/*
|
||||
* TypeDefaultRetrieve--
|
||||
*
|
||||
* Given a type OID, return the typdefault field associated with that
|
||||
* type. The typdefault is returned as the car of a dotted pair which
|
||||
* is passed to TypeDefaultRetrieve by the calling routine.
|
||||
*
|
||||
* Returns a fixnum for types which are passed by value and a ppreserve'd
|
||||
* vectori for types which are not.
|
||||
*
|
||||
* [identical to get_typdefault, expecting a (struct varlena *) as ret val.
|
||||
* some day, either of the functions should be removed -ay 10/94]
|
||||
*/
|
||||
void *
|
||||
TypeDefaultRetrieve(Oid typId)
|
||||
{
|
||||
HeapTuple typeTuple;
|
||||
TypeTupleForm type;
|
||||
int32 typByVal, typLen;
|
||||
struct varlena *typDefault;
|
||||
int32 dataSize;
|
||||
void *returnValue;
|
||||
|
||||
typeTuple = SearchSysCacheTuple(TYPOID,
|
||||
ObjectIdGetDatum(typId),
|
||||
0,0,0);
|
||||
|
||||
if (!HeapTupleIsValid(typeTuple)) {
|
||||
#ifdef CACHEDEBUG
|
||||
elog(DEBUG, "TypeDefaultRetrieve: Lookup in %s(%d) failed",
|
||||
(*cacheinfo[TYPOID].name)->data, TYPOID);
|
||||
#endif /* defined(CACHEDEBUG) */
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
type = (TypeTupleForm) GETSTRUCT(typeTuple);
|
||||
typByVal = type->typbyval;
|
||||
typLen = type->typlen;
|
||||
|
||||
typDefault = (struct varlena *)
|
||||
SearchSysCacheGetAttribute(TYPOID,
|
||||
Anum_pg_type_typdefault,
|
||||
ObjectIdGetDatum(typId),
|
||||
0,0,0);
|
||||
|
||||
if (typDefault == (struct varlena *)NULL) {
|
||||
#ifdef CACHEDEBUG
|
||||
elog(DEBUG, "TypeDefaultRetrieve: No extractable typdefault",
|
||||
(*cacheinfo[TYPOID].name)->data, TYPOID);
|
||||
#endif /* defined(CACHEDEBUG) */
|
||||
return (NULL);
|
||||
|
||||
}
|
||||
|
||||
dataSize = VARSIZE(typDefault) - VARHDRSZ;
|
||||
|
||||
if (typByVal) {
|
||||
int8 i8;
|
||||
int16 i16;
|
||||
int32 i32;
|
||||
|
||||
if (dataSize == typLen) {
|
||||
switch (typLen) {
|
||||
case sizeof(int8):
|
||||
memmove((char *) &i8, VARDATA(typDefault), sizeof(int8));
|
||||
i32 = i8;
|
||||
break;
|
||||
case sizeof(int16):
|
||||
memmove((char *) &i16, VARDATA(typDefault), sizeof(int16));
|
||||
i32 = i16;
|
||||
break;
|
||||
case sizeof(int32):
|
||||
memmove((char *) &i32, VARDATA(typDefault), sizeof(int32));
|
||||
break;
|
||||
}
|
||||
returnValue = (void *)i32;
|
||||
} else {
|
||||
returnValue = NULL;
|
||||
}
|
||||
} else {
|
||||
if ((typLen < 0 && dataSize < 0) || dataSize != typLen)
|
||||
returnValue = NULL;
|
||||
else {
|
||||
returnValue = (void *)palloc(VARSIZE(typDefault));
|
||||
memmove((char *) returnValue,
|
||||
(char *) typDefault,
|
||||
(int) VARSIZE(typDefault));
|
||||
}
|
||||
}
|
||||
|
||||
return(returnValue);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user