aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache
diff options
context:
space:
mode:
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"