1
0
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:
Marc G. Fournier
1996-07-09 06:22:35 +00:00
commit d31084e9d1
868 changed files with 242656 additions and 0 deletions

15
src/backend/utils/cache/Makefile.inc vendored Normal file
View 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

File diff suppressed because it is too large Load Diff

297
src/backend/utils/cache/fcache.c vendored Normal file
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

630
src/backend/utils/cache/syscache.c vendored Normal file
View 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);
}