From 27fee810ff9968a1034fea4bba4cd8d078c5d2d1 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 23 Jan 2000 03:43:24 +0000 Subject: [PATCH] Replace SearchSysCacheGetAttribute with SysCacheGetAttr, which fetches an attribute of a tuple previously fetched with SearchSysCacheTuple. This avoids a lot of redundant cache lookups, particularly in selfuncs.c. Also, remove SearchSysCacheStruct, which was unused and grotty. --- src/backend/utils/adt/selfuncs.c | 56 ++++------ src/backend/utils/cache/fcache.c | 85 ++++++--------- src/backend/utils/cache/lsyscache.c | 44 ++++---- src/backend/utils/cache/syscache.c | 158 ++++++---------------------- src/include/utils/syscache.h | 10 +- 5 files changed, 110 insertions(+), 243 deletions(-) diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 6af241f9a1..5838fdc471 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.50 2000/01/23 02:06:56 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.51 2000/01/23 03:43:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -587,9 +587,6 @@ getattproperties(Oid relid, AttrNumber attnum, * commonval, loval, hival are returned as Datums holding the internal * representation of the values. (Note that these should be pfree'd * after use if the data type is not by-value.) - * - * XXX currently, this does a linear search of pg_statistic because there - * is no index nor syscache for pg_statistic. FIX THIS! */ static bool getattstatistics(Oid relid, AttrNumber attnum, Oid opid, Oid typid, @@ -600,29 +597,26 @@ getattstatistics(Oid relid, AttrNumber attnum, Oid opid, Oid typid, Datum *loval, Datum *hival) { - Relation rel; - bool isnull; HeapTuple tuple; HeapTuple typeTuple; FmgrInfo inputproc; Oid typelem; - - rel = heap_openr(StatisticRelationName, AccessShareLock); - - tuple = SearchSysCacheTuple(STATRELID, - ObjectIdGetDatum(relid), - Int16GetDatum((int16) attnum), - opid, 0); - if (!HeapTupleIsValid(tuple)) - { - /* no such stats entry */ - heap_close(rel, AccessShareLock); - return false; - } + bool isnull; /* We assume that there will only be one entry in pg_statistic * for the given rel/att. Someday, VACUUM might store more than one... */ + tuple = SearchSysCacheTuple(STATRELID, + ObjectIdGetDatum(relid), + Int16GetDatum((int16) attnum), + opid, + 0); + if (!HeapTupleIsValid(tuple)) + { + /* no such stats entry */ + return false; + } + if (nullfrac) *nullfrac = ((Form_pg_statistic) GETSTRUCT(tuple))->stanullfrac; if (commonfrac) @@ -639,14 +633,13 @@ getattstatistics(Oid relid, AttrNumber attnum, Oid opid, Oid typid, typelem = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem; /* Values are variable-length fields, so cannot access as struct fields. - * Must do it the hard way with heap_getattr. + * Must do it the hard way with SysCacheGetAttr. */ if (commonval) { - text *val = (text *) heap_getattr(tuple, - Anum_pg_statistic_stacommonval, - RelationGetDescr(rel), - &isnull); + text *val = (text *) SysCacheGetAttr(STATRELID, tuple, + Anum_pg_statistic_stacommonval, + &isnull); if (isnull) { elog(DEBUG, "getattstatistics: stacommonval is null"); @@ -663,10 +656,9 @@ getattstatistics(Oid relid, AttrNumber attnum, Oid opid, Oid typid, if (loval) { - text *val = (text *) heap_getattr(tuple, - Anum_pg_statistic_staloval, - RelationGetDescr(rel), - &isnull); + text *val = (text *) SysCacheGetAttr(STATRELID, tuple, + Anum_pg_statistic_staloval, + &isnull); if (isnull) { elog(DEBUG, "getattstatistics: staloval is null"); @@ -683,10 +675,9 @@ getattstatistics(Oid relid, AttrNumber attnum, Oid opid, Oid typid, if (hival) { - text *val = (text *) heap_getattr(tuple, - Anum_pg_statistic_stahival, - RelationGetDescr(rel), - &isnull); + text *val = (text *) SysCacheGetAttr(STATRELID, tuple, + Anum_pg_statistic_stahival, + &isnull); if (isnull) { elog(DEBUG, "getattstatistics: stahival is null"); @@ -701,7 +692,6 @@ getattstatistics(Oid relid, AttrNumber attnum, Oid opid, Oid typid, } } - heap_close(rel, AccessShareLock); return true; } diff --git a/src/backend/utils/cache/fcache.c b/src/backend/utils/cache/fcache.c index 69ef78af09..49a2642e86 100644 --- a/src/backend/utils/cache/fcache.c +++ b/src/backend/utils/cache/fcache.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.27 1999/11/22 17:56:32 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.28 2000/01/23 03:43:24 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -74,13 +74,12 @@ init_fcache(Oid foid, Form_pg_proc procedureStruct; Form_pg_type typeStruct; FunctionCachePtr retval; - text *tmp; int nargs; + text *tmp; + bool isNull; /* ---------------- - * get the procedure tuple corresponding to the given - * functionOid. If this fails, returnValue has been - * pre-initialized to "null" so we just return it. + * get the procedure tuple corresponding to the given functionOid * ---------------- */ retval = (FunctionCachePtr) palloc(sizeof(FunctionCache)); @@ -94,20 +93,13 @@ init_fcache(Oid foid, 0, 0, 0); if (!HeapTupleIsValid(procedureTuple)) - elog(ERROR, - "init_fcache: %s %u", - "Cache lookup failed for procedure", foid); + elog(ERROR, "init_fcache: Cache lookup failed for procedure %u", + 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. + * get the return type from the procedure tuple * ---------------- */ typeTuple = SearchSysCacheTuple(TYPEOID, @@ -115,27 +107,24 @@ init_fcache(Oid foid, 0, 0, 0); if (!HeapTupleIsValid(typeTuple)) - elog(ERROR, - "init_fcache: %s %u", - "Cache lookup failed for type", - (procedureStruct)->prorettype); + elog(ERROR, "init_fcache: Cache lookup failed for type %u", + procedureStruct->prorettype); + + typeStruct = (Form_pg_type) GETSTRUCT(typeTuple); /* ---------------- * get the type length and by-value from the type tuple and * save the information in our one element cache. * ---------------- */ - typeStruct = (Form_pg_type) GETSTRUCT(typeTuple); - - retval->typlen = (typeStruct)->typlen; - if ((typeStruct)->typrelid == InvalidOid) + 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; + retval->typbyval = typeStruct->typbyval; } else { - /* * This is a hack. We assume here that any function returning a * relation returns it by reference. This needs to be fixed. @@ -147,7 +136,7 @@ init_fcache(Oid foid, retval->func_state = (char *) NULL; retval->setArg = NULL; retval->hasSetArg = false; - retval->oneResult = !procedureStruct->proretset; + retval->oneResult = ! procedureStruct->proretset; retval->istrusted = procedureStruct->proistrusted; /* @@ -157,8 +146,8 @@ init_fcache(Oid foid, * allocated by the executor (i.e. slots and tuples) is freed. */ if ((retval->language == SQLlanguageId) && - (retval->oneResult) && - !(retval->typbyval)) + retval->oneResult && + ! retval->typbyval) { Form_pg_class relationStruct; HeapTuple relationTuple; @@ -198,7 +187,7 @@ init_fcache(Oid foid, { Oid *argTypes; - retval->nullVect = (bool *) palloc((retval->nargs) * sizeof(bool)); + retval->nullVect = (bool *) palloc(retval->nargs * sizeof(bool)); if (retval->language == SQLlanguageId) { @@ -230,43 +219,36 @@ init_fcache(Oid foid, 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)); + tmp = (text *) SysCacheGetAttr(PROCOID, + procedureTuple, + Anum_pg_proc_prosrc, + &isNull); + if (isNull) + elog(ERROR, "init_fcache: null prosrc for procedure %u", + foid); + retval->src = textout(tmp); retval->bin = (char *) NULL; } else { - - /* - * I'm not sure that we even need to do this at all. - */ - - /* - * We do for untrusted functions. - */ - + retval->src = (char *) NULL; if (procedureStruct->proistrusted) retval->bin = (char *) NULL; else { - tmp = (text *) - SearchSysCacheGetAttribute(PROCOID, + tmp = (text *) SysCacheGetAttr(PROCOID, + procedureTuple, Anum_pg_proc_probin, - ObjectIdGetDatum(foid), - 0, 0, 0); + &isNull); + if (isNull) + elog(ERROR, "init_fcache: null probin for procedure %u", + foid); retval->bin = textout(tmp); } - retval->src = (char *) NULL; } - - - if (retval->language != SQLlanguageId) { fmgr_info(foid, &(retval->func)); @@ -275,7 +257,6 @@ init_fcache(Oid foid, else retval->func.fn_addr = (func_ptr) NULL; - return retval; } diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 1c34486b74..406c476182 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -6,7 +6,7 @@ * Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.37 1999/12/31 03:18:43 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.38 2000/01/23 03:43:24 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -617,35 +617,15 @@ get_typalign(Oid typid) Datum get_typdefault(Oid typid) { - struct varlena *typDefault; - int32 dataSize; HeapTuple typeTuple; Form_pg_type type; + struct varlena *typDefault; + bool isNull; + int32 dataSize; int32 typLen; bool typByVal; Datum returnValue; - /* - * First, see if there is a non-null typdefault field (usually there isn't) - */ - typDefault = (struct varlena *) - SearchSysCacheGetAttribute(TYPEOID, - Anum_pg_type_typdefault, - ObjectIdGetDatum(typid), - 0, 0, 0); - - if (typDefault == NULL) - return PointerGetDatum(NULL); - - dataSize = VARSIZE(typDefault) - VARHDRSZ; - - /* - * Need the type's length and byVal fields. - * - * XXX silly to repeat the syscache search that SearchSysCacheGetAttribute - * just did --- but at present this path isn't taken often enough to - * make it worth fixing. - */ typeTuple = SearchSysCacheTuple(TYPEOID, ObjectIdGetDatum(typid), 0, 0, 0); @@ -654,6 +634,22 @@ get_typdefault(Oid typid) elog(ERROR, "get_typdefault: failed to lookup type %u", typid); type = (Form_pg_type) GETSTRUCT(typeTuple); + + /* + * First, see if there is a non-null typdefault field (usually there isn't) + */ + typDefault = (struct varlena *) SysCacheGetAttr(TYPEOID, + typeTuple, + Anum_pg_type_typdefault, + &isNull); + + if (isNull) + return PointerGetDatum(NULL); + + /* + * Otherwise, extract/copy the value. + */ + dataSize = VARSIZE(typDefault) - VARHDRSZ; typLen = type->typlen; typByVal = type->typbyval; diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 9c94c1e05a..0d4c1e3e05 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.44 1999/11/24 17:09:27 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.45 2000/01/23 03:43:24 tgl Exp $ * * NOTES * These routines allow the parser/planner/executor to perform @@ -535,140 +535,42 @@ SearchSysCacheTuple(int cacheId,/* cache selection code */ 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(ERROR, "SearchSysCacheStruct: No receiving struct"); - return 0; - } - tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4); - if (!HeapTupleIsValid(tp)) - return 0; - memcpy(returnStruct, (char *) GETSTRUCT(tp), cacheinfo[cacheId].size); - return 1; -} - /* - * SearchSysCacheGetAttribute - * Returns the attribute corresponding to 'attributeNumber' for - * a given cached tuple. This routine usually needs to be used for - * attributes that might be NULL or might be at a variable offset - * in the tuple. + * SysCacheGetAttr * - * XXX This re-opens the relation, so this is slower than just pulling - * fixed-location fields out of the struct returned by SearchSysCacheTuple. + * Given a tuple previously fetched by SearchSysCacheTuple() or + * SearchSysCacheTupleCopy(), extract a specific attribute. * - * [callers all assume this returns a (struct varlena *). -ay 10/94] + * This is equivalent to using heap_getattr() on a tuple fetched + * from a non-cached relation. Usually, this is only used for attributes + * that could be NULL or variable length; the fixed-size attributes in + * a system table are accessed just by mapping the tuple onto the C struct + * declarations from include/catalog/. + * + * As with heap_getattr(), if the attribute is of a pass-by-reference type + * then a pointer into the tuple data area is returned --- the caller must + * not modify or pfree the datum! */ -void * -SearchSysCacheGetAttribute(int cacheId, - AttrNumber attributeNumber, - Datum key1, - Datum key2, - Datum key3, - Datum key4) +Datum +SysCacheGetAttr(int cacheId, HeapTuple tup, + AttrNumber attributeNumber, + bool *isnull) { - HeapTuple tp; - char *cacheName; - Relation relation; - int32 attributeLength, - attributeByValue; - bool isNull; - Datum attributeValue; - void *returnValue; - /* - * Open the relation first, to ensure we are in sync with SI inval - * events --- we don't want the tuple found in the cache to be - * invalidated out from under us. + * We just need to get the TupleDesc out of the cache entry, + * and then we can apply heap_getattr(). We expect that the cache + * control data is currently valid --- if the caller just fetched + * the tuple, then it should be. */ - cacheName = cacheinfo[cacheId].name; - relation = heap_openr(cacheName, AccessShareLock); + if (cacheId < 0 || cacheId >= SysCacheSize) + elog(ERROR, "SysCacheGetAttr: Bad cache id %d", cacheId); + if (! PointerIsValid(SysCache[cacheId]) || + SysCache[cacheId]->relationId == InvalidOid || + ! PointerIsValid(SysCache[cacheId]->cc_tupdesc)) + elog(ERROR, "SysCacheGetAttr: missing cache data for id %d", cacheId); - tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4); - - if (!HeapTupleIsValid(tp)) - { - heap_close(relation, AccessShareLock); -#ifdef CACHEDEBUG - elog(DEBUG, - "SearchSysCacheGetAttribute: Lookup in %s(%d) failed", - cacheName, cacheId); -#endif /* defined(CACHEDEBUG) */ - return NULL; - } - - 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 - { - heap_close(relation, AccessShareLock); - elog(ERROR, - "SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)", - attributeNumber, cacheName, cacheId); - return NULL; - } - - attributeValue = heap_getattr(tp, - attributeNumber, - RelationGetDescr(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 - */ - heap_close(relation, AccessShareLock); - 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); - memcpy(tmp, (void *) attributeValue, size); - returnValue = (void *) tmp; - } - - heap_close(relation, AccessShareLock); - return returnValue; + return heap_getattr(tup, attributeNumber, + SysCache[cacheId]->cc_tupdesc, + isnull); } diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 158a7bdb36..a6acff0265 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -8,7 +8,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: syscache.h,v 1.22 1999/11/24 16:52:50 momjian Exp $ + * $Id: syscache.h,v 1.23 2000/01/23 03:43:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -81,10 +81,8 @@ extern HeapTuple SearchSysCacheTupleCopy(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4); extern HeapTuple SearchSysCacheTuple(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4); -extern int32 SearchSysCacheStruct(int cacheId, char *returnStruct, - Datum key1, Datum key2, Datum key3, Datum key4); -extern void *SearchSysCacheGetAttribute(int cacheId, - AttrNumber attributeNumber, - Datum key1, Datum key2, Datum key3, Datum key4); +extern Datum SysCacheGetAttr(int cacheId, HeapTuple tup, + AttrNumber attributeNumber, + bool *isnull); #endif /* SYSCACHE_H */