aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2000-11-16 22:30:52 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2000-11-16 22:30:52 +0000
commita933ee38bbb8dffbc48a3363a94ff6f2a9f7964d (patch)
tree1c32737389b2530e7152dc2287161b36d9001e8c /src/backend/utils/cache
parentcff23842a4c68301ddf34559c7af383bb5557054 (diff)
downloadpostgresql-a933ee38bbb8dffbc48a3363a94ff6f2a9f7964d.tar.gz
postgresql-a933ee38bbb8dffbc48a3363a94ff6f2a9f7964d.zip
Change SearchSysCache coding conventions so that a reference count is
maintained for each cache entry. A cache entry will not be freed until the matching ReleaseSysCache call has been executed. This eliminates worries about cache entries getting dropped while still in use. See my posting to pg-hackers of even date for more info.
Diffstat (limited to 'src/backend/utils/cache')
-rw-r--r--src/backend/utils/cache/catcache.c391
-rw-r--r--src/backend/utils/cache/lsyscache.c349
-rw-r--r--src/backend/utils/cache/syscache.c187
-rw-r--r--src/backend/utils/cache/temprel.c3
4 files changed, 527 insertions, 403 deletions
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index 39e05d0fb09..3d8e7d80ba8 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.71 2000/11/10 00:33:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.72 2000/11/16 22:30:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,7 +28,8 @@
#include "utils/catcache.h"
#include "utils/syscache.h"
-static void CatCacheRemoveCTup(CatCache *cache, Dlelem *e);
+
+static void CatCacheRemoveCTup(CatCache *cache, CatCTup *ct);
static Index CatalogCacheComputeHashIndex(CatCache *cache,
ScanKey cur_skey);
static Index CatalogCacheComputeTupleHashIndex(CatCache *cache,
@@ -388,28 +389,17 @@ CatalogCacheComputeTupleHashIndex(CatCache *cache,
* --------------------------------
*/
static void
-CatCacheRemoveCTup(CatCache *cache, Dlelem *elt)
+CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
{
- CatCTup *ct;
- CatCTup *other_ct;
- Dlelem *other_elt;
-
- if (!elt) /* probably-useless safety check */
- return;
-
- /* We need to zap both linked-list elements as well as the tuple */
+ Assert(ct->refcount == 0);
- ct = (CatCTup *) DLE_VAL(elt);
- other_elt = ct->ct_node;
- other_ct = (CatCTup *) DLE_VAL(other_elt);
+ /* delink from linked lists */
+ DLRemove(&ct->lrulist_elem);
+ DLRemove(&ct->cache_elem);
- heap_freetuple(ct->ct_tup);
-
- DLRemove(other_elt);
- DLFreeElem(other_elt);
- pfree(other_ct);
- DLRemove(elt);
- DLFreeElem(elt);
+ /* free associated tuple data */
+ if (ct->tuple.t_data != NULL)
+ pfree(ct->tuple.t_data);
pfree(ct);
--cache->cc_ntup;
@@ -425,13 +415,11 @@ CatCacheRemoveCTup(CatCache *cache, Dlelem *elt)
* --------------------------------
*/
void
-CatalogCacheIdInvalidate(int cacheId, /* XXX */
+CatalogCacheIdInvalidate(int cacheId,
Index hashIndex,
ItemPointer pointer)
{
CatCache *ccp;
- CatCTup *ct;
- Dlelem *elt;
/* ----------------
* sanity checks
@@ -442,54 +430,101 @@ CatalogCacheIdInvalidate(int cacheId, /* XXX */
CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");
/* ----------------
- * inspect every cache that could contain the tuple
+ * inspect caches to find the proper cache
* ----------------
*/
for (ccp = Caches; ccp; ccp = ccp->cc_next)
{
+ Dlelem *elt,
+ *nextelt;
+
if (cacheId != ccp->id)
continue;
/* ----------------
* inspect the hash bucket until we find a match or exhaust
* ----------------
*/
- for (elt = DLGetHead(ccp->cc_cache[hashIndex]);
- elt;
- elt = DLGetSucc(elt))
+ for (elt = DLGetHead(&ccp->cc_cache[hashIndex]); elt; elt = nextelt)
{
- ct = (CatCTup *) DLE_VAL(elt);
- if (ItemPointerEquals(pointer, &ct->ct_tup->t_self))
- break;
- }
-
- /* ----------------
- * if we found a matching tuple, invalidate it.
- * ----------------
- */
+ CatCTup *ct = (CatCTup *) DLE_VAL(elt);
- if (elt)
- {
- CatCacheRemoveCTup(ccp, elt);
+ nextelt = DLGetSucc(elt);
- CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated");
+ if (ItemPointerEquals(pointer, &ct->tuple.t_self))
+ {
+ if (ct->refcount > 0)
+ ct->dead = true;
+ else
+ CatCacheRemoveCTup(ccp, ct);
+ CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated");
+ /* could be multiple matches, so keep looking! */
+ }
}
-
- if (cacheId != InvalidCatalogCacheId)
- break;
+ break; /* need only search this one cache */
}
}
/* ----------------------------------------------------------------
* public functions
*
+ * AtEOXact_CatCache
* ResetSystemCache
- * InitSysCache
- * SearchSysCache
+ * InitCatCache
+ * SearchCatCache
+ * ReleaseCatCache
* RelationInvalidateCatalogCacheTuple
* ----------------------------------------------------------------
*/
+
+
+/* --------------------------------
+ * AtEOXact_CatCache
+ *
+ * Clean up catcaches at end of transaction (either commit or abort)
+ *
+ * We scan the caches to reset refcounts to zero. This is of course
+ * necessary in the abort case, since elog() may have interrupted routines.
+ * In the commit case, any nonzero counts indicate failure to call
+ * ReleaseSysCache, so we put out a notice for debugging purposes.
+ * --------------------------------
+ */
+void
+AtEOXact_CatCache(bool isCommit)
+{
+ CatCache *cache;
+
+ for (cache = Caches; cache; cache = cache->cc_next)
+ {
+ Dlelem *elt,
+ *nextelt;
+
+ for (elt = DLGetHead(&cache->cc_lrulist); elt; elt = nextelt)
+ {
+ CatCTup *ct = (CatCTup *) DLE_VAL(elt);
+
+ nextelt = DLGetSucc(elt);
+
+ if (ct->refcount != 0)
+ {
+ if (isCommit)
+ elog(NOTICE, "Cache reference leak: cache %s (%d), tuple %u has count %d",
+ cache->cc_relname, cache->id,
+ ct->tuple.t_data->t_oid,
+ ct->refcount);
+ ct->refcount = 0;
+ }
+
+ /* Clean up any now-deletable dead entries */
+ if (ct->dead)
+ CatCacheRemoveCTup(cache, ct);
+ }
+ }
+}
+
/* --------------------------------
* ResetSystemCache
+ *
+ * Reset caches when a shared cache inval event forces it
* --------------------------------
*/
void
@@ -503,34 +538,25 @@ ResetSystemCache(void)
* here we purge the contents of all the caches
*
* for each system cache
- * for each hash bucket
- * for each tuple in hash bucket
- * remove the tuple
+ * for each tuple
+ * remove the tuple, or at least mark it dead
* ----------------
*/
- for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)
+ for (cache = Caches; cache; cache = cache->cc_next)
{
- int hash;
+ Dlelem *elt,
+ *nextelt;
- for (hash = 0; hash < NCCBUCK; hash += 1)
+ for (elt = DLGetHead(&cache->cc_lrulist); elt; elt = nextelt)
{
- Dlelem *elt,
- *nextelt;
+ CatCTup *ct = (CatCTup *) DLE_VAL(elt);
- for (elt = DLGetHead(cache->cc_cache[hash]); elt; elt = nextelt)
- {
- nextelt = DLGetSucc(elt);
- CatCacheRemoveCTup(cache, elt);
- }
- }
+ nextelt = DLGetSucc(elt);
- /* double-check that ntup is now zero */
- if (cache->cc_ntup != 0)
- {
- elog(NOTICE,
- "ResetSystemCache: cache %d has cc_ntup = %d, should be 0",
- cache->id, cache->cc_ntup);
- cache->cc_ntup = 0;
+ if (ct->refcount > 0)
+ ct->dead = true;
+ else
+ CatCacheRemoveCTup(cache, ct);
}
}
@@ -572,7 +598,7 @@ SystemCacheRelationFlushed(Oid relId)
}
/* --------------------------------
- * InitSysCache
+ * InitCatCache
*
* This allocates and initializes a cache for a system catalog relation.
* Actually, the cache is only partially initialized to avoid opening the
@@ -581,18 +607,18 @@ SystemCacheRelationFlushed(Oid relId)
* --------------------------------
*/
#ifdef CACHEDEBUG
-#define InitSysCache_DEBUG1 \
+#define InitCatCache_DEBUG1 \
do { \
- elog(DEBUG, "InitSysCache: rel=%s id=%d nkeys=%d size=%d\n", \
+ elog(DEBUG, "InitCatCache: rel=%s id=%d nkeys=%d size=%d\n", \
cp->cc_relname, cp->id, cp->cc_nkeys, cp->cc_size); \
} while(0)
#else
-#define InitSysCache_DEBUG1
+#define InitCatCache_DEBUG1
#endif
CatCache *
-InitSysCache(int id,
+InitCatCache(int id,
char *relname,
char *indname,
int nkeys,
@@ -624,25 +650,9 @@ InitSysCache(int id,
* and the LRU tuple list
* ----------------
*/
- {
-
- /*
- * We can only do this optimization because the number of hash
- * buckets never changes. Without it, we call palloc() too much.
- * We could move this to dllist.c, but the way we do this is not
- * dynamic/portable, so why allow other routines to use it.
- */
- Dllist *cache_begin = palloc((NCCBUCK + 1) * sizeof(Dllist));
-
- for (i = 0; i <= NCCBUCK; ++i)
- {
- cp->cc_cache[i] = &cache_begin[i];
- cp->cc_cache[i]->dll_head = 0;
- cp->cc_cache[i]->dll_tail = 0;
- }
- }
-
- cp->cc_lrulist = DLNewList();
+ DLInitList(&cp->cc_lrulist);
+ for (i = 0; i < NCCBUCK; ++i)
+ DLInitList(&cp->cc_cache[i]);
/* ----------------
* Caches is the pointer to the head of the list of all the
@@ -673,7 +683,7 @@ InitSysCache(int id,
* information, if appropriate.
* ----------------
*/
- InitSysCache_DEBUG1;
+ InitCatCache_DEBUG1;
/* ----------------
* back to the old context before we return...
@@ -742,14 +752,14 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
}
/* --------------------------------
- * SearchSysCache
+ * SearchCatCache
*
* This call searches a system cache for a tuple, opening the relation
* if necessary (the first access to a particular cache).
* --------------------------------
*/
HeapTuple
-SearchSysCache(CatCache *cache,
+SearchCatCache(CatCache *cache,
Datum v1,
Datum v2,
Datum v3,
@@ -757,10 +767,8 @@ SearchSysCache(CatCache *cache,
{
ScanKeyData cur_skey[4];
Index hash;
- CatCTup *ct = NULL;
- CatCTup *nct;
- CatCTup *nct2;
Dlelem *elt;
+ CatCTup *ct;
HeapTuple ntp;
Relation relation;
MemoryContext oldcxt;
@@ -792,48 +800,50 @@ SearchSysCache(CatCache *cache,
* scan the hash bucket until we find a match or exhaust our tuples
* ----------------
*/
- for (elt = DLGetHead(cache->cc_cache[hash]);
+ for (elt = DLGetHead(&cache->cc_cache[hash]);
elt;
elt = DLGetSucc(elt))
{
bool res;
ct = (CatCTup *) DLE_VAL(elt);
+
+ if (ct->dead)
+ continue; /* ignore dead entries */
+
/* ----------------
* see if the cached tuple matches our key.
* (should we be worried about time ranges? -cim 10/2/90)
* ----------------
*/
- HeapKeyTest(ct->ct_tup,
+ HeapKeyTest(&ct->tuple,
cache->cc_tupdesc,
cache->cc_nkeys,
cur_skey,
res);
- if (res)
- break;
- }
+ if (! res)
+ continue;
- /* ----------------
- * if we found a tuple in the cache, move it to the top of the
- * lru list, and return it. We also move it to the front of the
- * list for its hashbucket, in order to speed subsequent searches.
- * (The most frequently accessed elements in any hashbucket will
- * tend to be near the front of the hashbucket's list.)
- * ----------------
- */
- if (elt)
- {
- Dlelem *old_lru_elt = ((CatCTup *) DLE_VAL(elt))->ct_node;
+ /* ----------------
+ * we found a tuple in the cache: bump its refcount, move it to
+ * the front of the LRU list, and return it. We also move it
+ * to the front of the list for its hashbucket, in order to speed
+ * subsequent searches. (The most frequently accessed elements
+ * in any hashbucket will tend to be near the front of the
+ * hashbucket's list.)
+ * ----------------
+ */
+ ct->refcount++;
- DLMoveToFront(old_lru_elt);
- DLMoveToFront(elt);
+ DLMoveToFront(&ct->lrulist_elem);
+ DLMoveToFront(&ct->cache_elem);
#ifdef CACHEDEBUG
- CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d",
+ CACHE3_elog(DEBUG, "SearchCatCache(%s): found in bucket %d",
cache->cc_relname, hash);
#endif /* CACHEDEBUG */
- return ct->ct_tup;
+ return &ct->tuple;
}
/* ----------------
@@ -864,7 +874,7 @@ SearchSysCache(CatCache *cache,
* if it's safe to do so, use the index. Else do a heap scan.
* ----------------
*/
- ntp = NULL;
+ ct = NULL;
if ((RelationGetForm(relation))->relhasindex &&
!IsIgnoringSystemIndexes() &&
@@ -876,7 +886,7 @@ SearchSysCache(CatCache *cache,
HeapTupleData tuple;
Buffer buffer;
- CACHE2_elog(DEBUG, "SearchSysCache(%s): performing index scan",
+ CACHE2_elog(DEBUG, "SearchCatCache(%s): performing index scan",
cache->cc_relname);
idesc = index_openr(cache->cc_indname);
@@ -892,7 +902,8 @@ SearchSysCache(CatCache *cache,
{
/* Copy tuple into our context */
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
- ntp = heap_copytuple(&tuple);
+ ct = (CatCTup *) palloc(sizeof(CatCTup));
+ heap_copytuple_with_tuple(&tuple, &ct->tuple);
MemoryContextSwitchTo(oldcxt);
ReleaseBuffer(buffer);
break;
@@ -906,7 +917,7 @@ SearchSysCache(CatCache *cache,
HeapScanDesc sd;
int i;
- CACHE2_elog(DEBUG, "SearchSysCache(%s): performing heap scan",
+ CACHE2_elog(DEBUG, "SearchCatCache(%s): performing heap scan",
cache->cc_relname);
/*
@@ -925,7 +936,8 @@ SearchSysCache(CatCache *cache,
{
/* Copy tuple into our context */
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
- ntp = heap_copytuple(ntp);
+ ct = (CatCTup *) palloc(sizeof(CatCTup));
+ heap_copytuple_with_tuple(ntp, &ct->tuple);
MemoryContextSwitchTo(oldcxt);
/* We should not free the result of heap_getnext... */
}
@@ -934,77 +946,102 @@ SearchSysCache(CatCache *cache,
}
/* ----------------
- * scan is complete. if tup is valid, we can add it to the cache.
- * note we have already copied it into the cache memory context.
+ * close the relation
* ----------------
*/
- if (HeapTupleIsValid(ntp))
- {
- /* ----------------
- * allocate a new cache tuple holder, store the pointer
- * to the heap tuple there and initialize the list pointers.
- * ----------------
- */
- Dlelem *lru_elt;
-
- CACHE1_elog(DEBUG, "SearchSysCache: found tuple");
+ heap_close(relation, AccessShareLock);
- oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+ /* ----------------
+ * scan is complete. if tup was found, we can add it to the cache.
+ * ----------------
+ */
+ if (ct == NULL)
+ return NULL;
- /*
- * this is a little cumbersome here because we want the Dlelem's
- * in both doubly linked lists to point to one another. That makes
- * it easier to remove something from both the cache bucket and
- * the lru list at the same time
- */
- nct = (CatCTup *) palloc(sizeof(CatCTup));
- nct->ct_tup = ntp;
- elt = DLNewElem(nct);
- nct2 = (CatCTup *) palloc(sizeof(CatCTup));
- nct2->ct_tup = ntp;
- lru_elt = DLNewElem(nct2);
- nct2->ct_node = elt;
- nct->ct_node = lru_elt;
+ /* ----------------
+ * Finish initializing the CatCTup header, and add it to the
+ * linked lists.
+ * ----------------
+ */
+ CACHE1_elog(DEBUG, "SearchCatCache: found tuple");
- DLAddHead(cache->cc_lrulist, lru_elt);
- DLAddHead(cache->cc_cache[hash], elt);
+ ct->ct_magic = CT_MAGIC;
+ DLInitElem(&ct->lrulist_elem, (void *) ct);
+ DLInitElem(&ct->cache_elem, (void *) ct);
+ ct->refcount = 1; /* count this first reference */
+ ct->dead = false;
- MemoryContextSwitchTo(oldcxt);
+ DLAddHead(&cache->cc_lrulist, &ct->lrulist_elem);
+ DLAddHead(&cache->cc_cache[hash], &ct->cache_elem);
- /* ----------------
- * If we've exceeded the desired size of this cache,
- * throw away the least recently used entry.
- * ----------------
- */
- if (++cache->cc_ntup > cache->cc_maxtup)
+ /* ----------------
+ * If we've exceeded the desired size of this cache,
+ * try to throw away the least recently used entry.
+ * ----------------
+ */
+ if (++cache->cc_ntup > cache->cc_maxtup)
+ {
+ for (elt = DLGetTail(&cache->cc_lrulist);
+ elt;
+ elt = DLGetPred(elt))
{
- CatCTup *ct;
+ CatCTup *oldct = (CatCTup *) DLE_VAL(elt);
- elt = DLGetTail(cache->cc_lrulist);
- ct = (CatCTup *) DLE_VAL(elt);
-
- if (ct != nct) /* shouldn't be possible, but be safe... */
+ if (oldct->refcount == 0)
{
- CACHE2_elog(DEBUG, "SearchSysCache(%s): Overflow, LRU removal",
+ CACHE2_elog(DEBUG, "SearchCatCache(%s): Overflow, LRU removal",
cache->cc_relname);
-
- CatCacheRemoveCTup(cache, elt);
+ CatCacheRemoveCTup(cache, oldct);
+ break;
}
}
-
- CACHE4_elog(DEBUG, "SearchSysCache(%s): Contains %d/%d tuples",
- cache->cc_relname, cache->cc_ntup, cache->cc_maxtup);
- CACHE3_elog(DEBUG, "SearchSysCache(%s): put in bucket %d",
- cache->cc_relname, hash);
}
- /* ----------------
- * close the relation and return the tuple we found (or NULL)
- * ----------------
- */
- heap_close(relation, AccessShareLock);
+ CACHE4_elog(DEBUG, "SearchCatCache(%s): Contains %d/%d tuples",
+ cache->cc_relname, cache->cc_ntup, cache->cc_maxtup);
+ CACHE3_elog(DEBUG, "SearchCatCache(%s): put in bucket %d",
+ cache->cc_relname, hash);
+
+ return &ct->tuple;
+}
- return ntp;
+/* --------------------------------
+ * ReleaseCatCache()
+ *
+ * Decrement the reference count of a catcache entry (releasing the
+ * hold grabbed by a successful SearchCatCache).
+ *
+ * NOTE: if compiled with -DCATCACHE_FORCE_RELEASE then catcache entries
+ * will be freed as soon as their refcount goes to zero. In combination
+ * with aset.c's CLOBBER_FREED_MEMORY option, this provides a good test
+ * to catch references to already-released catcache entries.
+ * --------------------------------
+ */
+void
+ReleaseCatCache(HeapTuple tuple)
+{
+ CatCTup *ct = (CatCTup *) (((char *) tuple) -
+ offsetof(CatCTup, tuple));
+
+ /* Safety checks to ensure we were handed a cache entry */
+ Assert(ct->ct_magic == CT_MAGIC);
+ Assert(ct->refcount > 0);
+
+ ct->refcount--;
+
+ if (ct->refcount == 0
+#ifndef CATCACHE_FORCE_RELEASE
+ && ct->dead
+#endif
+ )
+ {
+ /* We can find the associated cache using the dllist pointers */
+ Dllist *lru = DLGetListHdr(&ct->lrulist_elem);
+ CatCache *cache = (CatCache *) (((char *) lru) -
+ offsetof(CatCache, cc_lrulist));
+
+ CatCacheRemoveCTup(cache, ct);
+ }
}
/* --------------------------------
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index b9bd9f8b9e9..e07445837a5 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.46 2000/10/05 19:48:29 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.47 2000/11/16 22:30:33 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
@@ -32,14 +32,11 @@
bool
op_class(Oid opno, Oid opclass, Oid amopid)
{
- if (HeapTupleIsValid(SearchSysCacheTuple(AMOPOPID,
- ObjectIdGetDatum(opclass),
- ObjectIdGetDatum(opno),
- ObjectIdGetDatum(amopid),
- 0)))
- return true;
- else
- return false;
+ return SearchSysCacheExists(AMOPOPID,
+ ObjectIdGetDatum(opclass),
+ ObjectIdGetDatum(opno),
+ ObjectIdGetDatum(amopid),
+ 0);
}
/* ---------- ATTRIBUTE CACHES ---------- */
@@ -49,21 +46,26 @@ op_class(Oid opno, Oid opclass, Oid amopid)
*
* Given the relation id and the attribute number,
* return the "attname" field from the attribute relation.
+ *
+ * Note: returns a palloc'd copy of the string, or NULL if no such operator.
*/
char *
get_attname(Oid relid, AttrNumber attnum)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(ATTNUM,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum),
- 0, 0);
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ char *result;
- return pstrdup(NameStr(att_tup->attname));
+ result = pstrdup(NameStr(att_tup->attname));
+ ReleaseSysCache(tp);
+ return result;
}
else
return NULL;
@@ -80,15 +82,18 @@ get_attnum(Oid relid, char *attname)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(ATTNAME,
- ObjectIdGetDatum(relid),
- PointerGetDatum(attname),
- 0, 0);
+ tp = SearchSysCache(ATTNAME,
+ ObjectIdGetDatum(relid),
+ PointerGetDatum(attname),
+ 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ AttrNumber result;
- return att_tup->attnum;
+ result = att_tup->attnum;
+ ReleaseSysCache(tp);
+ return result;
}
else
return InvalidAttrNumber;
@@ -105,15 +110,18 @@ get_atttype(Oid relid, AttrNumber attnum)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(ATTNUM,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum),
- 0, 0);
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ Oid result;
- return att_tup->atttypid;
+ result = att_tup->atttypid;
+ ReleaseSysCache(tp);
+ return result;
}
else
return InvalidOid;
@@ -128,15 +136,18 @@ get_attisset(Oid relid, char *attname)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(ATTNAME,
- ObjectIdGetDatum(relid),
- PointerGetDatum(attname),
- 0, 0);
+ tp = SearchSysCache(ATTNAME,
+ ObjectIdGetDatum(relid),
+ PointerGetDatum(attname),
+ 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ bool result;
- return att_tup->attisset;
+ result = att_tup->attisset;
+ ReleaseSysCache(tp);
+ return result;
}
else
return false;
@@ -153,15 +164,18 @@ get_atttypmod(Oid relid, AttrNumber attnum)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(ATTNUM,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum),
- 0, 0);
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ int32 result;
- return att_tup->atttypmod;
+ result = att_tup->atttypmod;
+ ReleaseSysCache(tp);
+ return result;
}
else
return -1;
@@ -185,12 +199,13 @@ get_attdispersion(Oid relid, AttrNumber attnum, double min_estimate)
HeapTuple atp;
Form_pg_attribute att_tup;
double dispersion;
+ Oid atttypid;
int32 ntuples;
- atp = SearchSysCacheTuple(ATTNUM,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum),
- 0, 0);
+ atp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
if (!HeapTupleIsValid(atp))
{
/* this should not happen */
@@ -198,9 +213,14 @@ get_attdispersion(Oid relid, AttrNumber attnum, double min_estimate)
relid, attnum);
return min_estimate;
}
+
att_tup = (Form_pg_attribute) GETSTRUCT(atp);
dispersion = att_tup->attdispersion;
+ atttypid = att_tup->atttypid;
+
+ ReleaseSysCache(atp);
+
if (dispersion > 0.0)
return dispersion; /* we have a specific estimate from VACUUM */
@@ -211,7 +231,7 @@ get_attdispersion(Oid relid, AttrNumber attnum, double min_estimate)
*
* Are there any other cases we should wire in special estimates for?
*/
- if (att_tup->atttypid == BOOLOID)
+ if (atttypid == BOOLOID)
return 0.5;
/*
@@ -219,9 +239,9 @@ get_attdispersion(Oid relid, AttrNumber attnum, double min_estimate)
* 1/numtuples). Either way, we need the relation size.
*/
- atp = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
+ atp = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0);
if (!HeapTupleIsValid(atp))
{
/* this should not happen */
@@ -231,6 +251,8 @@ get_attdispersion(Oid relid, AttrNumber attnum, double min_estimate)
ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
+ ReleaseSysCache(atp);
+
if (ntuples == 0)
return min_estimate; /* no data available */
@@ -277,14 +299,17 @@ get_opcode(Oid opno)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ RegProcedure result;
- return optup->oprcode;
+ result = optup->oprcode;
+ ReleaseSysCache(tp);
+ return result;
}
else
return (RegProcedure) InvalidOid;
@@ -301,14 +326,17 @@ get_opname(Oid opno)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ char *result;
- return pstrdup(NameStr(optup->oprname));
+ result = pstrdup(NameStr(optup->oprname));
+ ReleaseSysCache(tp);
+ return result;
}
else
return NULL;
@@ -324,10 +352,11 @@ bool
op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
{
HeapTuple tp;
+ bool result = false;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
@@ -339,10 +368,11 @@ op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
{
*leftOp = optup->oprlsortop;
*rightOp = optup->oprrsortop;
- return true;
+ result = true;
}
+ ReleaseSysCache(tp);
}
- return false;
+ return result;
}
/*
@@ -355,10 +385,11 @@ Oid
op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
{
HeapTuple tp;
+ Oid result = InvalidOid;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
@@ -366,9 +397,10 @@ op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
if (optup->oprcanhash &&
optup->oprleft == ltype &&
optup->oprright == rtype)
- return opno;
+ result = opno;
+ ReleaseSysCache(tp);
}
- return InvalidOid;
+ return result;
}
/*
@@ -387,14 +419,6 @@ op_iscachable(Oid opno)
return func_iscachable((Oid) funcid);
}
-HeapTuple
-get_operator_tuple(Oid opno)
-{
- return SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
-}
-
/*
* get_commutator
*
@@ -405,14 +429,17 @@ get_commutator(Oid opno)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ Oid result;
- return optup->oprcom;
+ result = optup->oprcom;
+ ReleaseSysCache(tp);
+ return result;
}
else
return InvalidOid;
@@ -428,14 +455,17 @@ get_negator(Oid opno)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ Oid result;
- return optup->oprnegate;
+ result = optup->oprnegate;
+ ReleaseSysCache(tp);
+ return result;
}
else
return InvalidOid;
@@ -451,14 +481,17 @@ get_oprrest(Oid opno)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ RegProcedure result;
- return optup->oprrest;
+ result = optup->oprrest;
+ ReleaseSysCache(tp);
+ return result;
}
else
return (RegProcedure) InvalidOid;
@@ -474,14 +507,17 @@ get_oprjoin(Oid opno)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ RegProcedure result;
- return optup->oprjoin;
+ result = optup->oprjoin;
+ ReleaseSysCache(tp);
+ return result;
}
else
return (RegProcedure) InvalidOid;
@@ -496,15 +532,18 @@ get_oprjoin(Oid opno)
Oid
get_func_rettype(Oid funcid)
{
- HeapTuple func_tuple;
+ HeapTuple tp;
+ Oid result;
- func_tuple = SearchSysCacheTuple(PROCOID,
- ObjectIdGetDatum(funcid),
- 0, 0, 0);
- if (!HeapTupleIsValid(func_tuple))
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
elog(ERROR, "Function OID %u does not exist", funcid);
- return ((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype;
+ result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
+ ReleaseSysCache(tp);
+ return result;
}
/*
@@ -514,15 +553,18 @@ get_func_rettype(Oid funcid)
bool
func_iscachable(Oid funcid)
{
- HeapTuple func_tuple;
+ HeapTuple tp;
+ bool result;
- func_tuple = SearchSysCacheTuple(PROCOID,
- ObjectIdGetDatum(funcid),
- 0, 0, 0);
- if (!HeapTupleIsValid(func_tuple))
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
elog(ERROR, "Function OID %u does not exist", funcid);
- return ((Form_pg_proc) GETSTRUCT(func_tuple))->proiscachable;
+ result = ((Form_pg_proc) GETSTRUCT(tp))->proiscachable;
+ ReleaseSysCache(tp);
+ return result;
}
/* ---------- RELATION CACHE ---------- */
@@ -538,14 +580,17 @@ get_relnatts(Oid relid)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
+ tp = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+ int result;
- return reltup->relnatts;
+ result = reltup->relnatts;
+ ReleaseSysCache(tp);
+ return result;
}
else
return InvalidAttrNumber;
@@ -556,20 +601,25 @@ get_relnatts(Oid relid)
* get_rel_name
*
* Returns the name of a given relation.
+ *
+ * Note: returns a palloc'd copy of the string, or NULL if no such operator.
*/
char *
get_rel_name(Oid relid)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
+ tp = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+ char *result;
- return pstrdup(NameStr(reltup->relname));
+ result = pstrdup(NameStr(reltup->relname));
+ ReleaseSysCache(tp);
+ return result;
}
else
return NULL;
@@ -587,14 +637,17 @@ get_typlen(Oid typid)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ int16 result;
- return typtup->typlen;
+ result = typtup->typlen;
+ ReleaseSysCache(tp);
+ return result;
}
else
return 0;
@@ -611,33 +664,66 @@ get_typbyval(Oid typid)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ bool result;
- return typtup->typbyval;
+ result = typtup->typbyval;
+ ReleaseSysCache(tp);
+ return result;
}
else
return false;
}
+/*
+ * get_typlenbyval
+ *
+ * A two-fer: given the type OID, return both typlen and typbyval.
+ *
+ * Since both pieces of info are needed to know how to copy a Datum,
+ * many places need both. Might as well get them with one cache lookup
+ * instead of two. Also, this routine raises an error instead of
+ * returning a bogus value when given a bad type OID.
+ */
+void
+get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
+{
+ HeapTuple tp;
+ Form_pg_type typtup;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for type %u", typid);
+ typtup = (Form_pg_type) GETSTRUCT(tp);
+ *typlen = typtup->typlen;
+ *typbyval = typtup->typbyval;
+ ReleaseSysCache(tp);
+}
+
#ifdef NOT_USED
char
get_typalign(Oid typid)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ char result;
- return typtup->typalign;
+ result = typtup->typalign;
+ ReleaseSysCache(tp);
+ return result;
}
else
return 'i';
@@ -666,9 +752,9 @@ get_typdefault(Oid typid)
bool typByVal;
Datum returnValue;
- typeTuple = SearchSysCacheTuple(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "get_typdefault: failed to lookup type %u", typid);
@@ -679,13 +765,17 @@ get_typdefault(Oid typid)
* 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);
+ typDefault = (struct varlena *)
+ DatumGetPointer(SysCacheGetAttr(TYPEOID,
+ typeTuple,
+ Anum_pg_type_typdefault,
+ &isNull));
if (isNull)
+ {
+ ReleaseSysCache(typeTuple);
return PointerGetDatum(NULL);
+ }
/*
* Otherwise, extract/copy the value.
@@ -748,6 +838,8 @@ get_typdefault(Oid typid)
}
}
+ ReleaseSysCache(typeTuple);
+
return returnValue;
}
@@ -764,14 +856,17 @@ get_typtype(Oid typid)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ char result;
- return typtup->typtype;
+ result = typtup->typtype;
+ ReleaseSysCache(tp);
+ return result;
}
else
return '\0';
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 7f35f192089..bb9a55b869a 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.56 2000/11/10 00:33:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.57 2000/11/16 22:30:33 tgl Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
@@ -343,7 +343,7 @@ static struct cachedesc cacheinfo[] = {
};
static CatCache *SysCache[lengthof(cacheinfo)];
-static int32 SysCacheSize = lengthof(cacheinfo);
+static int SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false;
@@ -355,98 +355,67 @@ IsCacheInitialized(void)
/*
- * zerocaches
+ * InitCatalogCache - initialize the caches
*
- * Make sure the SysCache structure is zero'd.
+ * Note that no database access is done here; we only allocate memory
+ * and initialize the cache structure. Interrogation of the database
+ * to complete initialization of a cache happens only upon first use
+ * of that cache.
*/
void
-zerocaches()
+InitCatalogCache(void)
{
- MemSet((char *) SysCache, 0, SysCacheSize * sizeof(CatCache *));
-}
+ int cacheId;
+ Assert(!CacheInitialized);
-/*
- * InitCatalogCache - initialize the caches
- */
-void
-InitCatalogCache()
-{
- int cacheId; /* XXX type */
+ MemSet((char *) SysCache, 0, sizeof(SysCache));
- if (!AMI_OVERRIDE)
+ for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
{
- for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
- {
- Assert(!PointerIsValid(SysCache[cacheId]));
-
- SysCache[cacheId] = InitSysCache(cacheId,
- cacheinfo[cacheId].name,
- cacheinfo[cacheId].indname,
- cacheinfo[cacheId].nkeys,
- cacheinfo[cacheId].key);
- if (!PointerIsValid(SysCache[cacheId]))
- {
- elog(ERROR,
- "InitCatalogCache: Can't init cache %s (%d)",
- cacheinfo[cacheId].name,
- cacheId);
- }
-
- }
+ SysCache[cacheId] = InitCatCache(cacheId,
+ cacheinfo[cacheId].name,
+ cacheinfo[cacheId].indname,
+ cacheinfo[cacheId].nkeys,
+ cacheinfo[cacheId].key);
+ if (!PointerIsValid(SysCache[cacheId]))
+ elog(ERROR, "InitCatalogCache: Can't init cache %s (%d)",
+ cacheinfo[cacheId].name, cacheId);
}
CacheInitialized = true;
}
/*
- * SearchSysCacheTuple
+ * SearchSysCache
*
- * A layer on top of SearchSysCache that does the initialization and
+ * A layer on top of SearchCatCache that does the initialization and
* key-setting for you.
*
* Returns the cache copy of the tuple if one is found, NULL if not.
- * The tuple is the 'cache' copy.
- *
- * CAUTION: The tuple that is returned must NOT be freed by the caller!
+ * The tuple is the 'cache' copy and must NOT be modified!
*
- * CAUTION: The returned tuple may be flushed from the cache during
- * subsequent cache lookup operations, or by shared cache invalidation.
- * Callers should not expect the pointer to remain valid for long.
+ * When the caller is done using the tuple, call ReleaseSysCache()
+ * to release the reference count grabbed by SearchSysCache(). If this
+ * is not done, the tuple will remain locked in cache until end of
+ * transaction, which is tolerable but not desirable.
*
- * XXX we ought to have some kind of referencecount mechanism for
- * cache entries, to ensure entries aren't deleted while in use.
+ * CAUTION: The tuple that is returned must NOT be freed by the caller!
*/
HeapTuple
-SearchSysCacheTuple(int cacheId,/* cache selection code */
- Datum key1,
- Datum key2,
- Datum key3,
- Datum key4)
+SearchSysCache(int cacheId,
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
{
- HeapTuple tp;
-
if (cacheId < 0 || cacheId >= SysCacheSize)
{
- elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
+ elog(ERROR, "SearchSysCache: Bad cache id %d", cacheId);
return (HeapTuple) NULL;
}
- Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
-
- if (!PointerIsValid(SysCache[cacheId]))
- {
- SysCache[cacheId] = InitSysCache(cacheId,
- cacheinfo[cacheId].name,
- cacheinfo[cacheId].indname,
- cacheinfo[cacheId].nkeys,
- cacheinfo[cacheId].key);
- if (!PointerIsValid(SysCache[cacheId]))
- elog(ERROR,
- "InitCatalogCache: Can't init cache %s(%d)",
- cacheinfo[cacheId].name,
- cacheId);
- }
+ Assert(PointerIsValid(SysCache[cacheId]));
/*
* If someone tries to look up a relname, translate temp relation
@@ -464,51 +433,75 @@ SearchSysCacheTuple(int cacheId,/* cache selection code */
key1 = CStringGetDatum(nontemp_relname);
}
- 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,
- cacheId, key1, key2, key3, key4);
-#endif
- return (HeapTuple) NULL;
- }
- return tp;
+ return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
}
+/*
+ * ReleaseSysCache
+ * Release previously grabbed reference count on a tuple
+ */
+void
+ReleaseSysCache(HeapTuple tuple)
+{
+ ReleaseCatCache(tuple);
+}
/*
- * SearchSysCacheTupleCopy
+ * SearchSysCacheCopy
*
- * This is like SearchSysCacheTuple, except it returns a palloc'd copy of
- * the tuple. The caller should heap_freetuple() the returned copy when
- * done with it. This routine should be used when the caller intends to
- * continue to access the tuple for more than a very short period of time.
+ * A convenience routine that does SearchSysCache and (if successful)
+ * returns a modifiable copy of the syscache entry. The original
+ * syscache entry is released before returning. The caller should
+ * heap_freetuple() the result when done with it.
*/
HeapTuple
-SearchSysCacheTupleCopy(int cacheId, /* cache selection code */
- Datum key1,
- Datum key2,
- Datum key3,
- Datum key4)
+SearchSysCacheCopy(int cacheId,
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
{
- HeapTuple cachetup;
-
- cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
- if (PointerIsValid(cachetup))
- return heap_copytuple(cachetup);
- else
- return cachetup; /* NULL */
+ HeapTuple tuple,
+ newtuple;
+
+ tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
+ if (!HeapTupleIsValid(tuple))
+ return tuple;
+ newtuple = heap_copytuple(tuple);
+ ReleaseSysCache(tuple);
+ return newtuple;
}
+/*
+ * GetSysCacheOid
+ *
+ * A convenience routine that does SearchSysCache and returns the OID
+ * of the found tuple, or InvalidOid if no tuple could be found.
+ * No lock is retained on the syscache entry.
+ */
+Oid
+GetSysCacheOid(int cacheId,
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
+{
+ HeapTuple tuple;
+ Oid result;
+
+ tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
+ if (!HeapTupleIsValid(tuple))
+ return InvalidOid;
+ result = tuple->t_data->t_oid;
+ ReleaseSysCache(tuple);
+ return result;
+}
/*
* SysCacheGetAttr
*
- * Given a tuple previously fetched by SearchSysCacheTuple() or
- * SearchSysCacheTupleCopy(), extract a specific attribute.
+ * Given a tuple previously fetched by SearchSysCache(),
+ * extract a specific attribute.
*
* This is equivalent to using heap_getattr() on a tuple fetched
* from a non-cached relation. Usually, this is only used for attributes
diff --git a/src/backend/utils/cache/temprel.c b/src/backend/utils/cache/temprel.c
index 31591663cee..0134b47a0f9 100644
--- a/src/backend/utils/cache/temprel.c
+++ b/src/backend/utils/cache/temprel.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.30 2000/11/08 22:10:01 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.31 2000/11/16 22:30:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,7 +34,6 @@
#include "catalog/heap.h"
#include "catalog/index.h"
#include "miscadmin.h"
-#include "utils/catcache.h"
#include "utils/temprel.h"