diff --git a/contrib/array/array_iterator.c b/contrib/array/array_iterator.c
index c480f7dfc70982ddb95c4db4125cd1043bc38a8b..653979ada866b0a5cf3eb506225e4f8ffcd3ad3e 100644
--- a/contrib/array/array_iterator.c
+++ b/contrib/array/array_iterator.c
@@ -14,30 +14,29 @@
  * either version 2, or (at your option) any later version.
  */
 
+#include "postgres.h"
+
 #include <ctype.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <string.h>
 
-#include "postgres.h"
-#include "miscadmin.h"
 #include "access/xact.h"
 #include "fmgr.h"
-#include "catalog/pg_type.h"
+#include "miscadmin.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/memutils.h"
-#include "utils/syscache.h"
+#include "utils/lsyscache.h"
 
 #include "array_iterator.h"
 
+
 static int32
 array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
 {
-	HeapTuple	typ_tuple;
-	Form_pg_type typ_struct;
+	int16		typlen;
 	bool		typbyval;
-	int			typlen;
 	int			nitems,
 				i;
 	Datum		result;
@@ -66,16 +65,7 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
 	}
 
 	/* Lookup element type information */
-	typ_tuple = SearchSysCacheTuple(TYPEOID, ObjectIdGetDatum(elemtype),
-									0, 0, 0);
-	if (!HeapTupleIsValid(typ_tuple))
-	{
-		elog(ERROR, "array_iterator: cache lookup failed for type %u", elemtype);
-		return 0;
-	}
-	typ_struct = (Form_pg_type) GETSTRUCT(typ_tuple);
-	typlen = typ_struct->typlen;
-	typbyval = typ_struct->typbyval;
+	get_typlenbyval(elemtype, &typlen, &typbyval);
 
 	/* Lookup the function entry point */
 	fmgr_info(proc, &finfo);
diff --git a/doc/FAQ_DEV b/doc/FAQ_DEV
index e8f046d0fa529a238cd6863f7bb213606ed6f2e8..bb14d5f49ac5cd2d59e28129cd5a78e5f5c6ad87 100644
--- a/doc/FAQ_DEV
+++ b/doc/FAQ_DEV
@@ -311,7 +311,7 @@ c-mode)
   9) How do I efficiently access information in tables from the backend code?
   
    You first need to find the tuples(rows) you are interested in. There
-   are two ways. First, SearchSysCacheTuple() and related functions allow
+   are two ways. First, SearchSysCache() and related functions allow
    you to query the system catalogs. This is the preferred way to access
    system tables, because the first call to the cache loads the needed
    rows, and future requests can return the results without accessing the
@@ -321,14 +321,13 @@ c-mode)
    src/backend/utils/cache/lsyscache.c contains many column-specific
    cache lookup functions.
    
-   The rows returned are cached-owned versions of the heap rows. They are
-   invalidated when the base table changes. Because the cache is local to
-   each backend, you may use the pointer returned from the cache for
-   short periods without making a copy of the tuple. If you send the
-   pointer into a large function that will be doing its own cache
-   lookups, it is possible the cache entry may be flushed, so you should
-   use SearchSysCacheTupleCopy() in these cases, and pfree() the tuple
-   when you are done.
+   The rows returned are cache-owned versions of the heap rows.  Therefore,
+   you must not modify or delete the tuple returned by SearchSysCache().
+   What you *should* do is release it with ReleaseSysCache() when you are
+   done using it; this informs the cache that it can discard that tuple
+   if necessary.  If you neglect to call ReleaseSysCache(), then the cache
+   entry will remain locked in the cache until end of transaction, which is
+   tolerable but not very desirable.
    
    If you can't use the system cache, you will need to retrieve the data
    directly from the heap table, using the buffer cache that is shared by
@@ -344,7 +343,9 @@ c-mode)
    You can also use heap_fetch() to fetch rows by block number/offset.
    While scans automatically lock/unlock rows from the buffer cache, with
    heap_fetch(), you must pass a Buffer pointer, and ReleaseBuffer() it
-   when completed. Once you have the row, you can get data that is common
+   when completed.
+
+   Once you have the row, you can get data that is common
    to all tuples, like t_self and t_oid, by merely accessing the
    HeapTuple structure entries. If you need a table-specific column, you
    should take the HeapTuple pointer, and use the GETSTRUCT() macro to
@@ -355,15 +356,16 @@ c-mode)
 
         ((Form_pg_class) GETSTRUCT(tuple))->relnatts
 
-   You should not directly change live tuples in this way. The best way
-   is to use heap_tuplemodify() and pass it your palloc'ed tuple, and the
-   values you want changed. It returns another palloc'ed tuple, which you
+   You must not directly change live tuples in this way. The best way
+   is to use heap_modifytuple() and pass it your original tuple, and the
+   values you want changed. It returns a palloc'ed tuple, which you
    pass to heap_replace(). You can delete tuples by passing the tuple's
-   t_self to heap_destroy(). You can use it for heap_update() too.
-   Remember, tuples can be either system cache versions, which may go
-   away soon after you get them, buffer cache versions, which go away
-   when you heap_getnext(), heap_endscan, or ReleaseBuffer(), in the
-   heap_fetch() case. Or it may be a palloc'ed tuple, that you must
+   t_self to heap_destroy(). You use t_self for heap_update() too.
+
+   Remember, tuples can be either system cache copies, which may go away
+   after you call ReleaseSysCache(), or read directly from disk buffers,
+   which go away when you heap_getnext(), heap_endscan, or ReleaseBuffer(),
+   in the heap_fetch() case. Or it may be a palloc'ed tuple, that you must
    pfree() when finished.
    
   10) What is elog()?
diff --git a/doc/src/FAQ/FAQ_DEV.html b/doc/src/FAQ/FAQ_DEV.html
index e62d0c3533acdb21b0b6b93688a6946236b5626b..3c1433d345b33deb41e4c5a5a00001313667dca3 100644
--- a/doc/src/FAQ/FAQ_DEV.html
+++ b/doc/src/FAQ/FAQ_DEV.html
@@ -358,7 +358,7 @@ cases where Name and char * are used interchangeably.<P>
 tables from the backend code?</H3><P>
 
 You first need to find the tuples(rows) you are interested in.  There
-are two ways.  First, <I>SearchSysCacheTuple()</I> and related functions
+are two ways.  First, <I>SearchSysCache()</I> and related functions
 allow you to query the system catalogs.  This is the preferred way to
 access system tables, because the first call to the cache loads the
 needed rows, and future requests can return the results without
@@ -367,15 +367,14 @@ to look up tuples.  A list of available caches is located in
 <I>src/backend/utils/cache/syscache.c.</I> 
 <I>src/backend/utils/cache/lsyscache.c</I> contains many column-specific
 cache lookup functions.<P>
-
-The rows returned are cached-owned versions of the heap rows.  They are
-invalidated when the base table changes.   Because the cache is local to
-each backend, you may use the pointer returned from the cache for short
-periods without making a copy of the tuple.  If you send the pointer
-into a large function that will be doing its own cache lookups, it is
-possible the cache entry may be flushed, so you should use
-<I>SearchSysCacheTupleCopy()</I> in these cases, and <I>pfree()</I> the
-tuple when you are done.<P>
+   
+The rows returned are cache-owned versions of the heap rows.  Therefore, you
+must not modify or delete the tuple returned by <I>SearchSysCache()</I>.  What
+you <I>should</I> do is release it with <I>ReleaseSysCache()</I> when you are
+done using it; this informs the cache that it can discard that tuple if
+necessary.  If you neglect to call <I>ReleaseSysCache()</I>, then the cache
+entry will remain locked in the cache until end of transaction, which is
+tolerable but not very desirable.<P>
 
 If you can't use the system cache, you will need to retrieve the data
 directly from the heap table, using the buffer cache that is shared by
@@ -392,12 +391,11 @@ and only the valid rows returned.<P>
 You can also use <I>heap_fetch()</I> to fetch rows by block
 number/offset.  While scans automatically lock/unlock rows from the
 buffer cache, with <I>heap_fetch(),</I> you must pass a <I>Buffer</I>
-pointer, and <I>ReleaseBuffer()</I> it when completed.
+pointer, and <I>ReleaseBuffer()</I> it when completed.<P>
 
 Once you have the row, you can get data that is common to all tuples,
 like <I>t_self</I> and <I>t_oid,</I> by merely accessing the
 <I>HeapTuple</I> structure entries.
-
 If you need a table-specific column, you should take the HeapTuple
 pointer, and use the <I>GETSTRUCT()</I> macro to access the
 table-specific start of the tuple.  You then cast the pointer as a
@@ -411,18 +409,18 @@ the columns by using a structure pointer:
 </CODE>
 </PRE>
 
-You should not directly change <I>live</I> tuples in this way.  The best
-way is to use <I>heap_tuplemodify()</I> and pass it your palloc'ed
-tuple, and the values you want changed.  It returns another palloc'ed
+You must not directly change <I>live</I> tuples in this way.  The best
+way is to use <I>heap_modifytuple()</I> and pass it your original
+tuple, and the values you want changed.  It returns a palloc'ed
 tuple, which you pass to <I>heap_replace().</I>
 
 You can delete tuples by passing the tuple's <I>t_self</I> to
-<I>heap_destroy().</I>  You can use it for <I>heap_update()</I> too.
+<I>heap_destroy().</I>  You use <I>t_self</I> for <I>heap_update()</I> too.
 
-Remember, tuples can be either system cache versions, which may go away
-soon after you get them, buffer cache versions, which go away when
-you <I>heap_getnext(),</I> <I>heap_endscan,</I> or
-<I>ReleaseBuffer()</I>, in the <I>heap_fetch()</I> case.  Or it may be a
+Remember, tuples can be either system cache copies, which may go away after
+you call <I>ReleaseSysCache()</I>, or read directly from disk buffers, which
+go away when you <I>heap_getnext()</I>, <I>heap_endscan</I>, or
+<I>ReleaseBuffer()</I>, in the <I>heap_fetch()</I> case. Or it may be a
 palloc'ed tuple, that you must <I>pfree()</I> when finished.
 
 <H3><a name="10">10</a>)	What is elog()?</H3><P>
diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c
index 6fe0e9652c21272a1eb10615a30915dda9b8e4cb..ccf3071b502d2cd8ba2866ead9d027fa23a47d1a 100644
--- a/src/backend/access/common/printtup.c
+++ b/src/backend/access/common/printtup.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.53 2000/05/30 04:24:27 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.54 2000/11/16 22:30:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,7 +36,7 @@ static void printtup_cleanup(DestReceiver *self);
  *		getTypeOutAndElem -- get both typoutput and typelem for a type
  *
  * We used to fetch these with two separate function calls,
- * typtoout() and gettypelem(), which each called SearchSysCacheTuple.
+ * typtoout() and gettypelem(), which each called SearchSysCache.
  * This way takes half the time.
  * ----------------
  */
@@ -44,25 +44,19 @@ int
 getTypeOutAndElem(Oid type, Oid *typOutput, Oid *typElem)
 {
 	HeapTuple	typeTuple;
-
-	typeTuple = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(type),
-									0, 0, 0);
-
-	if (HeapTupleIsValid(typeTuple))
-	{
-		Form_pg_type pt = (Form_pg_type) GETSTRUCT(typeTuple);
-
-		*typOutput = (Oid) pt->typoutput;
-		*typElem = (Oid) pt->typelem;
-		return OidIsValid(*typOutput);
-	}
-
-	elog(ERROR, "getTypeOutAndElem: Cache lookup of type %u failed", type);
-
-	*typOutput = InvalidOid;
-	*typElem = InvalidOid;
-	return 0;
+	Form_pg_type pt;
+
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(type),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(typeTuple))
+		elog(ERROR, "getTypeOutAndElem: Cache lookup of type %u failed", type);
+	pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+	*typOutput = pt->typoutput;
+	*typElem = pt->typelem;
+	ReleaseSysCache(typeTuple);
+	return OidIsValid(*typOutput);
 }
 
 /* ----------------
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index 1ed2366efdae695f4453ef29fff0fba809a82229..8b9b7cd537fbaae833039e3107d4b7bcaf7b0741 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.68 2000/11/08 22:09:53 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.69 2000/11/16 22:30:15 tgl Exp $
  *
  * NOTES
  *	  some of the executor utility code such as "ExecTypeFromTL" should be
@@ -401,9 +401,9 @@ TupleDescInitEntry(TupleDesc desc,
 	 *	-cim 6/14/90
 	 * ----------------
 	 */
-	tuple = SearchSysCacheTuple(TYPEOID,
-								ObjectIdGetDatum(oidtypeid),
-								0, 0, 0);
+	tuple = SearchSysCache(TYPEOID,
+						   ObjectIdGetDatum(oidtypeid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 	{
 		/* ----------------
@@ -455,25 +455,18 @@ TupleDescInitEntry(TupleDesc desc,
 	   */
 	if (attisset)
 	{
-		Type		t = typeidType(OIDOID);
-
-		att->attlen = typeLen(t);
-		att->attbyval = typeByVal(t);
+		att->attlen = sizeof(Oid);
+		att->attbyval = true;
+		att->attstorage = 'p';
 	}
 	else
 	{
 		att->attlen = typeForm->typlen;
 		att->attbyval = typeForm->typbyval;
-/*
- * Default to the types storage
- */
-#ifdef TUPLE_TOASTER_ACTIVE
 		att->attstorage = typeForm->typstorage;
-#else
-		att->attstorage = 'p';
-#endif
 	}
 
+	ReleaseSysCache(tuple);
 
 	return true;
 }
@@ -496,12 +489,11 @@ TupleDescMakeSelfReference(TupleDesc desc,
 						   char *relname)
 {
 	Form_pg_attribute att;
-	Type		t = typeidType(OIDOID);
 
 	att = desc->attrs[attnum - 1];
 	att->atttypid = TypeShellMake(relname);
-	att->attlen = typeLen(t);
-	att->attbyval = typeByVal(t);
+	att->attlen = sizeof(Oid);
+	att->attbyval = true;
 	att->attstorage = 'p';
 	att->attnelems = 0;
 }
@@ -580,7 +572,7 @@ BuildDescForRelation(List *schema, char *relname)
 		}
 
 		if (!TupleDescInitEntry(desc, attnum, attname,
-								typeTypeId(typenameType(typename)),
+								typenameTypeId(typename),
 								atttypmod, attdim, attisset))
 		{
 			/* ----------------
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index d7bfeb1287d491c757a9dfd92243603c57595855..d8e9005e93375486f9244e40e2b72301bcc203f2 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.64 2000/11/08 22:09:53 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.65 2000/11/16 22:30:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1140,6 +1140,7 @@ initGISTstate(GISTSTATE *giststate, Relation index)
 				equal_proc;
 	HeapTuple	htup;
 	Form_pg_index itupform;
+	Oid			indexrelid;
 
 	consistent_proc = index_getprocid(index, 1, GIST_CONSISTENT_PROC);
 	union_proc = index_getprocid(index, 1, GIST_UNION_PROC);
@@ -1157,32 +1158,32 @@ initGISTstate(GISTSTATE *giststate, Relation index)
 	fmgr_info(equal_proc, &giststate->equalFn);
 
 	/* see if key type is different from type of attribute being indexed */
-	htup = SearchSysCacheTuple(INDEXRELID,
-							   ObjectIdGetDatum(RelationGetRelid(index)),
-							   0, 0, 0);
-	itupform = (Form_pg_index) GETSTRUCT(htup);
+	htup = SearchSysCache(INDEXRELID,
+						  ObjectIdGetDatum(RelationGetRelid(index)),
+						  0, 0, 0);
 	if (!HeapTupleIsValid(htup))
 		elog(ERROR, "initGISTstate: index %u not found",
 			 RelationGetRelid(index));
+	itupform = (Form_pg_index) GETSTRUCT(htup);
 	giststate->haskeytype = itupform->indhaskeytype;
+	indexrelid = itupform->indexrelid;
+	ReleaseSysCache(htup);
+
 	if (giststate->haskeytype)
 	{
 		/* key type is different -- is it byval? */
-		htup = SearchSysCacheTuple(ATTNUM,
-								   ObjectIdGetDatum(itupform->indexrelid),
-								   UInt16GetDatum(FirstOffsetNumber),
-								   0, 0);
+		htup = SearchSysCache(ATTNUM,
+							  ObjectIdGetDatum(indexrelid),
+							  UInt16GetDatum(FirstOffsetNumber),
+							  0, 0);
 		if (!HeapTupleIsValid(htup))
-		{
 			elog(ERROR, "initGISTstate: no attribute tuple %u %d",
-				 itupform->indexrelid, FirstOffsetNumber);
-			return;
-		}
+				 indexrelid, FirstOffsetNumber);
 		giststate->keytypbyval = (((Form_pg_attribute) htup)->attbyval);
+		ReleaseSysCache(htup);
 	}
 	else
 		giststate->keytypbyval = FALSE;
-	return;
 }
 
 
diff --git a/src/backend/access/index/istrat.c b/src/backend/access/index/istrat.c
index d6a966bcd44a700c19f0ac8c6c45ef56787d7fb8..681b80e1e86d537aa6691ed557743d4395232cf9 100644
--- a/src/backend/access/index/istrat.c
+++ b/src/backend/access/index/istrat.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.46 2000/07/14 22:17:30 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.47 2000/11/16 22:30:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -482,9 +482,9 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation,
 
 	if (cachesearch)
 	{
-		tuple = SearchSysCacheTuple(OPEROID,
-									ObjectIdGetDatum(operatorObjectId),
-									0, 0, 0);
+		tuple = SearchSysCache(OPEROID,
+							   ObjectIdGetDatum(operatorObjectId),
+							   0, 0, 0);
 	}
 	else
 	{
@@ -505,24 +505,25 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation,
 	{
 		if (!cachesearch)
 			heap_endscan(scan);
-		elog(ERROR, "OperatorObjectIdFillScanKeyEntry: unknown operator %u",
+		elog(ERROR, "OperatorRelationFillScanKeyEntry: unknown operator %u",
 			 operatorObjectId);
 	}
 
 	entry->sk_flags = 0;
 	entry->sk_procedure = ((Form_pg_operator) GETSTRUCT(tuple))->oprcode;
-	fmgr_info(entry->sk_procedure, &entry->sk_func);
-	entry->sk_nargs = entry->sk_func.fn_nargs;
 
-	if (!cachesearch)
+	if (cachesearch)
+		ReleaseSysCache(tuple);
+	else
 		heap_endscan(scan);
 
 	if (!RegProcedureIsValid(entry->sk_procedure))
-	{
 		elog(ERROR,
-		"OperatorObjectIdFillScanKeyEntry: no procedure for operator %u",
+			 "OperatorRelationFillScanKeyEntry: no procedure for operator %u",
 			 operatorObjectId);
-	}
+
+	fmgr_info(entry->sk_procedure, &entry->sk_func);
+	entry->sk_nargs = entry->sk_func.fn_nargs;
 }
 
 
@@ -547,16 +548,16 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 	HeapTuple	tuple;
 	Form_pg_index iform;
 	StrategyMap map;
-	AttrNumber	attributeNumber;
-	int			attributeIndex;
+	AttrNumber	attNumber;
+	int			attIndex;
 	Oid			operatorClassObjectId[INDEX_MAX_KEYS];
 	bool		cachesearch = (!IsBootstrapProcessingMode()) && IsCacheInitialized();
 
 	if (cachesearch)
 	{
-		tuple = SearchSysCacheTuple(INDEXRELID,
-									ObjectIdGetDatum(indexObjectId),
-									0, 0, 0);
+		tuple = SearchSysCache(INDEXRELID,
+							   ObjectIdGetDatum(indexObjectId),
+							   0, 0, 0);
 	}
 	else
 	{
@@ -583,19 +584,23 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 	 * XXX note that the following assumes the INDEX tuple is well formed
 	 * and that the *key and *class are 0 terminated.
 	 */
-	for (attributeIndex = 0; attributeIndex < maxAttributeNumber; attributeIndex++)
+	for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
 	{
-		if (!OidIsValid(iform->indkey[attributeIndex]))
+		if (!OidIsValid(iform->indkey[attIndex]))
 		{
-			if (attributeIndex == InvalidAttrNumber)
+			if (attIndex == InvalidAttrNumber)
 				elog(ERROR, "IndexSupportInitialize: no pg_index tuple");
 			break;
 		}
 
-		operatorClassObjectId[attributeIndex] = iform->indclass[attributeIndex];
+		operatorClassObjectId[attIndex] = iform->indclass[attIndex];
 	}
 
-	if (!cachesearch)
+	if (cachesearch)
+	{
+		ReleaseSysCache(tuple);
+	}
+	else
 	{
 		heap_endscan(scan);
 		heap_close(relation, AccessShareLock);
@@ -614,20 +619,19 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 		relation = heap_openr(AccessMethodProcedureRelationName,
 							  AccessShareLock);
 
-		for (attributeNumber = 1; attributeNumber <= maxAttributeNumber;
-			 attributeNumber++)
+		for (attNumber = 1; attNumber <= maxAttributeNumber; attNumber++)
 		{
 			int16		support;
 			Form_pg_amproc aform;
 			RegProcedure *loc;
 
-			loc = &indexSupport[((attributeNumber - 1) * maxSupportNumber)];
+			loc = &indexSupport[((attNumber - 1) * maxSupportNumber)];
 
 			for (support = 0; support < maxSupportNumber; ++support)
 				loc[support] = InvalidOid;
 
 			entry[1].sk_argument =
-				ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);
+				ObjectIdGetDatum(operatorClassObjectId[attNumber - 1]);
 
 			scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
 
@@ -654,17 +658,16 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
 	relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
 	operatorRelation = heap_openr(OperatorRelationName, AccessShareLock);
 
-	for (attributeNumber = maxAttributeNumber; attributeNumber > 0;
-		 attributeNumber--)
+	for (attNumber = maxAttributeNumber; attNumber > 0; attNumber--)
 	{
 		StrategyNumber strategy;
 
 		entry[1].sk_argument =
-			ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);
+			ObjectIdGetDatum(operatorClassObjectId[attNumber - 1]);
 
 		map = IndexStrategyGetStrategyMap(indexStrategy,
 										  maxStrategyNumber,
-										  attributeNumber);
+										  attNumber);
 
 		for (strategy = 1; strategy <= maxStrategyNumber; strategy++)
 			ScanKeyEntrySetIllegal(StrategyMapGetScanKeyEntry(map, strategy));
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 6d950e969425b96d8e491c34fcef841abe2f60fe..600e9ddcaec0d67a6e203c84b7f04c2241bde993 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.82 2000/11/10 00:33:08 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.83 2000/11/16 22:30:16 tgl Exp $
  *
  * NOTES
  *		Transaction aborts can now occur two ways:
@@ -1112,6 +1112,7 @@ CommitTransaction(void)
 	AtEOXact_nbtree();
 	AtCommit_Cache();
 	AtCommit_Locks();
+	AtEOXact_CatCache(true);
 	AtCommit_Memory();
 	AtEOXact_Files();
 
@@ -1192,6 +1193,7 @@ AbortTransaction(void)
 	AtEOXact_SPI();
 	AtEOXact_nbtree();
 	AtAbort_Cache();
+	AtEOXact_CatCache(false);
 	AtAbort_Memory();
 	AtEOXact_Files();
 
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index b7013d28824d0df09ec958ba3dcc237a0e9e8dde..b2698ad19b645f43d2d32dbfdbefb0e60f081d2b 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.42 2000/11/03 19:02:18 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.43 2000/11/16 22:30:17 tgl Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -77,6 +77,7 @@ ChangeAcl(char *relname,
 			   *new_acl;
 	Relation	relation;
 	HeapTuple	tuple;
+	HeapTuple	newtuple;
 	Datum		aclDatum;
 	Datum		values[Natts_pg_class];
 	char		nulls[Natts_pg_class];
@@ -89,9 +90,9 @@ ChangeAcl(char *relname,
 	 * there's no ACL, create a default using the pg_class.relowner field.
 	 */
 	relation = heap_openr(RelationRelationName, RowExclusiveLock);
-	tuple = SearchSysCacheTuple(RELNAME,
-								PointerGetDatum(relname),
-								0, 0, 0);
+	tuple = SearchSysCache(RELNAME,
+						   PointerGetDatum(relname),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 	{
 		heap_close(relation, RowExclusiveLock);
@@ -134,14 +135,16 @@ ChangeAcl(char *relname,
 	}
 	replaces[Anum_pg_class_relacl - 1] = 'r';
 	values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
-	tuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
+	newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
 
-	heap_update(relation, &tuple->t_self, tuple, NULL);
+	ReleaseSysCache(tuple);
+
+	heap_update(relation, &newtuple->t_self, newtuple, NULL);
 
 	/* keep the catalog indices up to date */
 	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
 					   idescs);
-	CatalogIndexInsert(idescs, Num_pg_class_indices, relation, tuple);
+	CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newtuple);
 	CatalogCloseIndices(Num_pg_class_indices, idescs);
 
 	heap_close(relation, RowExclusiveLock);
@@ -156,11 +159,14 @@ get_grosysid(char *groname)
 	HeapTuple	tuple;
 	AclId		id = 0;
 
-	tuple = SearchSysCacheTuple(GRONAME,
-								PointerGetDatum(groname),
-								0, 0, 0);
+	tuple = SearchSysCache(GRONAME,
+						   PointerGetDatum(groname),
+						   0, 0, 0);
 	if (HeapTupleIsValid(tuple))
+	{
 		id = ((Form_pg_group) GETSTRUCT(tuple))->grosysid;
+		ReleaseSysCache(tuple);
+	}
 	else
 		elog(ERROR, "non-existent group \"%s\"", groname);
 	return id;
@@ -172,11 +178,14 @@ get_groname(AclId grosysid)
 	HeapTuple	tuple;
 	char	   *name = NULL;
 
-	tuple = SearchSysCacheTuple(GROSYSID,
-								ObjectIdGetDatum(grosysid),
-								0, 0, 0);
+	tuple = SearchSysCache(GROSYSID,
+						   ObjectIdGetDatum(grosysid),
+						   0, 0, 0);
 	if (HeapTupleIsValid(tuple))
-		name = NameStr(((Form_pg_group) GETSTRUCT(tuple))->groname);
+	{
+		name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tuple))->groname));
+		ReleaseSysCache(tuple);
+	}
 	else
 		elog(NOTICE, "get_groname: group %u not found", grosysid);
 	return name;
@@ -185,6 +194,7 @@ get_groname(AclId grosysid)
 static bool
 in_group(AclId uid, AclId gid)
 {
+	bool		result = false;
 	HeapTuple	tuple;
 	Datum		att;
 	bool		isNull;
@@ -193,9 +203,9 @@ in_group(AclId uid, AclId gid)
 	int			i,
 				num;
 
-	tuple = SearchSysCacheTuple(GROSYSID,
-								ObjectIdGetDatum(gid),
-								0, 0, 0);
+	tuple = SearchSysCache(GROSYSID,
+						   ObjectIdGetDatum(gid),
+						   0, 0, 0);
 	if (HeapTupleIsValid(tuple))
 	{
 		att = SysCacheGetAttr(GROSYSID,
@@ -212,13 +222,17 @@ in_group(AclId uid, AclId gid)
 			for (i = 0; i < num; ++i)
 			{
 				if (aidp[i] == uid)
-					return true;
+				{
+					result = true;
+					break;
+				}
 			}
 		}
+		ReleaseSysCache(tuple);
 	}
 	else
 		elog(NOTICE, "in_group: group %u not found", gid);
-	return false;
+	return result;
 }
 
 /*
@@ -342,9 +356,9 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode)
 	bool		isNull;
 	Acl		   *acl;
 
-	tuple = SearchSysCacheTuple(SHADOWSYSID,
-								ObjectIdGetDatum(userid),
-								0, 0, 0);
+	tuple = SearchSysCache(SHADOWSYSID,
+						   ObjectIdGetDatum(userid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "pg_aclcheck: invalid user id %u",
 			 (unsigned) userid);
@@ -363,6 +377,7 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode)
 	{
 		elog(DEBUG, "pg_aclcheck: catalog update to \"%s\": permission denied",
 			 relname);
+		ReleaseSysCache(tuple);
 		return ACLCHECK_NO_PRIV;
 	}
 
@@ -375,15 +390,19 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode)
 		elog(DEBUG, "pg_aclcheck: \"%s\" is superuser",
 			 usename);
 #endif
+		ReleaseSysCache(tuple);
 		return ACLCHECK_OK;
 	}
 
+	ReleaseSysCache(tuple);
+	/* caution: usename is inaccessible beyond this point... */
+
 	/*
 	 * Normal case: get the relation's ACL from pg_class
 	 */
-	tuple = SearchSysCacheTuple(RELNAME,
-								PointerGetDatum(relname),
-								0, 0, 0);
+	tuple = SearchSysCache(RELNAME,
+						   PointerGetDatum(relname),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "pg_aclcheck: class \"%s\" not found", relname);
 
@@ -404,8 +423,11 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode)
 	}
 
 	result = aclcheck(relname, acl, userid, (AclIdType) ACL_IDTYPE_UID, mode);
+
 	if (acl)
 		pfree(acl);
+	ReleaseSysCache(tuple);
+
 	return result;
 }
 
@@ -415,12 +437,12 @@ pg_ownercheck(Oid userid,
 			  int cacheid)
 {
 	HeapTuple	tuple;
-	AclId		owner_id = 0;
+	AclId		owner_id;
 	char       *usename;
 
-	tuple = SearchSysCacheTuple(SHADOWSYSID,
-								ObjectIdGetDatum(userid),
-								0, 0, 0);
+	tuple = SearchSysCache(SHADOWSYSID,
+						   ObjectIdGetDatum(userid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "pg_ownercheck: invalid user id %u",
 			 (unsigned) userid);
@@ -435,11 +457,16 @@ pg_ownercheck(Oid userid,
 		elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
 			 usename);
 #endif
+		ReleaseSysCache(tuple);
 		return 1;
 	}
 
-	tuple = SearchSysCacheTuple(cacheid, PointerGetDatum(value),
-								0, 0, 0);
+	ReleaseSysCache(tuple);
+	/* caution: usename is inaccessible beyond this point... */
+
+	tuple = SearchSysCache(cacheid,
+						   PointerGetDatum(value),
+						   0, 0, 0);
 	switch (cacheid)
 	{
 		case OPEROID:
@@ -468,9 +495,12 @@ pg_ownercheck(Oid userid,
 			break;
 		default:
 			elog(ERROR, "pg_ownercheck: invalid cache id: %d", cacheid);
+			owner_id = 0;		/* keep compiler quiet */
 			break;
 	}
 
+	ReleaseSysCache(tuple);
+
 	return userid == owner_id;
 }
 
@@ -482,15 +512,15 @@ pg_func_ownercheck(Oid userid,
 {
 	HeapTuple	tuple;
 	AclId		owner_id;
-	char *username;
+	char	   *usename;
 
-	tuple = SearchSysCacheTuple(SHADOWSYSID,
-								ObjectIdGetDatum(userid),
-								0, 0, 0);
+	tuple = SearchSysCache(SHADOWSYSID,
+						   ObjectIdGetDatum(userid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "pg_func_ownercheck: invalid user id %u",
 			 (unsigned) userid);
-	username = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
+	usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
 
 	/*
 	 * Superusers bypass all permission-checking.
@@ -499,21 +529,27 @@ pg_func_ownercheck(Oid userid,
 	{
 #ifdef ACLDEBUG_TRACE
 		elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
-			 username);
+			 usename);
 #endif
+		ReleaseSysCache(tuple);
 		return 1;
 	}
 
-	tuple = SearchSysCacheTuple(PROCNAME,
-								PointerGetDatum(funcname),
-								Int32GetDatum(nargs),
-								PointerGetDatum(arglist),
-								0);
+	ReleaseSysCache(tuple);
+	/* caution: usename is inaccessible beyond this point... */
+
+	tuple = SearchSysCache(PROCNAME,
+						   PointerGetDatum(funcname),
+						   Int32GetDatum(nargs),
+						   PointerGetDatum(arglist),
+						   0);
 	if (!HeapTupleIsValid(tuple))
 		func_error("pg_func_ownercheck", funcname, nargs, arglist, NULL);
 
 	owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
 
+	ReleaseSysCache(tuple);
+
 	return userid == owner_id;
 }
 
@@ -524,15 +560,15 @@ pg_aggr_ownercheck(Oid userid,
 {
 	HeapTuple	tuple;
 	AclId		owner_id;
-	char *username;
+	char	   *usename;
 
-	tuple = SearchSysCacheTuple(SHADOWSYSID,
-								PointerGetDatum(userid),
-								0, 0, 0);
+	tuple = SearchSysCache(SHADOWSYSID,
+						   PointerGetDatum(userid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "pg_aggr_ownercheck: invalid user id %u",
 			 (unsigned) userid);
-	username = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
+	usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
 
 	/*
 	 * Superusers bypass all permission-checking.
@@ -541,20 +577,25 @@ pg_aggr_ownercheck(Oid userid,
 	{
 #ifdef ACLDEBUG_TRACE
 		elog(DEBUG, "pg_aggr_ownercheck: user \"%s\" is superuser",
-			 username);
+			 usename);
 #endif
+		ReleaseSysCache(tuple);
 		return 1;
 	}
 
-	tuple = SearchSysCacheTuple(AGGNAME,
-								PointerGetDatum(aggname),
-								ObjectIdGetDatum(basetypeID),
-								0, 0);
+	ReleaseSysCache(tuple);
+	/* caution: usename is inaccessible beyond this point... */
 
+	tuple = SearchSysCache(AGGNAME,
+						   PointerGetDatum(aggname),
+						   ObjectIdGetDatum(basetypeID),
+						   0, 0);
 	if (!HeapTupleIsValid(tuple))
 		agg_error("pg_aggr_ownercheck", aggname, basetypeID);
 
 	owner_id = ((Form_pg_aggregate) GETSTRUCT(tuple))->aggowner;
 
+	ReleaseSysCache(tuple);
+
 	return userid == owner_id;
 }
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index c7b191dd2da2203f4bd1c205cb8fbee8365f73cc..aed3864e90023c640cd1f83d52c86f00280de0b8 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.36 2000/10/22 05:14:01 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.37 2000/11/16 22:30:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,7 +20,7 @@
 #include "catalog/catname.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
-#include "utils/syscache.h"
+#include "utils/lsyscache.h"
 
 #ifdef OLD_FILE_NAMING
 /*
@@ -251,12 +251,10 @@ newoid()
 void
 fillatt(TupleDesc tupleDesc)
 {
-	Form_pg_attribute *attributeP;
-	Form_pg_type typp;
-	HeapTuple	tuple;
-	int			i;
 	int			natts = tupleDesc->natts;
 	Form_pg_attribute *att = tupleDesc->attrs;
+	Form_pg_attribute *attributeP;
+	int			i;
 
 	if (natts < 0 || natts > MaxHeapAttributeNumber)
 		elog(ERROR, "fillatt: %d attributes is too large", natts);
@@ -268,33 +266,23 @@ fillatt(TupleDesc tupleDesc)
 
 	attributeP = &att[0];
 
-	for (i = 0; i < natts;)
+	for (i = 1; i <= natts; i++)
 	{
-		tuple = SearchSysCacheTuple(TYPEOID,
-							   ObjectIdGetDatum((*attributeP)->atttypid),
-									0, 0, 0);
-		if (!HeapTupleIsValid(tuple))
+		(*attributeP)->attnum = (int16) i;
+
+		/*
+		 * Check if the attr is a set before messing with the length
+		 * and byval, since those were already set in
+		 * TupleDescInitEntry.	In fact, this seems redundant here,
+		 * but who knows what I'll break if I take it out...
+		 */
+		if (!(*attributeP)->attisset)
 		{
-			elog(ERROR, "fillatt: unknown atttypid %d",
-				 (*attributeP)->atttypid);
+			get_typlenbyval((*attributeP)->atttypid,
+							& (*attributeP)->attlen,
+							& (*attributeP)->attbyval);
 		}
-		else
-		{
-			(*attributeP)->attnum = (int16) ++i;
 
-			/*
-			 * Check if the attr is a set before messing with the length
-			 * and byval, since those were already set in
-			 * TupleDescInitEntry.	In fact, this seems redundant here,
-			 * but who knows what I'll break if I take it out...
-			 */
-			if (!(*attributeP)->attisset)
-			{
-				typp = (Form_pg_type) GETSTRUCT(tuple); /* XXX */
-				(*attributeP)->attlen = typp->typlen;
-				(*attributeP)->attbyval = typp->typbyval;
-			}
-		}
-		attributeP += 1;
+		attributeP++;
 	}
 }
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 2c4a9e515b24149be509194795d06bd9031525e4..3da6d82d4d0ee3fa141602f17642051980dfe9e7 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.151 2000/11/08 22:09:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.152 2000/11/16 22:30:17 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -488,7 +488,6 @@ CheckAttributeNames(TupleDesc tupdesc)
 Oid
 RelnameFindRelid(const char *relname)
 {
-	HeapTuple	tuple;
 	Oid			relid;
 
 	/*
@@ -497,19 +496,16 @@ RelnameFindRelid(const char *relname)
 	 */
 	if (!IsBootstrapProcessingMode())
 	{
-		tuple = SearchSysCacheTuple(RELNAME,
-									PointerGetDatum(relname),
-									0, 0, 0);
-		if (HeapTupleIsValid(tuple))
-			relid = tuple->t_data->t_oid;
-		else
-			relid = InvalidOid;
+		relid = GetSysCacheOid(RELNAME,
+							   PointerGetDatum(relname),
+							   0, 0, 0);
 	}
 	else
 	{
 		Relation	pg_class_desc;
 		ScanKeyData key;
 		HeapScanDesc pg_class_scan;
+		HeapTuple	tuple;
 
 		pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
 
@@ -756,8 +752,8 @@ AddNewRelationType(char *typeName, Oid new_rel_oid)
 	 */
 	new_type_oid = TypeCreate(typeName, /* type name */
 							  new_rel_oid,		/* relation oid */
-							  typeLen(typeidType(OIDOID)),		/* internal size */
-							  typeLen(typeidType(OIDOID)),		/* external size */
+							  sizeof(Oid),		/* internal size */
+							  sizeof(Oid),		/* external size */
 							  'c',		/* type-type (catalog) */
 							  ',',		/* default array delimiter */
 							  "int4in", /* input procedure */
@@ -1080,15 +1076,12 @@ DeleteRelationTuple(Relation rel)
 	 */
 	pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);
 
-	tup = SearchSysCacheTupleCopy(RELOID,
-								  ObjectIdGetDatum(rel->rd_id),
-								  0, 0, 0);
+	tup = SearchSysCacheCopy(RELOID,
+							 ObjectIdGetDatum(rel->rd_id),
+							 0, 0, 0);
 	if (!HeapTupleIsValid(tup))
-	{
-		heap_close(pg_class_desc, RowExclusiveLock);
 		elog(ERROR, "Relation \"%s\" does not exist",
 			 RelationGetRelationName(rel));
-	}
 
 	/* ----------------
 	 *	delete the relation tuple from pg_class, and finish up.
@@ -1136,14 +1129,15 @@ RelationTruncateIndexes(Oid heapId)
 		indexId = ((Form_pg_index) GETSTRUCT(indexTuple))->indexrelid;
 		indexInfo = BuildIndexInfo(indexTuple);
 
-		/* Fetch the pg_class tuple associated with this index */
-		classTuple = SearchSysCacheTupleCopy(RELOID,
-											 ObjectIdGetDatum(indexId),
-											 0, 0, 0);
+		/* Fetch access method from pg_class tuple for this index */
+		classTuple = SearchSysCache(RELOID,
+									ObjectIdGetDatum(indexId),
+									0, 0, 0);
 		if (!HeapTupleIsValid(classTuple))
 			elog(ERROR, "RelationTruncateIndexes: index %u not found in pg_class",
 				 indexId);
 		accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
+		ReleaseSysCache(classTuple);
 
 		/*
 		 * We have to re-open the heap rel each time through this loop
@@ -1258,19 +1252,17 @@ DeleteAttributeTuples(Relation rel)
 		 attnum <= rel->rd_att->natts;
 		 attnum++)
 	{
-		if (HeapTupleIsValid(tup = SearchSysCacheTupleCopy(ATTNUM,
+		tup = SearchSysCacheCopy(ATTNUM,
 								 ObjectIdGetDatum(RelationGetRelid(rel)),
-												   Int16GetDatum(attnum),
-														   0, 0)))
+								 Int16GetDatum(attnum),
+								 0, 0);
+		if (HeapTupleIsValid(tup))
 		{
-
 			/*** Delete any comments associated with this attribute ***/
-
 			DeleteComments(tup->t_data->t_oid);
 
 			heap_delete(pg_attribute_desc, &tup->t_self, NULL);
 			heap_freetuple(tup);
-
 		}
 	}
 
@@ -1586,9 +1578,10 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin,
 		return;					/* done if pg_attribute is OK */
 
 	attrrel = heap_openr(AttributeRelationName, RowExclusiveLock);
-	atttup = SearchSysCacheTupleCopy(ATTNUM,
-								 ObjectIdGetDatum(RelationGetRelid(rel)),
-									 (Datum) attnum, 0, 0);
+	atttup = SearchSysCacheCopy(ATTNUM,
+								ObjectIdGetDatum(RelationGetRelid(rel)),
+								Int16GetDatum(attnum),
+								0, 0);
 	if (!HeapTupleIsValid(atttup))
 		elog(ERROR, "cache lookup of attribute %d in relation %u failed",
 			 attnum, RelationGetRelid(rel));
@@ -1953,11 +1946,12 @@ AddRelationRawConstraints(Relation rel,
 	 * message, but for ALTER TABLE ADD ATTRIBUTE this'd be important.)
 	 */
 	relrel = heap_openr(RelationRelationName, RowExclusiveLock);
-	reltup = SearchSysCacheTupleCopy(RELOID,
-								 ObjectIdGetDatum(RelationGetRelid(rel)),
-									 0, 0, 0);
+	reltup = SearchSysCacheCopy(RELOID,
+								ObjectIdGetDatum(RelationGetRelid(rel)),
+								0, 0, 0);
 	if (!HeapTupleIsValid(reltup))
-		elog(ERROR, "cache lookup of relation %u failed", RelationGetRelid(rel));
+		elog(ERROR, "cache lookup of relation %u failed",
+			 RelationGetRelid(rel));
 	relStruct = (Form_pg_class) GETSTRUCT(reltup);
 
 	relStruct->relchecks = numchecks;
@@ -1970,8 +1964,8 @@ AddRelationRawConstraints(Relation rel,
 	CatalogIndexInsert(relidescs, Num_pg_class_indices, relrel, reltup);
 	CatalogCloseIndices(Num_pg_class_indices, relidescs);
 
-	heap_close(relrel, RowExclusiveLock);
 	heap_freetuple(reltup);
+	heap_close(relrel, RowExclusiveLock);
 }
 
 static void
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 3833c961f40a4b8648e294828c405f7d36c05570..d379246a922be408e29684595a4f59cf8aa5ad04 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.129 2000/11/08 22:09:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.130 2000/11/16 22:30:17 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -174,9 +174,9 @@ BuildFuncTupleDesc(Oid funcOid)
 	/*
 	 * Lookup the function to get its name and return type.
 	 */
-	tuple = SearchSysCacheTuple(PROCOID,
-								ObjectIdGetDatum(funcOid),
-								0, 0, 0);
+	tuple = SearchSysCache(PROCOID,
+						   ObjectIdGetDatum(funcOid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "Function %u does not exist", funcOid);
 	retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
@@ -187,12 +187,14 @@ BuildFuncTupleDesc(Oid funcOid)
 	namestrcpy(&funcTupDesc->attrs[0]->attname,
 			   NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname));
 
+	ReleaseSysCache(tuple);
+
 	/*
 	 * Lookup the return type in pg_type for the type length etc.
 	 */
-	tuple = SearchSysCacheTuple(TYPEOID,
-								ObjectIdGetDatum(retType),
-								0, 0, 0);
+	tuple = SearchSysCache(TYPEOID,
+						   ObjectIdGetDatum(retType),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "Type %u does not exist", retType);
 
@@ -208,6 +210,8 @@ BuildFuncTupleDesc(Oid funcOid)
 	funcTupDesc->attrs[0]->attstorage = 'p';
 	funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
 
+	ReleaseSysCache(tuple);
+
 	return funcTupDesc;
 }
 
@@ -759,10 +763,12 @@ UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
 	/* open the index system catalog relation */
 	pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
 
-	tuple = SearchSysCacheTuple(INDEXRELID,
-								ObjectIdGetDatum(indexoid),
-								0, 0, 0);
-	Assert(HeapTupleIsValid(tuple));
+	tuple = SearchSysCache(INDEXRELID,
+						   ObjectIdGetDatum(indexoid),
+						   0, 0, 0);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "UpdateIndexPredicate: cache lookup failed for index %u",
+			 indexoid);
 
 	for (i = 0; i < Natts_pg_index; i++)
 	{
@@ -779,6 +785,8 @@ UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
 	heap_update(pg_index, &newtup->t_self, newtup, NULL);
 
 	heap_freetuple(newtup);
+	ReleaseSysCache(tuple);
+
 	heap_close(pg_index, RowExclusiveLock);
 	pfree(predText);
 }
@@ -1069,11 +1077,12 @@ index_drop(Oid indexId)
 	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
 
 	/* Remove the pg_class tuple for the index itself */
-	tuple = SearchSysCacheTupleCopy(RELOID,
-									ObjectIdGetDatum(indexId),
-									0, 0, 0);
-
-	Assert(HeapTupleIsValid(tuple));
+	tuple = SearchSysCacheCopy(RELOID,
+							   ObjectIdGetDatum(indexId),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "index_drop: cache lookup failed for index %u",
+			 indexId);
 
 	heap_delete(relationRelation, &tuple->t_self, NULL);
 	heap_freetuple(tuple);
@@ -1098,10 +1107,10 @@ index_drop(Oid indexId)
 
 	attnum = 1;					/* indexes start at 1 */
 
-	while (HeapTupleIsValid(tuple = SearchSysCacheTupleCopy(ATTNUM,
+	while (HeapTupleIsValid(tuple = SearchSysCacheCopy(ATTNUM,
 											   ObjectIdGetDatum(indexId),
 												   Int16GetDatum(attnum),
-															0, 0)))
+													   0, 0)))
 	{
 		heap_delete(attributeRelation, &tuple->t_self, NULL);
 		heap_freetuple(tuple);
@@ -1115,10 +1124,12 @@ index_drop(Oid indexId)
 	 */
 	indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
 
-	tuple = SearchSysCacheTupleCopy(INDEXRELID,
-									ObjectIdGetDatum(indexId),
-									0, 0, 0);
-	Assert(HeapTupleIsValid(tuple));
+	tuple = SearchSysCacheCopy(INDEXRELID,
+							   ObjectIdGetDatum(indexId),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "index_drop: cache lookup failed for index %u",
+			 indexId);
 
 	heap_delete(indexRelation, &tuple->t_self, NULL);
 	heap_freetuple(tuple);
@@ -1318,21 +1329,24 @@ LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
 					   Buffer *buffer, bool confirmCommitted)
 {
 	HeapTuple	classTuple;
-	Form_pg_class pgcform;
 	bool		test;
 	Relation	relationRelation;
 
-	classTuple = SearchSysCacheTuple(RELOID, PointerGetDatum(relid),
-									 0, 0, 0);
-	if (!HeapTupleIsValid(classTuple))
-		return false;
-	rtup->t_self = classTuple->t_self;
-	pgcform = (Form_pg_class) GETSTRUCT(classTuple);
 	/*
 	 * NOTE: get and hold RowExclusiveLock on pg_class, because caller will
 	 * probably modify the rel's pg_class tuple later on.
 	 */
 	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
+	classTuple = SearchSysCache(RELOID, PointerGetDatum(relid),
+								0, 0, 0);
+	if (!HeapTupleIsValid(classTuple))
+	{
+		heap_close(relationRelation, NoLock);
+		return false;
+	}
+	rtup->t_self = classTuple->t_self;
+	ReleaseSysCache(classTuple);
+
 	test = heap_mark4update(relationRelation, rtup, buffer);
 	switch (test)
 	{
@@ -1418,9 +1432,9 @@ setRelhasindex(Oid relid, bool hasindex)
 
 	if (!IsIgnoringSystemIndexes())
 	{
-		tuple = SearchSysCacheTupleCopy(RELOID,
-										ObjectIdGetDatum(relid),
-										0, 0, 0);
+		tuple = SearchSysCacheCopy(RELOID,
+								   ObjectIdGetDatum(relid),
+								   0, 0, 0);
 	}
 	else
 	{
@@ -1542,9 +1556,9 @@ UpdateStats(Oid relid, long reltuples)
 
 	if (!in_place_upd)
 	{
-		tuple = SearchSysCacheTupleCopy(RELOID,
-										ObjectIdGetDatum(relid),
-										0, 0, 0);
+		tuple = SearchSysCacheCopy(RELOID,
+								   ObjectIdGetDatum(relid),
+								   0, 0, 0);
 	}
 	else
 	{
@@ -1887,19 +1901,20 @@ IndexGetRelation(Oid indexId)
 {
 	HeapTuple	tuple;
 	Form_pg_index index;
+	Oid			result;
 
-	tuple = SearchSysCacheTuple(INDEXRELID,
-								ObjectIdGetDatum(indexId),
-								0, 0, 0);
+	tuple = SearchSysCache(INDEXRELID,
+						   ObjectIdGetDatum(indexId),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
-	{
 		elog(ERROR, "IndexGetRelation: can't find index id %u",
 			 indexId);
-	}
 	index = (Form_pg_index) GETSTRUCT(tuple);
 	Assert(index->indexrelid == indexId);
 
-	return index->indrelid;
+	result = index->indrelid;
+	ReleaseSysCache(tuple);
+	return result;
 }
 
 /* ---------------------------------
@@ -1965,12 +1980,13 @@ reindex_index(Oid indexId, bool force)
 	heap_close(indexRelation, AccessShareLock);
 
 	/* Fetch the classTuple associated with this index */
-	classTuple = SearchSysCacheTuple(RELOID,
-									 ObjectIdGetDatum(indexId),
-									 0, 0, 0);
+	classTuple = SearchSysCache(RELOID,
+								ObjectIdGetDatum(indexId),
+								0, 0, 0);
 	if (!HeapTupleIsValid(classTuple))
 		elog(ERROR, "reindex_index: index %u not found in pg_class", indexId);
 	accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
+	ReleaseSysCache(classTuple);
 
 	/* Open our index relation */
 	heapRelation = heap_open(heapId, ExclusiveLock);
diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c
index 6003ab6bc5383af0202af81a7972e8915c5aa492..60eae115ec7b12a9d0049910514304d8376e1c30 100644
--- a/src/backend/catalog/indexing.c
+++ b/src/backend/catalog/indexing.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.73 2000/11/10 00:33:09 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.74 2000/11/16 22:30:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -153,13 +153,14 @@ CatalogIndexInsert(Relation *idescs,
 		IndexInfo  *indexInfo;
 		InsertIndexResult indexRes;
 
-		index_tup = SearchSysCacheTuple(INDEXRELID,
-										ObjectIdGetDatum(idescs[i]->rd_id),
-										0, 0, 0);
+		index_tup = SearchSysCache(INDEXRELID,
+								   ObjectIdGetDatum(idescs[i]->rd_id),
+								   0, 0, 0);
 		if (!HeapTupleIsValid(index_tup))
 			elog(ERROR, "CatalogIndexInsert: index %u not found",
 				 idescs[i]->rd_id);
 		indexInfo = BuildIndexInfo(index_tup);
+		ReleaseSysCache(index_tup);
 
 		FormIndexDatum(indexInfo,
 					   heapTuple,
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index e3fa7c5535be56ed69d40570b9b2ab1d49982548..9c9d54c8f3e90bae75a1c04080fd49357025b903 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.35 2000/07/17 03:04:43 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.36 2000/11/16 22:30:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -82,15 +82,10 @@ AggregateCreate(char *aggName,
 	 * specified as 'ANY' for a data-independent transition function,
 	 * such as COUNT(*).
 	 */
-	tup = SearchSysCacheTuple(TYPENAME,
+	basetype = GetSysCacheOid(TYPENAME,
 							  PointerGetDatum(aggbasetypeName),
 							  0, 0, 0);
-	if (HeapTupleIsValid(tup))
-	{
-		basetype = tup->t_data->t_oid;
-		Assert(OidIsValid(basetype));
-	}
-	else
+	if (!OidIsValid(basetype))
 	{
 		if (strcasecmp(aggbasetypeName, "ANY") != 0)
 			elog(ERROR, "AggregateCreate: Type '%s' undefined",
@@ -99,24 +94,21 @@ AggregateCreate(char *aggName,
 	}
 
 	/* make sure there is no existing agg of same name and base type */
-	tup = SearchSysCacheTuple(AGGNAME,
-							  PointerGetDatum(aggName),
-							  ObjectIdGetDatum(basetype),
-							  0, 0);
-	if (HeapTupleIsValid(tup))
+	if (SearchSysCacheExists(AGGNAME,
+							 PointerGetDatum(aggName),
+							 ObjectIdGetDatum(basetype),
+							 0, 0))
 		elog(ERROR,
 			 "AggregateCreate: aggregate '%s' with base type '%s' already exists",
 			 aggName, aggbasetypeName);
 
 	/* handle transtype */
-	tup = SearchSysCacheTuple(TYPENAME,
-							  PointerGetDatum(aggtranstypeName),
-							  0, 0, 0);
-	if (!HeapTupleIsValid(tup))
+	transtype = GetSysCacheOid(TYPENAME,
+							   PointerGetDatum(aggtranstypeName),
+							   0, 0, 0);
+	if (!OidIsValid(transtype))
 		elog(ERROR, "AggregateCreate: Type '%s' undefined",
 			 aggtranstypeName);
-	transtype = tup->t_data->t_oid;
-	Assert(OidIsValid(transtype));
 
 	/* handle transfn */
 	fnArgs[0] = transtype;
@@ -129,48 +121,50 @@ AggregateCreate(char *aggName,
 	{
 		nargs = 1;
 	}
-	tup = SearchSysCacheTuple(PROCNAME,
-							  PointerGetDatum(aggtransfnName),
-							  Int32GetDatum(nargs),
-							  PointerGetDatum(fnArgs),
-							  0);
+	tup = SearchSysCache(PROCNAME,
+						 PointerGetDatum(aggtransfnName),
+						 Int32GetDatum(nargs),
+						 PointerGetDatum(fnArgs),
+						 0);
 	if (!HeapTupleIsValid(tup))
 		func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
 	transfn = tup->t_data->t_oid;
+	Assert(OidIsValid(transfn));
 	proc = (Form_pg_proc) GETSTRUCT(tup);
 	if (proc->prorettype != transtype)
 		elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
 			 aggtransfnName, aggtranstypeName);
-	Assert(OidIsValid(transfn));
 	/*
 	 * If the transfn is strict and the initval is NULL, make sure
 	 * input type and transtype are the same (or at least binary-
 	 * compatible), so that it's OK to use the first input value
 	 * as the initial transValue.
 	 */
-	if (((Form_pg_proc) GETSTRUCT(tup))->proisstrict && agginitval == NULL)
+	if (proc->proisstrict && agginitval == NULL)
 	{
 		if (basetype != transtype &&
 			! IS_BINARY_COMPATIBLE(basetype, transtype))
 			elog(ERROR, "AggregateCreate: must not omit initval when transfn is strict and transtype is not compatible with input type");
 	}
+	ReleaseSysCache(tup);
 
 	/* handle finalfn, if supplied */
 	if (aggfinalfnName)
 	{
 		fnArgs[0] = transtype;
 		fnArgs[1] = 0;
-		tup = SearchSysCacheTuple(PROCNAME,
-								  PointerGetDatum(aggfinalfnName),
-								  Int32GetDatum(1),
-								  PointerGetDatum(fnArgs),
-								  0);
+		tup = SearchSysCache(PROCNAME,
+							 PointerGetDatum(aggfinalfnName),
+							 Int32GetDatum(1),
+							 PointerGetDatum(fnArgs),
+							 0);
 		if (!HeapTupleIsValid(tup))
 			func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
 		finalfn = tup->t_data->t_oid;
+		Assert(OidIsValid(finalfn));
 		proc = (Form_pg_proc) GETSTRUCT(tup);
 		finaltype = proc->prorettype;
-		Assert(OidIsValid(finalfn));
+		ReleaseSysCache(tup);
 	}
 	else
 	{
@@ -237,10 +231,10 @@ AggNameGetInitVal(char *aggName, Oid basetype, bool *isNull)
 	Assert(PointerIsValid(aggName));
 	Assert(PointerIsValid(isNull));
 
-	tup = SearchSysCacheTuple(AGGNAME,
-							  PointerGetDatum(aggName),
-							  ObjectIdGetDatum(basetype),
-							  0, 0);
+	tup = SearchSysCache(AGGNAME,
+						 PointerGetDatum(aggName),
+						 ObjectIdGetDatum(basetype),
+						 0, 0);
 	if (!HeapTupleIsValid(tup))
 		elog(ERROR, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
 			 aggName);
@@ -254,20 +248,24 @@ AggNameGetInitVal(char *aggName, Oid basetype, bool *isNull)
 								  Anum_pg_aggregate_agginitval,
 								  isNull);
 	if (*isNull)
+	{
+		ReleaseSysCache(tup);
 		return (Datum) 0;
+	}
 
 	strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
 
-	tup = SearchSysCacheTuple(TYPEOID,
-							  ObjectIdGetDatum(transtype),
-							  0, 0, 0);
+	ReleaseSysCache(tup);
+
+	tup = SearchSysCache(TYPEOID,
+						 ObjectIdGetDatum(transtype),
+						 0, 0, 0);
 	if (!HeapTupleIsValid(tup))
-	{
-		pfree(strInitVal);
 		elog(ERROR, "AggNameGetInitVal: cache lookup failed on aggregate transition function return type %u", transtype);
-	}
+
 	typinput = ((Form_pg_type) GETSTRUCT(tup))->typinput;
 	typelem = ((Form_pg_type) GETSTRUCT(tup))->typelem;
+	ReleaseSysCache(tup);
 
 	initVal = OidFunctionCall3(typinput,
 							   CStringGetDatum(strInitVal),
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 388bad8a583977e3a1ed5b97d0a3362fa3c536eb..29f404063ff87e87cf7de163b725f32a9e7a40fe 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.52 2000/10/22 23:32:38 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.53 2000/11/16 22:30:17 tgl Exp $
  *
  * NOTES
  *	  these routines moved here from commands/define.c and somewhat cleaned up.
@@ -575,12 +575,11 @@ OperatorDef(char *operatorName,
 		typeId[1] = rightTypeId;
 		nargs = 2;
 	}
-	tup = SearchSysCacheTuple(PROCNAME,
-							  PointerGetDatum(procedureName),
-							  Int32GetDatum(nargs),
-							  PointerGetDatum(typeId),
-							  0);
-
+	tup = SearchSysCache(PROCNAME,
+						 PointerGetDatum(procedureName),
+						 Int32GetDatum(nargs),
+						 PointerGetDatum(typeId),
+						 0);
 	if (!HeapTupleIsValid(tup))
 		func_error("OperatorDef", procedureName, nargs, typeId, NULL);
 
@@ -588,27 +587,32 @@ OperatorDef(char *operatorName,
 	values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc)
 											GETSTRUCT(tup))->prorettype);
 
+	ReleaseSysCache(tup);
+
 	/* ----------------
 	 *	find restriction
 	 * ----------------
 	 */
 	if (restrictionName)
 	{							/* optional */
+		Oid		restOid;
+
 		MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
 		typeId[0] = OIDOID;		/* operator OID */
 		typeId[1] = OIDOID;		/* relation OID */
 		typeId[2] = INT2OID;	/* attribute number */
 		typeId[3] = 0;			/* value - can be any type	*/
 		typeId[4] = INT4OID;	/* flags - left or right selectivity */
-		tup = SearchSysCacheTuple(PROCNAME,
-								  PointerGetDatum(restrictionName),
-								  Int32GetDatum(5),
-								  PointerGetDatum(typeId),
-								  0);
-		if (!HeapTupleIsValid(tup))
+
+		restOid = GetSysCacheOid(PROCNAME,
+								 PointerGetDatum(restrictionName),
+								 Int32GetDatum(5),
+								 PointerGetDatum(typeId),
+								 0);
+		if (!OidIsValid(restOid))
 			func_error("OperatorDef", restrictionName, 5, typeId, NULL);
 
-		values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
+		values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restOid);
 	}
 	else
 		values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
@@ -619,6 +623,8 @@ OperatorDef(char *operatorName,
 	 */
 	if (joinName)
 	{							/* optional */
+		Oid		joinOid;
+
 		MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
 		typeId[0] = OIDOID;		/* operator OID */
 		typeId[1] = OIDOID;		/* relation OID 1 */
@@ -626,15 +632,15 @@ OperatorDef(char *operatorName,
 		typeId[3] = OIDOID;		/* relation OID 2 */
 		typeId[4] = INT2OID;	/* attribute number 2 */
 
-		tup = SearchSysCacheTuple(PROCNAME,
-								  PointerGetDatum(joinName),
-								  Int32GetDatum(5),
-								  PointerGetDatum(typeId),
-								  0);
-		if (!HeapTupleIsValid(tup))
+		joinOid = GetSysCacheOid(PROCNAME,
+								 PointerGetDatum(joinName),
+								 Int32GetDatum(5),
+								 PointerGetDatum(typeId),
+								 0);
+		if (!OidIsValid(joinOid))
 			func_error("OperatorDef", joinName, 5, typeId, NULL);
 
-		values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
+		values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
 	}
 	else
 		values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 26861047b24420126b65443c35c6271322470afe..9d3ce5c50d6b084d1f880315cc797c3f2e290862 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.49 2000/10/07 00:58:15 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.50 2000/11/16 22:30:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -71,7 +71,7 @@ ProcedureCreate(char *procedureName,
 	Oid			toid;
 	NameData	procname;
 	TupleDesc	tupDesc;
-	Oid		retval;
+	Oid			retval;
 
 	/* ----------------
 	 *	sanity checks
@@ -80,15 +80,12 @@ ProcedureCreate(char *procedureName,
 	Assert(PointerIsValid(prosrc));
 	Assert(PointerIsValid(probin));
 
-	tup = SearchSysCacheTuple(LANGNAME,
-							  PointerGetDatum(languageName),
-							  0, 0, 0);
-
-	if (!HeapTupleIsValid(tup))
+	languageObjectId = GetSysCacheOid(LANGNAME,
+									  PointerGetDatum(languageName),
+									  0, 0, 0);
+	if (!OidIsValid(languageObjectId))
 		elog(ERROR, "ProcedureCreate: no such language '%s'", languageName);
 
-	languageObjectId = tup->t_data->t_oid;
-
 	parameterCount = 0;
 	MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid));
 	foreach(x, argList)
@@ -124,13 +121,12 @@ ProcedureCreate(char *procedureName,
 		typev[parameterCount++] = toid;
 	}
 
-	tup = SearchSysCacheTuple(PROCNAME,
-							  PointerGetDatum(procedureName),
-							  UInt16GetDatum(parameterCount),
-							  PointerGetDatum(typev),
-							  0);
-
-	if (HeapTupleIsValid(tup))
+	/* Check for duplicate definition */
+	if (SearchSysCacheExists(PROCNAME,
+							 PointerGetDatum(procedureName),
+							 UInt16GetDatum(parameterCount),
+							 PointerGetDatum(typev),
+							 0))
 		elog(ERROR, "ProcedureCreate: procedure %s already exists with same arguments",
 			 procedureName);
 
@@ -161,12 +157,12 @@ ProcedureCreate(char *procedureName,
 
 			prosrctext = DatumGetTextP(DirectFunctionCall1(textin,
 													CStringGetDatum(prosrc)));
-			tup = SearchSysCacheTuple(PROSRC,
-									  PointerGetDatum(prosrctext),
-									  0, 0, 0);
+			retval = GetSysCacheOid(PROSRC,
+									PointerGetDatum(prosrctext),
+									0, 0, 0);
 			pfree(prosrctext);
-			if (HeapTupleIsValid(tup))
-				return tup->t_data->t_oid;
+			if (OidIsValid(retval))
+				return retval;
 #else
 			elog(ERROR, "lookup for procedure by source needs fix (Jan)");
 #endif	 /* SETS_FIXED */
@@ -351,7 +347,7 @@ checkretval(Oid rettype, List *queryTreeList)
 	List	   *tlist;
 	List	   *tlistitem;
 	int			tlistlen;
-	Type		typ;
+	Oid			typerelid;
 	Resdom	   *resnode;
 	Relation	reln;
 	Oid			relid;
@@ -375,11 +371,9 @@ checkretval(Oid rettype, List *queryTreeList)
 	}
 
 	/* by here, the function is declared to return some type */
-	if ((typ = typeidType(rettype)) == NULL)
-		elog(ERROR, "can't find return type %u for function", rettype);
-
 	if (cmd != CMD_SELECT)
-		elog(ERROR, "function declared to return %s, but final query is not a SELECT", typeTypeName(typ));
+		elog(ERROR, "function declared to return %s, but final query is not a SELECT",
+			 typeidTypeName(rettype));
 
 	/*
 	 * Count the non-junk entries in the result targetlist.
@@ -390,14 +384,17 @@ checkretval(Oid rettype, List *queryTreeList)
 	 * For base-type returns, the target list should have exactly one entry,
 	 * and its type should agree with what the user declared.
 	 */
-	if (typeTypeRelid(typ) == InvalidOid)
+	typerelid = typeidTypeRelid(rettype);
+	if (typerelid == InvalidOid)
 	{
 		if (tlistlen != 1)
-			elog(ERROR, "function declared to return %s returns multiple columns in final SELECT", typeTypeName(typ));
+			elog(ERROR, "function declared to return %s returns multiple columns in final SELECT",
+				 typeidTypeName(rettype));
 
 		resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;
 		if (resnode->restype != rettype)
-			elog(ERROR, "return type mismatch in function: declared to return %s, returns %s", typeTypeName(typ), typeidTypeName(resnode->restype));
+			elog(ERROR, "return type mismatch in function: declared to return %s, returns %s",
+				 typeidTypeName(rettype), typeidTypeName(resnode->restype));
 
 		return;
 	}
@@ -422,12 +419,13 @@ checkretval(Oid rettype, List *queryTreeList)
 	 * declared return type, and be sure that attributes 1 .. n in the target
 	 * list match the declared types.
 	 */
-	reln = heap_open(typeTypeRelid(typ), AccessShareLock);
+	reln = heap_open(typerelid, AccessShareLock);
 	relid = reln->rd_id;
 	relnatts = reln->rd_rel->relnatts;
 
 	if (tlistlen != relnatts)
-		elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)", typeTypeName(typ), relnatts);
+		elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
+			 typeidTypeName(rettype), relnatts);
 
 	/* expect attributes 1 .. n in order */
 	i = 0;
@@ -441,7 +439,7 @@ checkretval(Oid rettype, List *queryTreeList)
 		tletype = exprType(tle->expr);
 		if (tletype != reln->rd_att->attrs[i]->atttypid)
 			elog(ERROR, "function declared to return %s returns %s instead of %s at column %d",
-				 typeTypeName(typ),
+				 typeidTypeName(rettype),
 				 typeidTypeName(tletype),
 				 typeidTypeName(reln->rd_att->attrs[i]->atttypid),
 				 i+1);
@@ -450,7 +448,8 @@ checkretval(Oid rettype, List *queryTreeList)
 
 	/* this shouldn't happen, but let's just check... */
 	if (i != relnatts)
-		elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)", typeTypeName(typ), relnatts);
+		elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
+			 typeidTypeName(rettype), relnatts);
 
 	heap_close(reln, AccessShareLock);
 }
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 2e5970cfcc856d109cbe5943eaa2ced78d0c4da6..f1f306424f070b6bd136baa6fec4f794926ab27d 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.55 2000/08/21 17:22:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.56 2000/11/16 22:30:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -388,6 +388,8 @@ TypeCreate(char *typeName,
 
 	for (j = 0; j < 4; ++j)
 	{
+		Oid		procOid;
+
 		procname = procs[j];
 
 		/*
@@ -396,13 +398,13 @@ TypeCreate(char *typeName,
 		 */
 		MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
 
-		tup = SearchSysCacheTuple(PROCNAME,
-								  PointerGetDatum(procname),
-								  Int32GetDatum(1),
-								  PointerGetDatum(argList),
-								  0);
+		procOid = GetSysCacheOid(PROCNAME,
+								 PointerGetDatum(procname),
+								 Int32GetDatum(1),
+								 PointerGetDatum(argList),
+								 0);
 
-		if (!HeapTupleIsValid(tup))
+		if (!OidIsValid(procOid))
 		{
 
 			/*
@@ -428,17 +430,17 @@ TypeCreate(char *typeName,
 					argList[1] = OIDOID;
 					argList[2] = INT4OID;
 				}
-				tup = SearchSysCacheTuple(PROCNAME,
-										  PointerGetDatum(procname),
-										  Int32GetDatum(nargs),
-										  PointerGetDatum(argList),
-										  0);
+				procOid = GetSysCacheOid(PROCNAME,
+										 PointerGetDatum(procname),
+										 Int32GetDatum(nargs),
+										 PointerGetDatum(argList),
+										 0);
 			}
-			if (!HeapTupleIsValid(tup))
+			if (!OidIsValid(procOid))
 				func_error("TypeCreate", procname, 1, argList, NULL);
 		}
 
-		values[i++] = ObjectIdGetDatum(tup->t_data->t_oid);	/* 11 - 14 */
+		values[i++] = ObjectIdGetDatum(procOid);	/* 11 - 14 */
 	}
 
 	/* ----------------
@@ -536,41 +538,31 @@ TypeRename(const char *oldTypeName, const char *newTypeName)
 {
 	Relation	pg_type_desc;
 	Relation	idescs[Num_pg_type_indices];
-	HeapTuple	oldtup,
-				newtup;
+	HeapTuple	tuple;
 
 	pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
 
-	oldtup = SearchSysCacheTupleCopy(TYPENAME,
-									 PointerGetDatum(oldTypeName),
-									 0, 0, 0);
-
-	if (!HeapTupleIsValid(oldtup))
-	{
-		heap_close(pg_type_desc, RowExclusiveLock);
-		elog(ERROR, "TypeRename: type %s not defined", oldTypeName);
-	}
+	tuple = SearchSysCacheCopy(TYPENAME,
+							   PointerGetDatum(oldTypeName),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "TypeRename: type \"%s\" not defined", oldTypeName);
 
-	newtup = SearchSysCacheTuple(TYPENAME,
-								 PointerGetDatum(newTypeName),
-								 0, 0, 0);
-	if (HeapTupleIsValid(newtup))
-	{
-		heap_freetuple(oldtup);
-		heap_close(pg_type_desc, RowExclusiveLock);
-		elog(ERROR, "TypeRename: type %s already defined", newTypeName);
-	}
+	if (SearchSysCacheExists(TYPENAME,
+							 PointerGetDatum(newTypeName),
+							 0, 0, 0))
+		elog(ERROR, "TypeRename: type \"%s\" already defined", newTypeName);
 
-	namestrcpy(&(((Form_pg_type) GETSTRUCT(oldtup))->typname), newTypeName);
+	namestrcpy(&(((Form_pg_type) GETSTRUCT(tuple))->typname), newTypeName);
 
-	heap_update(pg_type_desc, &oldtup->t_self, oldtup, NULL);
+	heap_update(pg_type_desc, &tuple->t_self, tuple, NULL);
 
 	/* update the system catalog indices */
 	CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
-	CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, oldtup);
+	CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tuple);
 	CatalogCloseIndices(Num_pg_type_indices, idescs);
 
-	heap_freetuple(oldtup);
+	heap_freetuple(tuple);
 	heap_close(pg_type_desc, RowExclusiveLock);
 }
 
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index a83a5b7c3ab25082ca249d7569a350b122f56505..bc1a2b9918fa64eab54106d2b25383a10a87c94f 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.8 2000/10/16 17:08:05 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.9 2000/11/16 22:30:19 tgl Exp $
  *
 
  *-------------------------------------------------------------------------
@@ -58,8 +58,7 @@ static void del_stats(Oid relid, int attcnt, int *attnums);
 void
 analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
 {
-	HeapTuple	tuple,
-				typetuple;
+	HeapTuple	tuple;
 	Relation	onerel;
 	int32		i;
 	int			attr_cnt,
@@ -81,20 +80,26 @@ analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
 	 * Race condition -- if the pg_class tuple has gone away since the
 	 * last time we saw it, we don't need to vacuum it.
 	 */
-	tuple = SearchSysCacheTuple(RELOID,
-								ObjectIdGetDatum(relid),
-								0, 0, 0);
+	tuple = SearchSysCache(RELOID,
+						   ObjectIdGetDatum(relid),
+						   0, 0, 0);
+	if (!HeapTupleIsValid(tuple))
+	{
+		CommitTransactionCommand();
+		return;
+	}
 	/*
 	 * We can VACUUM ANALYZE any table except pg_statistic.
 	 * see update_relstats
 	 */
-	if (!HeapTupleIsValid(tuple) ||
-		strcmp(NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname),
-				StatisticRelationName) == 0)
+	if (strcmp(NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname),
+			   StatisticRelationName) == 0)
 	{
+		ReleaseSysCache(tuple);
 		CommitTransactionCommand();
 		return;
 	}
+	ReleaseSysCache(tuple);
 
 	onerel = heap_open(relid, AccessShareLock);
 
@@ -168,6 +173,7 @@ analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
 		{
 			pgopform = (Form_pg_operator) GETSTRUCT(func_operator);
 			fmgr_info(pgopform->oprcode, &(stats->f_cmpeq));
+			ReleaseSysCache(func_operator);
 		}
 		else
 			stats->f_cmpeq.fn_addr = NULL;
@@ -178,6 +184,7 @@ analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
 			pgopform = (Form_pg_operator) GETSTRUCT(func_operator);
 			fmgr_info(pgopform->oprcode, &(stats->f_cmplt));
 			stats->op_cmplt = oprid(func_operator);
+			ReleaseSysCache(func_operator);
 		}
 		else
 		{
@@ -190,17 +197,19 @@ analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
 		{
 			pgopform = (Form_pg_operator) GETSTRUCT(func_operator);
 			fmgr_info(pgopform->oprcode, &(stats->f_cmpgt));
+			ReleaseSysCache(func_operator);
 		}
 		else
 			stats->f_cmpgt.fn_addr = NULL;
 
-		typetuple = SearchSysCacheTuple(TYPEOID,
-							 ObjectIdGetDatum(stats->attr->atttypid),
-										0, 0, 0);
-		if (HeapTupleIsValid(typetuple))
+		tuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(stats->attr->atttypid),
+							   0, 0, 0);
+		if (HeapTupleIsValid(tuple))
 		{
-			stats->outfunc = ((Form_pg_type) GETSTRUCT(typetuple))->typoutput;
-			stats->typelem = ((Form_pg_type) GETSTRUCT(typetuple))->typelem;
+			stats->outfunc = ((Form_pg_type) GETSTRUCT(tuple))->typoutput;
+			stats->typelem = ((Form_pg_type) GETSTRUCT(tuple))->typelem;
+			ReleaseSysCache(tuple);
 		}
 		else
 		{
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 6611f134727b97fb62e1bd2a79ca1f0f4908e94f..77f7776f6d9220b97ee870776d45ad70a1f73512 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.70 2000/10/03 03:11:13 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.71 2000/11/16 22:30:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -193,9 +193,7 @@ void
 Async_Listen(char *relname, int pid)
 {
 	Relation	lRel;
-	TupleDesc	tdesc;
-	HeapTuple	tuple,
-				newtup;
+	HeapTuple	tuple;
 	Datum		values[Natts_pg_listener];
 	char		nulls[Natts_pg_listener];
 	int			i;
@@ -205,13 +203,12 @@ Async_Listen(char *relname, int pid)
 		elog(DEBUG, "Async_Listen: %s", relname);
 
 	lRel = heap_openr(ListenerRelationName, AccessExclusiveLock);
-	tdesc = RelationGetDescr(lRel);
 
 	/* Detect whether we are already listening on this relname */
-	tuple = SearchSysCacheTuple(LISTENREL, Int32GetDatum(pid),
-								PointerGetDatum(relname),
-								0, 0);
-	if (tuple != NULL)
+	if (SearchSysCacheExists(LISTENREL,
+							 Int32GetDatum(pid),
+							 PointerGetDatum(relname),
+							 0, 0))
 	{
 		/* No need to scan the rest of the table */
 		heap_close(lRel, AccessExclusiveLock);
@@ -235,18 +232,18 @@ Async_Listen(char *relname, int pid)
 	values[i++] = (Datum) 0;	/* no notifies pending */
 
 	tupDesc = lRel->rd_att;
-	newtup = heap_formtuple(tupDesc, values, nulls);
-	heap_insert(lRel, newtup);
+	tuple = heap_formtuple(tupDesc, values, nulls);
+	heap_insert(lRel, tuple);
 	if (RelationGetForm(lRel)->relhasindex)
 	{
 		Relation	idescs[Num_pg_listener_indices];
 
 		CatalogOpenIndices(Num_pg_listener_indices, Name_pg_listener_indices, idescs);
-		CatalogIndexInsert(idescs, Num_pg_listener_indices, lRel, newtup);
+		CatalogIndexInsert(idescs, Num_pg_listener_indices, lRel, tuple);
 		CatalogCloseIndices(Num_pg_listener_indices, idescs);
 	}
 
-	heap_freetuple(newtup);
+	heap_freetuple(tuple);
 
 	heap_close(lRel, AccessExclusiveLock);
 
@@ -296,11 +293,15 @@ Async_Unlisten(char *relname, int pid)
 
 	lRel = heap_openr(ListenerRelationName, AccessExclusiveLock);
 	/* Note we assume there can be only one matching tuple. */
-	lTuple = SearchSysCacheTuple(LISTENREL, Int32GetDatum(pid),
-								PointerGetDatum(relname),
-								0, 0);
-	if (lTuple != NULL)
+	lTuple = SearchSysCache(LISTENREL,
+							Int32GetDatum(pid),
+							PointerGetDatum(relname),
+							0, 0);
+	if (HeapTupleIsValid(lTuple))
+	{
 		heap_delete(lRel, &lTuple->t_self, NULL);
+		ReleaseSysCache(lTuple);
+	}
 	heap_close(lRel, AccessExclusiveLock);
 
 	/*
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index c02bafc322733bd0a6dac0716f0854d04644368d..5c263e4c26c09d2c0279ecf97f44757afbf2c038 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.59 2000/11/08 22:09:57 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.60 2000/11/16 22:30:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -84,15 +84,16 @@ cluster(char *oldrelname, char *oldindexname)
 	/*
 	 * Check that index is in fact an index on the given relation
 	 */
-	tuple = SearchSysCacheTuple(INDEXRELID,
-								ObjectIdGetDatum(OIDOldIndex),
-								0, 0, 0);
+	tuple = SearchSysCache(INDEXRELID,
+						   ObjectIdGetDatum(OIDOldIndex),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "CLUSTER: no pg_index entry for index %u",
 			 OIDOldIndex);
 	if (((Form_pg_index) GETSTRUCT(tuple))->indrelid != OIDOldHeap)
 		elog(ERROR, "CLUSTER: \"%s\" is not an index for table \"%s\"",
 			 saveoldindexname, saveoldrelname);
+	ReleaseSysCache(tuple);
 
 	/* Drop relcache refcnts, but do NOT give up the locks */
 	heap_close(OldHeap, NoLock);
@@ -184,17 +185,17 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName)
 	 * To do this I get the info from pg_index, and add a new index with
 	 * a temporary name.
 	 */
-	Old_pg_index_Tuple = SearchSysCacheTupleCopy(INDEXRELID,
-												 ObjectIdGetDatum(OIDOldIndex),
-												 0, 0, 0);
+	Old_pg_index_Tuple = SearchSysCache(INDEXRELID,
+										ObjectIdGetDatum(OIDOldIndex),
+										0, 0, 0);
 	Assert(Old_pg_index_Tuple);
 	Old_pg_index_Form = (Form_pg_index) GETSTRUCT(Old_pg_index_Tuple);
 
 	indexInfo = BuildIndexInfo(Old_pg_index_Tuple);
 
-	Old_pg_index_relation_Tuple = SearchSysCacheTupleCopy(RELOID,
-														  ObjectIdGetDatum(OIDOldIndex),
-														  0, 0, 0);
+	Old_pg_index_relation_Tuple = SearchSysCache(RELOID,
+												 ObjectIdGetDatum(OIDOldIndex),
+												 0, 0, 0);
 	Assert(Old_pg_index_relation_Tuple);
 	Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple);
 
@@ -209,6 +210,9 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName)
 
 	setRelhasindex(OIDNewHeap, true);
 
+	ReleaseSysCache(Old_pg_index_Tuple);
+	ReleaseSysCache(Old_pg_index_relation_Tuple);
+
 	index_close(OldIndex);
 	heap_close(NewHeap, NoLock);
 }
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index 958469fa4e1808269339f6b4fe80d3b1373101c6..42f05f0761cf0c2c013d987d95368602c88b175b 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.111 2000/11/14 01:57:30 inoue Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.112 2000/11/16 22:30:19 tgl Exp $
  *
  * NOTES
  *	  The PerformAddAttribute() code, like most of the relation
@@ -274,13 +274,13 @@ AlterTableAddColumn(const char *relationName,
 				attrdesc;
 	Oid			myrelid;
 	HeapTuple	reltup;
+	HeapTuple	newreltup;
 	HeapTuple	attributeTuple;
 	Form_pg_attribute attribute;
 	FormData_pg_attribute attributeD;
 	int			i;
 	int			minattnum,
 				maxatts;
-	HeapTuple	tup;
 	Relation	idescs[Num_pg_attr_indices];
 	Relation	ridescs[Num_pg_class_indices];
 	bool		hasindex;
@@ -359,9 +359,9 @@ AlterTableAddColumn(const char *relationName,
 
 	rel = heap_openr(RelationRelationName, RowExclusiveLock);
 
-	reltup = SearchSysCacheTupleCopy(RELNAME,
-									 PointerGetDatum(relationName),
-									 0, 0, 0);
+	reltup = SearchSysCache(RELNAME,
+							PointerGetDatum(relationName),
+							0, 0, 0);
 
 	if (!HeapTupleIsValid(reltup))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" not found",
@@ -371,10 +371,8 @@ AlterTableAddColumn(const char *relationName,
 	 * XXX is the following check sufficient?
 	 */
 	if (((Form_pg_class) GETSTRUCT(reltup))->relkind != RELKIND_RELATION)
-	{
 		elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
 			 relationName);
-	}
 
 	minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
 	maxatts = minattnum + 1;
@@ -407,12 +405,10 @@ AlterTableAddColumn(const char *relationName,
 		char	   *typename;
 		int			attnelems;
 
-		tup = SearchSysCacheTuple(ATTNAME,
-								  ObjectIdGetDatum(reltup->t_data->t_oid),
-								  PointerGetDatum(colDef->colname),
-								  0, 0);
-
-		if (HeapTupleIsValid(tup))
+		if (SearchSysCacheExists(ATTNAME,
+								 ObjectIdGetDatum(reltup->t_data->t_oid),
+								 PointerGetDatum(colDef->colname),
+								 0, 0))
 			elog(ERROR, "ALTER TABLE: column name \"%s\" already exists in table \"%s\"",
 				 colDef->colname, relationName);
 
@@ -430,13 +426,13 @@ AlterTableAddColumn(const char *relationName,
 		else
 			attnelems = 0;
 
-		typeTuple = SearchSysCacheTuple(TYPENAME,
-										PointerGetDatum(typename),
-										0, 0, 0);
-		tform = (Form_pg_type) GETSTRUCT(typeTuple);
-
+		typeTuple = SearchSysCache(TYPENAME,
+								   PointerGetDatum(typename),
+								   0, 0, 0);
 		if (!HeapTupleIsValid(typeTuple))
 			elog(ERROR, "ALTER TABLE: type \"%s\" does not exist", typename);
+		tform = (Form_pg_type) GETSTRUCT(typeTuple);
+
 		namestrcpy(&(attribute->attname), colDef->colname);
 		attribute->atttypid = typeTuple->t_data->t_oid;
 		attribute->attlen = tform->typlen;
@@ -453,6 +449,8 @@ AlterTableAddColumn(const char *relationName,
 		attribute->atthasdef = (colDef->raw_default != NULL ||
 								colDef->cooked_default != NULL);
 
+		ReleaseSysCache(typeTuple);
+
 		heap_insert(attrdesc, attributeTuple);
 		if (hasindex)
 			CatalogIndexInsert(idescs,
@@ -466,15 +464,21 @@ AlterTableAddColumn(const char *relationName,
 
 	heap_close(attrdesc, RowExclusiveLock);
 
-	((Form_pg_class) GETSTRUCT(reltup))->relnatts = maxatts;
-	heap_update(rel, &reltup->t_self, reltup, NULL);
+	/*
+	 * Update number of attributes in pg_class tuple
+	 */
+	newreltup = heap_copytuple(reltup);
+
+	((Form_pg_class) GETSTRUCT(newreltup))->relnatts = maxatts;
+	heap_update(rel, &newreltup->t_self, newreltup, NULL);
 
 	/* keep catalog indices current */
 	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
-	CatalogIndexInsert(ridescs, Num_pg_class_indices, rel, reltup);
+	CatalogIndexInsert(ridescs, Num_pg_class_indices, rel, newreltup);
 	CatalogCloseIndices(Num_pg_class_indices, ridescs);
 
-	heap_freetuple(reltup);
+	heap_freetuple(newreltup);
+	ReleaseSysCache(reltup);
 
 	heap_close(rel, NoLock);
 
@@ -555,11 +559,10 @@ AlterTableAlterColumn(const char *relationName,
 	/*
 	 * get the number of the attribute
 	 */
-	tuple = SearchSysCacheTuple(ATTNAME,
-								ObjectIdGetDatum(myrelid),
-								PointerGetDatum(colName),
-								0, 0);
-
+	tuple = SearchSysCache(ATTNAME,
+						   ObjectIdGetDatum(myrelid),
+						   PointerGetDatum(colName),
+						   0, 0);
 	if (!HeapTupleIsValid(tuple))
 	{
 		heap_close(rel, AccessExclusiveLock);
@@ -568,6 +571,7 @@ AlterTableAlterColumn(const char *relationName,
 	}
 
 	attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
+	ReleaseSysCache(tuple);
 
 	if (newDefault)				/* SET DEFAULT */
 	{
@@ -595,7 +599,6 @@ AlterTableAlterColumn(const char *relationName,
 		Relation	attr_rel;
 		ScanKeyData scankeys[3];
 		HeapScanDesc scan;
-		HeapTuple	tuple;
 
 		attr_rel = heap_openr(AttributeRelationName, AccessExclusiveLock);
 		ScanKeyEntryInitialize(&scankeys[0], 0x0,
@@ -867,10 +870,11 @@ RemoveColumnReferences(Oid reloid, int attnum, bool checkonly, HeapTuple reltup)
 				}
 				else
 				{
-					htup = SearchSysCacheTuple(RELOID,
-									 ObjectIdGetDatum(index->indexrelid),
-											   0, 0, 0);
+					htup = SearchSysCache(RELOID,
+										  ObjectIdGetDatum(index->indexrelid),
+										  0, 0, 0);
 					RemoveIndex(NameStr(((Form_pg_class) GETSTRUCT(htup))->relname));
+					ReleaseSysCache(htup);
 				}
 				break;
 			}
@@ -941,18 +945,19 @@ AlterTableDropColumn(const char *relationName,
 	if (length(find_all_inheritors(myrelid)) > 1)
 		elog(ERROR, "ALTER TABLE: cannot drop a column on table that is inherited from");
 
-
 	/*
 	 * lock the pg_class tuple for update
 	 */
-	reltup = SearchSysCacheTuple(RELNAME, PointerGetDatum(relationName),
-								 0, 0, 0);
-
+	rel = heap_openr(RelationRelationName, RowExclusiveLock);
+	reltup = SearchSysCache(RELNAME,
+							PointerGetDatum(relationName),
+							0, 0, 0);
 	if (!HeapTupleIsValid(reltup))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" not found",
 			 relationName);
-	rel = heap_openr(RelationRelationName, RowExclusiveLock);
 	classtuple.t_self = reltup->t_self;
+	ReleaseSysCache(reltup);
+
 	switch (heap_mark4update(rel, &classtuple, &buffer))
 	{
 		case HeapTupleSelfUpdated:
@@ -976,19 +981,21 @@ AlterTableDropColumn(const char *relationName,
 	attrdesc = heap_openr(AttributeRelationName, RowExclusiveLock);
 
 	/*
-	 * Get the target pg_attribute tuple
+	 * Get the target pg_attribute tuple and make a modifiable copy
 	 */
-	tup = SearchSysCacheTupleCopy(ATTNAME,
-								  ObjectIdGetDatum(reltup->t_data->t_oid),
-								  PointerGetDatum(colName), 0, 0);
+	tup = SearchSysCacheCopy(ATTNAME,
+							 ObjectIdGetDatum(reltup->t_data->t_oid),
+							 PointerGetDatum(colName),
+							 0, 0);
 	if (!HeapTupleIsValid(tup))
 		elog(ERROR, "ALTER TABLE: column name \"%s\" doesn't exist in table \"%s\"",
 			 colName, relationName);
 
 	attribute = (Form_pg_attribute) GETSTRUCT(tup);
-	if (attribute->attnum <= 0)
-		elog(ERROR, "ALTER TABLE: column name \"%s\" was already dropped", colName);
 	attnum = attribute->attnum;
+	if (attnum <= 0)
+		elog(ERROR, "ALTER TABLE: column name \"%s\" was already dropped",
+			 colName);
 	attoid = tup->t_data->t_oid;
 
 	/*
@@ -1226,10 +1233,9 @@ AlterTableAddConstraint(char *relationName,
 			int			count;
 			List       *indexoidlist,
 				*indexoidscan;
-			Form_pg_index indexStruct = NULL;
 			Form_pg_attribute *rel_attrs = NULL;
-			int                     i;
-			int found=0;
+			int			i;
+			bool		found = false;
 
 			if (get_temp_rel_by_username(fkconstraint->pktable_name)!=NULL &&
 				get_temp_rel_by_username(relationName)==NULL) {
@@ -1264,42 +1270,50 @@ AlterTableAddConstraint(char *relationName,
 			indexoidlist = RelationGetIndexList(pkrel);
 
 			foreach(indexoidscan, indexoidlist)
+			{
+				Oid             indexoid = lfirsti(indexoidscan);
+				HeapTuple       indexTuple;
+				Form_pg_index	indexStruct;
+
+				indexTuple = SearchSysCache(INDEXRELID,
+											ObjectIdGetDatum(indexoid),
+											0, 0, 0);
+				if (!HeapTupleIsValid(indexTuple))
+					elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found",
+						 indexoid);
+				indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
+
+				if (indexStruct->indisunique)
 				{
-					Oid             indexoid = lfirsti(indexoidscan);
-					HeapTuple       indexTuple;
-					List *attrl;
-					indexTuple = SearchSysCacheTuple(INDEXRELID,
-													 ObjectIdGetDatum(indexoid),
-													 0, 0, 0);
-					if (!HeapTupleIsValid(indexTuple))
-						elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found",
-							 indexoid);
-					indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
-
-					if (indexStruct->indisunique) {
-						/* go through the fkconstraint->pk_attrs list */
-						foreach(attrl, fkconstraint->pk_attrs) {
-							Ident *attr=lfirst(attrl);
-							found=0;
-							for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
+					List	   *attrl;
+
+					/* go through the fkconstraint->pk_attrs list */
+					foreach(attrl, fkconstraint->pk_attrs)
+					{
+						Ident *attr=lfirst(attrl);
+						found = false;
+						for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
+						{
+							int pkattno = indexStruct->indkey[i];
+							if (pkattno>0)
 							{
-								int pkattno = indexStruct->indkey[i];
-								if (pkattno>0) {
-									char *name = NameStr(rel_attrs[pkattno-1]->attname);
-									if (strcmp(name, attr->name)==0) {
-										found=1;
-										break;
-									}
+								char *name = NameStr(rel_attrs[pkattno-1]->attname);
+								if (strcmp(name, attr->name)==0)
+								{
+									found = true;
+									break;
 								}
 							}
-							if (!found)
-								break;
 						}
+						if (!found)
+							break;
 					}
-					if (found)
-						break;
-					indexStruct = NULL;
 				}
+				ReleaseSysCache(indexTuple);
+				if (found)
+					break;
+			}
+
 			if (!found)
 				elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
 					 fkconstraint->pktable_name);
@@ -1309,17 +1323,18 @@ AlterTableAddConstraint(char *relationName,
 
 			rel_attrs = rel->rd_att->attrs;
 			if (fkconstraint->fk_attrs!=NIL) {
-				int found=0;
 				List *fkattrs;
 				Ident *fkattr;
+
+				found = false;
 				foreach(fkattrs, fkconstraint->fk_attrs) {
-					int count=0;
-					found=0;
+					int count;
+					found = false;
 					fkattr=lfirst(fkattrs);
-					for (; count < rel->rd_att->natts; count++) {
+					for (count = 0; count < rel->rd_att->natts; count++) {
 						char *name = NameStr(rel->rd_att->attrs[count]->attname);
 						if (strcmp(name, fkattr->name)==0) {
-							found=1;
+							found = true;
 							break;
 						}
 					}
@@ -1441,20 +1456,22 @@ AlterTableOwner(const char *relationName, const char *newOwnerName)
 	/*
 	 * look up the new owner in pg_shadow and get the sysid
 	 */
-	tuple = SearchSysCacheTuple(SHADOWNAME, PointerGetDatum(newOwnerName),
-								0, 0, 0);
+	tuple = SearchSysCache(SHADOWNAME,
+						   PointerGetDatum(newOwnerName),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "ALTER TABLE: user \"%s\" not found", newOwnerName);
-
 	newOwnerSysid = ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid;
+	ReleaseSysCache(tuple);
 
 	/*
-	 * find the table's entry in pg_class and lock it for writing
+	 * find the table's entry in pg_class and make a modifiable copy
 	 */
 	class_rel = heap_openr(RelationRelationName, RowExclusiveLock);
 
-	tuple = SearchSysCacheTupleCopy(RELNAME, PointerGetDatum(relationName),
-								 0, 0, 0);
+	tuple = SearchSysCacheCopy(RELNAME,
+							   PointerGetDatum(relationName),
+							   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" not found",
 			 relationName);
@@ -1525,13 +1542,15 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
 	 */
 	class_rel = heap_openr(RelationRelationName, RowExclusiveLock);
 
-	reltup = SearchSysCacheTuple(RELNAME, PointerGetDatum(relationName),
-								 0, 0, 0);
+	reltup = SearchSysCache(RELNAME,
+							PointerGetDatum(relationName),
+							0, 0, 0);
 	if (!HeapTupleIsValid(reltup))
 		elog(ERROR, "ALTER TABLE: relation \"%s\" not found",
 			 relationName);
-
 	classtuple.t_self = reltup->t_self;
+	ReleaseSysCache(reltup);
+
 	switch (heap_mark4update(class_rel, &classtuple, &buffer))
 	{
 		case HeapTupleSelfUpdated:
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index bff2b897c6e0fe0073964d5cac673aecaf03f12e..8ab997831b9dcc265f6ccc7436cf772a53ed6904 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -276,7 +276,6 @@ DeleteComments(Oid oid)
 static void
 CommentRelation(int reltype, char *relname, char *comment)
 {
-
 	HeapTuple	reltuple;
 	Oid			oid;
 	char		relkind;
@@ -288,17 +287,20 @@ CommentRelation(int reltype, char *relname, char *comment)
 
 	/*** Now, attempt to find the oid in the cached version of pg_class ***/
 
-	reltuple = SearchSysCacheTuple(RELNAME, PointerGetDatum(relname),
-								   0, 0, 0);
+	reltuple = SearchSysCache(RELNAME,
+							  PointerGetDatum(relname),
+							  0, 0, 0);
 	if (!HeapTupleIsValid(reltuple))
 		elog(ERROR, "relation '%s' does not exist", relname);
 
 	oid = reltuple->t_data->t_oid;
 
-	/*** Next, verify that the relation type matches the intent ***/
-
 	relkind = ((Form_pg_class) GETSTRUCT(reltuple))->relkind;
 
+	ReleaseSysCache(reltuple);
+
+	/*** Next, verify that the relation type matches the intent ***/
+
 	switch (reltype)
 	{
 		case (INDEX):
@@ -322,7 +324,6 @@ CommentRelation(int reltype, char *relname, char *comment)
 	/*** Create the comments using the tuple's oid ***/
 
 	CreateComments(oid, comment);
-
 }
 
 /*------------------------------------------------------------------
@@ -340,9 +341,7 @@ CommentRelation(int reltype, char *relname, char *comment)
 static void
 CommentAttribute(char *relname, char *attrname, char *comment)
 {
-
 	Relation	relation;
-	HeapTuple	attrtuple;
 	Oid			oid;
 
 	/*** First, check object security ***/
@@ -350,15 +349,19 @@ CommentAttribute(char *relname, char *attrname, char *comment)
 	if (!pg_ownercheck(GetUserId(), relname, RELNAME))
 		elog(ERROR, "you are not permitted to comment on class '%s\'", relname);
 
-	/*** Now, fetch the attribute oid from the system cache ***/
+	/* Open the containing relation to ensure it won't go away meanwhile */
 
 	relation = heap_openr(relname, AccessShareLock);
-	attrtuple = SearchSysCacheTuple(ATTNAME, ObjectIdGetDatum(relation->rd_id),
-									PointerGetDatum(attrname), 0, 0);
-	if (!HeapTupleIsValid(attrtuple))
+
+	/*** Now, fetch the attribute oid from the system cache ***/
+
+	oid = GetSysCacheOid(ATTNAME,
+						 ObjectIdGetDatum(relation->rd_id),
+						 PointerGetDatum(attrname),
+						 0, 0);
+	if (!OidIsValid(oid))
 		elog(ERROR, "'%s' is not an attribute of class '%s'",
 			 attrname, relname);
-	oid = attrtuple->t_data->t_oid;
 
 	/*** Call CreateComments() to create/drop the comments ***/
 
@@ -412,11 +415,13 @@ CommentDatabase(char *database, char *comment)
 	/*** Now, fetch user information ***/
 
 	userid = GetUserId();
-	usertuple = SearchSysCacheTuple(SHADOWSYSID, ObjectIdGetDatum(userid),
-									0, 0, 0);
+	usertuple = SearchSysCache(SHADOWSYSID,
+							   ObjectIdGetDatum(userid),
+							   0, 0, 0);
 	if (!HeapTupleIsValid(usertuple))
 		elog(ERROR, "invalid user id %u", (unsigned) userid);
 	superuser = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesuper;
+	ReleaseSysCache(usertuple);
 
 	/*** Allow if the userid matches the database dba or is a superuser ***/
 
@@ -452,8 +457,6 @@ CommentDatabase(char *database, char *comment)
 static void
 CommentRewrite(char *rule, char *comment)
 {
-
-	HeapTuple	rewritetuple;
 	Oid			oid;
 	char	   *relation;
 	int			aclcheck;
@@ -472,17 +475,15 @@ CommentRewrite(char *rule, char *comment)
 
 	/*** Next, find the rule's oid ***/
 
-	rewritetuple = SearchSysCacheTuple(RULENAME, PointerGetDatum(rule),
-									   0, 0, 0);
-	if (!HeapTupleIsValid(rewritetuple))
+	oid = GetSysCacheOid(RULENAME,
+						 PointerGetDatum(rule),
+						 0, 0, 0);
+	if (!OidIsValid(oid))
 		elog(ERROR, "rule '%s' does not exist", rule);
 
-	oid = rewritetuple->t_data->t_oid;
-
 	/*** Call CreateComments() to create/drop the comments ***/
 
 	CreateComments(oid, comment);
-
 }
 
 /*------------------------------------------------------------------
@@ -499,8 +500,6 @@ CommentRewrite(char *rule, char *comment)
 static void
 CommentType(char *type, char *comment)
 {
-
-	HeapTuple	typetuple;
 	Oid			oid;
 
 	/*** First, validate user ***/
@@ -515,17 +514,15 @@ CommentType(char *type, char *comment)
 
 	/*** Next, find the type's oid ***/
 
-	typetuple = SearchSysCacheTuple(TYPENAME, PointerGetDatum(type),
-									0, 0, 0);
-	if (!HeapTupleIsValid(typetuple))
+	oid = GetSysCacheOid(TYPENAME,
+						 PointerGetDatum(type),
+						 0, 0, 0);
+	if (!OidIsValid(oid))
 		elog(ERROR, "type '%s' does not exist", type);
 
-	oid = typetuple->t_data->t_oid;
-
 	/*** Call CreateComments() to create/drop the comments ***/
 
 	CreateComments(oid, comment);
-
 }
 
 /*------------------------------------------------------------------
@@ -543,7 +540,6 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
 {
 	TypeName   *aggtype = (TypeName *) lfirst(arguments);
 	char	   *aggtypename = NULL;
-	HeapTuple	aggtuple;
 	Oid			baseoid,
 				oid;
 	bool		defined;
@@ -580,9 +576,11 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
 
 	/*** Now, attempt to find the actual tuple in pg_aggregate ***/
 
-	aggtuple = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggregate),
-								   ObjectIdGetDatum(baseoid), 0, 0);
-	if (!HeapTupleIsValid(aggtuple))
+	oid = GetSysCacheOid(AGGNAME,
+						 PointerGetDatum(aggregate),
+						 ObjectIdGetDatum(baseoid),
+						 0, 0);
+	if (!OidIsValid(oid))
 	{
 		if (aggtypename)
 		{
@@ -593,12 +591,9 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
 			elog(ERROR, "aggregate '%s' does not exist", aggregate);
 	}
 
-	oid = aggtuple->t_data->t_oid;
-
 	/*** Call CreateComments() to create/drop the comments ***/
 
 	CreateComments(oid, comment);
-
 }
 
 /*------------------------------------------------------------------
@@ -615,8 +610,6 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
 static void
 CommentProc(char *function, List *arguments, char *comment)
 {
-	HeapTuple	argtuple,
-				functuple;
 	Oid			oid,
 				argoids[FUNC_MAX_ARGS];
 	int			i,
@@ -640,12 +633,11 @@ CommentProc(char *function, List *arguments, char *comment)
 			argoids[i] = InvalidOid;
 		else
 		{
-			argtuple = SearchSysCacheTuple(TYPENAME,
-										   PointerGetDatum(typnam),
-										   0, 0, 0);
-			if (!HeapTupleIsValid(argtuple))
+			argoids[i] = GetSysCacheOid(TYPENAME,
+										PointerGetDatum(typnam),
+										0, 0, 0);
+			if (!OidIsValid(argoids[i]))
 				elog(ERROR, "CommentProc: type '%s' not found", typnam);
-			argoids[i] = argtuple->t_data->t_oid;
 		}
 	}
 
@@ -659,14 +651,14 @@ CommentProc(char *function, List *arguments, char *comment)
 
 	/*** Now, find the corresponding oid for this procedure ***/
 
-	functuple = SearchSysCacheTuple(PROCNAME, PointerGetDatum(function),
-									Int32GetDatum(argcount),
-									PointerGetDatum(argoids), 0);
-	if (!HeapTupleIsValid(functuple))
+	oid = GetSysCacheOid(PROCNAME,
+						 PointerGetDatum(function),
+						 Int32GetDatum(argcount),
+						 PointerGetDatum(argoids),
+						 0);
+	if (!OidIsValid(oid))
 		func_error("CommentProc", function, argcount, argoids, NULL);
 
-	oid = functuple->t_data->t_oid;
-
 	/*** Call CreateComments() to create/drop the comments ***/
 
 	CreateComments(oid, comment);
@@ -738,10 +730,11 @@ CommentOperator(char *opername, List *arguments, char *comment)
 
 	/*** Attempt to fetch the operator oid ***/
 
-	optuple = SearchSysCacheTupleCopy(OPERNAME, PointerGetDatum(opername),
-									  ObjectIdGetDatum(leftoid),
-									  ObjectIdGetDatum(rightoid),
-									  CharGetDatum(oprtype));
+	optuple = SearchSysCache(OPERNAME,
+							 PointerGetDatum(opername),
+							 ObjectIdGetDatum(leftoid),
+							 ObjectIdGetDatum(rightoid),
+							 CharGetDatum(oprtype));
 	if (!HeapTupleIsValid(optuple))
 		elog(ERROR, "operator '%s' does not exist", opername);
 
@@ -764,6 +757,8 @@ CommentOperator(char *opername, List *arguments, char *comment)
 	if (oid == InvalidOid)
 		elog(ERROR, "operator '%s' does not have an underlying function", opername);
 
+	ReleaseSysCache(optuple);
+
 	/*** Call CreateComments() to create/drop the comments ***/
 
 	CreateComments(oid, comment);
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 2877999500c32eb98b2b693e11959f12d41ee286..bbbb5aa2cfcb446109bdf1df498876452c85a18f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.123 2000/11/12 00:36:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.124 2000/11/16 22:30:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,9 +48,9 @@
 static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
 static void CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
 static Oid	GetOutputFunction(Oid type);
-static Oid	GetTypeElement(Oid type);
 static Oid	GetInputFunction(Oid type);
-static Oid	IsTypeByVal(Oid type);
+static Oid	GetTypeElement(Oid type);
+static bool IsTypeByVal(Oid type);
 static void CopyReadNewline(FILE *fp, int *newline);
 static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline, char *null_print);
 
@@ -669,7 +669,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
 			continue;
 		}
 #endif	 /* _DROP_COLUMN_HACK__ */
-		byval[i] = (bool) IsTypeByVal(attr[i]->atttypid);
+		byval[i] = IsTypeByVal(attr[i]->atttypid);
 	}
 
 	lineno = 0;
@@ -893,65 +893,64 @@ static Oid
 GetOutputFunction(Oid type)
 {
 	HeapTuple	typeTuple;
-
-	typeTuple = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(type),
-									0, 0, 0);
-
-	if (HeapTupleIsValid(typeTuple))
-		return (int) ((Form_pg_type) GETSTRUCT(typeTuple))->typoutput;
-
-	elog(ERROR, "GetOutputFunction: Cache lookup of type %u failed", type);
-	return InvalidOid;
+	Oid			result;
+
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(type),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(typeTuple))
+		elog(ERROR, "GetOutputFunction: Cache lookup of type %u failed", type);
+	result = ((Form_pg_type) GETSTRUCT(typeTuple))->typoutput;
+	ReleaseSysCache(typeTuple);
+	return result;
 }
 
 static Oid
-GetTypeElement(Oid type)
+GetInputFunction(Oid type)
 {
 	HeapTuple	typeTuple;
-
-	typeTuple = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(type),
-									0, 0, 0);
-
-	if (HeapTupleIsValid(typeTuple))
-		return (int) ((Form_pg_type) GETSTRUCT(typeTuple))->typelem;
-
-	elog(ERROR, "GetOutputFunction: Cache lookup of type %u failed", type);
-	return InvalidOid;
+	Oid			result;
+
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(type),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(typeTuple))
+		elog(ERROR, "GetInputFunction: Cache lookup of type %u failed", type);
+	result = ((Form_pg_type) GETSTRUCT(typeTuple))->typinput;
+	ReleaseSysCache(typeTuple);
+	return result;
 }
 
 static Oid
-GetInputFunction(Oid type)
+GetTypeElement(Oid type)
 {
 	HeapTuple	typeTuple;
-
-	typeTuple = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(type),
-									0, 0, 0);
-
-	if (HeapTupleIsValid(typeTuple))
-		return (int) ((Form_pg_type) GETSTRUCT(typeTuple))->typinput;
-
-	elog(ERROR, "GetInputFunction: Cache lookup of type %u failed", type);
-	return InvalidOid;
+	Oid			result;
+
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(type),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(typeTuple))
+		elog(ERROR, "GetTypeElement: Cache lookup of type %u failed", type);
+	result = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem;
+	ReleaseSysCache(typeTuple);
+	return result;
 }
 
-static Oid
+static bool
 IsTypeByVal(Oid type)
 {
 	HeapTuple	typeTuple;
-
-	typeTuple = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(type),
-									0, 0, 0);
-
-	if (HeapTupleIsValid(typeTuple))
-		return (int) ((Form_pg_type) GETSTRUCT(typeTuple))->typbyval;
-
-	elog(ERROR, "GetInputFunction: Cache lookup of type %u failed", type);
-
-	return InvalidOid;
+	bool		result;
+
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(type),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(typeTuple))
+		elog(ERROR, "IsTypeByVal: Cache lookup of type %u failed", type);
+	result = ((Form_pg_type) GETSTRUCT(typeTuple))->typbyval;
+	ReleaseSysCache(typeTuple);
+	return result;
 }
 
 
diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c
index a1d45d170a19f5d3a598d1e61ec3c6a136d244d1..970782d6da30b8574bf9e385272ac9c3cd758280 100644
--- a/src/backend/commands/creatinh.c
+++ b/src/backend/commands/creatinh.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.66 2000/11/13 09:16:55 inoue Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.67 2000/11/16 22:30:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -408,11 +408,14 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
 			 * form name, type and constraints
 			 */
 			attributeName = NameStr(attribute->attname);
-			tuple = SearchSysCacheTuple(TYPEOID,
+			tuple = SearchSysCache(TYPEOID,
 								   ObjectIdGetDatum(attribute->atttypid),
-										0, 0, 0);
-			Assert(HeapTupleIsValid(tuple));
-			attributeType = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname);
+								   0, 0, 0);
+			if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "CREATE TABLE: cache lookup failed for type %u",
+					 attribute->atttypid);
+			attributeType = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname));
+			ReleaseSysCache(tuple);
 
 			/*
 			 * check validity
@@ -554,22 +557,25 @@ StoreCatalogInheritance(Oid relationId, List *supers)
 	idList = NIL;
 	foreach(entry, supers)
 	{
+		Oid			entryOid;
 		Datum		datum[Natts_pg_inherits];
 		char		nullarr[Natts_pg_inherits];
 
-		tuple = SearchSysCacheTuple(RELNAME,
+		entryOid = GetSysCacheOid(RELNAME,
 								  PointerGetDatum(strVal(lfirst(entry))),
-									0, 0, 0);
-		AssertArg(HeapTupleIsValid(tuple));
+								  0, 0, 0);
+		if (!OidIsValid(entryOid))
+			elog(ERROR, "StoreCatalogInheritance: cache lookup failed for relation \"%s\"",
+				 strVal(lfirst(entry)));
 
 		/*
 		 * build idList for use below
 		 */
-		idList = lappendi(idList, tuple->t_data->t_oid);
+		idList = lappendi(idList, entryOid);
 
-		datum[0] = ObjectIdGetDatum(relationId);		/* inhrel */
-		datum[1] = ObjectIdGetDatum(tuple->t_data->t_oid);		/* inhparent */
-		datum[2] = Int16GetDatum(seqNumber);	/* inhseqno */
+		datum[0] = ObjectIdGetDatum(relationId);	/* inhrel */
+		datum[1] = ObjectIdGetDatum(entryOid);		/* inhparent */
+		datum[2] = Int16GetDatum(seqNumber);		/* inhseqno */
 
 		nullarr[0] = ' ';
 		nullarr[1] = ' ';
@@ -624,11 +630,10 @@ StoreCatalogInheritance(Oid relationId, List *supers)
 
 		for (number = 1;; number += 1)
 		{
-			tuple = SearchSysCacheTuple(INHRELID,
-										ObjectIdGetDatum(id),
-										Int16GetDatum(number),
-										0, 0);
-
+			tuple = SearchSysCache(INHRELID,
+								   ObjectIdGetDatum(id),
+								   Int16GetDatum(number),
+								   0, 0);
 			if (!HeapTupleIsValid(tuple))
 				break;
 
@@ -636,6 +641,8 @@ StoreCatalogInheritance(Oid relationId, List *supers)
 									 GETSTRUCT(tuple))->inhparent,
 									NIL);
 
+			ReleaseSysCache(tuple);
+
 			current = lnext(current);
 		}
 		lnext(current) = next;
@@ -746,35 +753,28 @@ checkAttrExists(const char *attributeName, const char *attributeType, List *sche
 static void
 setRelhassubclassInRelation(Oid relationId, bool relhassubclass)
 {
-        Relation        relationRelation;
-        HeapTuple       tuple;
-        Relation        idescs[Num_pg_class_indices];
-
-        /*
-         * Lock a relation given its Oid. Go to the RelationRelation (i.e.
-         * pg_relation), find the appropriate tuple, and add the specified
-         * lock to it.
-         */
-        relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
-        tuple = SearchSysCacheTupleCopy(RELOID,
-                                    ObjectIdGetDatum(relationId),
-                                    0, 0, 0)
-;
-        Assert(HeapTupleIsValid(tuple));
-
-        ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass = relhassubclass;
-        heap_update(relationRelation, &tuple->t_self, tuple, NULL);
-
-        /* keep the catalog indices up to date */
-        CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
-        CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple
-);
-        CatalogCloseIndices(Num_pg_class_indices, idescs);
-
-	heap_freetuple(tuple);
-        heap_close(relationRelation, RowExclusiveLock);
-}
+	Relation		relationRelation;
+	HeapTuple       tuple;
+	Relation        idescs[Num_pg_class_indices];
 
+	/*
+	 * Fetch a modifiable copy of the tuple, modify it, update pg_class.
+	 */
+	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
+	tuple = SearchSysCacheCopy(RELOID,
+							   ObjectIdGetDatum(relationId),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "setRelhassubclassInRelation: cache lookup failed for relation %u", relationId);
 
+	((Form_pg_class) GETSTRUCT(tuple))->relhassubclass = relhassubclass;
+	heap_update(relationRelation, &tuple->t_self, tuple, NULL);
 
+	/* keep the catalog indices up to date */
+	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+	CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple);
+	CatalogCloseIndices(Num_pg_class_indices, idescs);
 
+	heap_freetuple(tuple);
+	heap_close(relationRelation, RowExclusiveLock);
+}
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 70fd952db63ad3bf6a029c73a790b45239f0671b..464a9b68fb2006e057e9909465c1731a240a9e51 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.67 2000/11/14 18:37:41 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.68 2000/11/16 22:30:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -445,9 +445,9 @@ get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb)
 {
 	HeapTuple	utup;
 
-	utup = SearchSysCacheTuple(SHADOWSYSID,
-							   ObjectIdGetDatum(use_sysid),
-							   0, 0, 0);
+	utup = SearchSysCache(SHADOWSYSID,
+						  ObjectIdGetDatum(use_sysid),
+						  0, 0, 0);
 
 	if (!HeapTupleIsValid(utup))
 		return false;
@@ -457,6 +457,8 @@ get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb)
 	if (use_createdb)
 		*use_createdb = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb;
 
+	ReleaseSysCache(utup);
+
 	return true;
 }
 
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index a33d155db9faabee49fb018df7440ed552710873..9d681a4a50fe2b6d814ed4df6963e1d986da94c4 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.47 2000/10/07 00:58:16 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.48 2000/11/16 22:30:18 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -277,10 +277,9 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
 		Form_pg_language languageStruct;
 
 		/* Lookup the language in the system cache */
-		languageTuple = SearchSysCacheTuple(LANGNAME,
-											PointerGetDatum(languageName),
-											0, 0, 0);
-
+		languageTuple = SearchSysCache(LANGNAME,
+									   PointerGetDatum(languageName),
+									   0, 0, 0);
 		if (!HeapTupleIsValid(languageTuple))
 			elog(ERROR,
 				 "Unrecognized language specified in a CREATE FUNCTION: "
@@ -299,12 +298,12 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
 		 * be defined by postgres superusers only
 		 */
 		if (!languageStruct->lanpltrusted && !superuser())
-		{
 			elog(ERROR, "Only users with Postgres superuser privilege "
 				 "are permitted to create a function in the '%s' "
 				 "language.",
 				 languageName);
-		}
+
+		ReleaseSysCache(languageTuple);
 	}
 
 	/*
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index fff6d56975398076ddc4978d2fac6bfedf836497..788701b20fe0a71c163df89562e2d1d7da881712 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.40 2000/11/08 22:09:57 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.41 2000/11/16 22:30:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -86,7 +86,6 @@ DefineIndex(char *heapRelationName,
 	Oid			relationId;
 	IndexInfo  *indexInfo;
 	int			numberOfAttributes;
-	HeapTuple	tuple;
 	List	   *cnfPred = NIL;
 	bool		lossy = false;
 	List	   *pl;
@@ -111,13 +110,12 @@ DefineIndex(char *heapRelationName,
 	/*
 	 * compute access method id
 	 */
-	tuple = SearchSysCacheTuple(AMNAME,
-								PointerGetDatum(accessMethodName),
-								0, 0, 0);
-	if (!HeapTupleIsValid(tuple))
+	accessMethodId = GetSysCacheOid(AMNAME,
+									PointerGetDatum(accessMethodName),
+									0, 0, 0);
+	if (!OidIsValid(accessMethodId))
 		elog(ERROR, "DefineIndex: access method \"%s\" not found",
 			 accessMethodName);
-	accessMethodId = tuple->t_data->t_oid;
 
 	/*
 	 * XXX Hardwired hacks to check for limitations on supported index types.
@@ -239,21 +237,22 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
 	/*
 	 * Get index's relation id and access method id from pg_class
 	 */
-	tuple = SearchSysCacheTuple(RELNAME,
-								PointerGetDatum(indexRelationName),
-								0, 0, 0);
+	tuple = SearchSysCache(RELNAME,
+						   PointerGetDatum(indexRelationName),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "ExtendIndex: index \"%s\" not found",
 			 indexRelationName);
 	indexId = tuple->t_data->t_oid;
 	accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam;
+	ReleaseSysCache(tuple);
 
 	/*
 	 * Extract info from the pg_index tuple for the index
 	 */
-	tuple = SearchSysCacheTuple(INDEXRELID,
-								ObjectIdGetDatum(indexId),
-								0, 0, 0);
+	tuple = SearchSysCache(INDEXRELID,
+						   ObjectIdGetDatum(indexId),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "ExtendIndex: relation \"%s\" is not an index",
 			 indexRelationName);
@@ -262,6 +261,7 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
 	relationId = index->indrelid;
 	indexInfo = BuildIndexInfo(tuple);
 	oldPred = indexInfo->ii_Predicate;
+	ReleaseSysCache(tuple);
 
 	if (oldPred == NULL)
 		elog(ERROR, "ExtendIndex: \"%s\" is not a partial index",
@@ -391,16 +391,16 @@ FuncIndexArgs(IndexInfo *indexInfo,
 		HeapTuple	tuple;
 		Form_pg_attribute att;
 
-		tuple = SearchSysCacheTuple(ATTNAME,
-									ObjectIdGetDatum(relId),
-									PointerGetDatum(arg),
-									0, 0);
+		tuple = SearchSysCache(ATTNAME,
+							   ObjectIdGetDatum(relId),
+							   PointerGetDatum(arg),
+							   0, 0);
 		if (!HeapTupleIsValid(tuple))
 			elog(ERROR, "DefineIndex: attribute \"%s\" not found", arg);
 		att = (Form_pg_attribute) GETSTRUCT(tuple);
-
 		indexInfo->ii_KeyAttrNumbers[nargs] = att->attnum;
 		argTypes[nargs] = att->atttypid;
+		ReleaseSysCache(tuple);
 		nargs++;
 	}
 
@@ -465,10 +465,10 @@ NormIndexAttrs(IndexInfo *indexInfo,
 		if (attribute->name == NULL)
 			elog(ERROR, "missing attribute for define index");
 
-		atttuple = SearchSysCacheTupleCopy(ATTNAME,
-										   ObjectIdGetDatum(relId),
-										PointerGetDatum(attribute->name),
-										   0, 0);
+		atttuple = SearchSysCache(ATTNAME,
+								  ObjectIdGetDatum(relId),
+								  PointerGetDatum(attribute->name),
+								  0, 0);
 		if (!HeapTupleIsValid(atttuple))
 			elog(ERROR, "DefineIndex: attribute \"%s\" not found",
 				 attribute->name);
@@ -479,7 +479,7 @@ NormIndexAttrs(IndexInfo *indexInfo,
 		classOidP[attn] = GetAttrOpClass(attribute, attform->atttypid,
 										 accessMethodName, accessMethodId);
 
-		heap_freetuple(atttuple);
+		ReleaseSysCache(atttuple);
 		attn++;
 	}
 }
@@ -507,13 +507,12 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
 		doTypeCheck = false;
 	}
 
-	tuple = SearchSysCacheTuple(CLANAME,
-								PointerGetDatum(attribute->class),
-								0, 0, 0);
-	if (!HeapTupleIsValid(tuple))
+	opClassId = GetSysCacheOid(CLANAME,
+							   PointerGetDatum(attribute->class),
+							   0, 0, 0);
+	if (!OidIsValid(opClassId))
 		elog(ERROR, "DefineIndex: opclass \"%s\" not found",
 			 attribute->class);
-	opClassId = tuple->t_data->t_oid;
 
 	/*
 	 * Assume the opclass is supported by this index access method
@@ -532,10 +531,8 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
 	scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
 
 	if (! HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
-	{
 		elog(ERROR, "DefineIndex: opclass \"%s\" not supported by access method \"%s\"",
 			 attribute->class, accessMethodName);
-	}
 
 	oprId = ((Form_pg_amop) GETSTRUCT(tuple))->amopopr;
 
@@ -557,9 +554,9 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
 	 */
 	if (doTypeCheck)
 	{
-		tuple = SearchSysCacheTuple(OPEROID,
-									ObjectIdGetDatum(oprId),
-									0, 0, 0);
+		tuple = SearchSysCache(OPEROID,
+							   ObjectIdGetDatum(oprId),
+							   0, 0, 0);
 		if (HeapTupleIsValid(tuple))
 		{
 			Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tuple);
@@ -570,6 +567,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
 				! IS_BINARY_COMPATIBLE(attrType, opInputType))
 				elog(ERROR, "DefineIndex: opclass \"%s\" does not accept datatype \"%s\"",
 					 attribute->class, typeidTypeName(attrType));
+			ReleaseSysCache(tuple);
 		}
 	}
 
@@ -580,15 +578,18 @@ static char *
 GetDefaultOpClass(Oid atttypid)
 {
 	HeapTuple	tuple;
+	char	   *result;
 
-	tuple = SearchSysCacheTuple(CLADEFTYPE,
-								ObjectIdGetDatum(atttypid),
-								0, 0, 0);
+	tuple = SearchSysCache(CLADEFTYPE,
+						   ObjectIdGetDatum(atttypid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		return NULL;
 
-	return DatumGetCString(DirectFunctionCall1(nameout,
-			NameGetDatum(&((Form_pg_opclass) GETSTRUCT(tuple))->opcname)));
+	result = pstrdup(NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname));
+
+	ReleaseSysCache(tuple);
+	return result;
 }
 
 /*
@@ -605,21 +606,19 @@ RemoveIndex(char *name)
 {
 	HeapTuple	tuple;
 
-	tuple = SearchSysCacheTuple(RELNAME,
-								PointerGetDatum(name),
-								0, 0, 0);
-
+	tuple = SearchSysCache(RELNAME,
+						   PointerGetDatum(name),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "index \"%s\" does not exist", name);
 
 	if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX)
-	{
 		elog(ERROR, "relation \"%s\" is of type \"%c\"",
-			 name,
-			 ((Form_pg_class) GETSTRUCT(tuple))->relkind);
-	}
+			 name, ((Form_pg_class) GETSTRUCT(tuple))->relkind);
 
 	index_drop(tuple->t_data->t_oid);
+
+	ReleaseSysCache(tuple);
 }
 
 /*
@@ -644,22 +643,20 @@ ReindexIndex(const char *name, bool force /* currently unused */ )
 	if (IsTransactionBlock())
 		elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
 
-	tuple = SearchSysCacheTuple(RELNAME,
-								PointerGetDatum(name),
-								0, 0, 0);
-
+	tuple = SearchSysCache(RELNAME,
+						   PointerGetDatum(name),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "index \"%s\" does not exist", name);
 
 	if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX)
-	{
 		elog(ERROR, "relation \"%s\" is of type \"%c\"",
-			 name,
-			 ((Form_pg_class) GETSTRUCT(tuple))->relkind);
-	}
+			 name, ((Form_pg_class) GETSTRUCT(tuple))->relkind);
 
 	if (!reindex_index(tuple->t_data->t_oid, force))
 		elog(NOTICE, "index \"%s\" wasn't reindexed", name);
+
+	ReleaseSysCache(tuple);
 }
 
 /*
@@ -684,22 +681,20 @@ ReindexTable(const char *name, bool force)
 	if (IsTransactionBlock())
 		elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
 
-	tuple = SearchSysCacheTuple(RELNAME,
-								PointerGetDatum(name),
-								0, 0, 0);
-
+	tuple = SearchSysCache(RELNAME,
+						   PointerGetDatum(name),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "table \"%s\" does not exist", name);
 
 	if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_RELATION)
-	{
 		elog(ERROR, "relation \"%s\" is of type \"%c\"",
-			 name,
-			 ((Form_pg_class) GETSTRUCT(tuple))->relkind);
-	}
+			 name, ((Form_pg_class) GETSTRUCT(tuple))->relkind);
 
 	if (!reindex_relation(tuple->t_data->t_oid, force))
 		elog(NOTICE, "table \"%s\" wasn't reindexed", name);
+
+	ReleaseSysCache(tuple);
 }
 
 /*
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index ec8aec7005f169e3df795090322a658d2403293d..5d4d3f09bf7df833f45af74b529f31de088c4743 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -48,7 +48,6 @@ void
 CreateProceduralLanguage(CreatePLangStmt *stmt)
 {
 	char		languageName[NAMEDATALEN];
-	HeapTuple	langTup;
 	HeapTuple	procTup;
 
 	Oid			typev[FUNC_MAX_ARGS];
@@ -77,10 +76,9 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 	 */
 	case_translate_language_name(stmt->plname, languageName);
 
-	langTup = SearchSysCacheTuple(LANGNAME,
-								  PointerGetDatum(languageName),
-								  0, 0, 0);
-	if (HeapTupleIsValid(langTup))
+	if (SearchSysCacheExists(LANGNAME,
+							 PointerGetDatum(languageName),
+							 0, 0, 0))
 		elog(ERROR, "Language %s already exists", languageName);
 
 	/* ----------------
@@ -89,21 +87,17 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 	 * ----------------
 	 */
 	memset(typev, 0, sizeof(typev));
-	procTup = SearchSysCacheTuple(PROCNAME,
-								  PointerGetDatum(stmt->plhandler),
-								  Int32GetDatum(0),
-								  PointerGetDatum(typev),
-								  0);
+	procTup = SearchSysCache(PROCNAME,
+							 PointerGetDatum(stmt->plhandler),
+							 Int32GetDatum(0),
+							 PointerGetDatum(typev),
+							 0);
 	if (!HeapTupleIsValid(procTup))
-	{
 		elog(ERROR, "PL handler function %s() doesn't exist",
 			 stmt->plhandler);
-	}
 	if (((Form_pg_proc) GETSTRUCT(procTup))->prorettype != InvalidOid)
-	{
 		elog(ERROR, "PL handler function %s() isn't of return type Opaque",
 			 stmt->plhandler);
-	}
 
 	/* ----------------
 	 * Insert the new language into pg_language
@@ -123,6 +117,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 	values[i++] = DirectFunctionCall1(textin,
 									  CStringGetDatum(stmt->plcompiler));
 
+	ReleaseSysCache(procTup);
+
 	rel = heap_openr(LanguageRelationName, RowExclusiveLock);
 
 	tupDesc = rel->rd_att;
@@ -173,9 +169,9 @@ DropProceduralLanguage(DropPLangStmt *stmt)
 
 	rel = heap_openr(LanguageRelationName, RowExclusiveLock);
 
-	langTup = SearchSysCacheTupleCopy(LANGNAME,
-									  PointerGetDatum(languageName),
-									  0, 0, 0);
+	langTup = SearchSysCacheCopy(LANGNAME,
+								 PointerGetDatum(languageName),
+								 0, 0, 0);
 	if (!HeapTupleIsValid(langTup))
 		elog(ERROR, "Language %s doesn't exist", languageName);
 
diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c
index a8ad2620ef7156bfade13a71057b424551c716af..fdcd0e7e744846e0664b8117ffb0d94c3f5ce4a0 100644
--- a/src/backend/commands/remove.c
+++ b/src/backend/commands/remove.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.54 2000/10/16 17:08:05 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.55 2000/11/16 22:30:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,11 +73,11 @@ RemoveOperator(char *operatorName,		/* operator name */
 
 	relation = heap_openr(OperatorRelationName, RowExclusiveLock);
 
-	tup = SearchSysCacheTupleCopy(OPERNAME,
-								  PointerGetDatum(operatorName),
-								  ObjectIdGetDatum(typeId1),
-								  ObjectIdGetDatum(typeId2),
-								  CharGetDatum(oprtype));
+	tup = SearchSysCacheCopy(OPERNAME,
+							 PointerGetDatum(operatorName),
+							 ObjectIdGetDatum(typeId1),
+							 ObjectIdGetDatum(typeId2),
+							 CharGetDatum(oprtype));
 
 	if (HeapTupleIsValid(tup))
 	{
@@ -254,14 +254,11 @@ RemoveType(char *typeName)		/* type name to be removed */
 
 	relation = heap_openr(TypeRelationName, RowExclusiveLock);
 
-	tup = SearchSysCacheTuple(TYPENAME,
-							  PointerGetDatum(typeName),
-							  0, 0, 0);
+	tup = SearchSysCache(TYPENAME,
+						 PointerGetDatum(typeName),
+						 0, 0, 0);
 	if (!HeapTupleIsValid(tup))
-	{
-		heap_close(relation, RowExclusiveLock);
 		elog(ERROR, "RemoveType: type '%s' does not exist", typeName);
-	}
 
 	typeOid = tup->t_data->t_oid;
 
@@ -271,19 +268,20 @@ RemoveType(char *typeName)		/* type name to be removed */
 
 	heap_delete(relation, &tup->t_self, NULL);
 
-	/* Now, Delete the "array of" that type */
+	ReleaseSysCache(tup);
+
+	/* Also, delete the "array of" that type */
 	shadow_type = makeArrayTypeName(typeName);
-	tup = SearchSysCacheTuple(TYPENAME,
-							  PointerGetDatum(shadow_type),
-							  0, 0, 0);
+	tup = SearchSysCache(TYPENAME,
+						 PointerGetDatum(shadow_type),
+						 0, 0, 0);
 	if (!HeapTupleIsValid(tup))
-	{
-		heap_close(relation, RowExclusiveLock);
 		elog(ERROR, "RemoveType: type '%s' does not exist", shadow_type);
-	}
 
 	heap_delete(relation, &tup->t_self, NULL);
 
+	ReleaseSysCache(tup);
+
 	heap_close(relation, RowExclusiveLock);
 }
 
@@ -321,12 +319,11 @@ RemoveFunction(char *functionName,		/* function name to be removed */
 			argList[i] = InvalidOid;
 		else
 		{
-			tup = SearchSysCacheTuple(TYPENAME,
-									  PointerGetDatum(typnam),
-									  0, 0, 0);
-			if (!HeapTupleIsValid(tup))
+			argList[i] = GetSysCacheOid(TYPENAME,
+										PointerGetDatum(typnam),
+										0, 0, 0);
+			if (!OidIsValid(argList[i]))
 				elog(ERROR, "RemoveFunction: type '%s' not found", typnam);
-			argList[i] = tup->t_data->t_oid;
 		}
 	}
 
@@ -337,11 +334,12 @@ RemoveFunction(char *functionName,		/* function name to be removed */
 	}
 
 	relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
-	tup = SearchSysCacheTuple(PROCNAME,
-							  PointerGetDatum(functionName),
-							  Int32GetDatum(nargs),
-							  PointerGetDatum(argList),
-							  0);
+
+	tup = SearchSysCache(PROCNAME,
+						 PointerGetDatum(functionName),
+						 Int32GetDatum(nargs),
+						 PointerGetDatum(argList),
+						 0);
 
 	if (!HeapTupleIsValid(tup))
 		func_error("RemoveFunction", functionName, nargs, argList, NULL);
@@ -359,6 +357,8 @@ RemoveFunction(char *functionName,		/* function name to be removed */
 
 	heap_delete(relation, &tup->t_self, NULL);
 
+	ReleaseSysCache(tup);
+
 	heap_close(relation, RowExclusiveLock);
 }
 
@@ -370,7 +370,6 @@ RemoveAggregate(char *aggName, char *aggType)
 	Oid			basetypeID = InvalidOid;
 	bool		defined;
 
-
 	/*
 	 * if a basetype is passed in, then attempt to find an aggregate for
 	 * that specific type.
@@ -405,10 +404,11 @@ RemoveAggregate(char *aggName, char *aggType)
 	}
 
 	relation = heap_openr(AggregateRelationName, RowExclusiveLock);
-	tup = SearchSysCacheTuple(AGGNAME,
-							  PointerGetDatum(aggName),
-							  ObjectIdGetDatum(basetypeID),
-							  0, 0);
+
+	tup = SearchSysCache(AGGNAME,
+						 PointerGetDatum(aggName),
+						 ObjectIdGetDatum(basetypeID),
+						 0, 0);
 
 	if (!HeapTupleIsValid(tup))
 	{
@@ -431,5 +431,7 @@ RemoveAggregate(char *aggName, char *aggType)
 
 	heap_delete(relation, &tup->t_self, NULL);
 
+	ReleaseSysCache(tup);
+
 	heap_close(relation, RowExclusiveLock);
 }
diff --git a/src/backend/commands/rename.c b/src/backend/commands/rename.c
index 6a9de4abf000d9d48abcd1c8f4c9241deae64448..3722948047b16ea1e8f49f2fb8fecf74869dfea0 100644
--- a/src/backend/commands/rename.c
+++ b/src/backend/commands/rename.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.52 2000/11/08 22:09:57 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.53 2000/11/16 22:30:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,8 +58,7 @@ renameatt(char *relname,
 	Relation	targetrelation;
 	Relation	attrelation;
 	HeapTuple	reltup,
-				oldatttup,
-				newatttup;
+				atttup;
 	Oid			relid;
 
 	/*
@@ -113,9 +112,9 @@ renameatt(char *relname,
 
 			if (childrelid == relid)
 				continue;
-			reltup = SearchSysCacheTuple(RELOID,
-										 ObjectIdGetDatum(childrelid),
-										 0, 0, 0);
+			reltup = SearchSysCache(RELOID,
+									ObjectIdGetDatum(childrelid),
+									0, 0, 0);
 			if (!HeapTupleIsValid(reltup))
 			{
 				elog(ERROR, "renameatt: can't find catalog entry for inheriting class with oid %u",
@@ -125,6 +124,7 @@ renameatt(char *relname,
 			StrNCpy(childname,
 					NameStr(((Form_pg_class) GETSTRUCT(reltup))->relname),
 					NAMEDATALEN);
+			ReleaseSysCache(reltup);
 			/* note we need not recurse again! */
 			renameatt(childname, oldattname, newattname, 0);
 		}
@@ -132,42 +132,38 @@ renameatt(char *relname,
 
 	attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);
 
-	oldatttup = SearchSysCacheTupleCopy(ATTNAME,
-										ObjectIdGetDatum(relid),
-										PointerGetDatum(oldattname),
-										0, 0);
-	if (!HeapTupleIsValid(oldatttup))
+	atttup = SearchSysCacheCopy(ATTNAME,
+								ObjectIdGetDatum(relid),
+								PointerGetDatum(oldattname),
+								0, 0);
+	if (!HeapTupleIsValid(atttup))
 		elog(ERROR, "renameatt: attribute \"%s\" does not exist", oldattname);
 
-	if (((Form_pg_attribute) GETSTRUCT(oldatttup))->attnum < 0)
+	if (((Form_pg_attribute) GETSTRUCT(atttup))->attnum < 0)
 		elog(ERROR, "renameatt: system attribute \"%s\" not renamed", oldattname);
 
-	newatttup = SearchSysCacheTuple(ATTNAME,
-									ObjectIdGetDatum(relid),
-									PointerGetDatum(newattname),
-									0, 0);
 	/* should not already exist */
-	if (HeapTupleIsValid(newatttup))
-	{
-		heap_freetuple(oldatttup);
+	if (SearchSysCacheExists(ATTNAME,
+							 ObjectIdGetDatum(relid),
+							 PointerGetDatum(newattname),
+							 0, 0))
 		elog(ERROR, "renameatt: attribute \"%s\" exists", newattname);
-	}
 
-	StrNCpy(NameStr(((Form_pg_attribute) GETSTRUCT(oldatttup))->attname),
+	StrNCpy(NameStr(((Form_pg_attribute) GETSTRUCT(atttup))->attname),
 			newattname, NAMEDATALEN);
 
-	heap_update(attrelation, &oldatttup->t_self, oldatttup, NULL);
+	heap_update(attrelation, &atttup->t_self, atttup, NULL);
 
 	/* keep system catalog indices current */
 	{
 		Relation	irelations[Num_pg_attr_indices];
 
 		CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations);
-		CatalogIndexInsert(irelations, Num_pg_attr_indices, attrelation, oldatttup);
+		CatalogIndexInsert(irelations, Num_pg_attr_indices, attrelation, atttup);
 		CatalogCloseIndices(Num_pg_attr_indices, irelations);
 	}
 
-	heap_freetuple(oldatttup);
+	heap_freetuple(atttup);
 	heap_close(attrelation, RowExclusiveLock);
 }
 
@@ -179,7 +175,7 @@ renamerel(const char *oldrelname, const char *newrelname)
 {
 	Relation	targetrelation;
 	Relation	relrelation;	/* for RELATION relation */
-	HeapTuple	oldreltup;
+	HeapTuple	reltup;
 	Oid			reloid;
 	char		relkind;
 	Relation	irelations[Num_pg_class_indices];
@@ -238,27 +234,27 @@ renamerel(const char *oldrelname, const char *newrelname)
 	 */
 	relrelation = heap_openr(RelationRelationName, RowExclusiveLock);
 
-	oldreltup = SearchSysCacheTupleCopy(RELNAME,
-										PointerGetDatum(oldrelname),
-										0, 0, 0);
-	if (!HeapTupleIsValid(oldreltup))
+	reltup = SearchSysCacheCopy(RELNAME,
+								PointerGetDatum(oldrelname),
+								0, 0, 0);
+	if (!HeapTupleIsValid(reltup))
 		elog(ERROR, "renamerel: relation \"%s\" does not exist", oldrelname);
 
 	if (RelnameFindRelid(newrelname) != InvalidOid)
 		elog(ERROR, "renamerel: relation \"%s\" exists", newrelname);
 
 	/*
-	 * Update pg_class tuple with new relname.  (Scribbling on oldreltup
+	 * Update pg_class tuple with new relname.  (Scribbling on reltup
 	 * is OK because it's a copy...)
 	 */
-	StrNCpy(NameStr(((Form_pg_class) GETSTRUCT(oldreltup))->relname),
+	StrNCpy(NameStr(((Form_pg_class) GETSTRUCT(reltup))->relname),
 			newrelname, NAMEDATALEN);
 
-	heap_update(relrelation, &oldreltup->t_self, oldreltup, NULL);
+	heap_update(relrelation, &reltup->t_self, reltup, NULL);
 
 	/* keep the system catalog indices current */
 	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, irelations);
-	CatalogIndexInsert(irelations, Num_pg_class_indices, relrelation, oldreltup);
+	CatalogIndexInsert(irelations, Num_pg_class_indices, relrelation, reltup);
 	CatalogCloseIndices(Num_pg_class_indices, irelations);
 
 	heap_close(relrelation, NoLock);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 33340291e1c93f919cb101f540c3cae2a8615727..22dfcac05244d438de49ed929f4c4bb2cd0be29b 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.79 2000/11/08 22:09:57 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.80 2000/11/16 22:30:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -154,11 +154,11 @@ CreateTrigger(CreateTrigStmt *stmt)
 	 * Find and validate the trigger function.
 	 */
 	MemSet(fargtypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
-	tuple = SearchSysCacheTuple(PROCNAME,
-								PointerGetDatum(stmt->funcname),
-								Int32GetDatum(0),
-								PointerGetDatum(fargtypes),
-								0);
+	tuple = SearchSysCache(PROCNAME,
+						   PointerGetDatum(stmt->funcname),
+						   Int32GetDatum(0),
+						   PointerGetDatum(fargtypes),
+						   0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "CreateTrigger: function %s() does not exist",
 			 stmt->funcname);
@@ -167,6 +167,8 @@ CreateTrigger(CreateTrigStmt *stmt)
 			 stmt->funcname);
 	funcoid = tuple->t_data->t_oid;
 	funclang = ((Form_pg_proc) GETSTRUCT(tuple))->prolang;
+	ReleaseSysCache(tuple);
+
 	if (funclang != ClanguageId &&
 		funclang != NEWClanguageId &&
 		funclang != INTERNALlanguageId &&
@@ -174,14 +176,15 @@ CreateTrigger(CreateTrigStmt *stmt)
 	{
 		HeapTuple	langTup;
 
-		langTup = SearchSysCacheTuple(LANGOID,
-									  ObjectIdGetDatum(funclang),
-									  0, 0, 0);
+		langTup = SearchSysCache(LANGOID,
+								 ObjectIdGetDatum(funclang),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(langTup))
 			elog(ERROR, "CreateTrigger: cache lookup for PL %u failed",
 				 funclang);
 		if (((Form_pg_language) GETSTRUCT(langTup))->lanispl == false)
 			elog(ERROR, "CreateTrigger: only builtin, C and PL functions are supported");
+		ReleaseSysCache(langTup);
 	}
 
 	/*
@@ -268,9 +271,9 @@ CreateTrigger(CreateTrigStmt *stmt)
 	 * rebuild relcache entries.
 	 */
 	pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
-	tuple = SearchSysCacheTupleCopy(RELNAME,
-									PointerGetDatum(stmt->relname),
-									0, 0, 0);
+	tuple = SearchSysCacheCopy(RELNAME,
+							   PointerGetDatum(stmt->relname),
+							   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "CreateTrigger: relation %s not found in pg_class",
 			 stmt->relname);
@@ -353,9 +356,9 @@ DropTrigger(DropTrigStmt *stmt)
 	 * rebuild relcache entries.
 	 */
 	pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
-	tuple = SearchSysCacheTupleCopy(RELNAME,
-									PointerGetDatum(stmt->relname),
-									0, 0, 0);
+	tuple = SearchSysCacheCopy(RELNAME,
+							   PointerGetDatum(stmt->relname),
+							   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "DropTrigger: relation %s not found in pg_class",
 			 stmt->relname);
@@ -426,9 +429,9 @@ RelationRemoveTriggers(Relation rel)
 		Relation	ridescs[Num_pg_class_indices];
 
 		pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
-		tup = SearchSysCacheTupleCopy(RELOID,
-									  RelationGetRelid(rel),
-									  0, 0, 0);
+		tup = SearchSysCacheCopy(RELOID,
+								 RelationGetRelid(rel),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(tup))
 			elog(ERROR, "RelationRemoveTriggers: relation %u not found in pg_class",
 				 RelationGetRelid(rel));
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 55064bf5126bcfd9987fd72cc63fde7727925a00..a33098b2e0b96bbc2dcabef1c4bbe591a2d7e65d 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.69 2000/10/19 03:55:51 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.70 2000/11/16 22:30:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -363,9 +363,9 @@ AlterUser(AlterUserStmt *stmt)
 	pg_shadow_rel = heap_openr(ShadowRelationName, AccessExclusiveLock);
 	pg_shadow_dsc = RelationGetDescr(pg_shadow_rel);
 
-	tuple = SearchSysCacheTuple(SHADOWNAME,
-								PointerGetDatum(stmt->user),
-								0, 0, 0);
+	tuple = SearchSysCache(SHADOWNAME,
+						   PointerGetDatum(stmt->user),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 	{
 		heap_close(pg_shadow_rel, AccessExclusiveLock);
@@ -470,10 +470,13 @@ AlterUser(AlterUserStmt *stmt)
 		CatalogOpenIndices(Num_pg_shadow_indices,
 						   Name_pg_shadow_indices, idescs);
 		CatalogIndexInsert(idescs, Num_pg_shadow_indices, pg_shadow_rel,
-						   tuple);
+						   new_tuple);
 		CatalogCloseIndices(Num_pg_shadow_indices, idescs);
 	}
 
+	ReleaseSysCache(tuple);
+	heap_freetuple(new_tuple);
+
 	/*
 	 * Write the updated pg_shadow data to the flat password file.
 	 */
@@ -525,9 +528,9 @@ DropUser(DropUserStmt *stmt)
 		int32		usesysid;
 		const char *user = strVal(lfirst(item));
 
-		tuple = SearchSysCacheTuple(SHADOWNAME,
-									PointerGetDatum(user),
-									0, 0, 0);
+		tuple = SearchSysCache(SHADOWNAME,
+							   PointerGetDatum(user),
+							   0, 0, 0);
 		if (!HeapTupleIsValid(tuple))
 		{
 			heap_close(pg_shadow_rel, AccessExclusiveLock);
@@ -579,6 +582,8 @@ DropUser(DropUserStmt *stmt)
 		 */
 		heap_delete(pg_shadow_rel, &tuple->t_self, NULL);
 
+		ReleaseSysCache(tuple);
+
 		/*
 		 * Remove user from groups
 		 *
@@ -633,24 +638,21 @@ CheckPgUserAclNotNull()
 {
 	HeapTuple	htup;
 
-	htup = SearchSysCacheTuple(RELNAME,
-							   PointerGetDatum(ShadowRelationName),
-							   0, 0, 0);
+	htup = SearchSysCache(RELNAME,
+						  PointerGetDatum(ShadowRelationName),
+						  0, 0, 0);
 	if (!HeapTupleIsValid(htup))
-	{
-		/* BIG problem */
-		elog(ERROR, "IsPgUserAclNull: \"%s\" not found",
+		elog(ERROR, "CheckPgUserAclNotNull: \"%s\" not found",
 			 ShadowRelationName);
-	}
 
 	if (heap_attisnull(htup, Anum_pg_class_relacl))
-	{
 		elog(ERROR,
 			 "To use passwords, you have to revoke permissions on %s "
 			 "so normal users cannot read the passwords. "
 			 "Try 'REVOKE ALL ON \"%s\" FROM PUBLIC'.",
 			 ShadowRelationName, ShadowRelationName);
-	}
+
+	ReleaseSysCache(htup);
 }
 
 
@@ -716,24 +718,21 @@ CreateGroup(CreateGroupStmt *stmt)
 	/*
 	 * Translate the given user names to ids
 	 */
-
 	foreach(item, stmt->initUsers)
 	{
 		const char *groupuser = strVal(lfirst(item));
 		Value	   *v;
 
-		tuple = SearchSysCacheTuple(SHADOWNAME,
-									PointerGetDatum(groupuser),
-									0, 0, 0);
+		tuple = SearchSysCache(SHADOWNAME,
+							   PointerGetDatum(groupuser),
+							   0, 0, 0);
 		if (!HeapTupleIsValid(tuple))
-		{
-			heap_close(pg_group_rel, AccessExclusiveLock);
 			elog(ERROR, "CREATE GROUP: user \"%s\" does not exist", groupuser);
-		}
 
 		v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid);
 		if (!member(v, newlist))
 			newlist = lcons(v, newlist);
+		ReleaseSysCache(tuple);
 	}
 
 	/* build an array to insert */
@@ -817,20 +816,19 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag)
 	pg_group_dsc = RelationGetDescr(pg_group_rel);
 
 	/*
-	 * Verify that group exists. If we find a tuple, will take that the
-	 * rest of the way and make our modifications on it.
+	 * Fetch existing tuple for group.
 	 */
-	if (!HeapTupleIsValid(group_tuple = SearchSysCacheTupleCopy(GRONAME, PointerGetDatum(stmt->name), 0, 0, 0)))
-	{
-		heap_close(pg_group_rel, AccessExclusiveLock);
+	group_tuple = SearchSysCache(GRONAME,
+								 PointerGetDatum(stmt->name),
+								 0, 0, 0);
+	if (!HeapTupleIsValid(group_tuple))
 		elog(ERROR, "%s: group \"%s\" does not exist", tag, stmt->name);
-	}
-
-	AssertState(stmt->action == +1 || stmt->action == -1);
 
 	/*
 	 * Now decide what to do.
 	 */
+	AssertState(stmt->action == +1 || stmt->action == -1);
+
 	if (stmt->action == +1)		/* add users, might also be invoked by
 								 * create user */
 	{
@@ -876,15 +874,14 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag)
 			if (strcmp(tag, "ALTER GROUP") == 0)
 			{
 				/* Get the uid of the proposed user to add. */
-				tuple = SearchSysCacheTuple(SHADOWNAME,
-								   PointerGetDatum(strVal(lfirst(item))),
-											0, 0, 0);
+				tuple = SearchSysCache(SHADOWNAME,
+									   PointerGetDatum(strVal(lfirst(item))),
+									   0, 0, 0);
 				if (!HeapTupleIsValid(tuple))
-				{
-					heap_close(pg_group_rel, AccessExclusiveLock);
-					elog(ERROR, "%s: user \"%s\" does not exist", tag, strVal(lfirst(item)));
-				}
+					elog(ERROR, "%s: user \"%s\" does not exist",
+						 tag, strVal(lfirst(item)));
 				v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid);
+				ReleaseSysCache(tuple);
 			}
 			else if (strcmp(tag, "CREATE USER") == 0)
 			{
@@ -999,15 +996,13 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag)
 				if (!is_dropuser)
 				{
 					/* Get the uid of the proposed user to drop. */
-					tuple = SearchSysCacheTuple(SHADOWNAME,
-								   PointerGetDatum(strVal(lfirst(item))),
-												0, 0, 0);
+					tuple = SearchSysCache(SHADOWNAME,
+										   PointerGetDatum(strVal(lfirst(item))),
+										   0, 0, 0);
 					if (!HeapTupleIsValid(tuple))
-					{
-						heap_close(pg_group_rel, AccessExclusiveLock);
 						elog(ERROR, "ALTER GROUP: user \"%s\" does not exist", strVal(lfirst(item)));
-					}
 					v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid);
+					ReleaseSysCache(tuple);
 				}
 				else
 				{
@@ -1056,9 +1051,9 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag)
 		}						/* endif group not null */
 	}							/* endif alter group drop user */
 
-	heap_close(pg_group_rel, AccessExclusiveLock);
+	ReleaseSysCache(group_tuple);
 
-	pfree(group_tuple);
+	heap_close(pg_group_rel, AccessExclusiveLock);
 }
 
 
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 403d80942de0af867a5b1bb8ee24059480c279f0..3aeae1409bd59db008f883813d8ade19bf2d9117 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.172 2000/11/16 05:50:59 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.173 2000/11/16 22:30:19 tgl Exp $
  *
 
  *-------------------------------------------------------------------------
@@ -356,7 +356,6 @@ getrels(NameData *VacRelP)
 static void
 vacuum_rel(Oid relid, bool analyze, bool is_toastrel)
 {
-	HeapTuple	tuple;
 	Relation	onerel;
 	VacPageListData vacuum_pages; /* List of pages to vacuum and/or clean
 								 * indices */
@@ -384,10 +383,9 @@ vacuum_rel(Oid relid, bool analyze, bool is_toastrel)
 	 * Race condition -- if the pg_class tuple has gone away since the
 	 * last time we saw it, we don't need to vacuum it.
 	 */
-	tuple = SearchSysCacheTuple(RELOID,
-								ObjectIdGetDatum(relid),
-								0, 0, 0);
-	if (!HeapTupleIsValid(tuple))
+	if (!SearchSysCacheExists(RELOID,
+							  ObjectIdGetDatum(relid),
+							  0, 0, 0))
 	{
 		if (!is_toastrel)
 			CommitTransactionCommand();
@@ -2237,17 +2235,17 @@ update_relstats(Oid relid, int num_pages, int num_tuples, bool hasindex,
 	 */
 	rd = heap_openr(RelationRelationName, RowExclusiveLock);
 
-	ctup = SearchSysCacheTupleCopy(RELOID,
-								   ObjectIdGetDatum(relid),
-								   0, 0, 0);
+	ctup = SearchSysCache(RELOID,
+						  ObjectIdGetDatum(relid),
+						  0, 0, 0);
 	if (!HeapTupleIsValid(ctup))
 		elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",
 			 relid);
 
 	/* get the buffer cache tuple */
 	rtup.t_self = ctup->t_self;
+	ReleaseSysCache(ctup);
 	heap_fetch(rd, SnapshotNow, &rtup, &buffer);
-	heap_freetuple(ctup);
 
 	/* overwrite the existing statistics in the tuple */
 	pgcform = (Form_pg_class) GETSTRUCT(&rtup);
@@ -2481,13 +2479,14 @@ get_index_desc(Relation onerel, int nindices, Relation *Irel)
 
 	for (i = 0; i < nindices; i++)
 	{
-		cachetuple = SearchSysCacheTuple(INDEXRELID,
+		cachetuple = SearchSysCache(INDEXRELID,
 							 ObjectIdGetDatum(RelationGetRelid(Irel[i])),
-										 0, 0, 0);
+									0, 0, 0);
 		if (!HeapTupleIsValid(cachetuple))
 			elog(ERROR, "get_index_desc: index %u not found",
 				 RelationGetRelid(Irel[i]));
 		indexInfo[i] = BuildIndexInfo(cachetuple);
+		ReleaseSysCache(cachetuple);
 	}
 
 	return indexInfo;
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index ecdda594188e14107cad331d789be7490c34de0b..3b05a78e83add3975a7dbf2a5a70b4dd6873e00c 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.68 2000/11/12 00:36:57 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.69 2000/11/16 22:30:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -740,9 +740,9 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
 		 *	Get the pg_index tuple for the index
 		 * ----------------
 		 */
-		indexTuple = SearchSysCacheTuple(INDEXRELID,
-										 ObjectIdGetDatum(indexOid),
-										 0, 0, 0);
+		indexTuple = SearchSysCache(INDEXRELID,
+									ObjectIdGetDatum(indexOid),
+									0, 0, 0);
 		if (!HeapTupleIsValid(indexTuple))
 			elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
 
@@ -752,6 +752,8 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
 		 */
 		ii = BuildIndexInfo(indexTuple);
 
+		ReleaseSysCache(indexTuple);
+
 		relationDescs[i] = indexDesc;
 		indexInfoArray[i] = ii;
 		i++;
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index ca9c48e294d5222ef6a92f0196b51d6925fea823..98b28c61e1058ab6c5a6e166d6957eecf6bd04fe 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.40 2000/11/12 00:36:57 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.41 2000/11/16 22:30:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -183,14 +183,11 @@ init_sql_fcache(FmgrInfo *finfo)
 
 	/* ----------------
 	 *	 get the procedure tuple corresponding to the given function Oid
-	 *
-	 *	 NB: use SearchSysCacheTupleCopy to ensure tuple lives long enough
 	 * ----------------
 	 */
-	procedureTuple = SearchSysCacheTupleCopy(PROCOID,
-											 ObjectIdGetDatum(foid),
-											 0, 0, 0);
-
+	procedureTuple = SearchSysCache(PROCOID,
+									ObjectIdGetDatum(foid),
+									0, 0, 0);
 	if (!HeapTupleIsValid(procedureTuple))
 		elog(ERROR, "init_sql_fcache: Cache lookup failed for procedure %u",
 			 foid);
@@ -201,10 +198,9 @@ init_sql_fcache(FmgrInfo *finfo)
 	 *	 get the return type from the procedure tuple
 	 * ----------------
 	 */
-	typeTuple = SearchSysCacheTuple(TYPEOID,
-						   ObjectIdGetDatum(procedureStruct->prorettype),
-									0, 0, 0);
-
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(procedureStruct->prorettype),
+							   0, 0, 0);
 	if (!HeapTupleIsValid(typeTuple))
 		elog(ERROR, "init_sql_fcache: Cache lookup failed for type %u",
 			 procedureStruct->prorettype);
@@ -286,7 +282,8 @@ init_sql_fcache(FmgrInfo *finfo)
 
 	pfree(src);
 
-	heap_freetuple(procedureTuple);
+	ReleaseSysCache(typeTuple);
+	ReleaseSysCache(procedureTuple);
 
 	finfo->fn_extra = (void *) fcache;
 }
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index fae1a5b0d87feeef87bef2e7937b1028e8ca85db..827001384f6dbdcda5908bb2e4a768654092d3a4 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -34,7 +34,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.71 2000/08/24 03:29:03 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.72 2000/11/16 22:30:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,6 +51,7 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_type.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 #include "utils/tuplesort.h"
 #include "utils/datum.h"
@@ -105,7 +106,7 @@ typedef struct AggStatePerAggData
 	 * We need the len and byval info for the agg's input, result, and
 	 * transition data types in order to know how to copy/delete values.
 	 */
-	int			inputtypeLen,
+	int16		inputtypeLen,
 				resulttypeLen,
 				transtypeLen;
 	bool		inputtypeByVal,
@@ -827,7 +828,6 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
 		char	   *aggname = aggref->aggname;
 		HeapTuple	aggTuple;
 		Form_pg_aggregate aggform;
-		Type		typeInfo;
 		Oid			transfn_oid,
 					finalfn_oid;
 
@@ -837,23 +837,23 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
 		/* Fill in the peraggstate data */
 		peraggstate->aggref = aggref;
 
-		aggTuple = SearchSysCacheTupleCopy(AGGNAME,
-										   PointerGetDatum(aggname),
-										   ObjectIdGetDatum(aggref->basetype),
-										   0, 0);
+		aggTuple = SearchSysCache(AGGNAME,
+								  PointerGetDatum(aggname),
+								  ObjectIdGetDatum(aggref->basetype),
+								  0, 0);
 		if (!HeapTupleIsValid(aggTuple))
 			elog(ERROR, "ExecAgg: cache lookup failed for aggregate %s(%s)",
 				 aggname,
-				 typeidTypeName(aggref->basetype));
+				 aggref->basetype ?
+				 typeidTypeName(aggref->basetype) : (char *) "");
 		aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
 
-		typeInfo = typeidType(aggform->aggfinaltype);
-		peraggstate->resulttypeLen = typeLen(typeInfo);
-		peraggstate->resulttypeByVal = typeByVal(typeInfo);
-
-		typeInfo = typeidType(aggform->aggtranstype);
-		peraggstate->transtypeLen = typeLen(typeInfo);
-		peraggstate->transtypeByVal = typeByVal(typeInfo);
+		get_typlenbyval(aggform->aggfinaltype,
+						&peraggstate->resulttypeLen,
+						&peraggstate->resulttypeByVal);
+		get_typlenbyval(aggform->aggtranstype,
+						&peraggstate->transtypeLen,
+						&peraggstate->transtypeByVal);
 
 		peraggstate->initValue =
 			AggNameGetInitVal(aggname,
@@ -901,23 +901,22 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
 			Form_pg_operator pgopform;
 
 			peraggstate->inputType = inputType;
-			typeInfo = typeidType(inputType);
-			peraggstate->inputtypeLen = typeLen(typeInfo);
-			peraggstate->inputtypeByVal = typeByVal(typeInfo);
+			get_typlenbyval(inputType,
+							&peraggstate->inputtypeLen,
+							&peraggstate->inputtypeByVal);
 
 			eq_operator = oper("=", inputType, inputType, true);
 			if (!HeapTupleIsValid(eq_operator))
-			{
 				elog(ERROR, "Unable to identify an equality operator for type '%s'",
 					 typeidTypeName(inputType));
-			}
 			pgopform = (Form_pg_operator) GETSTRUCT(eq_operator);
 			fmgr_info(pgopform->oprcode, &(peraggstate->equalfn));
+			ReleaseSysCache(eq_operator);
 			peraggstate->sortOperator = any_ordering_op(inputType);
 			peraggstate->sortstate = NULL;
 		}
 
-		heap_freetuple(aggTuple);
+		ReleaseSysCache(aggTuple);
 	}
 
 	return TRUE;
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index 8fc319a77f0e67c770b0c5e12e9de473ca230df3..88b4cd273352b59fd77b285fd91a4e99e0013237 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -15,7 +15,7 @@
  *	  locate group boundaries.
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.38 2000/08/24 03:29:03 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.39 2000/11/16 22:30:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,6 +28,8 @@
 #include "executor/nodeGroup.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_type.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
 
 static TupleTableSlot *ExecGroupEveryTuple(Group *node);
 static TupleTableSlot *ExecGroupOneTuple(Group *node);
@@ -498,12 +500,11 @@ execTuplesMatchPrepare(TupleDesc tupdesc,
 
 		eq_operator = oper("=", typid, typid, true);
 		if (!HeapTupleIsValid(eq_operator))
-		{
 			elog(ERROR, "Unable to identify an equality operator for type '%s'",
 				 typeidTypeName(typid));
-		}
 		pgopform = (Form_pg_operator) GETSTRUCT(eq_operator);
 		fmgr_info(pgopform->oprcode, &eqfunctions[i]);
+		ReleaseSysCache(eq_operator);
 	}
 
 	return eqfunctions;
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 9cd85195cdcc4fe85ea3de4328a3c0b95b1ca168..1969c5f0bd6737571279426f629efd1fcfab6733 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
- *	$Id: nodeHash.c,v 1.52 2000/08/24 03:29:03 tgl Exp $
+ *	$Id: nodeHash.c,v 1.53 2000/11/16 22:30:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,8 +29,8 @@
 #include "executor/nodeHashjoin.h"
 #include "miscadmin.h"
 #include "parser/parse_expr.h"
-#include "parser/parse_type.h"
 #include "utils/memutils.h"
+#include "utils/lsyscache.h"
 
 
 static int	hashFunc(Datum key, int len, bool byVal);
@@ -237,7 +237,6 @@ ExecHashTableCreate(Hash *node)
 	int			totalbuckets;
 	int			bucketsize;
 	int			i;
-	Type		typeInfo;
 	MemoryContext oldcxt;
 
 	/* ----------------
@@ -353,9 +352,9 @@ ExecHashTableCreate(Hash *node)
 	 *	Get info about the datatype of the hash key.
 	 * ----------------
 	 */
-	typeInfo = typeidType(exprType(node->hashkey));
-	hashtable->typByVal = typeByVal(typeInfo);
-	hashtable->typLen = typeLen(typeInfo);
+	get_typlenbyval(exprType(node->hashkey),
+					&hashtable->typLen,
+					&hashtable->typByVal);
 
 	/* ----------------
 	 *	Create temporary memory contexts in which to keep the hashtable
@@ -546,7 +545,9 @@ ExecHashGetBucket(HashJoinTable hashtable,
 	}
 	else
 	{
-		bucketno = hashFunc(keyval, hashtable->typLen, hashtable->typByVal)
+		bucketno = hashFunc(keyval,
+							(int) hashtable->typLen,
+							hashtable->typByVal)
 			% hashtable->totalbuckets;
 	}
 
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 9d4ca0a8d54e91ec96ee390fce4ee390226bc8f8..dbeaa7a2a533106360fd0b035b26d161632ce3da 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.38 2000/09/12 21:06:48 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.39 2000/11/16 22:30:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -147,26 +147,29 @@ MJFormSkipQual(List *qualList, char *replaceopname)
 		 *	 if we search with the actual operand types.
 		 * ----------------
 		 */
-		optup = get_operator_tuple(op->opno);
+		optup = SearchSysCache(OPEROID,
+							   ObjectIdGetDatum(op->opno),
+							   0, 0, 0);
 		if (!HeapTupleIsValid(optup))	/* shouldn't happen */
 			elog(ERROR, "MJFormSkipQual: operator %u not found", op->opno);
 		opform = (Form_pg_operator) GETSTRUCT(optup);
 		oprleft = opform->oprleft;
 		oprright = opform->oprright;
+		ReleaseSysCache(optup);
 
 		/* ----------------
 		 *	 Now look up the matching "<" or ">" operator.	If there isn't one,
 		 *	 whoever marked the "=" operator mergejoinable was a loser.
 		 * ----------------
 		 */
-		optup = SearchSysCacheTuple(OPERNAME,
-									PointerGetDatum(replaceopname),
-									ObjectIdGetDatum(oprleft),
-									ObjectIdGetDatum(oprright),
-									CharGetDatum('b'));
+		optup = SearchSysCache(OPERNAME,
+							   PointerGetDatum(replaceopname),
+							   ObjectIdGetDatum(oprleft),
+							   ObjectIdGetDatum(oprright),
+							   CharGetDatum('b'));
 		if (!HeapTupleIsValid(optup))
 			elog(ERROR,
-			"MJFormSkipQual: mergejoin operator %u has no matching %s op",
+				 "MJFormSkipQual: mergejoin operator %u has no matching %s op",
 				 op->opno, replaceopname);
 		opform = (Form_pg_operator) GETSTRUCT(optup);
 
@@ -177,6 +180,7 @@ MJFormSkipQual(List *qualList, char *replaceopname)
 		op->opno = optup->t_data->t_oid;
 		op->opid = opform->oprcode;
 		op->op_fcache = NULL;
+		ReleaseSysCache(optup);
 	}
 
 	return qualCopy;
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 07a05561a64701c8e13959ee0a3c9941b04d09b3..74a5dc44415fb05b9a758dd0f9243e4a9a056808 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -3,7 +3,7 @@
  * spi.c
  *				Server Programming Interface
  *
- * $Id: spi.c,v 1.48 2000/10/26 21:35:15 tgl Exp $
+ * $Id: spi.c,v 1.49 2000/11/16 22:30:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -447,6 +447,7 @@ char *
 SPI_gettype(TupleDesc tupdesc, int fnumber)
 {
 	HeapTuple	typeTuple;
+	char	   *result;
 
 	SPI_result = 0;
 	if (tupdesc->natts < fnumber || fnumber <= 0)
@@ -455,9 +456,9 @@ SPI_gettype(TupleDesc tupdesc, int fnumber)
 		return NULL;
 	}
 
-	typeTuple = SearchSysCacheTuple(TYPEOID,
+	typeTuple = SearchSysCache(TYPEOID,
 				 ObjectIdGetDatum(tupdesc->attrs[fnumber - 1]->atttypid),
-									0, 0, 0);
+							   0, 0, 0);
 
 	if (!HeapTupleIsValid(typeTuple))
 	{
@@ -465,7 +466,9 @@ SPI_gettype(TupleDesc tupdesc, int fnumber)
 		return NULL;
 	}
 
-	return pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
+	result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
+	ReleaseSysCache(typeTuple);
+	return result;
 }
 
 Oid
diff --git a/src/backend/lib/dllist.c b/src/backend/lib/dllist.c
index f38251934c4d87751f212437fc5a4de18546e966..175c02c3e7cd89325d3dd9da7d7068de161a4562 100644
--- a/src/backend/lib/dllist.c
+++ b/src/backend/lib/dllist.c
@@ -2,7 +2,6 @@
  *
  * dllist.c
  *	  this is a simple doubly linked list implementation
- *	  replaces the old simplelists stuff
  *	  the elements of the lists are void*
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
@@ -10,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/lib/dllist.c,v 1.18 2000/06/08 22:37:05 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/lib/dllist.c,v 1.19 2000/11/16 22:30:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,25 +32,33 @@ DLNewList(void)
 {
 	Dllist	   *l;
 
-	l = malloc(sizeof(Dllist));
+	l = (Dllist *) malloc(sizeof(Dllist));
 	l->dll_head = 0;
 	l->dll_tail = 0;
 
 	return l;
 }
 
-/* free up a list and all the nodes in it --- but *not* whatever the nodes
+void
+DLInitList(Dllist *list)
+{
+	list->dll_head = 0;
+	list->dll_tail = 0;
+}
+
+/*
+ * free up a list and all the nodes in it --- but *not* whatever the nodes
  * might point to!
  */
 void
-DLFreeList(Dllist *l)
+DLFreeList(Dllist *list)
 {
 	Dlelem	   *curr;
 
-	while ((curr = DLRemHead(l)) != 0)
+	while ((curr = DLRemHead(list)) != 0)
 		free(curr);
 
-	free(l);
+	free(list);
 }
 
 Dlelem *
@@ -59,7 +66,7 @@ DLNewElem(void *val)
 {
 	Dlelem	   *e;
 
-	e = malloc(sizeof(Dlelem));
+	e = (Dlelem *) malloc(sizeof(Dlelem));
 	e->dle_next = 0;
 	e->dle_prev = 0;
 	e->dle_val = val;
@@ -68,59 +75,18 @@ DLNewElem(void *val)
 }
 
 void
-DLFreeElem(Dlelem *e)
-{
-	free(e);
-}
-
-Dlelem *
-DLGetHead(Dllist *l)
-{
-	return l ? l->dll_head : 0;
-}
-
-/* get the value stored in the first element */
-#ifdef NOT_USED
-void *
-DLGetHeadVal(Dllist *l)
+DLInitElem(Dlelem *e, void *val)
 {
-	Dlelem	   *e = DLGetHead(l);
-
-	return e ? e->dle_val : 0;
-}
-
-#endif
-
-Dlelem *
-DLGetTail(Dllist *l)
-{
-	return l ? l->dll_tail : 0;
-}
-
-/* get the value stored in the last element */
-#ifdef NOT_USED
-void *
-DLGetTailVal(Dllist *l)
-{
-	Dlelem	   *e = DLGetTail(l);
-
-	return e ? e->dle_val : 0;
-}
-
-#endif
-
-#ifdef NOT_USED
-Dlelem *
-DLGetPred(Dlelem *e)			/* get predecessor */
-{
-	return e ? e->dle_prev : 0;
+	e->dle_next = 0;
+	e->dle_prev = 0;
+	e->dle_val = val;
+	e->dle_list = 0;
 }
-#endif
 
-Dlelem *
-DLGetSucc(Dlelem *e)			/* get successor */
+void
+DLFreeElem(Dlelem *e)
 {
-	return e ? e->dle_next : 0;
+	free(e);
 }
 
 void
@@ -131,16 +97,16 @@ DLRemove(Dlelem *e)
 	if (e->dle_prev)
 		e->dle_prev->dle_next = e->dle_next;
 	else
-/* must be the head element */
 	{
+		/* must be the head element */
 		Assert(e == l->dll_head);
 		l->dll_head = e->dle_next;
 	}
 	if (e->dle_next)
 		e->dle_next->dle_prev = e->dle_prev;
 	else
-/* must be the tail element */
 	{
+		/* must be the tail element */
 		Assert(e == l->dll_tail);
 		l->dll_tail = e->dle_prev;
 	}
@@ -194,12 +160,12 @@ DLRemHead(Dllist *l)
 
 	l->dll_head = result->dle_next;
 
-	result->dle_next = 0;
-	result->dle_list = 0;
-
 	if (result == l->dll_tail)	/* if the head is also the tail */
 		l->dll_tail = 0;
 
+	result->dle_next = 0;
+	result->dle_list = 0;
+
 	return result;
 }
 
@@ -217,12 +183,12 @@ DLRemTail(Dllist *l)
 
 	l->dll_tail = result->dle_prev;
 
-	result->dle_prev = 0;
-	result->dle_list = 0;
-
 	if (result == l->dll_head)	/* if the tail is also the head */
 		l->dll_head = 0;
 
+	result->dle_prev = 0;
+	result->dle_list = 0;
+
 	return result;
 }
 
@@ -241,8 +207,8 @@ DLMoveToFront(Dlelem *e)
 	if (e->dle_next)
 		e->dle_next->dle_prev = e->dle_prev;
 	else
-/* must be the tail element */
 	{
+		/* must be the tail element */
 		Assert(e == l->dll_tail);
 		l->dll_tail = e->dle_prev;
 	}
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 45e1c03738c6de3aac16578707e0ef32eb4578ac..95bf730963f403fb88496c0cf8690212c92c7a93 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.22 2000/08/08 15:41:24 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.23 2000/11/16 22:30:23 tgl Exp $
  *
  * NOTES
  *	  Creator functions in POSTGRES 4.2 are generated automatically. Most of
@@ -20,7 +20,10 @@
  *	  Andrew Yu			Oct 20, 1994	file creation
  */
 #include "postgres.h"
+
 #include "nodes/makefuncs.h"
+#include "utils/lsyscache.h"
+
 
 /*
  * makeOper -
@@ -143,6 +146,26 @@ makeConst(Oid consttype,
 	return cnst;
 }
 
+/*
+ * makeNullConst -
+ *	  creates a Const node representing a NULL of the specified type
+ */
+Const *
+makeNullConst(Oid consttype)
+{
+	int16		typLen;
+	bool		typByVal;
+
+	get_typlenbyval(consttype, &typLen, &typByVal);
+	return makeConst(consttype,
+					 (int) typLen,
+					 (Datum) 0,
+					 true,
+					 typByVal,
+					 false,
+					 false);
+}
+
 /*
  * makeAttr -
  *	  creates an Attr node
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index db318a1b31275555b38d4ffc9762e433c9dd4b9e..7abca0990e6e510c1791ca81fd48380f30721928 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.133 2000/11/16 05:51:00 momjian Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.134 2000/11/16 22:30:23 tgl Exp $
  *
  * NOTES
  *	  Every (plan) node in POSTGRES has an associated "out" routine which
@@ -1236,8 +1236,8 @@ _outJoinInfo(StringInfo str, JoinInfo *node)
 static void
 _outDatum(StringInfo str, Datum value, Oid type)
 {
+	int16		typeLength;
 	bool		byValue;
-	int			typeLength;
 	Size		length;
 	char	   *s;
 	int			i;
@@ -1246,8 +1246,7 @@ _outDatum(StringInfo str, Datum value, Oid type)
 	 * find some information about the type and the "real" length of the
 	 * datum.
 	 */
-	byValue = get_typbyval(type);
-	typeLength = get_typlen(type);
+	get_typlenbyval(type, &typeLength, &byValue);
 	length = datumGetSize(value, byValue, typeLength);
 
 	if (byValue)
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 5ed42accdb022a591a67d93259863ca802fc388e..43577f94f991b60cce1aaa41b463dd0c3284ab79 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.97 2000/09/29 18:21:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.98 2000/11/16 22:30:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -808,9 +808,9 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam,
 				   bool indexkey_on_left)
 {
 	Oid			expr_op = ((Oper *) clause->oper)->opno;
-	Oid			commuted_op;
-	Operator	oldop,
-				newop;
+	Oid			commuted_op,
+				new_op;
+	Operator	oldoptup;
 	Form_pg_operator oldopform;
 	char	   *opname;
 	Oid			ltype,
@@ -835,13 +835,16 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam,
 	 * Get the nominal input types of the given operator and the actual
 	 * type (before binary-compatible relabeling) of the index key.
 	 */
-	oldop = get_operator_tuple(expr_op);
-	if (! HeapTupleIsValid(oldop))
+	oldoptup = SearchSysCache(OPEROID,
+							  ObjectIdGetDatum(expr_op),
+							  0, 0, 0);
+	if (! HeapTupleIsValid(oldoptup))
 		return InvalidOid;		/* probably can't happen */
-	oldopform = (Form_pg_operator) GETSTRUCT(oldop);
-	opname = NameStr(oldopform->oprname);
+	oldopform = (Form_pg_operator) GETSTRUCT(oldoptup);
+	opname = pstrdup(NameStr(oldopform->oprname));
 	ltype = oldopform->oprleft;
 	rtype = oldopform->oprright;
+	ReleaseSysCache(oldoptup);
 
 	if (indexkey_on_left)
 	{
@@ -875,13 +878,11 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam,
 	 * (In theory this might find a non-semantically-comparable operator,
 	 * but in practice that seems pretty unlikely for binary-compatible types.)
 	 */
-	newop = oper(opname, indexkeytype, indexkeytype, TRUE);
+	new_op = oper_oid(opname, indexkeytype, indexkeytype, true);
 
-	if (HeapTupleIsValid(newop))
+	if (OidIsValid(new_op))
 	{
-		Oid			new_expr_op = oprid(newop);
-
-		if (new_expr_op != expr_op)
+		if (new_op != expr_op)
 		{
 
 			/*
@@ -889,14 +890,14 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam,
 			 * name; now does it match the index?
 			 */
 			if (indexkey_on_left)
-				commuted_op = new_expr_op;
+				commuted_op = new_op;
 			else
-				commuted_op = get_commutator(new_expr_op);
+				commuted_op = get_commutator(new_op);
 			if (commuted_op == InvalidOid)
 				return InvalidOid;
 
 			if (op_class(commuted_op, opclass, relam))
-				return new_expr_op;
+				return new_op;
 		}
 	}
 
@@ -2079,16 +2080,11 @@ prefix_quals(Var *leftop, Oid expr_op,
 static Oid
 find_operator(const char *opname, Oid datatype)
 {
-	HeapTuple	optup;
-
-	optup = SearchSysCacheTuple(OPERNAME,
-								PointerGetDatum(opname),
-								ObjectIdGetDatum(datatype),
-								ObjectIdGetDatum(datatype),
-								CharGetDatum('b'));
-	if (!HeapTupleIsValid(optup))
-		return InvalidOid;
-	return optup->t_data->t_oid;
+	return GetSysCacheOid(OPERNAME,
+						  PointerGetDatum(opname),
+						  ObjectIdGetDatum(datatype),
+						  ObjectIdGetDatum(datatype),
+						  CharGetDatum('b'));
 }
 
 /*
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 4069ed66e58fced530f167af9f646b88a3e8bafa..bfb97bc1eb522d7e3f83daf1d4709ca11eba6cc8 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.100 2000/11/12 00:36:58 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.101 2000/11/16 22:30:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -396,17 +396,19 @@ create_indexscan_plan(Query *root,
 		HeapTuple	indexTuple;
 		Form_pg_index index;
 
-		indexTuple = SearchSysCacheTuple(INDEXRELID,
-										 ObjectIdGetDatum(lfirsti(ixid)),
-										 0, 0, 0);
+		indexTuple = SearchSysCache(INDEXRELID,
+									ObjectIdGetDatum(lfirsti(ixid)),
+									0, 0, 0);
 		if (!HeapTupleIsValid(indexTuple))
 			elog(ERROR, "create_plan: index %u not found", lfirsti(ixid));
 		index = (Form_pg_index) GETSTRUCT(indexTuple);
 		if (index->indislossy)
 		{
 			lossy = true;
+			ReleaseSysCache(indexTuple);
 			break;
 		}
+		ReleaseSysCache(indexTuple);
 	}
 
 	/*
@@ -904,18 +906,19 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
 		Form_pg_index index;
 
 		/* Get the relam from the index's pg_class entry */
-		indexTuple = SearchSysCacheTuple(RELOID,
-										 ObjectIdGetDatum(indexid),
-										 0, 0, 0);
+		indexTuple = SearchSysCache(RELOID,
+									ObjectIdGetDatum(indexid),
+									0, 0, 0);
 		if (!HeapTupleIsValid(indexTuple))
 			elog(ERROR, "fix_indxqual_references: index %u not found in pg_class",
 				 indexid);
 		relam = ((Form_pg_class) GETSTRUCT(indexTuple))->relam;
+		ReleaseSysCache(indexTuple);
 
 		/* Need the index's pg_index entry for other stuff */
-		indexTuple = SearchSysCacheTuple(INDEXRELID,
-										 ObjectIdGetDatum(indexid),
-										 0, 0, 0);
+		indexTuple = SearchSysCache(INDEXRELID,
+									ObjectIdGetDatum(indexid),
+									0, 0, 0);
 		if (!HeapTupleIsValid(indexTuple))
 			elog(ERROR, "fix_indxqual_references: index %u not found in pg_index",
 				 indexid);
@@ -927,6 +930,8 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
 												   relam,
 												   index));
 
+		ReleaseSysCache(indexTuple);
+
 		indexids = lnext(indexids);
 	}
 	return fixed_quals;
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index acee58b7f073f34b71fbc9cad52dbd645ff83260..3bea06e2af6b296f53a5d6e24e8d3b3881ce318e 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.51 2000/09/29 18:21:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.52 2000/11/16 22:30:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,6 +31,7 @@
 #include "parser/parse_oper.h"
 #include "parser/parse_type.h"
 #include "utils/lsyscache.h"
+#include "utils/syscache.h"
 
 
 static void mark_baserels_for_outer_join(Query *root, Relids rels,
@@ -636,6 +637,8 @@ process_implied_equality(Query *root, Node *item1, Node *item2,
 									 BOOLOID); /* operator result type */
 	clause->args = makeList2(item1, item2);
 
+	ReleaseSysCache(eq_operator);
+
 	/*
 	 * Note: we mark the qual "pushed down" to ensure that it can never be
 	 * taken for an original JOIN/ON clause.  We also claim it is an outer-
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 296164acb8916d9eaa4ec30436663363bad338b8..c36e7fe7b8104d7df99259bd61eb45af3c220489 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.44 2000/10/26 21:36:09 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.45 2000/11/16 22:30:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,7 +23,7 @@
 #include "optimizer/subselect.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_oper.h"
-#include "utils/lsyscache.h"
+#include "utils/syscache.h"
 
 
 Index		PlannerQueryLevel;	/* level of current query */
@@ -271,8 +271,11 @@ make_subplan(SubLink *slink)
 			pfree(var);			/* var is only needed for new_param */
 
 			Assert(IsA(oper, Oper));
-			tup = get_operator_tuple(oper->opno);
-			Assert(HeapTupleIsValid(tup));
+			tup = SearchSysCache(OPEROID,
+								 ObjectIdGetDatum(oper->opno),
+								 0, 0, 0);
+			if (! HeapTupleIsValid(tup))
+				elog(ERROR, "cache lookup failed for operator %u", oper->opno);
 			opform = (Form_pg_operator) GETSTRUCT(tup);
 
 			/*
@@ -283,6 +286,8 @@ make_subplan(SubLink *slink)
 								exprType(lefthand), opform->oprleft);
 			right = make_operand("", (Node *) prm,
 								 prm->paramtype, opform->oprright);
+			ReleaseSysCache(tup);
+
 			newoper = lappend(newoper,
 							  make_opclause(oper,
 											(Var *) left,
@@ -401,15 +406,14 @@ make_subplan(SubLink *slink)
 			Node	   *left,
 					   *right;
 
-			/*
-			 * XXX really ought to fill in constlen and constbyval
-			 * correctly, but right now ExecEvalExpr won't look at them...
-			 */
-			con = makeConst(te->resdom->restype, 0, 0, true, 0, 0, 0);
+			con = makeNullConst(te->resdom->restype);
 
 			Assert(IsA(oper, Oper));
-			tup = get_operator_tuple(oper->opno);
-			Assert(HeapTupleIsValid(tup));
+			tup = SearchSysCache(OPEROID,
+								 ObjectIdGetDatum(oper->opno),
+								 0, 0, 0);
+			if (! HeapTupleIsValid(tup))
+				elog(ERROR, "cache lookup failed for operator %u", oper->opno);
 			opform = (Form_pg_operator) GETSTRUCT(tup);
 
 			/*
@@ -420,6 +424,8 @@ make_subplan(SubLink *slink)
 								exprType(lefthand), opform->oprleft);
 			right = make_operand("", (Node *) con,
 								 con->consttype, opform->oprright);
+			ReleaseSysCache(tup);
+
 			newoper = lappend(newoper,
 							  make_opclause(oper,
 											(Var *) left,
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index 822c0c79f0533e253663bd280a01bf00e31381a4..658c6c5e31236d45174eadc8b41fe289cada57fb 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.39 2000/10/05 19:11:30 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.40 2000/11/16 22:30:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -238,14 +238,7 @@ expand_targetlist(List *tlist, int command_type,
 
 #ifdef	_DROP_COLUMN_HACK__
 						if (COLUMN_IS_DROPPED(att_tup))
-						{
-							temp_var = (Var *) makeConst(atttype, 0,
-												   PointerGetDatum(NULL),
-														   true,
-														   false,
-														   false,		/* not a set */
-														   false);
-						}
+							temp_var = (Var *) makeNullConst(atttype);
 						else
 #endif	 /* _DROP_COLUMN_HACK__ */
 							temp_var = makeVar(result_relation,
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index f52ec6d2d874874d391185cd3d9455705641cf3e..c8df8b26fe4bbf74717f6a5bd4a1608b587fce26 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.77 2000/10/05 19:11:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.78 2000/11/16 22:30:26 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -28,7 +28,6 @@
 #include "optimizer/clauses.h"
 #include "optimizer/tlist.h"
 #include "optimizer/var.h"
-#include "parser/parse_type.h"
 #include "parser/parsetree.h"
 #include "utils/datum.h"
 #include "utils/lsyscache.h"
@@ -995,7 +994,8 @@ get_rels_atts(Node *clause,
 void
 CommuteClause(Expr *clause)
 {
-	HeapTuple	heapTup;
+	Oid			opoid;
+	HeapTuple	optup;
 	Form_pg_operator commuTup;
 	Oper	   *commu;
 	Node	   *temp;
@@ -1004,19 +1004,22 @@ CommuteClause(Expr *clause)
 		length(clause->args) != 2)
 		elog(ERROR, "CommuteClause: applied to non-binary-operator clause");
 
-	heapTup = (HeapTuple)
-		get_operator_tuple(get_commutator(((Oper *) clause->oper)->opno));
+	opoid = ((Oper *) clause->oper)->opno;
 
-	if (heapTup == (HeapTuple) NULL)
-		elog(ERROR, "CommuteClause: no commutator for operator %u",
-			 ((Oper *) clause->oper)->opno);
+	optup = SearchSysCache(OPEROID,
+						   ObjectIdGetDatum(get_commutator(opoid)),
+						   0, 0, 0);
+	if (!HeapTupleIsValid(optup))
+		elog(ERROR, "CommuteClause: no commutator for operator %u", opoid);
 
-	commuTup = (Form_pg_operator) GETSTRUCT(heapTup);
+	commuTup = (Form_pg_operator) GETSTRUCT(optup);
 
-	commu = makeOper(heapTup->t_data->t_oid,
+	commu = makeOper(optup->t_data->t_oid,
 					 commuTup->oprcode,
 					 commuTup->oprresult);
 
+	ReleaseSysCache(optup);
+
 	/*
 	 * re-form the clause in-place!
 	 */
@@ -1434,9 +1437,11 @@ simplify_op_or_func(Expr *expr, List *args)
 	Oid			result_typeid;
 	HeapTuple	func_tuple;
 	Form_pg_proc funcform;
-	Type		resultType;
+	bool		proiscachable;
+	bool		proisstrict;
+	bool		proretset;
+	int16		resultTypLen;
 	bool		resultTypByVal;
-	int			resultTypLen;
 	Expr	   *newexpr;
 	ExprContext *econtext;
 	Datum		const_val;
@@ -1491,36 +1496,37 @@ simplify_op_or_func(Expr *expr, List *args)
 	 * we could use func_iscachable() here, but we need several fields
 	 * out of the func tuple, so might as well just look it up once.
 	 */
-	func_tuple = SearchSysCacheTuple(PROCOID,
-									 ObjectIdGetDatum(funcid),
-									 0, 0, 0);
+	func_tuple = SearchSysCache(PROCOID,
+								ObjectIdGetDatum(funcid),
+								0, 0, 0);
 	if (!HeapTupleIsValid(func_tuple))
 		elog(ERROR, "Function OID %u does not exist", funcid);
 	funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
-	if (!funcform->proiscachable)
+	proiscachable = funcform->proiscachable;
+	proisstrict = funcform->proisstrict;
+	proretset = funcform->proretset;
+	ReleaseSysCache(func_tuple);
+
+	if (!proiscachable)
 		return NULL;
 
 	/*
 	 * Also check to make sure it doesn't return a set.
 	 */
-	if (funcform->proretset)
+	if (proretset)
 		return NULL;
 
 	/*
 	 * Now that we know if the function is strict, we can finish the
 	 * checks for simplifiable inputs that we started above.
 	 */
-	if (funcform->proisstrict && has_null_input)
+	if (proisstrict && has_null_input)
 	{
 		/*
 		 * It's strict and has NULL input, so must produce NULL output.
 		 * Return a NULL constant of the right type.
 		 */
-		resultType = typeidType(result_typeid);
-		return (Expr *) makeConst(result_typeid, typeLen(resultType),
-								  (Datum) 0, true,
-								  typeByVal(resultType),
-								  false, false);
+		return (Expr *) makeNullConst(result_typeid);
 	}
 
 	/*
@@ -1548,9 +1554,7 @@ simplify_op_or_func(Expr *expr, List *args)
 	newexpr->args = args;
 
 	/* Get info needed about result datatype */
-	resultType = typeidType(result_typeid);
-	resultTypByVal = typeByVal(resultType);
-	resultTypLen = typeLen(resultType);
+	get_typlenbyval(result_typeid, &resultTypLen, &resultTypByVal);
 
 	/*
 	 * It is OK to pass a dummy econtext because none of the ExecEvalExpr()
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 0d32e82ed9a382a3da2d35ec94da2aed9d55b0e2..055cd3788b903e4356c6ba7ff720132a1e8f2819 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.61 2000/09/29 18:21:23 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.62 2000/11/16 22:30:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,9 +48,9 @@ relation_info(Oid relationObjectId,
 	HeapTuple	relationTuple;
 	Form_pg_class relation;
 
-	relationTuple = SearchSysCacheTuple(RELOID,
-										ObjectIdGetDatum(relationObjectId),
-										0, 0, 0);
+	relationTuple = SearchSysCache(RELOID,
+								   ObjectIdGetDatum(relationObjectId),
+								   0, 0, 0);
 	if (!HeapTupleIsValid(relationTuple))
 		elog(ERROR, "relation_info: Relation %u not found",
 			 relationObjectId);
@@ -62,6 +62,7 @@ relation_info(Oid relationObjectId,
 		*hasindex = (relation->relhasindex) ? true : false;
 	*pages = relation->relpages;
 	*tuples = relation->reltuples;
+	ReleaseSysCache(relationTuple);
 }
 
 /*
@@ -100,9 +101,9 @@ find_secondary_indexes(Oid relationObjectId)
 		Oid			relam;
 		uint16		amorderstrategy;
 
-		indexTuple = SearchSysCacheTupleCopy(INDEXRELID,
-											 ObjectIdGetDatum(indexoid),
-											 0, 0, 0);
+		indexTuple = SearchSysCache(INDEXRELID,
+									ObjectIdGetDatum(indexoid),
+									0, 0, 0);
 		if (!HeapTupleIsValid(indexTuple))
 			elog(ERROR, "find_secondary_indexes: index %u not found",
 				 indexoid);
@@ -162,20 +163,22 @@ find_secondary_indexes(Oid relationObjectId)
 				Form_pg_amop amop;
 
 				amopTuple =
-					SearchSysCacheTuple(AMOPSTRATEGY,
-										ObjectIdGetDatum(relam),
-									ObjectIdGetDatum(index->indclass[i]),
-										UInt16GetDatum(amorderstrategy),
-										0);
+					SearchSysCache(AMOPSTRATEGY,
+								   ObjectIdGetDatum(relam),
+								   ObjectIdGetDatum(index->indclass[i]),
+								   UInt16GetDatum(amorderstrategy),
+								   0);
 				if (!HeapTupleIsValid(amopTuple))
 					elog(ERROR, "find_secondary_indexes: no amop %u %u %d",
-					   relam, index->indclass[i], (int) amorderstrategy);
+						 relam, index->indclass[i],
+						 (int) amorderstrategy);
 				amop = (Form_pg_amop) GETSTRUCT(amopTuple);
 				info->ordering[i] = amop->amopopr;
+				ReleaseSysCache(amopTuple);
 			}
 		}
 
-		heap_freetuple(indexTuple);
+		ReleaseSysCache(indexTuple);
 
 		indexinfos = lcons(info, indexinfos);
 	}
@@ -315,13 +318,16 @@ find_inheritance_children(Oid inhparent)
 bool
 has_subclass(Oid relationId)
 {
-	HeapTuple	tuple =
-		SearchSysCacheTuple(RELOID,
-							ObjectIdGetDatum(relationId),
-							0, 0, 0);
+	HeapTuple	tuple;
+	bool		result;
 
+	tuple = SearchSysCache(RELOID,
+						   ObjectIdGetDatum(relationId),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "has_subclass: Relation %u not found",
-			 relationId);
-	return ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass;
+		elog(ERROR, "has_subclass: Relation %u not found", relationId);
+
+	result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass;
+	ReleaseSysCache(tuple);
+	return result;
 }
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 63f39f2e4cbd0e0b94cd2d09ec1e90baa8fa5c69..478ae973e5c8790cfd584ba80efcf1f4750fe527 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: analyze.c,v 1.165 2000/11/08 22:09:58 tgl Exp $
+ *	$Id: analyze.c,v 1.166 2000/11/16 22:30:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2598,9 +2598,8 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
 	Form_pg_attribute *pkrel_attrs;
 	List	   *indexoidlist,
 			   *indexoidscan;
-	Form_pg_index indexStruct = NULL;
 	int			i;
-	int found=0;
+	bool		found = false;
 
 	/* ----------
 	 * Open the referenced table and get the attributes list
@@ -2616,7 +2615,7 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
 	 * Get the list of index OIDs for the table from the relcache,
 	 * and look up each one in the pg_index syscache for each unique
 	 * one, and then compare the attributes we were given to those
-         * defined.
+	 * defined.
 	 * ----------
 	 */
 	indexoidlist = RelationGetIndexList(pkrel);
@@ -2625,27 +2624,34 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
 	{
 		Oid		indexoid = lfirsti(indexoidscan);
 		HeapTuple	indexTuple;
-		List *attrl;
-		indexTuple = SearchSysCacheTuple(INDEXRELID,
-										 ObjectIdGetDatum(indexoid),
-										 0, 0, 0);
+		Form_pg_index indexStruct;
+
+		indexTuple = SearchSysCache(INDEXRELID,
+									ObjectIdGetDatum(indexoid),
+									0, 0, 0);
 		if (!HeapTupleIsValid(indexTuple))
 			elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found",
 				 indexoid);
 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
 
-		if (indexStruct->indisunique) {
+		if (indexStruct->indisunique)
+		{
+			List *attrl;
+
 			/* go through the fkconstraint->pk_attrs list */
-			foreach(attrl, fkconstraint->pk_attrs) {
+			foreach(attrl, fkconstraint->pk_attrs)
+			{
 				Ident *attr=lfirst(attrl);
-				found=0;
+				found = false;
 				for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
 				{
 					int		pkattno = indexStruct->indkey[i];
-					if (pkattno>0) {
+					if (pkattno>0)
+					{
 						char *name = NameStr(pkrel_attrs[pkattno - 1]->attname);
-						if (strcmp(name, attr->name)==0) {
-							found=1;
+						if (strcmp(name, attr->name)==0)
+						{
+							found = true;
 							break;
 						}
 					}
@@ -2654,9 +2660,9 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
 					break;
 			}
 		}
+		ReleaseSysCache(indexTuple);
 		if (found)
 			break;		
-		indexStruct = NULL;
 	}
 	if (!found)
 		elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
@@ -2681,6 +2687,7 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
 	Form_pg_attribute *pkrel_attrs;
 	List	   *indexoidlist,
 			   *indexoidscan;
+	HeapTuple	indexTuple = NULL;
 	Form_pg_index indexStruct = NULL;
 	int			i;
 
@@ -2705,17 +2712,17 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
 	foreach(indexoidscan, indexoidlist)
 	{
 		Oid		indexoid = lfirsti(indexoidscan);
-		HeapTuple	indexTuple;
 
-		indexTuple = SearchSysCacheTuple(INDEXRELID,
-										 ObjectIdGetDatum(indexoid),
-										 0, 0, 0);
+		indexTuple = SearchSysCache(INDEXRELID,
+									ObjectIdGetDatum(indexoid),
+									0, 0, 0);
 		if (!HeapTupleIsValid(indexTuple))
 			elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found",
 				 indexoid);
 		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
 		if (indexStruct->indisprimary)
 			break;
+		ReleaseSysCache(indexTuple);
 		indexStruct = NULL;
 	}
 
@@ -2747,6 +2754,8 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
 		fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr);
 	}
 
+	ReleaseSysCache(indexTuple);
+
 	heap_close(pkrel, AccessShareLock);
 }
 
@@ -2861,6 +2870,7 @@ static void
 transformColumnType(ParseState *pstate, ColumnDef *column)
 {
 	TypeName   *typename = column->typename;
+	Type		ctype = typenameType(typename->name);
 
 	/*
 	 * If the column doesn't have an explicitly specified typmod, check to
@@ -2871,7 +2881,7 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
 	 */
 	if (typename->typmod == -1)
 	{
-		switch (typeTypeId(typenameType(typename->name)))
+		switch (typeTypeId(ctype))
 		{
 			case BPCHAROID:
 				/* "char" -> "char(1)" */
@@ -2891,11 +2901,13 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
 	 * XXX this is a hangover from ancient Berkeley code that probably
 	 * doesn't work anymore anyway.
 	 */
-	 if (typeTypeRelid(typenameType(typename->name)) != InvalidOid)
+	 if (typeTypeRelid(ctype) != InvalidOid)
 	 {
 		 /* (Eventually add in here that the set can only
 		  * contain one element.)
 		  */
 		 typename->setof = true;
 	 }
+
+	 ReleaseSysCache(ctype);
 }
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index e7d8fe8d3b73f18c984e21a5349723a1f02f9ac0..1dc31dc1f075b97ac804ef4b15bdde5a095c82a6 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.42 2000/09/29 18:21:36 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.43 2000/11/16 22:30:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -190,18 +190,18 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
 		 List *args, bool agg_star, bool agg_distinct,
 		 int precedence)
 {
-	HeapTuple	theAggTuple;
+	HeapTuple	aggtuple;
 	Form_pg_aggregate aggform;
 	Aggref	   *aggref;
 
-	theAggTuple = SearchSysCacheTuple(AGGNAME,
-									  PointerGetDatum(aggname),
-									  ObjectIdGetDatum(basetype),
-									  0, 0);
+	aggtuple = SearchSysCache(AGGNAME,
+							  PointerGetDatum(aggname),
+							  ObjectIdGetDatum(basetype),
+							  0, 0);
 	/* shouldn't happen --- caller should have checked already */
-	if (!HeapTupleIsValid(theAggTuple))
+	if (!HeapTupleIsValid(aggtuple))
 		agg_error("ParseAgg", aggname, basetype);
-	aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
+	aggform = (Form_pg_aggregate) GETSTRUCT(aggtuple);
 
 	/*
 	 * There used to be a really ugly hack for count(*) here.
@@ -225,6 +225,8 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
 	aggref->aggstar = agg_star;
 	aggref->aggdistinct = agg_distinct;
 
+	ReleaseSysCache(aggtuple);
+
 	pstate->p_hasAggs = true;
 
 	return aggref;
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index cbd19f0aae4eb1ccddf06643a02e49f0eea7359a..c8f55c98e84843958b5a551315548a066e5369c9 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.72 2000/11/12 00:37:00 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.73 2000/11/16 22:30:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -953,9 +953,7 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
 
 			grpcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
 
-			grpcl->sortop = oprid(oper("<",
-									   tle->resdom->restype,
-									   tle->resdom->restype, false));
+			grpcl->sortop = any_ordering_op(tle->resdom->restype);
 
 			glist = lappend(glist, grpcl);
 		}
@@ -1151,9 +1149,10 @@ addTargetToSortList(TargetEntry *tle, List *sortlist, List *targetlist,
 		sortcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
 
 		if (opname)
-			sortcl->sortop = oprid(oper(opname,
-										tle->resdom->restype,
-										tle->resdom->restype, false));
+			sortcl->sortop = oper_oid(opname,
+									  tle->resdom->restype,
+									  tle->resdom->restype,
+									  false);
 		else
 			sortcl->sortop = any_ordering_op(tle->resdom->restype);
 
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index f0d3427d17ef5fc99c267bad7febe1bdbb7250f9..131d65cbcd07926993b8c6a98d4e47c80ef4c7d7 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.48 2000/11/09 04:14:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.49 2000/11/16 22:30:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -84,6 +84,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
 			pfree(val);
 		}
 
+		ReleaseSysCache(targetType);
+
 		result = (Node *) newcon;
 	}
 	else if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
@@ -124,9 +126,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
 		 * conversion function.
 		 */
 		FuncCall   *n = makeNode(FuncCall);
-		Type		targetType = typeidType(targetTypeId);
 
-		n->funcname = typeTypeName(targetType);
+		n->funcname = typeidTypeName(targetTypeId);
 		n->args = lcons(node, NIL);
 		n->agg_star = false;
 		n->agg_distinct = false;
@@ -136,7 +137,7 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
 		/* safety check that we got the right thing */
 		if (exprType(result) != targetTypeId)
 			elog(ERROR, "coerce_type: conversion function %s produced %s",
-				 typeTypeName(targetType),
+				 typeidTypeName(targetTypeId),
 				 typeidTypeName(exprType(result)));
 
 		/*
@@ -233,17 +234,21 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
 		MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
 		oid_array[0] = inputTypeId;
 
-		ftup = SearchSysCacheTuple(PROCNAME,
-						   PointerGetDatum(typeidTypeName(targetTypeId)),
-								   Int32GetDatum(1),
-								   PointerGetDatum(oid_array),
-								   0);
+		ftup = SearchSysCache(PROCNAME,
+							  PointerGetDatum(typeidTypeName(targetTypeId)),
+							  Int32GetDatum(1),
+							  PointerGetDatum(oid_array),
+							  0);
 		if (!HeapTupleIsValid(ftup))
 			return false;
 		/* Make sure the function's result type is as expected, too */
 		pform = (Form_pg_proc) GETSTRUCT(ftup);
 		if (pform->prorettype != targetTypeId)
+		{
+			ReleaseSysCache(ftup);
 			return false;
+		}
+		ReleaseSysCache(ftup);
 	}
 
 	return true;
@@ -272,7 +277,6 @@ coerce_type_typmod(ParseState *pstate, Node *node,
 {
 	char	   *funcname;
 	Oid			oid_array[FUNC_MAX_ARGS];
-	HeapTuple	ftup;
 
 	/*
 	 * We assume that only typmod values greater than 0 indicate a forced
@@ -288,13 +292,11 @@ coerce_type_typmod(ParseState *pstate, Node *node,
 	oid_array[1] = INT4OID;
 
 	/* attempt to find with arguments exactly as specified... */
-	ftup = SearchSysCacheTuple(PROCNAME,
-							   PointerGetDatum(funcname),
-							   Int32GetDatum(2),
-							   PointerGetDatum(oid_array),
-							   0);
-
-	if (HeapTupleIsValid(ftup))
+	if (SearchSysCacheExists(PROCNAME,
+							 PointerGetDatum(funcname),
+							 Int32GetDatum(2),
+							 PointerGetDatum(oid_array),
+							 0))
 	{
 		A_Const    *cons = makeNode(A_Const);
 		FuncCall   *func = makeNode(FuncCall);
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index ecf88ceea7e469b3790c13ec2cb905dc25eba8e7..97ed8123f673ee41e66aaa962cb7fcfcf36563cc 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.87 2000/11/16 17:27:10 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.88 2000/11/16 22:30:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -386,7 +386,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 						optup = oper(op,
 									 exprType(lexpr),
 									 exprType(tent->expr),
-									 FALSE);
+									 false);
 						opform = (Form_pg_operator) GETSTRUCT(optup);
 
 						if (opform->oprresult != BOOLOID)
@@ -399,6 +399,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 										 InvalidOid,	/* opid */
 										 opform->oprresult);
 						sublink->oper = lappend(sublink->oper, newop);
+						ReleaseSysCache(optup);
 					}
 					if (left_list != NIL)
 						elog(ERROR, "Subselect has too few fields");
@@ -740,7 +741,8 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
 {
 	Func	   *func;
 	Const	   *second_arg;
-	HeapTuple	tup;
+	HeapTuple	procTuple;
+	HeapTuple	typeTuple;
 	Form_pg_proc procStruct;
 	Form_pg_type typeStruct;
 
@@ -771,12 +773,12 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
 	/*
 	 * Lookup the function in pg_proc
 	 */
-	tup = SearchSysCacheTuple(PROCOID,
-							  ObjectIdGetDatum(func->funcid),
-							  0, 0, 0);
-	if (!HeapTupleIsValid(tup))
+	procTuple = SearchSysCache(PROCOID,
+							   ObjectIdGetDatum(func->funcid),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(procTuple))
 		elog(ERROR, "cache lookup for proc %u failed", func->funcid);
-	procStruct = (Form_pg_proc) GETSTRUCT(tup);
+	procStruct = (Form_pg_proc) GETSTRUCT(procTuple);
 
 	/*
 	 * It must be a function with two arguments where the first is of the
@@ -787,29 +789,39 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
 		procStruct->prorettype != procStruct->proargtypes[0] ||
 		procStruct->proargtypes[1] != INT4OID ||
 		procStruct->prorettype != ((Expr *) expr)->typeOid)
+	{
+		ReleaseSysCache(procTuple);
 		return false;
+	}
 
 	/*
 	 * Furthermore, the name of the function must be the same as the
 	 * argument/result type's name.
 	 */
-	tup = SearchSysCacheTuple(TYPEOID,
-							  ObjectIdGetDatum(procStruct->prorettype),
-							  0, 0, 0);
-	if (!HeapTupleIsValid(tup))
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(procStruct->prorettype),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(typeTuple))
 		elog(ERROR, "cache lookup for type %u failed",
 			 procStruct->prorettype);
-	typeStruct = (Form_pg_type) GETSTRUCT(tup);
+	typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
 	if (strncmp(NameStr(procStruct->proname),
 				NameStr(typeStruct->typname),
 				NAMEDATALEN) != 0)
+	{
+		ReleaseSysCache(procTuple);
+		ReleaseSysCache(typeTuple);
 		return false;
+	}
 
 	/*
 	 * OK, it is indeed a length-coercion function.
 	 */
 	if (coercedTypmod != NULL)
 		*coercedTypmod = DatumGetInt32(second_arg->constvalue);
+
+	ReleaseSysCache(procTuple);
+	ReleaseSysCache(typeTuple);
 	return true;
 }
 
@@ -865,6 +877,8 @@ parser_typecast_constant(Value *expr, TypeName *typename)
 	if (string_palloced)
 		pfree(const_string);
 
+	ReleaseSysCache(tp);
+
 	return (Node *) con;
 }
 
@@ -881,11 +895,9 @@ parser_typecast_expression(ParseState *pstate,
 						   Node *expr, TypeName *typename)
 {
 	Oid			inputType = exprType(expr);
-	Type		tp;
 	Oid			targetType;
 
-	tp = typenameType(TypeNameToInternalName(typename));
-	targetType = typeTypeId(tp);
+	targetType = typenameTypeId(TypeNameToInternalName(typename));
 
 	if (inputType == InvalidOid)
 		return expr;			/* do nothing if NULL input */
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index ea0544f701e97cfd0a3cc7044ea05c095737aa54..688c5bfa306c4ebb2227d25f02500efbb8fdd981 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.93 2000/11/11 19:49:26 thomas Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.94 2000/11/16 22:30:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -354,19 +354,19 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 		CandidateList candidates;
 
 		/* try for exact match first... */
-		if (SearchSysCacheTuple(AGGNAME,
-								PointerGetDatum(funcname),
-								ObjectIdGetDatum(basetype),
-								0, 0))
+		if (SearchSysCacheExists(AGGNAME,
+								 PointerGetDatum(funcname),
+								 ObjectIdGetDatum(basetype),
+								 0, 0))
 			return (Node *) ParseAgg(pstate, funcname, basetype,
 									 fargs, agg_star, agg_distinct,
 									 precedence);
 
 		/* check for aggregate-that-accepts-any-type (eg, COUNT) */
-		if (SearchSysCacheTuple(AGGNAME,
-								PointerGetDatum(funcname),
-								ObjectIdGetDatum(0),
-								0, 0))
+		if (SearchSysCacheExists(AGGNAME,
+								 PointerGetDatum(funcname),
+								 ObjectIdGetDatum(0),
+								 0, 0))
 			return (Node *) ParseAgg(pstate, funcname, 0,
 									 fargs, agg_star, agg_distinct,
 									 precedence);
@@ -450,7 +450,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 			if (rte->relname == NULL)
 				elog(ERROR,
 					 "function applied to tuple is not supported for subSELECTs");
-			toid = typeTypeId(typenameType(rte->relname));
+			toid = typenameTypeId(rte->relname);
 
 			/* replace it in the arg list */
 			lfirst(i) = makeVar(vnum, 0, toid, -1, sublevels_up);
@@ -531,15 +531,14 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 			 */
 			if (nargs == 1)
 			{
-				Type		tp;
+				Oid			targetType;
 
-				tp = SearchSysCacheTuple(TYPENAME,
-										 PointerGetDatum(funcname),
-										 0, 0, 0);
-				if (HeapTupleIsValid(tp))
+				targetType = GetSysCacheOid(TYPENAME,
+											PointerGetDatum(funcname),
+											0, 0, 0);
+				if (OidIsValid(targetType))
 				{
 					Oid			sourceType = oid_array[0];
-					Oid			targetType = typeTypeId(tp);
 					Node	   *arg1 = lfirst(fargs);
 
 					if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) ||
@@ -573,6 +572,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 				if (typeTypeFlag(tp) == 'c')
 					elog(ERROR, "No such attribute or function '%s'",
 						 funcname);
+				ReleaseSysCache(tp);
 			}
 
 			/* Else generate a detailed complaint */
@@ -1037,11 +1037,11 @@ func_get_detail(char *funcname,
 	HeapTuple	ftup;
 
 	/* attempt to find with arguments exactly as specified... */
-	ftup = SearchSysCacheTuple(PROCNAME,
-							   PointerGetDatum(funcname),
-							   Int32GetDatum(nargs),
-							   PointerGetDatum(argtypes),
-							   0);
+	ftup = SearchSysCache(PROCNAME,
+						  PointerGetDatum(funcname),
+						  Int32GetDatum(nargs),
+						  PointerGetDatum(argtypes),
+						  0);
 
 	if (HeapTupleIsValid(ftup))
 	{
@@ -1085,11 +1085,11 @@ func_get_detail(char *funcname,
 				if (ncandidates == 1)
 				{
 					*true_typeids = current_function_typeids->args;
-					ftup = SearchSysCacheTuple(PROCNAME,
-											   PointerGetDatum(funcname),
-											   Int32GetDatum(nargs),
+					ftup = SearchSysCache(PROCNAME,
+										  PointerGetDatum(funcname),
+										  Int32GetDatum(nargs),
 										  PointerGetDatum(*true_typeids),
-											   0);
+										  0);
 					Assert(HeapTupleIsValid(ftup));
 					break;
 				}
@@ -1107,12 +1107,13 @@ func_get_detail(char *funcname,
 					if (*true_typeids != NULL)
 					{
 						/* was able to choose a best candidate */
-						ftup = SearchSysCacheTuple(PROCNAME,
-											   PointerGetDatum(funcname),
-												   Int32GetDatum(nargs),
-										  PointerGetDatum(*true_typeids),
-												   0);
+						ftup = SearchSysCache(PROCNAME,
+											  PointerGetDatum(funcname),
+											  Int32GetDatum(nargs),
+											  PointerGetDatum(*true_typeids),
+											  0);
 						Assert(HeapTupleIsValid(ftup));
+						break;
 					}
 
 					/*
@@ -1143,6 +1144,7 @@ func_get_detail(char *funcname,
 		*funcid = ftup->t_data->t_oid;
 		*rettype = pform->prorettype;
 		*retset = pform->proretset;
+		ReleaseSysCache(ftup);
 		return true;
 	}
 	return false;
@@ -1284,7 +1286,7 @@ find_inheritors(Oid relid, Oid **supervec)
 
 			relid = lfirsti(elt);
 			rd = heap_open(relid, NoLock);
-			trelid = typeTypeId(typenameType(RelationGetRelationName(rd)));
+			trelid = typenameTypeId(RelationGetRelationName(rd));
 			heap_close(rd, NoLock);
 			*relidvec++ = trelid;
 		}
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index d23c5c1e7c749e1fb0bdc497795e2a8fc393b3a3..1d846bd4bba406a433f4706e990c2850ef358660 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.48 2000/10/31 10:22:11 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.49 2000/11/16 22:30:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -67,7 +67,6 @@ make_operand(char *opname,
 			 Oid target_typeId)
 {
 	Node	   *result;
-	Type		target_type = typeidType(target_typeId);
 
 	if (tree != NULL)
 	{
@@ -80,15 +79,7 @@ make_operand(char *opname,
 	else
 	{
 		/* otherwise, this is a NULL value */
-		Const	   *con = makeNode(Const);
-
-		con->consttype = target_typeId;
-		con->constlen = typeLen(target_type);
-		con->constvalue = (Datum) NULL;
-		con->constisnull = true;
-		con->constbyval = typeByVal(target_type);
-		con->constisset = false;
-		result = (Node *) con;
+		result = (Node *) makeNullConst(target_typeId);
 	}
 
 	return result;
@@ -137,7 +128,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
 	/* otherwise, binary operator */
 	else
 	{
-		tup = oper(opname, ltypeId, rtypeId, FALSE);
+		tup = oper(opname, ltypeId, rtypeId, false);
 		opform = (Form_pg_operator) GETSTRUCT(tup);
 		left = make_operand(opname, ltree, ltypeId, opform->oprleft);
 		right = make_operand(opname, rtree, rtypeId, opform->oprright);
@@ -159,6 +150,8 @@ make_op(char *opname, Node *ltree, Node *rtree)
 	else
 		result->args = makeList2(left, right);
 
+	ReleaseSysCache(tup);
+
 	return result;
 }	/* make_op() */
 
@@ -183,10 +176,10 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
 		HeapTuple	tp;
 		Form_pg_attribute att_tup;
 
-		tp = SearchSysCacheTuple(ATTNUM,
-								 ObjectIdGetDatum(rte->relid),
-								 Int16GetDatum(attrno),
-								 0, 0);
+		tp = SearchSysCache(ATTNUM,
+							ObjectIdGetDatum(rte->relid),
+							Int16GetDatum(attrno),
+							0, 0);
 		/* this shouldn't happen... */
 		if (!HeapTupleIsValid(tp))
 			elog(ERROR, "Relation %s does not have attribute %d",
@@ -194,6 +187,7 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
 		att_tup = (Form_pg_attribute) GETSTRUCT(tp);
 		vartypeid = att_tup->atttypid;
 		type_mod = att_tup->atttypmod;
+		ReleaseSysCache(tp);
 	}
 	else
 	{
@@ -249,7 +243,8 @@ transformArraySubscripts(ParseState *pstate,
 	Oid			typearray,
 				typeelement,
 				typeresult;
-	HeapTuple	type_tuple;
+	HeapTuple	type_tuple_array,
+				type_tuple_element;
 	Form_pg_type type_struct_array,
 				type_struct_element;
 	bool		isSlice = forceSlice;
@@ -261,13 +256,13 @@ transformArraySubscripts(ParseState *pstate,
 	/* Get the type tuple for the array */
 	typearray = exprType(arrayBase);
 
-	type_tuple = SearchSysCacheTuple(TYPEOID,
-									 ObjectIdGetDatum(typearray),
-									 0, 0, 0);
-	if (!HeapTupleIsValid(type_tuple))
+	type_tuple_array = SearchSysCache(TYPEOID,
+									  ObjectIdGetDatum(typearray),
+									  0, 0, 0);
+	if (!HeapTupleIsValid(type_tuple_array))
 		elog(ERROR, "transformArraySubscripts: Cache lookup failed for array type %u",
 			 typearray);
-	type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple);
+	type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple_array);
 
 	typeelement = type_struct_array->typelem;
 	if (typeelement == InvalidOid)
@@ -275,13 +270,13 @@ transformArraySubscripts(ParseState *pstate,
 			 NameStr(type_struct_array->typname));
 
 	/* Get the type tuple for the array element type */
-	type_tuple = SearchSysCacheTuple(TYPEOID,
-									 ObjectIdGetDatum(typeelement),
-									 0, 0, 0);
-	if (!HeapTupleIsValid(type_tuple))
+	type_tuple_element = SearchSysCache(TYPEOID,
+										ObjectIdGetDatum(typeelement),
+										0, 0, 0);
+	if (!HeapTupleIsValid(type_tuple_element))
 		elog(ERROR, "transformArraySubscripts: Cache lookup failed for array element type %u",
 			 typeelement);
-	type_struct_element = (Form_pg_type) GETSTRUCT(type_tuple);
+	type_struct_element = (Form_pg_type) GETSTRUCT(type_tuple_element);
 
 	/*
 	 * A list containing only single subscripts refers to a single array
@@ -398,6 +393,9 @@ transformArraySubscripts(ParseState *pstate,
 	aref->refexpr = arrayBase;
 	aref->refassgnexpr = assignFrom;
 
+	ReleaseSysCache(type_tuple_array);
+	ReleaseSysCache(type_tuple_element);
+
 	return aref;
 }
 
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 7d3919a1fc6edf5d059d3d16068cd08fedb362c9..a44a740dc926045b6dba4f7cfaa5835805a164fe 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.43 2000/11/11 19:49:26 thomas Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.44 2000/11/16 22:30:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,25 +38,21 @@ static void op_error(char *op, Oid arg1, Oid arg2);
 static void unary_op_error(char *op, Oid arg, bool is_left_op);
 
 
+/* Select an ordering operator for the given datatype */
 Oid
 any_ordering_op(Oid restype)
 {
-	Operator	order_op;
 	Oid			order_opid;
 
-	order_op = oper("<", restype, restype, TRUE);
-	if (!HeapTupleIsValid(order_op))
-	{
+	order_opid = oper_oid("<", restype, restype, true);
+	if (!OidIsValid(order_opid))
 		elog(ERROR, "Unable to identify an ordering operator '%s' for type '%s'"
 			 "\n\tUse an explicit ordering operator or modify the query",
 			 "<", typeidTypeName(restype));
-	}
-	order_opid = oprid(order_op);
-
 	return order_opid;
 }
 
-/* given operator, return the operator OID */
+/* given operator tuple, return the operator OID */
 Oid
 oprid(Operator op)
 {
@@ -502,9 +498,10 @@ oper_select_candidate(int nargs,
 
 
 /* oper_exact()
- * Given operator, and arguments, return oper struct or NULL.
- * Inputs:
- * arg1, arg2: Type IDs
+ * Given operator, types of arg1 and arg2, return oper struct or NULL.
+ *
+ * NOTE: on success, the returned object is a syscache entry.  The caller
+ * must ReleaseSysCache() the entry when done with it.
  */
 static Operator
 oper_exact(char *op, Oid arg1, Oid arg2)
@@ -517,20 +514,21 @@ oper_exact(char *op, Oid arg1, Oid arg2)
 	else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
 		arg2 = arg1;
 
-	tup = SearchSysCacheTuple(OPERNAME,
-							  PointerGetDatum(op),
-							  ObjectIdGetDatum(arg1),
-							  ObjectIdGetDatum(arg2),
-							  CharGetDatum('b'));
+	tup = SearchSysCache(OPERNAME,
+						 PointerGetDatum(op),
+						 ObjectIdGetDatum(arg1),
+						 ObjectIdGetDatum(arg2),
+						 CharGetDatum('b'));
 
 	return (Operator) tup;
-}	/* oper_exact() */
+}
 
 
 /* oper_inexact()
- * Given operator, types of arg1, and arg2, return oper struct or NULL.
- * Inputs:
- * arg1, arg2: Type IDs
+ * Given operator, types of arg1 and arg2, return oper struct or NULL.
+ *
+ * NOTE: on success, the returned object is a syscache entry.  The caller
+ * must ReleaseSysCache() the entry when done with it.
  */
 static Operator
 oper_inexact(char *op, Oid arg1, Oid arg2)
@@ -556,11 +554,11 @@ oper_inexact(char *op, Oid arg1, Oid arg2)
 	/* Or found exactly one? Then proceed... */
 	else if (ncandidates == 1)
 	{
-		tup = SearchSysCacheTuple(OPERNAME,
-								  PointerGetDatum(op),
-								  ObjectIdGetDatum(candidates->args[0]),
-								  ObjectIdGetDatum(candidates->args[1]),
-								  CharGetDatum('b'));
+		tup = SearchSysCache(OPERNAME,
+							 PointerGetDatum(op),
+							 ObjectIdGetDatum(candidates->args[0]),
+							 ObjectIdGetDatum(candidates->args[1]),
+							 CharGetDatum('b'));
 		Assert(HeapTupleIsValid(tup));
 	}
 
@@ -572,43 +570,68 @@ oper_inexact(char *op, Oid arg1, Oid arg2)
 		targetOids = oper_select_candidate(2, inputOids, candidates);
 		if (targetOids != NULL)
 		{
-			tup = SearchSysCacheTuple(OPERNAME,
-									  PointerGetDatum(op),
-									  ObjectIdGetDatum(targetOids[0]),
-									  ObjectIdGetDatum(targetOids[1]),
-									  CharGetDatum('b'));
+			tup = SearchSysCache(OPERNAME,
+								 PointerGetDatum(op),
+								 ObjectIdGetDatum(targetOids[0]),
+								 ObjectIdGetDatum(targetOids[1]),
+								 CharGetDatum('b'));
 		}
 		else
 			tup = NULL;
 	}
 	return (Operator) tup;
-}	/* oper_inexact() */
+}
 
 
-/* oper()
- * Given operator, types of arg1, and arg2, return oper struct.
- * Inputs:
- * arg1, arg2: Type IDs
+/* oper() -- search for a binary operator
+ * Given operator name, types of arg1 and arg2, return oper struct.
+ *
+ * If no matching operator found, return NULL if noError is true,
+ * raise an error if it is false.
+ *
+ * NOTE: on success, the returned object is a syscache entry.  The caller
+ * must ReleaseSysCache() the entry when done with it.
  */
 Operator
-oper(char *opname, Oid ltypeId, Oid rtypeId, bool noWarnings)
+oper(char *opname, Oid ltypeId, Oid rtypeId, bool noError)
 {
 	HeapTuple	tup;
 
 	/* check for exact match on this operator... */
 	if (HeapTupleIsValid(tup = oper_exact(opname, ltypeId, rtypeId)))
-	{
-	}
+		return (Operator) tup;
+
 	/* try to find a match on likely candidates... */
-	else if (HeapTupleIsValid(tup = oper_inexact(opname, ltypeId, rtypeId)))
-	{
-	}
-	else if (!noWarnings)
+	if (HeapTupleIsValid(tup = oper_inexact(opname, ltypeId, rtypeId)))
+		return (Operator) tup;
+
+	if (!noError)
 		op_error(opname, ltypeId, rtypeId);
 
-	return (Operator) tup;
-}	/* oper() */
+	return (Operator) NULL;
+}
+
+/* oper_oid() -- get OID of a binary operator
+ *
+ * This is a convenience routine that extracts only the operator OID
+ * from the result of oper().  InvalidOid is returned if the lookup
+ * fails and noError is true.
+ */
+Oid
+oper_oid(char *op, Oid arg1, Oid arg2, bool noError)
+{
+	Operator	optup;
+	Oid			result;
 
+	optup = oper(op, arg1, arg2, noError);
+	if (optup != NULL)
+	{
+		result = oprid(optup);
+		ReleaseSysCache(optup);
+		return result;
+	}
+	return InvalidOid;
+}
 
 /* unary_oper_get_candidates()
  *	given opname, find all possible types for which
@@ -671,8 +694,13 @@ unary_oper_get_candidates(char *opname,
 }	/* unary_oper_get_candidates() */
 
 
-/* Given unary right-side operator (operator on right), return oper struct */
-/* arg-- type id */
+/* Given unary right operator (operator on right), return oper struct
+ *
+ * Always raises error on failure.
+ *
+ * NOTE: on success, the returned object is a syscache entry.  The caller
+ * must ReleaseSysCache() the entry when done with it.
+ */
 Operator
 right_oper(char *op, Oid arg)
 {
@@ -682,11 +710,11 @@ right_oper(char *op, Oid arg)
 	Oid		   *targetOid;
 
 	/* Try for exact match */
-	tup = SearchSysCacheTuple(OPERNAME,
-							  PointerGetDatum(op),
-							  ObjectIdGetDatum(arg),
-							  ObjectIdGetDatum(InvalidOid),
-							  CharGetDatum('r'));
+	tup = SearchSysCache(OPERNAME,
+						 PointerGetDatum(op),
+						 ObjectIdGetDatum(arg),
+						 ObjectIdGetDatum(InvalidOid),
+						 CharGetDatum('r'));
 
 	if (!HeapTupleIsValid(tup))
 	{
@@ -696,21 +724,21 @@ right_oper(char *op, Oid arg)
 			unary_op_error(op, arg, FALSE);
 		else if (ncandidates == 1)
 		{
-			tup = SearchSysCacheTuple(OPERNAME,
-									  PointerGetDatum(op),
-								   ObjectIdGetDatum(candidates->args[0]),
-									  ObjectIdGetDatum(InvalidOid),
-									  CharGetDatum('r'));
+			tup = SearchSysCache(OPERNAME,
+								 PointerGetDatum(op),
+								 ObjectIdGetDatum(candidates->args[0]),
+								 ObjectIdGetDatum(InvalidOid),
+								 CharGetDatum('r'));
 		}
 		else
 		{
 			targetOid = oper_select_candidate(1, &arg, candidates);
 			if (targetOid != NULL)
-				tup = SearchSysCacheTuple(OPERNAME,
-										  PointerGetDatum(op),
-										  ObjectIdGetDatum(targetOid[0]),
-										  ObjectIdGetDatum(InvalidOid),
-										  CharGetDatum('r'));
+				tup = SearchSysCache(OPERNAME,
+									 PointerGetDatum(op),
+									 ObjectIdGetDatum(targetOid[0]),
+									 ObjectIdGetDatum(InvalidOid),
+									 CharGetDatum('r'));
 		}
 
 		if (!HeapTupleIsValid(tup))
@@ -721,8 +749,13 @@ right_oper(char *op, Oid arg)
 }	/* right_oper() */
 
 
-/* Given unary left-side operator (operator on left), return oper struct */
-/* arg--type id */
+/* Given unary left operator (operator on left), return oper struct
+ *
+ * Always raises error on failure.
+ *
+ * NOTE: on success, the returned object is a syscache entry.  The caller
+ * must ReleaseSysCache() the entry when done with it.
+ */
 Operator
 left_oper(char *op, Oid arg)
 {
@@ -732,11 +765,11 @@ left_oper(char *op, Oid arg)
 	Oid		   *targetOid;
 
 	/* Try for exact match */
-	tup = SearchSysCacheTuple(OPERNAME,
-							  PointerGetDatum(op),
-							  ObjectIdGetDatum(InvalidOid),
-							  ObjectIdGetDatum(arg),
-							  CharGetDatum('l'));
+	tup = SearchSysCache(OPERNAME,
+						 PointerGetDatum(op),
+						 ObjectIdGetDatum(InvalidOid),
+						 ObjectIdGetDatum(arg),
+						 CharGetDatum('l'));
 
 	if (!HeapTupleIsValid(tup))
 	{
@@ -746,21 +779,21 @@ left_oper(char *op, Oid arg)
 			unary_op_error(op, arg, TRUE);
 		else if (ncandidates == 1)
 		{
-			tup = SearchSysCacheTuple(OPERNAME,
-									  PointerGetDatum(op),
-									  ObjectIdGetDatum(InvalidOid),
-								   ObjectIdGetDatum(candidates->args[0]),
-									  CharGetDatum('l'));
+			tup = SearchSysCache(OPERNAME,
+								 PointerGetDatum(op),
+								 ObjectIdGetDatum(InvalidOid),
+								 ObjectIdGetDatum(candidates->args[0]),
+								 CharGetDatum('l'));
 		}
 		else
 		{
 			targetOid = oper_select_candidate(1, &arg, candidates);
 			if (targetOid != NULL)
-				tup = SearchSysCacheTuple(OPERNAME,
-										  PointerGetDatum(op),
-										  ObjectIdGetDatum(InvalidOid),
-										  ObjectIdGetDatum(targetOid[0]),
-										  CharGetDatum('l'));
+				tup = SearchSysCache(OPERNAME,
+									 PointerGetDatum(op),
+									 ObjectIdGetDatum(InvalidOid),
+									 ObjectIdGetDatum(targetOid[0]),
+									 CharGetDatum('l'));
 		}
 
 		if (!HeapTupleIsValid(tup))
@@ -778,24 +811,17 @@ left_oper(char *op, Oid arg)
 static void
 op_error(char *op, Oid arg1, Oid arg2)
 {
-	Type		tp1 = NULL,
-				tp2 = NULL;
-
-	if (typeidIsValid(arg1))
-		tp1 = typeidType(arg1);
-	else
+	if (!typeidIsValid(arg1))
 		elog(ERROR, "Left hand side of operator '%s' has an unknown type"
 			 "\n\tProbably a bad attribute name", op);
 
-	if (typeidIsValid(arg2))
-		tp2 = typeidType(arg2);
-	else
+	if (!typeidIsValid(arg2))
 		elog(ERROR, "Right hand side of operator %s has an unknown type"
 			 "\n\tProbably a bad attribute name", op);
 
 	elog(ERROR, "Unable to identify an operator '%s' for types '%s' and '%s'"
 		 "\n\tYou will have to retype this query using an explicit cast",
-		 op, typeTypeName(tp1), typeTypeName(tp2));
+		 op, typeidTypeName(arg1), typeidTypeName(arg2));
 }
 
 /* unary_op_error()
@@ -805,20 +831,14 @@ op_error(char *op, Oid arg1, Oid arg2)
 static void
 unary_op_error(char *op, Oid arg, bool is_left_op)
 {
-	Type		tp1 = NULL;
-
-	if (typeidIsValid(arg))
-		tp1 = typeidType(arg);
-	else
-	{
+	if (!typeidIsValid(arg))
 		elog(ERROR, "Argument of %s operator '%s' has an unknown type"
 			 "\n\tProbably a bad attribute name",
 			 (is_left_op ? "left" : "right"),
 			 op);
-	}
 
 	elog(ERROR, "Unable to identify a %s operator '%s' for type '%s'"
 		 "\n\tYou may need to add parentheses or an explicit cast",
 		 (is_left_op ? "left" : "right"),
-		 op, typeTypeName(tp1));
+		 op, typeidTypeName(arg));
 }
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index c582bd54abee770960100d928db50a9738f995be..5a699624097bc477322952caaefa30903455dcc4 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.32 2000/06/08 22:37:18 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.33 2000/11/16 22:30:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,63 +28,45 @@
 bool
 typeidIsValid(Oid id)
 {
-	return (SearchSysCacheTuple(TYPEOID,
+	return SearchSysCacheExists(TYPEOID,
 								ObjectIdGetDatum(id),
-								0, 0, 0) != NULL);
-}
-
-/* return a type name, given a typeid */
-char *
-typeidTypeName(Oid id)
-{
-	HeapTuple	tup;
-	Form_pg_type typetuple;
-
-	if (!(tup = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(id),
-									0, 0, 0)))
-	{
-		elog(ERROR, "Unable to locate type oid %u in catalog", id);
-		return NULL;
-	}
-	typetuple = (Form_pg_type) GETSTRUCT(tup);
-	/* pstrdup here because result may need to outlive the syscache entry */
-	return pstrdup(NameStr(typetuple->typname));
+								0, 0, 0);
 }
 
 /* return a Type structure, given a type id */
+/* NB: caller must ReleaseSysCache the type tuple when done with it */
 Type
 typeidType(Oid id)
 {
 	HeapTuple	tup;
 
-	if (!(tup = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(id),
-									0, 0, 0)))
-	{
+	tup = SearchSysCache(TYPEOID,
+						 ObjectIdGetDatum(id),
+						 0, 0, 0);
+	if (!HeapTupleIsValid(tup))
 		elog(ERROR, "Unable to locate type oid %u in catalog", id);
-		return NULL;
-	}
 	return (Type) tup;
 }
 
 /* return a Type structure, given type name */
+/* NB: caller must ReleaseSysCache the type tuple when done with it */
 Type
 typenameType(char *s)
 {
 	HeapTuple	tup;
 
 	if (s == NULL)
-		elog(ERROR, "type(): Null type");
+		elog(ERROR, "typenameType: Null typename");
 
-	if (!(tup = SearchSysCacheTuple(TYPENAME,
-									PointerGetDatum(s),
-									0, 0, 0)))
+	tup = SearchSysCache(TYPENAME,
+						 PointerGetDatum(s),
+						 0, 0, 0);
+	if (!HeapTupleIsValid(tup))
 		elog(ERROR, "Unable to locate type name '%s' in catalog", s);
 	return (Type) tup;
 }
 
-/* given type, return the type OID */
+/* given type (as type struct), return the type OID */
 Oid
 typeTypeId(Type tp)
 {
@@ -134,6 +116,54 @@ typeTypeFlag(Type t)
 	return typ->typtype;
 }
 
+Oid
+typeTypeRelid(Type typ)
+{
+	Form_pg_type typtup;
+
+	typtup = (Form_pg_type) GETSTRUCT(typ);
+
+	return typtup->typrelid;
+}
+
+#ifdef NOT_USED
+Oid
+typeTypElem(Type typ)
+{
+	Form_pg_type typtup;
+
+	typtup = (Form_pg_type) GETSTRUCT(typ);
+
+	return typtup->typelem;
+}
+#endif
+
+#ifdef NOT_USED
+/* Given a type structure, return the in-conversion function of the type */
+Oid
+typeInfunc(Type typ)
+{
+	Form_pg_type typtup;
+
+	typtup = (Form_pg_type) GETSTRUCT(typ);
+
+	return typtup->typinput;
+}
+#endif
+
+#ifdef NOT_USED
+/* Given a type structure, return the out-conversion function of the type */
+Oid
+typeOutfunc(Type typ)
+{
+	Form_pg_type typtup;
+
+	typtup = (Form_pg_type) GETSTRUCT(typ);
+
+	return typtup->typoutput;
+}
+#endif
+
 /* Given a type structure and a string, returns the internal form of
    that string */
 Datum
@@ -160,109 +190,72 @@ typeidOutfunc(Oid type_id)
 	Form_pg_type type;
 	Oid			outfunc;
 
-	typeTuple = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(type_id),
-									0, 0, 0);
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(type_id),
+							   0, 0, 0);
 	if (!HeapTupleIsValid(typeTuple))
 		elog(ERROR, "typeidOutfunc: Invalid type - oid = %u", type_id);
 
 	type = (Form_pg_type) GETSTRUCT(typeTuple);
 	outfunc = type->typoutput;
+	ReleaseSysCache(typeTuple);
 	return outfunc;
 }
 
 #endif
 
+/* return a type name, given a typeid */
+char *
+typeidTypeName(Oid id)
+{
+	HeapTuple	tup;
+	Form_pg_type typetuple;
+	char	   *result;
+
+	tup = SearchSysCache(TYPEOID,
+						 ObjectIdGetDatum(id),
+						 0, 0, 0);
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "Unable to locate type oid %u in catalog", id);
+	typetuple = (Form_pg_type) GETSTRUCT(tup);
+	/*
+	 * pstrdup here because result may need to outlive the syscache entry
+	 * (eg, it might end up as part of a parse tree that will outlive
+	 * the current transaction...)
+	 */
+	result = pstrdup(NameStr(typetuple->typname));
+	ReleaseSysCache(tup);
+	return result;
+}
+
+/* given a typeid, return the type's typrelid (associated relation, if any) */
 Oid
 typeidTypeRelid(Oid type_id)
 {
 	HeapTuple	typeTuple;
 	Form_pg_type type;
+	Oid			result;
 
-	typeTuple = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(type_id),
-									0, 0, 0);
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(type_id),
+							   0, 0, 0);
 	if (!HeapTupleIsValid(typeTuple))
 		elog(ERROR, "typeidTypeRelid: Invalid type - oid = %u", type_id);
 
 	type = (Form_pg_type) GETSTRUCT(typeTuple);
-	return type->typrelid;
-}
-
-Oid
-typeTypeRelid(Type typ)
-{
-	Form_pg_type typtup;
-
-	typtup = (Form_pg_type) GETSTRUCT(typ);
-
-	return typtup->typrelid;
-}
-
-#ifdef NOT_USED
-Oid
-typeTypElem(Type typ)
-{
-	Form_pg_type typtup;
-
-	typtup = (Form_pg_type) GETSTRUCT(typ);
-
-	return typtup->typelem;
-}
-#endif
-
-#ifdef NOT_USED
-/* Given the attribute type of an array return the attribute type of
-   an element of the array */
-Oid
-GetArrayElementType(Oid typearray)
-{
-	HeapTuple	type_tuple;
-	Form_pg_type type_struct_array;
-
-	type_tuple = SearchSysCacheTuple(TYPEOID,
-									 ObjectIdGetDatum(typearray),
-									 0, 0, 0);
-
-	if (!HeapTupleIsValid(type_tuple))
-		elog(ERROR, "GetArrayElementType: Cache lookup failed for type %u",
-			 typearray);
-
-	/* get the array type struct from the type tuple */
-	type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple);
-
-	if (type_struct_array->typelem == InvalidOid)
-	{
-		elog(ERROR, "GetArrayElementType: type %s is not an array",
-			 NameStr(type_struct_array->typname));
-	}
-
-	return type_struct_array->typelem;
+	result = type->typrelid;
+	ReleaseSysCache(typeTuple);
+	return result;
 }
-#endif
 
-#ifdef NOT_USED
-/* Given a type structure, return the in-conversion function of the type */
+/* given a type name, return the type's typeid */
 Oid
-typeInfunc(Type typ)
+typenameTypeId(char *s)
 {
-	Form_pg_type typtup;
-
-	typtup = (Form_pg_type) GETSTRUCT(typ);
+	Type		typ = typenameType(s);
+	Oid			result;
 
-	return typtup->typinput;
+	result = typ->t_data->t_oid;
+	ReleaseSysCache(typ);
+	return result;
 }
-#endif
-
-#ifdef NOT_USED
-/* Given a type structure, return the out-conversion function of the type */
-Oid
-typeOutfunc(Type typ)
-{
-	Form_pg_type typtup;
-
-	typtup = (Form_pg_type) GETSTRUCT(typ);
-
-	return typtup->typoutput;
-}
-#endif
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index cffe624deb4f60ac062f6767c5f29ab8d2ddfc92..3e1f8f4a68d72b9b4ed71775ba6235fa884bb874 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -7,12 +7,13 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.50 2000/10/05 19:11:34 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.51 2000/11/16 22:30:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
@@ -555,20 +556,6 @@ AddNotQual(Query *parsetree, Node *qual)
 }
 
 
-/* Build a NULL constant expression of the given type */
-static Node *
-make_null(Oid type)
-{
-	Const	   *c = makeNode(Const);
-
-	c->consttype = type;
-	c->constlen = get_typlen(type);
-	c->constvalue = PointerGetDatum(NULL);
-	c->constisnull = true;
-	c->constbyval = get_typbyval(type);
-	return (Node *) c;
-}
-
 /* Find a targetlist entry by resno */
 static Node *
 FindMatchingNew(List *tlist, int attno)
@@ -656,7 +643,7 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
 				else
 				{
 					/* Otherwise replace unmatched var with a null */
-					return make_null(var->vartype);
+					return (Node *) makeNullConst(var->vartype);
 				}
 			}
 			else
@@ -796,7 +783,7 @@ HandleRIRAttributeRule_mutator(Node *node,
 			{					/* HACK: disallow SET variables */
 				*context->modified = TRUE;
 				*context->badsql = TRUE;
-				return make_null(var->vartype);
+				return (Node *) makeNullConst(var->vartype);
 			}
 			else
 			{
@@ -813,7 +800,7 @@ HandleRIRAttributeRule_mutator(Node *node,
 					n = FindMatchingTLEntry(context->targetlist,
 											name_to_look_for);
 					if (n == NULL)
-						return make_null(var->vartype);
+						return (Node *) makeNullConst(var->vartype);
 					/* Make a copy of the tlist item to return */
 					n = copyObject(n);
 
diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c
index ba409f4fbf6fe27c57ec6fe905d57c157a1461ca..760614461cda72c482beb864dc8ff0b8be536911 100644
--- a/src/backend/rewrite/rewriteRemove.c
+++ b/src/backend/rewrite/rewriteRemove.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.40 2000/09/29 18:21:24 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.41 2000/11/16 22:30:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,21 +35,26 @@ RewriteGetRuleEventRel(char *rulename)
 {
 	HeapTuple	htup;
 	Oid			eventrel;
+	char	   *result;
 
-	htup = SearchSysCacheTuple(RULENAME,
-							   PointerGetDatum(rulename),
-							   0, 0, 0);
+	htup = SearchSysCache(RULENAME,
+						  PointerGetDatum(rulename),
+						  0, 0, 0);
 	if (!HeapTupleIsValid(htup))
 		elog(ERROR, "Rule or view \"%s\" not found",
 		  ((strncmp(rulename, "_RET", 4) == 0) ? (rulename + 4) : rulename));
 	eventrel = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class;
-	htup = SearchSysCacheTuple(RELOID,
-							   PointerGetDatum(eventrel),
-							   0, 0, 0);
+	ReleaseSysCache(htup);
+
+	htup = SearchSysCache(RELOID,
+						  PointerGetDatum(eventrel),
+						  0, 0, 0);
 	if (!HeapTupleIsValid(htup))
 		elog(ERROR, "Relation %u not found", eventrel);
 
-	return NameStr(((Form_pg_class) GETSTRUCT(htup))->relname);
+	result = pstrdup(NameStr(((Form_pg_class) GETSTRUCT(htup))->relname));
+	ReleaseSysCache(htup);
+	return result;
 }
 
 /*
@@ -75,9 +80,9 @@ RemoveRewriteRule(char *ruleName)
 	/*
 	 * Find the tuple for the target rule.
 	 */
-	tuple = SearchSysCacheTupleCopy(RULENAME,
-									PointerGetDatum(ruleName),
-									0, 0, 0);
+	tuple = SearchSysCacheCopy(RULENAME,
+							   PointerGetDatum(ruleName),
+							   0, 0, 0);
 
 	/*
 	 * complain if no rule with such name existed
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
index 264021da223fedfd33463bc103e5b34d224adc62..30e4ba6e603cc3cbd3d17b20bb9860051ca83e25 100644
--- a/src/backend/rewrite/rewriteSupport.c
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.44 2000/09/29 18:21:24 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.45 2000/11/16 22:30:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,19 +18,15 @@
 #include "catalog/catname.h"
 #include "catalog/indexing.h"
 #include "rewrite/rewriteSupport.h"
-#include "utils/catcache.h"
 #include "utils/syscache.h"
 
 
-int
+bool
 IsDefinedRewriteRule(char *ruleName)
 {
-	HeapTuple	tuple;
-
-	tuple = SearchSysCacheTuple(RULENAME,
+	return SearchSysCacheExists(RULENAME,
 								PointerGetDatum(ruleName),
 								0, 0, 0);
-	return HeapTupleIsValid(tuple);
 }
 
 /*
@@ -59,10 +55,11 @@ SetRelationRuleStatus(Oid relationId, bool relHasRules,
 	 * Find the tuple to update in pg_class, using syscache for the lookup.
 	 */
 	relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
-	tuple = SearchSysCacheTupleCopy(RELOID,
-									ObjectIdGetDatum(relationId),
-									0, 0, 0);
-	Assert(HeapTupleIsValid(tuple));
+	tuple = SearchSysCacheCopy(RELOID,
+							   ObjectIdGetDatum(relationId),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "SetRelationRuleStatus: cache lookup failed for relation %u", relationId);
 
 	/* Do the update */
 	((Form_pg_class) GETSTRUCT(tuple))->relhasrules = relHasRules;
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index 05640b5be8f003793c8b554add064f7d348934d9..c888ea012ac32c3cf2b69cc55af555322c5c1bf1 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.44 2000/10/24 20:59:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.45 2000/11/16 22:30:30 tgl Exp $
  *
  * NOTES
  *	  This cruft is the server side of PQfn.
@@ -202,14 +202,12 @@ update_fp_info(Oid func_id, struct fp_info * fip)
 	MemSet((char *) fip, 0, (int) sizeof(struct fp_info));
 	fip->funcid = InvalidOid;
 
-	func_htp = SearchSysCacheTuple(PROCOID,
-								   ObjectIdGetDatum(func_id),
-								   0, 0, 0);
+	func_htp = SearchSysCache(PROCOID,
+							  ObjectIdGetDatum(func_id),
+							  0, 0, 0);
 	if (!HeapTupleIsValid(func_htp))
-	{
 		elog(ERROR, "update_fp_info: cache lookup for function %u failed",
 			 func_id);
-	}
 	pp = (Form_pg_proc) GETSTRUCT(func_htp);
 	rettype = pp->prorettype;
 	argtypes = pp->proargtypes;
@@ -220,38 +218,38 @@ update_fp_info(Oid func_id, struct fp_info * fip)
 	{
 		if (OidIsValid(argtypes[i]))
 		{
-			type_htp = SearchSysCacheTuple(TYPEOID,
-										   ObjectIdGetDatum(argtypes[i]),
-										   0, 0, 0);
+			type_htp = SearchSysCache(TYPEOID,
+									  ObjectIdGetDatum(argtypes[i]),
+									  0, 0, 0);
 			if (!HeapTupleIsValid(type_htp))
-			{
 				elog(ERROR, "update_fp_info: bad argument type %u for %u",
 					 argtypes[i], func_id);
-			}
 			tp = (Form_pg_type) GETSTRUCT(type_htp);
 			fip->argbyval[i] = tp->typbyval;
 			fip->arglen[i] = tp->typlen;
+			ReleaseSysCache(type_htp);
 		}						/* else it had better be VAR_LENGTH_ARG */
 	}
 
 	if (OidIsValid(rettype))
 	{
-		type_htp = SearchSysCacheTuple(TYPEOID,
-									   ObjectIdGetDatum(rettype),
-									   0, 0, 0);
+		type_htp = SearchSysCache(TYPEOID,
+								  ObjectIdGetDatum(rettype),
+								  0, 0, 0);
 		if (!HeapTupleIsValid(type_htp))
-		{
 			elog(ERROR, "update_fp_info: bad return type %u for %u",
 				 rettype, func_id);
-		}
 		tp = (Form_pg_type) GETSTRUCT(type_htp);
 		fip->retbyval = tp->typbyval;
 		fip->retlen = tp->typlen;
+		ReleaseSysCache(type_htp);
 	}							/* else it had better by VAR_LENGTH_RESULT */
 
 	fip->xid = GetCurrentTransactionId();
 	fip->cid = GetCurrentCommandId();
 
+	ReleaseSysCache(func_htp);
+
 	/*
 	 * This must be last!
 	 */
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 63a43315286429a7fae2ac0d6a0a2e0af8a1a6f8..e725ff391f49c7ad1582eb91601feee45e3a124e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.102 2000/11/14 18:37:43 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.103 2000/11/16 22:30:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -102,9 +102,9 @@ CheckDropPermissions(char *name, char rightkind)
 			break;
 	Assert(rentry->kind != '\0');
 
-	tuple = SearchSysCacheTuple(RELNAME,
-								PointerGetDatum(name),
-								0, 0, 0);
+	tuple = SearchSysCache(RELNAME,
+						   PointerGetDatum(name),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "%s \"%s\" does not exist", rentry->name, name);
 
@@ -120,6 +120,8 @@ CheckDropPermissions(char *name, char rightkind)
 	if (!allowSystemTableMods && IsSystemRelationName(name))
 		elog(ERROR, "%s \"%s\" is a system %s",
 			 rentry->name, name, rentry->name);
+
+	ReleaseSysCache(tuple);
 }
 
 
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 1a2b2ef953e7bda0ae01ccdd9a1ef2a887dea805..a8bc5e349a3e960bd00da97213e5835b9d074d95 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.52 2000/11/03 19:01:36 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.53 2000/11/16 22:30:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -174,12 +174,13 @@ aclparse(char *s, AclItem *aip, unsigned *modechg)
 	switch (aip->ai_idtype)
 	{
 		case ACL_IDTYPE_UID:
-			htup = SearchSysCacheTuple(SHADOWNAME,
-									   PointerGetDatum(name),
-									   0, 0, 0);
+			htup = SearchSysCache(SHADOWNAME,
+								  PointerGetDatum(name),
+								  0, 0, 0);
 			if (!HeapTupleIsValid(htup))
 				elog(ERROR, "aclparse: non-existent user \"%s\"", name);
 			aip->ai_id = ((Form_pg_shadow) GETSTRUCT(htup))->usesysid;
+			ReleaseSysCache(htup);
 			break;
 		case ACL_IDTYPE_GID:
 			aip->ai_id = get_grosysid(name);
@@ -272,9 +273,9 @@ aclitemout(PG_FUNCTION_ARGS)
 	switch (aip->ai_idtype)
 	{
 		case ACL_IDTYPE_UID:
-			htup = SearchSysCacheTuple(SHADOWSYSID,
-									   ObjectIdGetDatum(aip->ai_id),
-									   0, 0, 0);
+			htup = SearchSysCache(SHADOWSYSID,
+								  ObjectIdGetDatum(aip->ai_id),
+								  0, 0, 0);
 			if (!HeapTupleIsValid(htup))
 			{
 				/* Generate numeric UID if we don't find an entry */
@@ -286,9 +287,12 @@ aclitemout(PG_FUNCTION_ARGS)
 				pfree(tmp);
 			}
 			else
+			{
 				strncat(p, (char *) &((Form_pg_shadow)
 									  GETSTRUCT(htup))->usename,
 						sizeof(NameData));
+				ReleaseSysCache(htup);
+			}
 			break;
 		case ACL_IDTYPE_GID:
 			strcat(p, "group ");
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 44f58840c3650d08879f7d22f9f7fe681bc395f0..47c1b814c4dc3b7571a491e7a7c41767ca1ee352 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.65 2000/11/14 23:28:13 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.66 2000/11/16 22:30:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1590,9 +1590,9 @@ system_cache_lookup(Oid element_type,
 	HeapTuple	typeTuple;
 	Form_pg_type typeStruct;
 
-	typeTuple = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(element_type),
-									0, 0, 0);
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(element_type),
+							   0, 0, 0);
 	if (!HeapTupleIsValid(typeTuple))
 		elog(ERROR, "array_out: Cache lookup failed for type %u",
 			 element_type);
@@ -1607,6 +1607,7 @@ system_cache_lookup(Oid element_type,
 		*proc = typeStruct->typinput;
 	else
 		*proc = typeStruct->typoutput;
+	ReleaseSysCache(typeTuple);
 }
 
 /*
diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c
index f32122173d8878f1e01f4adad908939c1f4be633..6022dc78519c9d684fa42143de9a5d573ab5c05a 100644
--- a/src/backend/utils/adt/format_type.c
+++ b/src/backend/utils/adt/format_type.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.5 2000/08/26 21:53:41 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.6 2000/11/16 22:30:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -98,9 +98,9 @@ format_type_internal(Oid type_oid, int32 typemod)
 	if (type_oid == InvalidOid)
 		return pstrdup("-");
 
-	tuple = SearchSysCacheTuple(TYPEOID, ObjectIdGetDatum(type_oid),
-								0, 0, 0);
-
+	tuple = SearchSysCache(TYPEOID,
+						   ObjectIdGetDatum(type_oid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		return pstrdup("???");
 
@@ -108,9 +108,11 @@ format_type_internal(Oid type_oid, int32 typemod)
 	typlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
 	if (array_base_type != 0 && typlen < 0)
 	{
-		tuple = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(array_base_type),
-									0, 0, 0);
+		/* Switch our attention to the array element type */
+		ReleaseSysCache(tuple);
+		tuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(array_base_type),
+							   0, 0, 0);
 		if (!HeapTupleIsValid(tuple))
 			return pstrdup("???[]");
 		is_array = true;
@@ -211,6 +213,8 @@ format_type_internal(Oid type_oid, int32 typemod)
 	if (is_array)
 		buf = psnprintf(strlen(buf) + 3, "%s[]", buf);
 
+	ReleaseSysCache(tuple);
+
 	return buf;
 }
 
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 84c4694115d067680e90b955465f4b0df7a23577..4a2bb3c4fd6d3bcf2c4501fbe245bfe5d11102a5 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.58 2000/07/09 21:30:12 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.59 2000/11/16 22:30:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -55,13 +55,12 @@ regprocin(PG_FUNCTION_ARGS)
 		if (pro_name_or_oid[0] >= '0' &&
 			pro_name_or_oid[0] <= '9')
 		{
-			proctup = SearchSysCacheTuple(PROCOID,
-										  DirectFunctionCall1(oidin,
+			result = (RegProcedure)
+				GetSysCacheOid(PROCOID,
+							   DirectFunctionCall1(oidin,
 											CStringGetDatum(pro_name_or_oid)),
-										  0, 0, 0);
-			if (HeapTupleIsValid(proctup))
-				result = (RegProcedure) proctup->t_data->t_oid;
-			else
+							   0, 0, 0);
+			if (!RegProcedureIsValid(result))
 				elog(ERROR, "No procedure with oid %s", pro_name_or_oid);
 		}
 		else
@@ -176,9 +175,9 @@ regprocout(PG_FUNCTION_ARGS)
 
 	if (!IsBootstrapProcessingMode())
 	{
-		proctup = SearchSysCacheTuple(PROCOID,
-									  ObjectIdGetDatum(proid),
-									  0, 0, 0);
+		proctup = SearchSysCache(PROCOID,
+								 ObjectIdGetDatum(proid),
+								 0, 0, 0);
 
 		if (HeapTupleIsValid(proctup))
 		{
@@ -186,6 +185,7 @@ regprocout(PG_FUNCTION_ARGS)
 
 			s = NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname);
 			StrNCpy(result, s, NAMEDATALEN);
+			ReleaseSysCache(proctup);
 		}
 		else
 		{
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 723adcda35cc2b583e4fd652d89c8c240095dc82..5bfea0ff42f9502fc0faaca4085f536e4caac9da 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -6,7 +6,7 @@
  *
  *	1999 Jan Wieck
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.17 2000/09/25 22:34:20 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.18 2000/11/16 22:30:31 tgl Exp $
  *
  * ----------
  */
@@ -3300,24 +3300,26 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
 		HeapTuple	opr_tup;
 		Form_pg_operator opr_struct;
 
-		opr_tup = SearchSysCacheTuple(OPERNAME,
-									  PointerGetDatum("="),
-									  ObjectIdGetDatum(typeid),
-									  ObjectIdGetDatum(typeid),
-									  CharGetDatum('b'));
-
+		opr_tup = SearchSysCache(OPERNAME,
+								 PointerGetDatum("="),
+								 ObjectIdGetDatum(typeid),
+								 ObjectIdGetDatum(typeid),
+								 CharGetDatum('b'));
 		if (!HeapTupleIsValid(opr_tup))
 			elog(ERROR, "ri_AttributesEqual(): cannot find '=' operator "
 				 "for type %u", typeid);
 		opr_struct = (Form_pg_operator) GETSTRUCT(opr_tup);
 
 		entry = (RI_OpreqHashEntry *) hash_search(ri_opreq_cache,
-								   (char *) &typeid, HASH_ENTER, &found);
+												  (char *) &typeid,
+												  HASH_ENTER,
+												  &found);
 		if (entry == NULL)
 			elog(FATAL, "can't insert into RI operator cache");
 
 		entry->typeid = typeid;
 		fmgr_info(opr_struct->oprcode, &(entry->oprfmgrinfo));
+		ReleaseSysCache(opr_tup);
 	}
 
 	/* ----------
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index cc25a5a026a84b9cc57956df9ed963b28da4f960..3cd543b5e686ba5ea552824cdefed5f4f78c857d 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
  *				back to source text
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.68 2000/11/05 00:15:53 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.69 2000/11/16 22:30:31 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -374,8 +374,9 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
 	 * Fetch the pg_index tuple by the Oid of the index
 	 * ----------
 	 */
-	ht_idx = SearchSysCacheTuple(INDEXRELID,
-								 ObjectIdGetDatum(indexrelid), 0, 0, 0);
+	ht_idx = SearchSysCache(INDEXRELID,
+							ObjectIdGetDatum(indexrelid),
+							0, 0, 0);
 	if (!HeapTupleIsValid(ht_idx))
 		elog(ERROR, "syscache lookup for index %u failed", indexrelid);
 	idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
@@ -384,8 +385,9 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
 	 * Fetch the pg_class tuple of the index relation
 	 * ----------
 	 */
-	ht_idxrel = SearchSysCacheTuple(RELOID,
-						  ObjectIdGetDatum(idxrec->indexrelid), 0, 0, 0);
+	ht_idxrel = SearchSysCache(RELOID,
+							   ObjectIdGetDatum(idxrec->indexrelid),
+							   0, 0, 0);
 	if (!HeapTupleIsValid(ht_idxrel))
 		elog(ERROR, "syscache lookup for relid %u failed", idxrec->indexrelid);
 	idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
@@ -394,8 +396,9 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
 	 * Fetch the pg_class tuple of the indexed relation
 	 * ----------
 	 */
-	ht_indrel = SearchSysCacheTuple(RELOID,
-							ObjectIdGetDatum(idxrec->indrelid), 0, 0, 0);
+	ht_indrel = SearchSysCache(RELOID,
+							   ObjectIdGetDatum(idxrec->indrelid),
+							   0, 0, 0);
 	if (!HeapTupleIsValid(ht_indrel))
 		elog(ERROR, "syscache lookup for relid %u failed", idxrec->indrelid);
 	indrelrec = (Form_pg_class) GETSTRUCT(ht_indrel);
@@ -484,12 +487,13 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
 		HeapTuple	proctup;
 		Form_pg_proc procStruct;
 
-		proctup = SearchSysCacheTuple(PROCOID,
-							 ObjectIdGetDatum(idxrec->indproc), 0, 0, 0);
+		proctup = SearchSysCache(PROCOID,
+								 ObjectIdGetDatum(idxrec->indproc),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(proctup))
 			elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc);
-
 		procStruct = (Form_pg_proc) GETSTRUCT(proctup);
+
 		appendStringInfo(&buf, "%s(%s) ",
 				 quote_identifier(pstrdup(NameStr(procStruct->proname))),
 						 keybuf.data);
@@ -508,6 +512,7 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
 		appendStringInfo(&buf, "%s",
 						 quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
 													   spi_fno)));
+		ReleaseSysCache(proctup);
 	}
 	else
 		/* ----------
@@ -523,15 +528,19 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
 	appendStringInfo(&buf, ")");
 
 	/* ----------
-	 * Create the result in upper executor memory
+	 * Create the result in upper executor memory, and free objects
 	 * ----------
 	 */
 	len = buf.len + VARHDRSZ;
 	indexdef = SPI_palloc(len);
 	VARATT_SIZEP(indexdef) = len;
 	memcpy(VARDATA(indexdef), buf.data, buf.len);
+
 	pfree(buf.data);
 	pfree(keybuf.data);
+	ReleaseSysCache(ht_idx);
+	ReleaseSysCache(ht_idxrel);
+	ReleaseSysCache(ht_indrel);
 
 	/* ----------
 	 * Disconnect from SPI manager
@@ -568,13 +577,14 @@ pg_get_userbyid(PG_FUNCTION_ARGS)
 	 * Get the pg_shadow entry and print the result
 	 * ----------
 	 */
-	usertup = SearchSysCacheTuple(SHADOWSYSID,
-								  ObjectIdGetDatum(uid),
-								  0, 0, 0);
+	usertup = SearchSysCache(SHADOWSYSID,
+							 ObjectIdGetDatum(uid),
+							 0, 0, 0);
 	if (HeapTupleIsValid(usertup))
 	{
 		user_rec = (Form_pg_shadow) GETSTRUCT(usertup);
 		StrNCpy(NameStr(*result), NameStr(user_rec->usename), NAMEDATALEN);
+		ReleaseSysCache(usertup);
 	}
 	else
 		sprintf(NameStr(*result), "unknown (UID=%d)", uid);
@@ -1392,10 +1402,11 @@ get_rule_expr(Node *node, deparse_context *context)
 							HeapTuple	tp;
 							Form_pg_operator optup;
 
-							tp = SearchSysCacheTuple(OPEROID,
-												  ObjectIdGetDatum(opno),
-													 0, 0, 0);
-							Assert(HeapTupleIsValid(tp));
+							tp = SearchSysCache(OPEROID,
+												ObjectIdGetDatum(opno),
+												0, 0, 0);
+							if (!HeapTupleIsValid(tp))
+								elog(ERROR, "cache lookup for operator %u failed", opno);
 							optup = (Form_pg_operator) GETSTRUCT(tp);
 							switch (optup->oprkind)
 							{
@@ -1414,6 +1425,7 @@ get_rule_expr(Node *node, deparse_context *context)
 								default:
 									elog(ERROR, "get_rule_expr: bogus oprkind");
 							}
+							ReleaseSysCache(tp);
 						}
 						appendStringInfoChar(buf, ')');
 						break;
@@ -1524,9 +1536,9 @@ get_rule_expr(Node *node, deparse_context *context)
 
 				/* we do NOT parenthesize the arg expression, for now */
 				get_rule_expr(fselect->arg, context);
-				typetup = SearchSysCacheTuple(TYPEOID,
-								   ObjectIdGetDatum(exprType(fselect->arg)),
-											  0, 0, 0);
+				typetup = SearchSysCache(TYPEOID,
+										 ObjectIdGetDatum(exprType(fselect->arg)),
+										 0, 0, 0);
 				if (!HeapTupleIsValid(typetup))
 					elog(ERROR, "cache lookup of type %u failed",
 						 exprType(fselect->arg));
@@ -1538,6 +1550,7 @@ get_rule_expr(Node *node, deparse_context *context)
 				fieldname = get_relid_attribute_name(typrelid,
 													 fselect->fieldnum);
 				appendStringInfo(buf, ".%s", quote_identifier(fieldname));
+				ReleaseSysCache(typetup);
 			}
 			break;
 
@@ -1550,9 +1563,9 @@ get_rule_expr(Node *node, deparse_context *context)
 
 				appendStringInfoChar(buf, '(');
 				get_rule_expr(relabel->arg, context);
-				typetup = SearchSysCacheTuple(TYPEOID,
+				typetup = SearchSysCache(TYPEOID,
 								   ObjectIdGetDatum(relabel->resulttype),
-											  0, 0, 0);
+										 0, 0, 0);
 				if (!HeapTupleIsValid(typetup))
 					elog(ERROR, "cache lookup of type %u failed",
 						 relabel->resulttype);
@@ -1560,6 +1573,7 @@ get_rule_expr(Node *node, deparse_context *context)
 				extval = pstrdup(NameStr(typeStruct->typname));
 				appendStringInfo(buf, ")::%s", quote_identifier(extval));
 				pfree(extval);
+				ReleaseSysCache(typetup);
 			}
 			break;
 
@@ -1616,14 +1630,14 @@ get_func_expr(Expr *expr, deparse_context *context)
 	/*
 	 * Get the functions pg_proc tuple
 	 */
-	proctup = SearchSysCacheTuple(PROCOID,
-								  ObjectIdGetDatum(func->funcid),
-								  0, 0, 0);
+	proctup = SearchSysCache(PROCOID,
+							 ObjectIdGetDatum(func->funcid),
+							 0, 0, 0);
 	if (!HeapTupleIsValid(proctup))
 		elog(ERROR, "cache lookup for proc %u failed", func->funcid);
 
 	procStruct = (Form_pg_proc) GETSTRUCT(proctup);
-	proname = pstrdup(NameStr(procStruct->proname));
+	proname = NameStr(procStruct->proname);
 
 	/*
 	 * nullvalue() and nonnullvalue() should get turned into special
@@ -1636,6 +1650,7 @@ get_func_expr(Expr *expr, deparse_context *context)
 			appendStringInfoChar(buf, '(');
 			get_rule_expr((Node *) lfirst(expr->args), context);
 			appendStringInfo(buf, " ISNULL)");
+			ReleaseSysCache(proctup);
 			return;
 		}
 		if (strcmp(proname, "nonnullvalue") == 0)
@@ -1643,6 +1658,7 @@ get_func_expr(Expr *expr, deparse_context *context)
 			appendStringInfoChar(buf, '(');
 			get_rule_expr((Node *) lfirst(expr->args), context);
 			appendStringInfo(buf, " NOTNULL)");
+			ReleaseSysCache(proctup);
 			return;
 		}
 	}
@@ -1657,8 +1673,9 @@ get_func_expr(Expr *expr, deparse_context *context)
 
 		/*
 		 * Strip off any RelabelType on the input, so we don't print
-		 * redundancies like x::bpchar::char(8). XXX Are there any cases
-		 * where this is a bad idea?
+		 * redundancies like x::bpchar::char(8).
+		 *
+		 * XXX Are there any cases where this is a bad idea?
 		 */
 		if (IsA(arg, RelabelType))
 			arg = ((RelabelType *) arg)->arg;
@@ -1696,6 +1713,8 @@ get_func_expr(Expr *expr, deparse_context *context)
 		}
 		else
 			appendStringInfo(buf, "%s", quote_identifier(proname));
+
+		ReleaseSysCache(proctup);
 		return;
 	}
 
@@ -1711,6 +1730,8 @@ get_func_expr(Expr *expr, deparse_context *context)
 		get_rule_expr((Node *) lfirst(l), context);
 	}
 	appendStringInfoChar(buf, ')');
+
+	ReleaseSysCache(proctup);
 }
 
 
@@ -1766,9 +1787,9 @@ get_const_expr(Const *constval, deparse_context *context)
 	char	   *extval;
 	char	   *valptr;
 
-	typetup = SearchSysCacheTuple(TYPEOID,
-								  ObjectIdGetDatum(constval->consttype),
-								  0, 0, 0);
+	typetup = SearchSysCache(TYPEOID,
+							 ObjectIdGetDatum(constval->consttype),
+							 0, 0, 0);
 	if (!HeapTupleIsValid(typetup))
 		elog(ERROR, "cache lookup of type %u failed", constval->consttype);
 
@@ -1785,6 +1806,7 @@ get_const_expr(Const *constval, deparse_context *context)
 		extval = pstrdup(NameStr(typeStruct->typname));
 		appendStringInfo(buf, "NULL::%s", quote_identifier(extval));
 		pfree(extval);
+		ReleaseSysCache(typetup);
 		return;
 	}
 
@@ -1843,6 +1865,8 @@ get_const_expr(Const *constval, deparse_context *context)
 			pfree(extval);
 			break;
 	}
+
+	ReleaseSysCache(typetup);
 }
 
 
@@ -2198,14 +2222,18 @@ get_relation_name(Oid relid)
 {
 	HeapTuple	classtup;
 	Form_pg_class classStruct;
+	char	   *result;
 
-	classtup = SearchSysCacheTuple(RELOID,
-								   ObjectIdGetDatum(relid), 0, 0, 0);
+	classtup = SearchSysCache(RELOID,
+							  ObjectIdGetDatum(relid),
+							  0, 0, 0);
 	if (!HeapTupleIsValid(classtup))
 		elog(ERROR, "cache lookup of relation %u failed", relid);
 
 	classStruct = (Form_pg_class) GETSTRUCT(classtup);
-	return pstrdup(NameStr(classStruct->relname));
+	result = pstrdup(NameStr(classStruct->relname));
+	ReleaseSysCache(classtup);
+	return result;
 }
 
 
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 818bc6ab082f8d83ac07576cf22016c5b846a170..63e4d9b46d2d5c50fec8622e3bc4e7111f82a354 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.81 2000/11/10 09:38:21 inoue Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.82 2000/11/16 22:30:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -324,12 +324,15 @@ scalarltsel(PG_FUNCTION_ARGS)
 		 * Get left and right datatypes of the operator so we know what
 		 * type the constant is.
 		 */
-		oprtuple = get_operator_tuple(opid);
+		oprtuple = SearchSysCache(OPEROID,
+								  ObjectIdGetDatum(opid),
+								  0, 0, 0);
 		if (!HeapTupleIsValid(oprtuple))
 			elog(ERROR, "scalarltsel: no tuple for operator %u", opid);
 		ltype = ((Form_pg_operator) GETSTRUCT(oprtuple))->oprleft;
 		rtype = ((Form_pg_operator) GETSTRUCT(oprtuple))->oprright;
 		contype = (flag & SEL_RIGHT) ? rtype : ltype;
+		ReleaseSysCache(oprtuple);
 
 		/* Now get info and stats about the attribute */
 		getattproperties(relid, attno,
@@ -482,11 +485,14 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
 		 * Get left and right datatypes of the operator so we know what
 		 * type the attribute is.
 		 */
-		oprtuple = get_operator_tuple(opid);
+		oprtuple = SearchSysCache(OPEROID,
+								  ObjectIdGetDatum(opid),
+								  0, 0, 0);
 		if (!HeapTupleIsValid(oprtuple))
 			elog(ERROR, "patternsel: no tuple for operator %u", opid);
 		ltype = ((Form_pg_operator) GETSTRUCT(oprtuple))->oprleft;
 		rtype = ((Form_pg_operator) GETSTRUCT(oprtuple))->oprright;
+		ReleaseSysCache(oprtuple);
 
 		/* the right-hand const is type text for all supported operators */
 		Assert(rtype == TEXTOID);
@@ -1189,10 +1195,10 @@ getattproperties(Oid relid, AttrNumber attnum,
 	HeapTuple	atp;
 	Form_pg_attribute att_tup;
 
-	atp = SearchSysCacheTuple(ATTNUM,
-							  ObjectIdGetDatum(relid),
-							  Int16GetDatum(attnum),
-							  0, 0);
+	atp = SearchSysCache(ATTNUM,
+						 ObjectIdGetDatum(relid),
+						 Int16GetDatum(attnum),
+						 0, 0);
 	if (!HeapTupleIsValid(atp))
 		elog(ERROR, "getattproperties: no attribute tuple %u %d",
 			 relid, (int) attnum);
@@ -1202,6 +1208,8 @@ getattproperties(Oid relid, AttrNumber attnum,
 	*typlen = att_tup->attlen;
 	*typbyval = att_tup->attbyval;
 	*typmod = att_tup->atttypmod;
+
+	ReleaseSysCache(atp);
 }
 
 /*
@@ -1250,11 +1258,10 @@ getattstatistics(Oid relid,
 	 * have at hand!  (For example, we might have a '>' operator rather
 	 * than the '<' operator that will appear in staop.)
 	 */
-	tuple = SearchSysCacheTupleCopy(STATRELID,
-								ObjectIdGetDatum(relid),
-								Int16GetDatum((int16) attnum),
-								0,
-								0);
+	tuple = SearchSysCache(STATRELID,
+						   ObjectIdGetDatum(relid),
+						   Int16GetDatum((int16) attnum),
+						   0, 0);
 	if (!HeapTupleIsValid(tuple))
 	{
 		/* no such stats entry */
@@ -1267,14 +1274,15 @@ getattstatistics(Oid relid,
 		*commonfrac = ((Form_pg_statistic) GETSTRUCT(tuple))->stacommonfrac;
 
 	/* Get the type input proc for the column datatype */
-	typeTuple = SearchSysCacheTuple(TYPEOID,
-									ObjectIdGetDatum(typid),
-									0, 0, 0);
+	typeTuple = SearchSysCache(TYPEOID,
+							   ObjectIdGetDatum(typid),
+							   0, 0, 0);
 	if (!HeapTupleIsValid(typeTuple))
 		elog(ERROR, "getattstatistics: Cache lookup failed for type %u",
 			 typid);
 	fmgr_info(((Form_pg_type) GETSTRUCT(typeTuple))->typinput, &inputproc);
 	typelem = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem;
+	ReleaseSysCache(typeTuple);
 
 	/*
 	 * Values are variable-length fields, so cannot access as struct
@@ -1351,7 +1359,8 @@ getattstatistics(Oid relid,
 			pfree(strval);
 		}
 	}
-	heap_freetuple(tuple);
+
+	ReleaseSysCache(tuple);
 
 	return true;
 }
@@ -1966,16 +1975,11 @@ string_lessthan(const char *str1, const char *str2, Oid datatype)
 static Oid
 find_operator(const char *opname, Oid datatype)
 {
-	HeapTuple	optup;
-
-	optup = SearchSysCacheTuple(OPERNAME,
-								PointerGetDatum(opname),
-								ObjectIdGetDatum(datatype),
-								ObjectIdGetDatum(datatype),
-								CharGetDatum('b'));
-	if (!HeapTupleIsValid(optup))
-		return InvalidOid;
-	return optup->t_data->t_oid;
+	return GetSysCacheOid(OPERNAME,
+						  PointerGetDatum(opname),
+						  ObjectIdGetDatum(datatype),
+						  ObjectIdGetDatum(datatype),
+						  CharGetDatum('b'));
 }
 
 /*
diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c
index 9a5f05134cd45f275b130f8d11ac16cdd5fd9578..6f64847dcab97d148fa4d5faa03c25ef7387284d 100644
--- a/src/backend/utils/adt/sets.c
+++ b/src/backend/utils/adt/sets.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.33 2000/08/24 03:29:06 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.34 2000/11/16 22:30:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -77,9 +77,11 @@ SetDefine(char *querystr, char *typename)
 	 */
 	CommandCounterIncrement();
 
-	tup = SearchSysCacheTuple(PROCOID,
-							  ObjectIdGetDatum(setoid),
-							  0, 0, 0);
+	procrel = heap_openr(ProcedureRelationName, RowExclusiveLock);
+
+	tup = SearchSysCache(PROCOID,
+						 ObjectIdGetDatum(setoid),
+						 0, 0, 0);
 	if (!HeapTupleIsValid(tup))
 		elog(ERROR, "SetDefine: unable to define set %s", querystr);
 
@@ -105,25 +107,15 @@ SetDefine(char *querystr, char *typename)
 			replNull[i] = ' ';
 
 		/* change the pg_proc tuple */
-		procrel = heap_openr(ProcedureRelationName, RowExclusiveLock);
+		newtup = heap_modifytuple(tup,
+								  procrel,
+								  replValue,
+								  replNull,
+								  repl);
 
-		tup = SearchSysCacheTuple(PROCOID,
-								  ObjectIdGetDatum(setoid),
-								  0, 0, 0);
-		if (HeapTupleIsValid(tup))
-		{
-			newtup = heap_modifytuple(tup,
-									  procrel,
-									  replValue,
-									  replNull,
-									  repl);
+		heap_update(procrel, &newtup->t_self, newtup, NULL);
 
-			heap_update(procrel, &tup->t_self, newtup, NULL);
-
-			setoid = newtup->t_data->t_oid;
-		}
-		else
-			elog(ERROR, "SetDefine: could not find new set oid tuple");
+		setoid = newtup->t_data->t_oid;
 
 		if (RelationGetForm(procrel)->relhasindex)
 		{
@@ -133,9 +125,13 @@ SetDefine(char *querystr, char *typename)
 			CatalogIndexInsert(idescs, Num_pg_proc_indices, procrel, newtup);
 			CatalogCloseIndices(Num_pg_proc_indices, idescs);
 		}
-		heap_close(procrel, RowExclusiveLock);
+		heap_freetuple(newtup);
 	}
 
+	ReleaseSysCache(tup);
+
+	heap_close(procrel, RowExclusiveLock);
+
 	return setoid;
 }
 
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index 39e05d0fb09ccb8d3faffd76c8ebfbaea0fddca0..3d8e7d80ba8cff72a59ec59cd845b8ca0153faab 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 b9bd9f8b9e91eeb1c30a4bf0eac415473f469119..e07445837a5b83f42e32be173cb743f468ba8919 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 7f35f192089d5688a422136438ad6f72b8f0c001..bb9a55b869a4ca52aa770444034c682f1c7edceb 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 31591663ceeda2e6d2acc2b4574499db2f6bab84..0134b47a0f9d71bf45c311815e5bceee810e286d 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"
 
 
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index 3913dddeec2c721e443100a083e6c2163f384ad6..2dfddebd0a8731dc29191f35fcb77167d62b7955 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.44 2000/07/05 23:11:40 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.45 2000/11/16 22:30:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,9 +59,9 @@ fmgr_dynamic(Oid functionId)
 	PGFunction	user_fn;
 	bool		isnull;
 
-	procedureTuple = SearchSysCacheTuple(PROCOID,
-										 ObjectIdGetDatum(functionId),
-										 0, 0, 0);
+	procedureTuple = SearchSysCache(PROCOID,
+									ObjectIdGetDatum(functionId),
+									0, 0, 0);
 	if (!HeapTupleIsValid(procedureTuple))
 		elog(ERROR, "fmgr_dynamic: function %u: cache lookup failed",
 			 functionId);
@@ -88,6 +88,8 @@ fmgr_dynamic(Oid functionId)
 	pfree(prosrcstring);
 	pfree(probinstring);
 
+	ReleaseSysCache(procedureTuple);
+
 	return user_fn;
 }
 
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index c7fbf251f9d96b6d52d591be6f5c4af852c20edf..5287615eea0fbcf491f6268dbbbf7dfbe9c2fe82 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.46 2000/08/24 03:29:07 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.47 2000/11/16 22:30:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -134,9 +134,9 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
 	}
 
 	/* Otherwise we need the pg_proc entry */
-	procedureTuple = SearchSysCacheTuple(PROCOID,
-										 ObjectIdGetDatum(functionId),
-										 0, 0, 0);
+	procedureTuple = SearchSysCache(PROCOID,
+									ObjectIdGetDatum(functionId),
+									0, 0, 0);
 	if (!HeapTupleIsValid(procedureTuple))
 		elog(ERROR, "fmgr_info: function %u: cache lookup failed",
 			 functionId);
@@ -149,6 +149,7 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
 	if (!procedureStruct->proistrusted)
 	{
 		finfo->fn_addr = fmgr_untrusted;
+		ReleaseSysCache(procedureTuple);
 		return;
 	}
 
@@ -202,14 +203,12 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
 			/*
 			 * Might be a created procedural language; try to look it up.
 			 */
-			languageTuple = SearchSysCacheTuple(LANGOID,
-												ObjectIdGetDatum(language),
-												0, 0, 0);
+			languageTuple = SearchSysCache(LANGOID,
+										   ObjectIdGetDatum(language),
+										   0, 0, 0);
 			if (!HeapTupleIsValid(languageTuple))
-			{
 				elog(ERROR, "fmgr_info: cache lookup for language %u failed",
 					 language);
-			}
 			languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
 			if (languageStruct->lanispl)
 			{
@@ -231,8 +230,11 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
 				elog(ERROR, "fmgr_info: function %u: unsupported language %u",
 					 functionId, language);
 			}
+			ReleaseSysCache(languageTuple);
 			break;
 	}
+
+	ReleaseSysCache(procedureTuple);
 }
 
 
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 026f2cc8114af34d0c06509f7ef20d776106aeec..ec223157c4b295fd3776f7541f9531f6b4706ef7 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.56 2000/11/04 12:43:24 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.57 2000/11/16 22:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -340,12 +340,15 @@ SetSessionUserIdFromUserName(const char *username)
 	 */
 	AssertState(!IsBootstrapProcessingMode());
 
-	userTup = SearchSysCacheTuple(SHADOWNAME,
-								  PointerGetDatum(username),
-								  0, 0, 0);
+	userTup = SearchSysCache(SHADOWNAME,
+							 PointerGetDatum(username),
+							 0, 0, 0);
 	if (!HeapTupleIsValid(userTup))
 		elog(FATAL, "user \"%s\" does not exist", username);
+
 	SetSessionUserId( ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid );
+
+	ReleaseSysCache(userTup);
 }
 
 
@@ -355,13 +358,19 @@ SetSessionUserIdFromUserName(const char *username)
 char *
 GetUserName(Oid userid)
 {
-	HeapTuple tuple;
+	HeapTuple	tuple;
+	char	   *result;
 
-	tuple = SearchSysCacheTuple(SHADOWSYSID, ObjectIdGetDatum(userid), 0, 0, 0);
+	tuple = SearchSysCache(SHADOWSYSID,
+						   ObjectIdGetDatum(userid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "invalid user id %u", (unsigned) userid);
 
-	return pstrdup( NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename) );
+	result = pstrdup( NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename) );
+
+	ReleaseSysCache(tuple);
+	return result;
 }
 
 
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 3a9e5a1797b909b310145510038f9541cf006226..bee4f7e9219063ac0870f3617f4f45ceb0a5be76 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.71 2000/11/14 18:37:44 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.72 2000/11/16 22:30:39 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -320,10 +320,7 @@ InitPostgres(const char *dbname, const char *username)
 
 	/*
 	 * Initialize all the system catalog caches.
-	 */
-	zerocaches();
-
-	/*
+	 *
 	 * Does not touch files since all routines are builtins (?) - thomas
 	 * 1997-11-01
 	 */
diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c
index 1852b35e465757e3b1561066299e738dec8bf533..5139247291d58cabf5c7ed35557add9a7555fe5b 100644
--- a/src/backend/utils/misc/superuser.c
+++ b/src/backend/utils/misc/superuser.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.15 2000/09/06 14:15:22 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.16 2000/11/16 22:30:40 tgl Exp $
  *
  * DESCRIPTION
  *	  See superuser().
@@ -29,10 +29,16 @@ superuser(void)
 	privileges.
 --------------------------------------------------------------------------*/
 	HeapTuple	utup;
+	bool		result;
 
-	utup = SearchSysCacheTuple(SHADOWSYSID,
-							   ObjectIdGetDatum(GetUserId()),
-							   0, 0, 0);
-	Assert(utup != NULL);
-	return ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
+	utup = SearchSysCache(SHADOWSYSID,
+						  ObjectIdGetDatum(GetUserId()),
+						  0, 0, 0);
+	if (HeapTupleIsValid(utup))
+	{
+		result = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
+		ReleaseSysCache(utup);
+		return result;
+	}
+	return false;
 }
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index 1a0781dd9217015d0dc9f6184c8e6ca3ec7bf9cf..a3c0784786d1ef15b3dc4901163e489583c97b1a 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -78,7 +78,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.10 2000/05/30 04:24:54 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.11 2000/11/16 22:30:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,7 +88,6 @@
 #include "access/heapam.h"
 #include "access/nbtree.h"
 #include "miscadmin.h"
-#include "parser/parse_type.h"
 #include "utils/logtape.h"
 #include "utils/lsyscache.h"
 #include "utils/tuplesort.h"
@@ -506,7 +505,8 @@ tuplesort_begin_datum(Oid datumType,
 					  bool randomAccess)
 {
 	Tuplesortstate *state = tuplesort_begin_common(randomAccess);
-	Type		typeInfo;
+	int16		typlen;
+	bool		typbyval;
 
 	state->comparetup = comparetup_datum;
 	state->copytup = copytup_datum;
@@ -519,9 +519,9 @@ tuplesort_begin_datum(Oid datumType,
 	/* lookup the function that implements the sort operator */
 	fmgr_info(get_opcode(sortOperator), &state->sortOpFn);
 	/* lookup necessary attributes of the datum type */
-	typeInfo = typeidType(datumType);
-	state->datumTypeLen = typeLen(typeInfo);
-	state->datumTypeByVal = typeByVal(typeInfo);
+	get_typlenbyval(datumType, &typlen, &typbyval);
+	state->datumTypeLen = typlen;
+	state->datumTypeByVal = typbyval;
 
 	return state;
 }
diff --git a/src/include/executor/hashjoin.h b/src/include/executor/hashjoin.h
index 25a8174f294ec7173ef2d02a0a054b6d6b33aa93..28581ad425a2ef936d990cf799d8418d8df5f26d 100644
--- a/src/include/executor/hashjoin.h
+++ b/src/include/executor/hashjoin.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: hashjoin.h,v 1.19 2000/08/22 04:06:21 tgl Exp $
+ * $Id: hashjoin.h,v 1.20 2000/11/16 22:30:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,8 +73,8 @@ typedef struct HashTableData
 	 * and outer sides of the hash are the same type, or at least
 	 * binary-compatible types.
 	 */
+	int16		typLen;
 	bool		typByVal;
-	int			typLen;
 
 	/*
 	 * During 1st scan of inner relation, we get tuples from executor. If
diff --git a/src/include/lib/dllist.h b/src/include/lib/dllist.h
index 9e357a7fd7657566d57d6e10dc751dc548e6cc8a..9306d4e6b676bc0e8abc9b2adaad706d37e2b333 100644
--- a/src/include/lib/dllist.h
+++ b/src/include/lib/dllist.h
@@ -2,12 +2,11 @@
  *
  * dllist.h
  *		simple doubly linked list primitives
- *		the elements of the list are void* so the lists can contain
- *		anything
+ *		the elements of the list are void* so the lists can contain anything
  *		Dlelem can only be in one list at a time
  *
  *
- *	 Here's a small example of how to use Dllist's :
+ *	 Here's a small example of how to use Dllists:
  *
  *	 Dllist *lst;
  *	 Dlelem *elt;
@@ -24,10 +23,18 @@
  *	 DLFreeElem(elt);				   -- free the element since we don't
  *										  use it anymore
  *
+ *
+ * It is also possible to use Dllist objects that are embedded in larger
+ * structures instead of being separately malloc'd.  To do this, use
+ * DLInitElem() to initialize a Dllist field within a larger object.
+ * Don't forget to DLRemove() each field from its list (if any) before
+ * freeing the larger object!
+ *
+ *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: dllist.h,v 1.13 2000/06/08 22:37:46 momjian Exp $
+ * $Id: dllist.h,v 1.14 2000/11/16 22:30:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,7 +42,6 @@
 #ifndef DLLIST_H
 #define DLLIST_H
 
-
 struct Dllist;
 struct Dlelem;
 
@@ -53,21 +59,27 @@ typedef struct Dllist
 	Dlelem	   *dll_tail;
 } Dllist;
 
-extern Dllist *DLNewList(void); /* initialize a new list */
-extern void DLFreeList(Dllist *);		/* free up a list and all the
+extern Dllist *DLNewList(void); /* allocate and initialize a list header */
+extern void DLInitList(Dllist *list);	/* init a header alloced by caller */
+extern void DLFreeList(Dllist *list);	/* free up a list and all the
 										 * nodes in it */
 extern Dlelem *DLNewElem(void *val);
-extern void DLFreeElem(Dlelem *);
-extern Dlelem *DLGetHead(Dllist *);
-extern Dlelem *DLGetTail(Dllist *);
-extern Dlelem *DLRemTail(Dllist *l);
-extern Dlelem *DLGetSucc(Dlelem *);		/* get successor */
-extern void DLRemove(Dlelem *); /* removes node from list */
+extern void DLInitElem(Dlelem *e, void *val);
+extern void DLFreeElem(Dlelem *e);
+extern void DLRemove(Dlelem *e);		/* removes node from list */
 extern void DLAddHead(Dllist *list, Dlelem *node);
 extern void DLAddTail(Dllist *list, Dlelem *node);
 extern Dlelem *DLRemHead(Dllist *list); /* remove and return the head */
-extern void DLMoveToFront(Dlelem *);	/* move node to front of its list */
+extern Dlelem *DLRemTail(Dllist *list);
+extern void DLMoveToFront(Dlelem *e);	/* move node to front of its list */
+
+/* These are macros for speed */
+#define DLGetHead(list)  ((list)->dll_head)
+#define DLGetTail(list)  ((list)->dll_tail)
+#define DLGetSucc(elem)  ((elem)->dle_next)
+#define DLGetPred(elem)  ((elem)->dle_prev)
+#define DLGetListHdr(elem)  ((elem)->dle_list)
 
-#define DLE_VAL(x)	(x->dle_val)
+#define DLE_VAL(elem)	((elem)->dle_val)
 
 #endif	 /* DLLIST_H */
diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h
index 1ec37fc7b6fefad4ff05faf308ae8186067442ea..08b0007fcaf7f5887892d94136169daa8d4bce19 100644
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: makefuncs.h,v 1.25 2000/08/08 15:42:59 tgl Exp $
+ * $Id: makefuncs.h,v 1.26 2000/11/16 22:30:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,7 +42,8 @@ extern Const *makeConst(Oid consttype,
 		  bool constisset,
 		  bool constiscast);
 
-extern Attr *
-			makeAttr(char *relname, char *attname);
+extern Const *makeNullConst(Oid consttype);
+
+extern Attr *makeAttr(char *relname, char *attname);
 
 #endif	 /* MAKEFUNC_H */
diff --git a/src/include/parser/parse_oper.h b/src/include/parser/parse_oper.h
index 4162cd6d2346909ab37da5f608ce91b53f9a3311..4e3c784c0dcbaa6a236125d74575becf45a75d63 100644
--- a/src/include/parser/parse_oper.h
+++ b/src/include/parser/parse_oper.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_oper.h,v 1.11 2000/01/26 05:58:27 momjian Exp $
+ * $Id: parse_oper.h,v 1.12 2000/11/16 22:30:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,10 +18,13 @@
 
 typedef HeapTuple Operator;
 
-extern Oid	any_ordering_op(Oid restype);
-extern Oid	oprid(Operator op);
-extern Operator oper(char *op, Oid arg1, Oid arg2, bool noWarnings);
+extern Operator oper(char *op, Oid arg1, Oid arg2, bool noError);
 extern Operator right_oper(char *op, Oid arg);
 extern Operator left_oper(char *op, Oid arg);
 
+extern Oid	oper_oid(char *op, Oid arg1, Oid arg2, bool noError);
+extern Oid	oprid(Operator op);
+
+extern Oid	any_ordering_op(Oid restype);
+
 #endif	 /* PARSE_OPER_H */
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index e2cfd7f4a2d296290c7f3e26711ead87f6b77e8b..0d8ba2f1bce7bc0b49bf50e6c00c1b20bbd0c55f 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_type.h,v 1.14 2000/06/08 22:37:53 momjian Exp $
+ * $Id: parse_type.h,v 1.15 2000/11/16 22:30:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,15 +21,18 @@ typedef HeapTuple Type;
 extern bool typeidIsValid(Oid id);
 extern Type typeidType(Oid id);
 extern Type typenameType(char *s);
-extern char *typeidTypeName(Oid id);
+
 extern Oid	typeTypeId(Type tp);
 extern int16 typeLen(Type t);
 extern bool typeByVal(Type t);
 extern char *typeTypeName(Type t);
 extern char typeTypeFlag(Type t);
+extern Oid	typeTypeRelid(Type typ);
 extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod);
+
+extern char *typeidTypeName(Oid id);
 extern Oid	typeidTypeRelid(Oid type_id);
-extern Oid	typeTypeRelid(Type typ);
+extern Oid	typenameTypeId(char *s);
 
 #define ISCOMPLEX(typeid) (typeidTypeRelid(typeid) != InvalidOid)
 
diff --git a/src/include/rewrite/rewriteSupport.h b/src/include/rewrite/rewriteSupport.h
index 39605df47ad9d72f521496662b2b636d4440c09b..20cf82cbd91f3598f182610162f882886ba1b47d 100644
--- a/src/include/rewrite/rewriteSupport.h
+++ b/src/include/rewrite/rewriteSupport.h
@@ -7,14 +7,14 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: rewriteSupport.h,v 1.13 2000/09/29 18:21:24 tgl Exp $
+ * $Id: rewriteSupport.h,v 1.14 2000/11/16 22:30:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef REWRITESUPPORT_H
 #define REWRITESUPPORT_H
 
-extern int	IsDefinedRewriteRule(char *ruleName);
+extern bool IsDefinedRewriteRule(char *ruleName);
 
 extern void SetRelationRuleStatus(Oid relationId, bool relHasRules,
 								  bool relIsBecomingView);
diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h
index e55b6492d8c8a77eb5b094235ed1931361935b3d..ed78284a47890ade71ef0466b346779bb0ea4371 100644
--- a/src/include/utils/catcache.h
+++ b/src/include/utils/catcache.h
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catcache.h,v 1.27 2000/11/10 00:33:12 tgl Exp $
+ * $Id: catcache.h,v 1.28 2000/11/16 22:30:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,18 +32,29 @@
 
 typedef struct catctup
 {
-	HeapTuple	ct_tup;			/* A pointer to a tuple */
+	int			ct_magic;		/* for Assert checks */
+#define CT_MAGIC   0x57261502
+
 	/*
-	 * Each tuple in the cache has two catctup items, one in the LRU list
-	 * and one in the hashbucket list for its hash value.  ct_node in each
-	 * one points to the other one.
+	 * Each tuple in a cache is a member of two lists: one lists all the
+	 * elements in that cache in LRU order, and the other lists just the
+	 * elements in one hashbucket, also in LRU order.
+	 *
+	 * A tuple marked "dead" must not be returned by subsequent searches.
+	 * However, it won't be physically deleted from the cache until its
+	 * refcount goes to zero.
 	 */
-	Dlelem	   *ct_node;		/* the other catctup for this tuple */
+	Dlelem		lrulist_elem;	/* list member of global LRU list */
+	Dlelem		cache_elem;		/* list member of per-bucket list */
+	int			refcount;		/* number of active references */
+	bool		dead;			/* dead but not yet removed? */
+	HeapTupleData tuple;		/* tuple management header */
 } CatCTup;
 
+
 /* voodoo constants */
 #define NCCBUCK 500				/* CatCache buckets */
-#define MAXTUP 300				/* Maximum # of tuples stored per cache */
+#define MAXTUP 500				/* Maximum # of tuples stored per cache */
 
 
 typedef struct catcache
@@ -60,8 +71,8 @@ typedef struct catcache
 	short		cc_key[4];		/* AttrNumber of each key */
 	PGFunction	cc_hashfunc[4]; /* hash function to use for each key */
 	ScanKeyData cc_skey[4];		/* precomputed key info for indexscans */
-	Dllist	   *cc_lrulist;		/* LRU list, most recent first */
-	Dllist	   *cc_cache[NCCBUCK + 1];	/* hash buckets */
+	Dllist		cc_lrulist;		/* overall LRU list, most recent first */
+	Dllist		cc_cache[NCCBUCK]; /* hash buckets */
 } CatCache;
 
 #define InvalidCatalogCacheId	(-1)
@@ -70,12 +81,15 @@ typedef struct catcache
 extern MemoryContext CacheMemoryContext;
 
 extern void CreateCacheMemoryContext(void);
+extern void AtEOXact_CatCache(bool isCommit);
 
-extern CatCache *InitSysCache(int id, char *relname, char *indname,
+extern CatCache *InitCatCache(int id, char *relname, char *indname,
 							  int nkeys, int *key);
-extern HeapTuple SearchSysCache(CatCache *cache,
+
+extern HeapTuple SearchCatCache(CatCache *cache,
 								Datum v1, Datum v2,
 								Datum v3, Datum v4);
+extern void ReleaseCatCache(HeapTuple tuple);
 
 extern void ResetSystemCache(void);
 extern void SystemCacheRelationFlushed(Oid relId);
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 516949d1de98b6dd46614a363a243dbdade2c879..f8547baa884664b84bf093b7f3525d9b66871ae4 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lsyscache.h,v 1.26 2000/10/05 19:48:34 momjian Exp $
+ * $Id: lsyscache.h,v 1.27 2000/11/16 22:30:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,7 +29,6 @@ extern bool op_mergejoinable(Oid opno, Oid ltype, Oid rtype,
 				 Oid *leftOp, Oid *rightOp);
 extern Oid	op_hashjoinable(Oid opno, Oid ltype, Oid rtype);
 extern bool op_iscachable(Oid opno);
-extern HeapTuple get_operator_tuple(Oid opno);
 extern Oid	get_commutator(Oid opno);
 extern Oid	get_negator(Oid opno);
 extern RegProcedure get_oprrest(Oid opno);
@@ -39,6 +38,7 @@ extern bool func_iscachable(Oid funcid);
 extern char *get_rel_name(Oid relid);
 extern int16 get_typlen(Oid typid);
 extern bool get_typbyval(Oid typid);
+extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
 extern Datum get_typdefault(Oid typid);
 
 #endif	 /* LSYSCACHE_H */
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index 5d17e8db44c1fc5491d4792a5bef94ac2c0ccde8..73abd53e134e11f6d5ba444f76081179b73bca2a 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: syscache.h,v 1.26 2000/06/17 04:56:29 tgl Exp $
+ * $Id: syscache.h,v 1.27 2000/11/16 22:30:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,12 +57,22 @@
 #define TYPENAME		26
 #define TYPEOID			27
 
-extern void zerocaches(void);
 extern void InitCatalogCache(void);
-extern HeapTuple SearchSysCacheTuple(int cacheId,
+
+extern HeapTuple SearchSysCache(int cacheId,
+					Datum key1, Datum key2, Datum key3, Datum key4);
+extern void ReleaseSysCache(HeapTuple tuple);
+
+/* convenience routines */
+extern HeapTuple SearchSysCacheCopy(int cacheId,
 					Datum key1, Datum key2, Datum key3, Datum key4);
-extern HeapTuple SearchSysCacheTupleCopy(int cacheId,
-						Datum key1, Datum key2, Datum key3, Datum key4);
+extern Oid GetSysCacheOid(int cacheId,
+					Datum key1, Datum key2, Datum key3, Datum key4);
+
+/* macro for just probing for existence of a tuple via the syscache */
+#define SearchSysCacheExists(c,k1,k2,k3,k4)  \
+	OidIsValid(GetSysCacheOid(c,k1,k2,k3,k4))
+
 extern Datum SysCacheGetAttr(int cacheId, HeapTuple tup,
 				AttrNumber attributeNumber, bool *isNull);
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index c1516ea692808e1419323e9fb3ff6da7efa55e89..81a4cd75d4b968922eaf5ddec2f53bc109e90d66 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -33,7 +33,7 @@
  *	  ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.14 2000/10/24 17:01:05 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.15 2000/11/16 22:30:49 tgl Exp $
  *
  **********************************************************************/
 
@@ -521,9 +521,9 @@ plperl_func_handler(PG_FUNCTION_ARGS)
 		/************************************************************
 		 * Lookup the pg_proc tuple by Oid
 		 ************************************************************/
-		procTup = SearchSysCacheTuple(PROCOID,
-									  ObjectIdGetDatum(fcinfo->flinfo->fn_oid),
-									  0, 0, 0);
+		procTup = SearchSysCache(PROCOID,
+								 ObjectIdGetDatum(fcinfo->flinfo->fn_oid),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(procTup))
 		{
 			free(prodesc->proname);
@@ -537,9 +537,9 @@ plperl_func_handler(PG_FUNCTION_ARGS)
 		 * Get the required information for input conversion of the
 		 * return value.
 		 ************************************************************/
-		typeTup = SearchSysCacheTuple(TYPEOID,
-								ObjectIdGetDatum(procStruct->prorettype),
-									  0, 0, 0);
+		typeTup = SearchSysCache(TYPEOID,
+								 ObjectIdGetDatum(procStruct->prorettype),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(typeTup))
 		{
 			free(prodesc->proname);
@@ -560,6 +560,8 @@ plperl_func_handler(PG_FUNCTION_ARGS)
 		prodesc->result_in_elem = (Oid) (typeStruct->typelem);
 		prodesc->result_in_len = typeStruct->typlen;
 
+		ReleaseSysCache(typeTup);
+
 		/************************************************************
 		 * Get the required information for output conversion
 		 * of all procedure arguments
@@ -567,9 +569,9 @@ plperl_func_handler(PG_FUNCTION_ARGS)
 		prodesc->nargs = procStruct->pronargs;
 		for (i = 0; i < prodesc->nargs; i++)
 		{
-			typeTup = SearchSysCacheTuple(TYPEOID,
+			typeTup = SearchSysCache(TYPEOID,
 							ObjectIdGetDatum(procStruct->proargtypes[i]),
-										  0, 0, 0);
+									 0, 0, 0);
 			if (!HeapTupleIsValid(typeTup))
 			{
 				free(prodesc->proname);
@@ -587,7 +589,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
 			fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i]));
 			prodesc->arg_out_elem[i] = (Oid) (typeStruct->typelem);
 			prodesc->arg_out_len[i] = typeStruct->typlen;
-
+			ReleaseSysCache(typeTup);
 		}
 
 		/************************************************************
@@ -617,6 +619,8 @@ plperl_func_handler(PG_FUNCTION_ARGS)
 		 ************************************************************/
 		hv_store(plperl_proc_hash, internal_proname, proname_len,
 				 newSViv((IV) prodesc), 0);
+
+		ReleaseSysCache(procTup);
 	}
 	else
 	{
@@ -744,9 +748,9 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
 		/************************************************************
 		 * Lookup the pg_proc tuple by Oid
 		 ************************************************************/
-		procTup = SearchSysCacheTuple(PROCOID,
-									  ObjectIdGetDatum(fcinfo->flinfo->fn_oid),
-									  0, 0, 0);
+		procTup = SearchSysCache(PROCOID,
+								 ObjectIdGetDatum(fcinfo->flinfo->fn_oid),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(procTup))
 		{
 			free(prodesc->proname);
@@ -819,6 +823,8 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
 		hashent = Tcl_CreateHashEntry(plperl_proc_hash,
 									  prodesc->proname, &hashnew);
 		Tcl_SetHashValue(hashent, (ClientData) prodesc);
+
+		ReleaseSysCache(procTup);
 	}
 	else
 	{
@@ -1068,9 +1074,9 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
 		 * Lookup the attribute type in the syscache
 		 * for the input function
 		 ************************************************************/
-		typeTup = SearchSysCacheTuple(TYPEOID,
+		typeTup = SearchSysCache(TYPEOID,
 				  ObjectIdGetDatum(tupdesc->attrs[attnum - 1]->atttypid),
-									  0, 0, 0);
+								 0, 0, 0);
 		if (!HeapTupleIsValid(typeTup))
 		{
 			elog(ERROR, "plperl: Cache lookup for attribute '%s' type %u failed",
@@ -1079,6 +1085,7 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
 		}
 		typinput = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typinput);
 		typelem = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typelem);
+		ReleaseSysCache(typeTup);
 
 		/************************************************************
 		 * Set the attribute to NOT NULL and convert the contents
@@ -1538,9 +1545,9 @@ plperl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
 	 ************************************************************/
 	for (i = 0; i < nargs; i++)
 	{
-		typeTup = SearchSysCacheTuple(TYPNAME,
-									  PointerGetDatum(args[i]),
-									  0, 0, 0);
+		typeTup = SearchSysCache(TYPNAME,
+								 PointerGetDatum(args[i]),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(typeTup))
 			elog(ERROR, "plperl: Cache lookup of type %s failed", args[i]);
 		qdesc->argtypes[i] = typeTup->t_data->t_oid;
@@ -1549,6 +1556,7 @@ plperl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
 		qdesc->argtypelems[i] = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
 		qdesc->argvalues[i] = (Datum) NULL;
 		qdesc->arglen[i] = (int) (((Form_pg_type) GETSTRUCT(typeTup))->typlen);
+		ReleaseSysCache(typeTup);
 	}
 
 	/************************************************************
@@ -2084,9 +2092,9 @@ plperl_set_tuple_values(Tcl_Interp *interp, char *arrayname,
 		 * Lookup the attribute type in the syscache
 		 * for the output function
 		 ************************************************************/
-		typeTup = SearchSysCacheTuple(TYPEOID,
+		typeTup = SearchSysCache(TYPEOID,
 						   ObjectIdGetDatum(tupdesc->attrs[i]->atttypid),
-									  0, 0, 0);
+								 0, 0, 0);
 		if (!HeapTupleIsValid(typeTup))
 		{
 			elog(ERROR, "plperl: Cache lookup for attribute '%s' type %u failed",
@@ -2095,6 +2103,7 @@ plperl_set_tuple_values(Tcl_Interp *interp, char *arrayname,
 
 		typoutput = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typoutput);
 		typelem = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typelem);
+		ReleaseSysCache(typeTup);
 
 		/************************************************************
 		 * If there is a value, set the variable
@@ -2156,9 +2165,9 @@ plperl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc)
 		 * Lookup the attribute type in the syscache
 		 * for the output function
 		 ************************************************************/
-		typeTup = SearchSysCacheTuple(TYPEOID,
+		typeTup = SearchSysCache(TYPEOID,
 						   ObjectIdGetDatum(tupdesc->attrs[i]->atttypid),
-									  0, 0, 0);
+								 0, 0, 0);
 		if (!HeapTupleIsValid(typeTup))
 		{
 			elog(ERROR, "plperl: Cache lookup for attribute '%s' type %u failed",
@@ -2167,6 +2176,7 @@ plperl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc)
 
 		typoutput = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typoutput);
 		typelem = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typelem);
+		ReleaseSysCache(typeTup);
 
 		/************************************************************
 		 * If there is a value, append the attribute name and the
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index bed95890968efb4f57af1dadf440a6ed827d4937..c0fe596897054b0c8b24532a7f7d26befb0764fe 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -3,7 +3,7 @@
  *			  procedural language
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.23 2000/08/31 13:26:16 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.24 2000/11/16 22:30:50 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -53,7 +53,6 @@
 #include "access/heapam.h"
 
 #include "utils/syscache.h"
-#include "utils/catcache.h"
 #include "catalog/catname.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
@@ -131,9 +130,9 @@ plpgsql_compile(Oid fn_oid, int functype)
 	 * Lookup the pg_proc tuple by Oid
 	 * ----------
 	 */
-	procTup = SearchSysCacheTuple(PROCOID,
-								  ObjectIdGetDatum(fn_oid),
-								  0, 0, 0);
+	procTup = SearchSysCache(PROCOID,
+							 ObjectIdGetDatum(fn_oid),
+							 0, 0, 0);
 	if (!HeapTupleIsValid(procTup))
 		elog(ERROR, "plpgsql: cache lookup for proc %u failed", fn_oid);
 
@@ -176,9 +175,9 @@ plpgsql_compile(Oid fn_oid, int functype)
 			 * Lookup the functions return type
 			 * ----------
 			 */
-			typeTup = SearchSysCacheTuple(TYPEOID,
-					  ObjectIdGetDatum(procStruct->prorettype), 0, 0, 0);
-
+			typeTup = SearchSysCache(TYPEOID,
+									 ObjectIdGetDatum(procStruct->prorettype),
+									 0, 0, 0);
 			if (!HeapTupleIsValid(typeTup))
 			{
 				plpgsql_comperrinfo();
@@ -195,6 +194,7 @@ plpgsql_compile(Oid fn_oid, int functype)
 				function->fn_rettypelem = typeStruct->typelem;
 				fmgr_info(typeStruct->typinput, &(function->fn_retinput));
 			}
+			ReleaseSysCache(typeTup);
 
 			/* ----------
 			 * Create the variables for the procedures parameters
@@ -208,9 +208,9 @@ plpgsql_compile(Oid fn_oid, int functype)
 				 * Get the parameters type
 				 * ----------
 				 */
-				typeTup = SearchSysCacheTuple(TYPEOID,
-				  ObjectIdGetDatum(procStruct->proargtypes[i]), 0, 0, 0);
-
+				typeTup = SearchSysCache(TYPEOID,
+										 ObjectIdGetDatum(procStruct->proargtypes[i]),
+										 0, 0, 0);
 				if (!HeapTupleIsValid(typeTup))
 				{
 					plpgsql_comperrinfo();
@@ -276,6 +276,7 @@ plpgsql_compile(Oid fn_oid, int functype)
 
 					arg_varnos[i] = var->varno;
 				}
+				ReleaseSysCache(typeTup);
 			}
 			break;
 
@@ -512,6 +513,7 @@ plpgsql_compile(Oid fn_oid, int functype)
 		function->datums[i] = plpgsql_Datums[i];
 	function->action = plpgsql_yylval.program;
 
+	ReleaseSysCache(procTup);
 
 	/* ----------
 	 * Finally return the compiled function
@@ -608,8 +610,9 @@ plpgsql_parse_word(char *word)
 	 * ----------
 	 */
 	typeXlated = xlateSqlType(cp);
-	typeTup = SearchSysCacheTuple(TYPENAME,
-								  PointerGetDatum(typeXlated), 0, 0, 0);
+	typeTup = SearchSysCache(TYPENAME,
+							 PointerGetDatum(typeXlated),
+							 0, 0, 0);
 	if (HeapTupleIsValid(typeTup))
 	{
 		PLpgSQL_type *typ;
@@ -618,6 +621,7 @@ plpgsql_parse_word(char *word)
 
 		if (typeStruct->typrelid != InvalidOid)
 		{
+			ReleaseSysCache(typeTup);
 			pfree(cp);
 			return T_WORD;
 		}
@@ -634,6 +638,7 @@ plpgsql_parse_word(char *word)
 
 		plpgsql_yylval.dtype = typ;
 
+		ReleaseSysCache(typeTup);
 		pfree(cp);
 		return T_DTYPE;
 	}
@@ -933,8 +938,9 @@ plpgsql_parse_wordtype(char *word)
 	 * ----------
 	 */
 	typeXlated = xlateSqlType(cp);
-	typeTup = SearchSysCacheTuple(TYPENAME,
-								  PointerGetDatum(typeXlated), 0, 0, 0);
+	typeTup = SearchSysCache(TYPENAME,
+							 PointerGetDatum(typeXlated),
+							 0, 0, 0);
 	if (HeapTupleIsValid(typeTup))
 	{
 		PLpgSQL_type *typ;
@@ -943,6 +949,7 @@ plpgsql_parse_wordtype(char *word)
 
 		if (typeStruct->typrelid != InvalidOid)
 		{
+			ReleaseSysCache(typeTup);
 			pfree(cp);
 			return T_ERROR;
 		}
@@ -959,6 +966,7 @@ plpgsql_parse_wordtype(char *word)
 
 		plpgsql_yylval.dtype = typ;
 
+		ReleaseSysCache(typeTup);
 		pfree(cp);
 		return T_DTYPE;
 	}
@@ -1045,8 +1053,9 @@ plpgsql_parse_dblwordtype(char *string)
 	 * First word could also be a table name
 	 * ----------
 	 */
-	classtup = SearchSysCacheTuple(RELNAME,
-								   PointerGetDatum(word1), 0, 0, 0);
+	classtup = SearchSysCache(RELNAME,
+							  PointerGetDatum(word1),
+							  0, 0, 0);
 	if (!HeapTupleIsValid(classtup))
 	{
 		pfree(word1);
@@ -1060,6 +1069,7 @@ plpgsql_parse_dblwordtype(char *string)
 	classStruct = (Form_pg_class) GETSTRUCT(classtup);
 	if (classStruct->relkind != 'r' && classStruct->relkind != 's')
 	{
+		ReleaseSysCache(classtup);
 		pfree(word1);
 		return T_ERROR;
 	}
@@ -1068,31 +1078,33 @@ plpgsql_parse_dblwordtype(char *string)
 	 * Fetch the named table field and it's type
 	 * ----------
 	 */
-	attrtup = SearchSysCacheTuple(ATTNAME,
-							   ObjectIdGetDatum(classtup->t_data->t_oid),
-								  PointerGetDatum(word2), 0, 0);
+	attrtup = SearchSysCache(ATTNAME,
+							 ObjectIdGetDatum(classtup->t_data->t_oid),
+							 PointerGetDatum(word2),
+							 0, 0);
 	if (!HeapTupleIsValid(attrtup))
 	{
+		ReleaseSysCache(classtup);
 		pfree(word1);
 		return T_ERROR;
 	}
 	attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
 
-	typetup = SearchSysCacheTuple(TYPEOID,
-						ObjectIdGetDatum(attrStruct->atttypid), 0, 0, 0);
+	typetup = SearchSysCache(TYPEOID,
+							 ObjectIdGetDatum(attrStruct->atttypid),
+							 0, 0, 0);
 	if (!HeapTupleIsValid(typetup))
 	{
 		plpgsql_comperrinfo();
 		elog(ERROR, "cache lookup for type %u of %s.%s failed",
 			 attrStruct->atttypid, word1, word2);
 	}
+	typeStruct = (Form_pg_type) GETSTRUCT(typetup);
 
 	/* ----------
 	 * Found that - build a compiler type struct and return it
 	 * ----------
 	 */
-	typeStruct = (Form_pg_type) GETSTRUCT(typetup);
-
 	typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
 
 	typ->typname = DatumGetCString(DirectFunctionCall1(nameout,
@@ -1105,6 +1117,9 @@ plpgsql_parse_dblwordtype(char *string)
 
 	plpgsql_yylval.dtype = typ;
 
+	ReleaseSysCache(classtup);
+	ReleaseSysCache(attrtup);
+	ReleaseSysCache(typetup);
 	pfree(word1);
 	return T_DTYPE;
 }
@@ -1138,8 +1153,9 @@ plpgsql_parse_wordrowtype(char *string)
 	cp = strchr(word1, '%');
 	*cp = '\0';
 
-	classtup = SearchSysCacheTuple(RELNAME,
-								   PointerGetDatum(word1), 0, 0, 0);
+	classtup = SearchSysCache(RELNAME,
+							  PointerGetDatum(word1),
+							  0, 0, 0);
 	if (!HeapTupleIsValid(classtup))
 	{
 		plpgsql_comperrinfo();
@@ -1156,8 +1172,9 @@ plpgsql_parse_wordrowtype(char *string)
 	 * Fetch the tables pg_type tuple too
 	 * ----------
 	 */
-	typetup = SearchSysCacheTuple(TYPENAME,
-								  PointerGetDatum(word1), 0, 0, 0);
+	typetup = SearchSysCache(TYPENAME,
+							 PointerGetDatum(word1),
+							 0, 0, 0);
 	if (!HeapTupleIsValid(typetup))
 	{
 		plpgsql_comperrinfo();
@@ -1178,15 +1195,18 @@ plpgsql_parse_wordrowtype(char *string)
 	row->fieldnames = malloc(sizeof(char *) * row->nfields);
 	row->varnos = malloc(sizeof(int) * row->nfields);
 
+	ReleaseSysCache(typetup);
+
 	for (i = 0; i < row->nfields; i++)
 	{
 		/* ----------
 		 * Get the attribute and it's type
 		 * ----------
 		 */
-		attrtup = SearchSysCacheTuple(ATTNUM,
-							   ObjectIdGetDatum(classtup->t_data->t_oid),
-									  (Datum) (i + 1), 0, 0);
+		attrtup = SearchSysCache(ATTNUM,
+								 ObjectIdGetDatum(classtup->t_data->t_oid),
+								 Int16GetDatum(i + 1),
+								 0, 0);
 		if (!HeapTupleIsValid(attrtup))
 		{
 			plpgsql_comperrinfo();
@@ -1198,8 +1218,9 @@ plpgsql_parse_wordrowtype(char *string)
 		cp = DatumGetCString(DirectFunctionCall1(nameout,
 						NameGetDatum(&(attrStruct->attname))));
 
-		typetup = SearchSysCacheTuple(TYPEOID,
-						ObjectIdGetDatum(attrStruct->atttypid), 0, 0, 0);
+		typetup = SearchSysCache(TYPEOID,
+								 ObjectIdGetDatum(attrStruct->atttypid),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(typetup))
 		{
 			plpgsql_comperrinfo();
@@ -1238,6 +1259,9 @@ plpgsql_parse_wordrowtype(char *string)
 		var->isnull = true;
 		var->shouldfree = false;
 
+		ReleaseSysCache(typetup);
+		ReleaseSysCache(attrtup);
+
 		plpgsql_adddatum((PLpgSQL_datum *) var);
 
 		/* ----------
@@ -1248,6 +1272,8 @@ plpgsql_parse_wordrowtype(char *string)
 		row->varnos[i] = var->varno;
 	}
 
+	ReleaseSysCache(classtup);
+
 	/* ----------
 	 * Return the complete row definition
 	 * ----------
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 9c094a0739a7110e0d09e30e8d44baf6fdf36e18..565e304f6494c62d7c4c4dc5449e3635d7d1421c 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3,7 +3,7 @@
  *			  procedural language
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.31 2000/09/12 19:41:40 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.32 2000/11/16 22:30:50 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -1641,10 +1641,12 @@ exec_stmt_raise(PLpgSQL_execstate * estate, PLpgSQL_stmt_raise * stmt)
 						extval = "<NULL>";
 					else
 					{
-						typetup = SearchSysCacheTuple(TYPEOID,
-						ObjectIdGetDatum(var->datatype->typoid), 0, 0, 0);
+						typetup = SearchSysCache(TYPEOID,
+												 ObjectIdGetDatum(var->datatype->typoid),
+												 0, 0, 0);
 						if (!HeapTupleIsValid(typetup))
-							elog(ERROR, "cache lookup for type %u failed (1)", var->datatype->typoid);
+							elog(ERROR, "cache lookup for type %u failed (1)",
+								 var->datatype->typoid);
 						typeStruct = (Form_pg_type) GETSTRUCT(typetup);
 
 						fmgr_info(typeStruct->typoutput, &finfo_output);
@@ -1652,6 +1654,7 @@ exec_stmt_raise(PLpgSQL_execstate * estate, PLpgSQL_stmt_raise * stmt)
 									var->value,
 									ObjectIdGetDatum(typeStruct->typelem),
 									Int32GetDatum(var->datatype->atttypmod)));
+						ReleaseSysCache(typetup);
 					}
 					plpgsql_dstring_append(&ds, extval);
 					break;
@@ -1961,21 +1964,24 @@ exec_stmt_dynexecute(PLpgSQL_execstate * estate,
 	 * Get the C-String representation.
 	 * ----------
 	 */
-	typetup = SearchSysCacheTuple(TYPEOID,
-		ObjectIdGetDatum(restype), 0, 0, 0);
+	typetup = SearchSysCache(TYPEOID,
+							 ObjectIdGetDatum(restype),
+							 0, 0, 0);
 	if (!HeapTupleIsValid(typetup))
 		elog(ERROR, "cache lookup for type %u failed (1)", restype);
 	typeStruct = (Form_pg_type) GETSTRUCT(typetup);
 
 	fmgr_info(typeStruct->typoutput, &finfo_output);
 	querystr = DatumGetCString(FunctionCall3(&finfo_output,
-				query,
-				ObjectIdGetDatum(typeStruct->typelem),
-				Int32GetDatum(-1)));
+											 query,
+											 ObjectIdGetDatum(typeStruct->typelem),
+											 Int32GetDatum(-1)));
 
 	if(!typeStruct->typbyval)
 		pfree((void *)query);
 
+	ReleaseSysCache(typetup);
+
 	/* ----------
 	 * Call SPI_exec() without preparing a saved plan. 
 	 * The returncode can be any OK except for OK_SELECT.
@@ -2064,8 +2070,9 @@ exec_stmt_dynfors(PLpgSQL_execstate * estate, PLpgSQL_stmt_dynfors * stmt)
 	 * Get the C-String representation.
 	 * ----------
 	 */
-	typetup = SearchSysCacheTuple(TYPEOID,
-		ObjectIdGetDatum(restype), 0, 0, 0);
+	typetup = SearchSysCache(TYPEOID,
+							 ObjectIdGetDatum(restype),
+							 0, 0, 0);
 	if (!HeapTupleIsValid(typetup))
 		elog(ERROR, "cache lookup for type %u failed (1)", restype);
 	typeStruct = (Form_pg_type) GETSTRUCT(typetup);
@@ -2079,6 +2086,8 @@ exec_stmt_dynfors(PLpgSQL_execstate * estate, PLpgSQL_stmt_dynfors * stmt)
 	if(!typeStruct->typbyval)
 		pfree((void *)query);
 
+	ReleaseSysCache(typetup);
+
 	/* ----------
 	 * Run the query
 	 * ----------
@@ -2283,8 +2292,9 @@ exec_assign_value(PLpgSQL_execstate * estate,
 				 */
 				atttype = SPI_gettypeid(rec->tupdesc, i + 1);
 				atttypmod = rec->tupdesc->attrs[i]->atttypmod;
-				typetup = SearchSysCacheTuple(TYPEOID,
-									 ObjectIdGetDatum(atttype), 0, 0, 0);
+				typetup = SearchSysCache(TYPEOID,
+										 ObjectIdGetDatum(atttype),
+										 0, 0, 0);
 				if (!HeapTupleIsValid(typetup))
 					elog(ERROR, "cache lookup for type %u failed", atttype);
 				typeStruct = (Form_pg_type) GETSTRUCT(typetup);
@@ -2299,6 +2309,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
 					nulls[i] = 'n';
 				else
 					nulls[i] = ' ';
+				ReleaseSysCache(typetup);
 			}
 
 			/* ----------
@@ -2603,9 +2614,13 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
 	 * so that we can free the expression context.
 	 */
 	if (! *isNull)
-		retval = datumCopy(retval,
-						   get_typbyval(*rettype),
-						   get_typlen(*rettype));
+	{
+		int16		typeLength;
+		bool		byValue;
+
+		get_typlenbyval(*rettype, &typeLength, &byValue);
+		retval = datumCopy(retval, byValue, typeLength);
+	}
 
 	FreeExprContext(econtext);
 
@@ -2726,8 +2741,9 @@ exec_cast_value(Datum value, Oid valtype,
 			FmgrInfo	finfo_output;
 			char	   *extval;
 
-			typetup = SearchSysCacheTuple(TYPEOID,
-									 ObjectIdGetDatum(valtype), 0, 0, 0);
+			typetup = SearchSysCache(TYPEOID,
+									 ObjectIdGetDatum(valtype),
+									 0, 0, 0);
 			if (!HeapTupleIsValid(typetup))
 				elog(ERROR, "cache lookup for type %u failed", valtype);
 			typeStruct = (Form_pg_type) GETSTRUCT(typetup);
@@ -2742,6 +2758,7 @@ exec_cast_value(Datum value, Oid valtype,
 								  ObjectIdGetDatum(reqtypelem),
 								  Int32GetDatum(reqtypmod));
 			pfree(extval);
+			ReleaseSysCache(typetup);
 		}
 	}
 
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 0c2ec992b7b6a0ebc309bdce396f1e13bee6e16c..8658cac3065322f0fbd0013a851fc2755f06fd78 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -31,7 +31,7 @@
  *	  ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.28 2000/07/19 11:53:02 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.29 2000/11/16 22:30:52 tgl Exp $
  *
  **********************************************************************/
 
@@ -437,9 +437,9 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 		/************************************************************
 		 * Lookup the pg_proc tuple by Oid
 		 ************************************************************/
-		procTup = SearchSysCacheTuple(PROCOID,
-									  ObjectIdGetDatum(fcinfo->flinfo->fn_oid),
-									  0, 0, 0);
+		procTup = SearchSysCache(PROCOID,
+								 ObjectIdGetDatum(fcinfo->flinfo->fn_oid),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(procTup))
 		{
 			free(prodesc->proname);
@@ -452,9 +452,9 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 		/************************************************************
 		 * Lookup the pg_language tuple by Oid
 		 ************************************************************/
-		langTup = SearchSysCacheTuple(LANGOID,
-									  ObjectIdGetDatum(procStruct->prolang),
-									  0, 0, 0);
+		langTup = SearchSysCache(LANGOID,
+								 ObjectIdGetDatum(procStruct->prolang),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(langTup))
 		{
 			free(prodesc->proname);
@@ -469,14 +469,15 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 			interp = pltcl_safe_interp;
 		else
 			interp = pltcl_norm_interp;
+		ReleaseSysCache(langTup);
 
 		/************************************************************
 		 * Get the required information for input conversion of the
 		 * return value.
 		 ************************************************************/
-		typeTup = SearchSysCacheTuple(TYPEOID,
-								ObjectIdGetDatum(procStruct->prorettype),
-									  0, 0, 0);
+		typeTup = SearchSysCache(TYPEOID,
+								 ObjectIdGetDatum(procStruct->prorettype),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(typeTup))
 		{
 			free(prodesc->proname);
@@ -496,6 +497,8 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 		fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
 		prodesc->result_in_elem = typeStruct->typelem;
 
+		ReleaseSysCache(typeTup);
+
 		/************************************************************
 		 * Get the required information for output conversion
 		 * of all procedure arguments
@@ -504,9 +507,9 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 		proc_internal_args[0] = '\0';
 		for (i = 0; i < prodesc->nargs; i++)
 		{
-			typeTup = SearchSysCacheTuple(TYPEOID,
+			typeTup = SearchSysCache(TYPEOID,
 							ObjectIdGetDatum(procStruct->proargtypes[i]),
-										  0, 0, 0);
+									 0, 0, 0);
 			if (!HeapTupleIsValid(typeTup))
 			{
 				free(prodesc->proname);
@@ -523,6 +526,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 					strcat(proc_internal_args, " ");
 				sprintf(buf, "__PLTcl_Tup_%d", i + 1);
 				strcat(proc_internal_args, buf);
+				ReleaseSysCache(typeTup);
 				continue;
 			}
 			else
@@ -536,6 +540,8 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 				strcat(proc_internal_args, " ");
 			sprintf(buf, "%d", i + 1);
 			strcat(proc_internal_args, buf);
+
+			ReleaseSysCache(typeTup);
 		}
 
 		/************************************************************
@@ -591,6 +597,8 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 		hashent = Tcl_CreateHashEntry(pltcl_proc_hash,
 									  prodesc->proname, &hashnew);
 		Tcl_SetHashValue(hashent, (ClientData) prodesc);
+
+		ReleaseSysCache(procTup);
 	}
 	else
 	{
@@ -800,9 +808,9 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 		/************************************************************
 		 * Lookup the pg_proc tuple by Oid
 		 ************************************************************/
-		procTup = SearchSysCacheTuple(PROCOID,
-									  ObjectIdGetDatum(fcinfo->flinfo->fn_oid),
-									  0, 0, 0);
+		procTup = SearchSysCache(PROCOID,
+								 ObjectIdGetDatum(fcinfo->flinfo->fn_oid),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(procTup))
 		{
 			free(prodesc->proname);
@@ -815,9 +823,9 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 		/************************************************************
 		 * Lookup the pg_language tuple by Oid
 		 ************************************************************/
-		langTup = SearchSysCacheTuple(LANGOID,
-									  ObjectIdGetDatum(procStruct->prolang),
-									  0, 0, 0);
+		langTup = SearchSysCache(LANGOID,
+								 ObjectIdGetDatum(procStruct->prolang),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(langTup))
 		{
 			free(prodesc->proname);
@@ -832,6 +840,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 			interp = pltcl_safe_interp;
 		else
 			interp = pltcl_norm_interp;
+		ReleaseSysCache(langTup);
 
 		/************************************************************
 		 * Create the tcl command to define the internal
@@ -896,6 +905,8 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 		hashent = Tcl_CreateHashEntry(pltcl_proc_hash,
 									  prodesc->proname, &hashnew);
 		Tcl_SetHashValue(hashent, (ClientData) prodesc);
+
+		ReleaseSysCache(procTup);
 	}
 	else
 	{
@@ -1151,9 +1162,9 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 		 * Lookup the attribute type in the syscache
 		 * for the input function
 		 ************************************************************/
-		typeTup = SearchSysCacheTuple(TYPEOID,
+		typeTup = SearchSysCache(TYPEOID,
 				  ObjectIdGetDatum(tupdesc->attrs[attnum - 1]->atttypid),
-									  0, 0, 0);
+								 0, 0, 0);
 		if (!HeapTupleIsValid(typeTup))
 		{
 			elog(ERROR, "pltcl: Cache lookup for attribute '%s' type %u failed",
@@ -1162,6 +1173,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 		}
 		typinput = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typinput);
 		typelem = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typelem);
+		ReleaseSysCache(typeTup);
 
 		/************************************************************
 		 * Set the attribute to NOT NULL and convert the contents
@@ -1706,9 +1718,9 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
 	 ************************************************************/
 	for (i = 0; i < nargs; i++)
 	{
-		typeTup = SearchSysCacheTuple(TYPENAME,
-									  PointerGetDatum(args[i]),
-									  0, 0, 0);
+		typeTup = SearchSysCache(TYPENAME,
+								 PointerGetDatum(args[i]),
+								 0, 0, 0);
 		if (!HeapTupleIsValid(typeTup))
 			elog(ERROR, "pltcl: Cache lookup of type %s failed", args[i]);
 		qdesc->argtypes[i] = typeTup->t_data->t_oid;
@@ -1717,6 +1729,7 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
 		qdesc->argtypelems[i] = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
 		qdesc->argvalues[i] = (Datum) NULL;
 		qdesc->arglen[i] = (int) (((Form_pg_type) GETSTRUCT(typeTup))->typlen);
+		ReleaseSysCache(typeTup);
 	}
 
 	/************************************************************
@@ -2263,9 +2276,9 @@ pltcl_set_tuple_values(Tcl_Interp *interp, char *arrayname,
 		 * Lookup the attribute type in the syscache
 		 * for the output function
 		 ************************************************************/
-		typeTup = SearchSysCacheTuple(TYPEOID,
+		typeTup = SearchSysCache(TYPEOID,
 						   ObjectIdGetDatum(tupdesc->attrs[i]->atttypid),
-									  0, 0, 0);
+								 0, 0, 0);
 		if (!HeapTupleIsValid(typeTup))
 		{
 			elog(ERROR, "pltcl: Cache lookup for attribute '%s' type %u failed",
@@ -2274,6 +2287,7 @@ pltcl_set_tuple_values(Tcl_Interp *interp, char *arrayname,
 
 		typoutput = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typoutput);
 		typelem = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typelem);
+		ReleaseSysCache(typeTup);
 
 		/************************************************************
 		 * If there is a value, set the variable
@@ -2332,9 +2346,9 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
 		 * Lookup the attribute type in the syscache
 		 * for the output function
 		 ************************************************************/
-		typeTup = SearchSysCacheTuple(TYPEOID,
+		typeTup = SearchSysCache(TYPEOID,
 						   ObjectIdGetDatum(tupdesc->attrs[i]->atttypid),
-									  0, 0, 0);
+								 0, 0, 0);
 		if (!HeapTupleIsValid(typeTup))
 		{
 			elog(ERROR, "pltcl: Cache lookup for attribute '%s' type %u failed",
@@ -2343,6 +2357,7 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
 
 		typoutput = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typoutput);
 		typelem = (Oid) (((Form_pg_type) GETSTRUCT(typeTup))->typelem);
+		ReleaseSysCache(typeTup);
 
 		/************************************************************
 		 * If there is a value, append the attribute name and the