Rearrange fmgr.c and relcache so that it's possible to keep FmgrInfo
authorTom Lane
Sat, 6 Oct 2001 23:21:45 +0000 (23:21 +0000)
committerTom Lane
Sat, 6 Oct 2001 23:21:45 +0000 (23:21 +0000)
lookup info in the relcache for index access method support functions.
This makes a huge difference for dynamically loaded support functions,
and should save a few cycles even for built-in ones.  Also tweak dfmgr.c
so that load_external_function is called only once, not twice, when
doing fmgr_info for a dynamically loaded function.  All per performance
gripe from Teodor Sigaev, 5-Oct-01.

31 files changed:
src/backend/access/common/scankey.c
src/backend/access/gist/gist.c
src/backend/access/hash/hashutil.c
src/backend/access/index/indexam.c
src/backend/access/index/istrat.c
src/backend/access/nbtree/nbtsearch.c
src/backend/access/nbtree/nbtutils.c
src/backend/access/rtree/rtree.c
src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/catalog/pg_proc.c
src/backend/utils/adt/ri_triggers.c
src/backend/utils/adt/varbit.c
src/backend/utils/adt/varchar.c
src/backend/utils/cache/Makefile
src/backend/utils/cache/catcache.c
src/backend/utils/cache/fcache.c
src/backend/utils/cache/rel.c [deleted file]
src/backend/utils/cache/relcache.c
src/backend/utils/fmgr/dfmgr.c
src/backend/utils/fmgr/fmgr.c
src/include/access/genam.h
src/include/access/skey.h
src/include/catalog/index.h
src/include/fmgr.h
src/include/utils/rel.h
src/include/utils/relcache.h
src/pl/plperl/plperl.c
src/pl/plpgsql/src/pl_comp.c
src/pl/plpython/plpython.c
src/pl/tcl/pltcl.c

index eb66d41bf26e43e31a1cef92b0141cca0791d34a..26112171911213701e5f77a5d97b58d36eff4496 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/common/scankey.c,v 1.19 2001/06/01 02:41:35 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/common/scankey.c,v 1.20 2001/10/06 23:21:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -69,3 +69,31 @@ ScanKeyEntryInitialize(ScanKey entry,
 
    Assert(ScanKeyEntryIsLegal(entry));
 }
+
+/*
+ * ScanKeyEntryInitializeWithInfo
+ *     Initializes a scan key entry using an already-completed FmgrInfo
+ *     function lookup record.
+ *
+ * mcxt is the memory context holding the scan key; it'll be used for
+ * any subsidiary info attached to the scankey's FmgrInfo record.
+ */
+void
+ScanKeyEntryInitializeWithInfo(ScanKey entry,
+                              bits16 flags,
+                              AttrNumber attributeNumber,
+                              FmgrInfo *finfo,
+                              MemoryContext mcxt,
+                              Datum argument)
+{
+   Assert(PointerIsValid(entry));
+   Assert(RegProcedureIsValid(finfo->fn_oid));
+
+   entry->sk_flags = flags;
+   entry->sk_attno = attributeNumber;
+   entry->sk_procedure = finfo->fn_oid;
+   entry->sk_argument = argument;
+   fmgr_info_copy(&entry->sk_func, finfo, mcxt);
+
+   Assert(ScanKeyEntryIsLegal(entry));
+}
index e05e07b6366522d8daf2af00e9445b63723db4be..4a702fe31741a8088611e0fbcd80462d689de5c0 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.83 2001/08/22 18:24:26 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.84 2001/10/06 23:21:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1542,13 +1542,6 @@ gistbulkdelete(PG_FUNCTION_ARGS)
 void
 initGISTstate(GISTSTATE *giststate, Relation index)
 {
-   RegProcedure consistent_proc,
-               union_proc,
-               compress_proc,
-               decompress_proc,
-               penalty_proc,
-               picksplit_proc,
-               equal_proc;
    int i;
 
    if (index->rd_att->natts > INDEX_MAX_KEYS)
@@ -1559,20 +1552,27 @@ initGISTstate(GISTSTATE *giststate, Relation index)
 
    for (i = 0; i < index->rd_att->natts; i++)
    {
-       consistent_proc = index_getprocid(index, i+1, GIST_CONSISTENT_PROC  );
-       union_proc  = index_getprocid(index, i+1, GIST_UNION_PROC       );
-       compress_proc   = index_getprocid(index, i+1, GIST_COMPRESS_PROC    );
-       decompress_proc = index_getprocid(index, i+1, GIST_DECOMPRESS_PROC  );
-       penalty_proc    = index_getprocid(index, i+1, GIST_PENALTY_PROC     );
-       picksplit_proc  = index_getprocid(index, i+1, GIST_PICKSPLIT_PROC   );
-       equal_proc  = index_getprocid(index, i+1, GIST_EQUAL_PROC       );
-       fmgr_info(consistent_proc,  &((giststate->consistentFn)[i])     );
-       fmgr_info(union_proc,       &((giststate->unionFn)[i])      );
-       fmgr_info(compress_proc,    &((giststate->compressFn)[i])       );
-       fmgr_info(decompress_proc,  &((giststate->decompressFn)[i])     );
-       fmgr_info(penalty_proc,     &((giststate->penaltyFn)[i])        );
-       fmgr_info(picksplit_proc,   &((giststate->picksplitFn)[i])      );
-       fmgr_info(equal_proc,       &((giststate->equalFn)[i])      );
+       fmgr_info_copy(&(giststate->consistentFn[i]),
+                      index_getprocinfo(index, i+1, GIST_CONSISTENT_PROC),
+                      CurrentMemoryContext);
+       fmgr_info_copy(&(giststate->unionFn[i]),
+                      index_getprocinfo(index, i+1, GIST_UNION_PROC),
+                      CurrentMemoryContext);
+       fmgr_info_copy(&(giststate->compressFn[i]),
+                      index_getprocinfo(index, i+1, GIST_COMPRESS_PROC),
+                      CurrentMemoryContext);
+       fmgr_info_copy(&(giststate->decompressFn[i]),
+                      index_getprocinfo(index, i+1, GIST_DECOMPRESS_PROC),
+                      CurrentMemoryContext);
+       fmgr_info_copy(&(giststate->penaltyFn[i]),
+                      index_getprocinfo(index, i+1, GIST_PENALTY_PROC),
+                      CurrentMemoryContext);
+       fmgr_info_copy(&(giststate->picksplitFn[i]),
+                      index_getprocinfo(index, i+1, GIST_PICKSPLIT_PROC),
+                      CurrentMemoryContext);
+       fmgr_info_copy(&(giststate->equalFn[i]),
+                      index_getprocinfo(index, i+1, GIST_EQUAL_PROC),
+                      CurrentMemoryContext);
    }
 }
 
index 0aac61fa025dcba02d98fcfc75eae6c2d90813a2..4680061118375f2d79c5ae779559e00d19635fd1 100644 (file)
@@ -8,13 +8,14 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/hash/hashutil.c,v 1.26 2001/02/22 21:48:49 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/hash/hashutil.c,v 1.27 2001/10/06 23:21:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
+#include "access/genam.h"
 #include "access/hash.h"
 #include "access/iqual.h"
 
@@ -27,8 +28,8 @@ _hash_mkscankey(Relation rel, IndexTuple itup, HashMetaPage metap)
    int         natts;
    AttrNumber  i;
    Datum       arg;
-   RegProcedure proc;
-   bool        null;
+   FmgrInfo   *procinfo;
+   bool        isnull;
 
    natts = rel->rd_rel->relnatts;
    itupdesc = RelationGetDescr(rel);
@@ -37,10 +38,14 @@ _hash_mkscankey(Relation rel, IndexTuple itup, HashMetaPage metap)
 
    for (i = 0; i < natts; i++)
    {
-       arg = index_getattr(itup, i + 1, itupdesc, &null);
-       proc = metap->hashm_procid;
-       ScanKeyEntryInitialize(&skey[i],
-                              0x0, (AttrNumber) (i + 1), proc, arg);
+       arg = index_getattr(itup, i + 1, itupdesc, &isnull);
+       procinfo = index_getprocinfo(rel, i + 1, HASHPROC);
+       ScanKeyEntryInitializeWithInfo(&skey[i],
+                                      0x0,
+                                      (AttrNumber) (i + 1),
+                                      procinfo,
+                                      CurrentMemoryContext,
+                                      arg);
    }
 
    return skey;
@@ -89,10 +94,13 @@ _hash_formitem(IndexTuple itup)
 Bucket
 _hash_call(Relation rel, HashMetaPage metap, Datum key)
 {
+   FmgrInfo   *procinfo;
    uint32      n;
    Bucket      bucket;
 
-   n = DatumGetUInt32(OidFunctionCall1(metap->hashm_procid, key));
+   /* XXX assumes index has only one attribute */
+   procinfo = index_getprocinfo(rel, 1, HASHPROC);
+   n = DatumGetUInt32(FunctionCall1(procinfo, key));
    bucket = n & metap->hashm_highmask;
    if (bucket > metap->hashm_maxbucket)
        bucket = bucket & metap->hashm_lowmask;
index 2b6be06168f234cec7865e46f858e2074bb74c70..2a1d3294dd0d446ae777bdea16f096f3af7bb7d1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.52 2001/07/15 22:48:15 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.53 2001/10/06 23:21:43 tgl Exp $
  *
  * INTERFACE ROUTINES
  *     index_open      - open an index relation by relationId
@@ -428,12 +428,58 @@ index_getprocid(Relation irel,
 {
    RegProcedure *loc;
    int         nproc;
+   int         procindex;
 
    nproc = irel->rd_am->amsupport;
 
+   Assert(procnum > 0 && procnum <= (uint16) nproc);
+
+   procindex = (nproc * (attnum - 1)) + (procnum - 1);
+
    loc = irel->rd_support;
 
    Assert(loc != NULL);
 
-   return loc[(nproc * (attnum - 1)) + (procnum - 1)];
+   return loc[procindex];
+}
+
+/* ----------------
+ *     index_getprocinfo
+ *
+ *     This routine allows index AMs to keep fmgr lookup info for
+ *     support procs in the relcache.
+ * ----------------
+ */
+struct FmgrInfo *
+index_getprocinfo(Relation irel,
+                 AttrNumber attnum,
+                 uint16 procnum)
+{
+   FmgrInfo   *locinfo;
+   int         nproc;
+   int         procindex;
+
+   nproc = irel->rd_am->amsupport;
+
+   Assert(procnum > 0 && procnum <= (uint16) nproc);
+
+   procindex = (nproc * (attnum - 1)) + (procnum - 1);
+
+   locinfo = irel->rd_supportinfo;
+
+   Assert(locinfo != NULL);
+
+   locinfo += procindex;
+
+   /* Initialize the lookup info if first time through */
+   if (locinfo->fn_oid == InvalidOid)
+   {
+       RegProcedure *loc = irel->rd_support;
+
+       Assert(loc != NULL);
+
+       fmgr_info_cxt(loc[procindex], locinfo, irel->rd_indexcxt);
+   }
+
+   return locinfo;
 }
index 35df06aeace8eda1ffcc255b67474d70ed24360b..568581fc18acfdbb98db164334ef64ad92166290 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.52 2001/08/21 16:36:00 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.53 2001/10/06 23:21:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -486,12 +486,9 @@ FillScanKeyEntry(Oid operatorObjectId, ScanKey entry)
             operatorObjectId);
 
    /*
-    * Formerly we initialized entry->sk_func here, but that's a waste of
-    * time because ScanKey entries in strategy maps are never actually
-    * used to invoke the operator.  Furthermore, to do that we'd have to
-    * worry about setting the proper memory context (the map is probably
-    * not allocated in the current memory context!)
+    * Mark entry->sk_func invalid, until and unless someone sets it up.
     */
+   entry->sk_func.fn_oid = InvalidOid;
 }
 
 
index 295387ed5177a0d9c2e10c2b7c21657e9160b9f1..86ff810845c4d6a37483307df008f4cdc0d8d934 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.67 2001/07/15 22:48:16 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.68 2001/10/06 23:21:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -435,7 +435,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
    BlockNumber blkno;
    StrategyNumber strat;
    RetrieveIndexResult res;
-   RegProcedure proc;
    int32       result;
    BTScanOpaque so;
    bool        continuescan;
@@ -532,6 +531,8 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
    scankeys = (ScanKey) palloc(keysCount * sizeof(ScanKeyData));
    for (i = 0; i < keysCount; i++)
    {
+       FmgrInfo   *procinfo;
+
        j = nKeyIs[i];
 
        /*
@@ -545,9 +546,13 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
            elog(ERROR, "_bt_first: btree doesn't support is(not)null, yet");
            return ((RetrieveIndexResult) NULL);
        }
-       proc = index_getprocid(rel, i + 1, BTORDER_PROC);
-       ScanKeyEntryInitialize(scankeys + i, so->keyData[j].sk_flags,
-                              i + 1, proc, so->keyData[j].sk_argument);
+       procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
+       ScanKeyEntryInitializeWithInfo(scankeys + i,
+                                      so->keyData[j].sk_flags,
+                                      i + 1,
+                                      procinfo,
+                                      CurrentMemoryContext,
+                                      so->keyData[j].sk_argument);
    }
    if (nKeyIs)
        pfree(nKeyIs);
index 28aa99237d298eaad5b4022f3b167d624503b71f..86d2e3cf8fa7a0cf04b028e399ec2469401fc538 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.45 2001/05/17 14:59:31 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.46 2001/10/06 23:21:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,7 +36,7 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
    TupleDesc   itupdesc;
    int         natts;
    int         i;
-   RegProcedure proc;
+   FmgrInfo   *procinfo;
    Datum       arg;
    bool        null;
    bits16      flag;
@@ -48,14 +48,15 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
 
    for (i = 0; i < natts; i++)
    {
-       proc = index_getprocid(rel, i + 1, BTORDER_PROC);
+       procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
        arg = index_getattr(itup, i + 1, itupdesc, &null);
        flag = null ? SK_ISNULL : 0x0;
-       ScanKeyEntryInitialize(&skey[i],
-                              flag,
-                              (AttrNumber) (i + 1),
-                              proc,
-                              arg);
+       ScanKeyEntryInitializeWithInfo(&skey[i],
+                                      flag,
+                                      (AttrNumber) (i + 1),
+                                      procinfo,
+                                      CurrentMemoryContext,
+                                      arg);
    }
 
    return skey;
@@ -76,7 +77,7 @@ _bt_mkscankey_nodata(Relation rel)
    ScanKey     skey;
    int         natts;
    int         i;
-   RegProcedure proc;
+   FmgrInfo   *procinfo;
 
    natts = RelationGetNumberOfAttributes(rel);
 
@@ -84,12 +85,13 @@ _bt_mkscankey_nodata(Relation rel)
 
    for (i = 0; i < natts; i++)
    {
-       proc = index_getprocid(rel, i + 1, BTORDER_PROC);
-       ScanKeyEntryInitialize(&skey[i],
-                              SK_ISNULL,
-                              (AttrNumber) (i + 1),
-                              proc,
-                              (Datum) NULL);
+       procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
+       ScanKeyEntryInitializeWithInfo(&skey[i],
+                                      SK_ISNULL,
+                                      (AttrNumber) (i + 1),
+                                      procinfo,
+                                      CurrentMemoryContext,
+                                      (Datum) 0);
    }
 
    return skey;
index f3b46f3144bac23c754aa037bae8cc119a5bcba0..42878248b0002546513e8e682f7dc393a6ea385f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.64 2001/09/29 03:46:12 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.65 2001/10/06 23:21:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1264,17 +1264,15 @@ rtbulkdelete(PG_FUNCTION_ARGS)
 static void
 initRtstate(RTSTATE *rtstate, Relation index)
 {
-   RegProcedure union_proc,
-               size_proc,
-               inter_proc;
-
-   union_proc = index_getprocid(index, 1, RT_UNION_PROC);
-   size_proc = index_getprocid(index, 1, RT_SIZE_PROC);
-   inter_proc = index_getprocid(index, 1, RT_INTER_PROC);
-   fmgr_info(union_proc, &rtstate->unionFn);
-   fmgr_info(size_proc, &rtstate->sizeFn);
-   fmgr_info(inter_proc, &rtstate->interFn);
-   return;
+   fmgr_info_copy(&rtstate->unionFn,
+                  index_getprocinfo(index, 1, RT_UNION_PROC),
+                  CurrentMemoryContext);
+   fmgr_info_copy(&rtstate->sizeFn,
+                  index_getprocinfo(index, 1, RT_SIZE_PROC),
+                  CurrentMemoryContext);
+   fmgr_info_copy(&rtstate->interFn,
+                  index_getprocinfo(index, 1, RT_INTER_PROC),
+                  CurrentMemoryContext);
 }
 
 /* for sorting SPLITCOST records in descending order */
index b68488ae0073c69adbff99636cb8bf706e279959..599e79a4ea67104ede684ade962c711b860b7f96 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.176 2001/09/06 02:07:42 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.177 2001/10/06 23:21:43 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -973,10 +973,8 @@ RelationTruncateIndexes(Oid heapId)
 
    while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
    {
-       Oid         indexId,
-                   accessMethodId;
+       Oid         indexId;
        IndexInfo  *indexInfo;
-       HeapTuple   classTuple;
        Relation    heapRelation,
                    currentIndex;
 
@@ -986,16 +984,6 @@ RelationTruncateIndexes(Oid heapId)
        indexId = ((Form_pg_index) GETSTRUCT(indexTuple))->indexrelid;
        indexInfo = BuildIndexInfo(indexTuple);
 
-       /* 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
         * because index_build will close it again.  We need grab no lock,
@@ -1022,8 +1010,6 @@ RelationTruncateIndexes(Oid heapId)
        currentIndex->rd_targblock = InvalidBlockNumber;
 
        /* Initialize the index and rebuild */
-       InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
-                         currentIndex, accessMethodId);
        index_build(heapRelation, currentIndex, indexInfo);
 
        /*
index c850c55a0f50f202c5e0a7ac69b2f8d2fcb318f3..b53eab86524a5a4769475988f3a9005e23f0b856 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.164 2001/09/26 21:09:27 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.165 2001/10/06 23:21:43 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -644,76 +644,6 @@ UpdateIndexRelation(Oid indexoid,
    heap_freetuple(tuple);
 }
 
-/* ----------------------------------------------------------------
- *     InitIndexStrategy
- *
- * XXX this is essentially the same as relcache.c's
- * IndexedAccessMethodInitialize(), and probably ought to be merged with it.
- * ----------------------------------------------------------------
- */
-void
-InitIndexStrategy(int numatts,
-                 Relation indexRelation,
-                 Oid accessMethodObjectId)
-{
-   IndexStrategy strategy;
-   RegProcedure *support;
-   uint16      amstrategies;
-   uint16      amsupport;
-   Size        strsize;
-
-   /*
-    * get information from the index relation descriptor
-    */
-   amstrategies = indexRelation->rd_am->amstrategies;
-   amsupport = indexRelation->rd_am->amsupport;
-
-   /*
-    * compute the size of the strategy array
-    */
-   strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
-
-   /*
-    * allocate the new index strategy structure
-    *
-    * the index strategy has to be allocated in the same context as the
-    * relation descriptor cache or else it will be lost at the end of the
-    * transaction.
-    */
-   if (!CacheMemoryContext)
-       CreateCacheMemoryContext();
-
-   strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
-                                                 strsize);
-
-   if (amsupport > 0)
-   {
-       strsize = numatts * (amsupport * sizeof(RegProcedure));
-       support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
-                                                     strsize);
-   }
-   else
-       support = (RegProcedure *) NULL;
-
-   /*
-    * fill in the index strategy structure with information from the
-    * catalogs.  First we must advance the command counter so that we
-    * will see the newly-entered index catalog tuples.
-    */
-   CommandCounterIncrement();
-
-   IndexSupportInitialize(strategy, support,
-                          &indexRelation->rd_uniqueindex,
-                          RelationGetRelid(indexRelation),
-                          accessMethodObjectId,
-                          amstrategies, amsupport, numatts);
-
-   /*
-    * store the strategy information in the index reldesc
-    */
-   RelationSetIndexSupport(indexRelation, strategy, support);
-}
-
 
 /* ----------------------------------------------------------------
  *     index_create
@@ -839,11 +769,13 @@ index_create(char *heapRelationName,
                        classObjectId, primary);
 
    /*
-    * initialize the index strategy
+    * fill in the index strategy structure with information from the
+    * catalogs.  First we must advance the command counter so that we
+    * will see the newly-entered index catalog tuples.
     */
-   InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
-                     indexRelation,
-                     accessMethodObjectId);
+   CommandCounterIncrement();
+
+   RelationInitIndexAccessInfo(indexRelation);
 
    /*
     * If this is bootstrap (initdb) time, then we don't actually fill in
@@ -1935,11 +1867,9 @@ reindex_index(Oid indexId, bool force, bool inplace)
                heapRelation;
    ScanKeyData entry;
    HeapScanDesc scan;
-   HeapTuple   indexTuple,
-               classTuple;
+   HeapTuple   indexTuple;
    IndexInfo  *indexInfo;
-   Oid         heapId,
-               accessMethodId;
+   Oid         heapId;
    bool        old;
 
    /*
@@ -1970,15 +1900,6 @@ reindex_index(Oid indexId, bool force, bool inplace)
    heap_endscan(scan);
    heap_close(indexRelation, AccessShareLock);
 
-   /* Fetch the classTuple associated with this index */
-   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);
    if (heapRelation == NULL)
@@ -2012,7 +1933,6 @@ reindex_index(Oid indexId, bool force, bool inplace)
    }
 
    /* Initialize the index and rebuild */
-   InitIndexStrategy(indexInfo->ii_NumIndexAttrs, iRel, accessMethodId);
    index_build(heapRelation, iRel, indexInfo);
 
    /*
index c15476217551d2b25f66bc199934fc37fc50bd2a..e83d35edbf669044bac91ee1222513a3072bb5ce 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.60 2001/10/02 21:39:35 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.61 2001/10/06 23:21:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -246,11 +246,14 @@ ProcedureCreate(char *procedureName,
 
    if (languageObjectId == ClanguageId)
    {
+       void   *libraryhandle;
+
        /* If link symbol is specified as "-", substitute procedure name */
        if (strcmp(prosrc, "-") == 0)
            prosrc = procedureName;
-       (void) load_external_function(probin, prosrc, true);
-       (void) fetch_finfo_record(probin, prosrc);
+       (void) load_external_function(probin, prosrc, true,
+                                     &libraryhandle);
+       (void) fetch_finfo_record(libraryhandle, prosrc);
    }
 
    /*
index ebbb8b07ee8f14ba933aa65a5667ea9368f532a1..a03ca7744081e7f5ba844dca69fef8d78cc92265 100644 (file)
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 2000-2001, PostgreSQL Global Development Group
  * Copyright 1999 Jan Wieck
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.27 2001/10/05 17:28:12 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.28 2001/10/06 23:21:44 tgl Exp $
  *
  * ----------
  */
@@ -3243,7 +3243,6 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
    {
        HeapTuple   opr_tup;
        Oid         opr_proc;
-       MemoryContext   oldcontext;
        FmgrInfo    finfo;
 
        opr_tup = SearchSysCache(OPERNAME,
@@ -3265,9 +3264,7 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
         * table entry, we must make sure any subsidiary structures of the
         * fmgr record are kept in TopMemoryContext.
         */
-       oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-       fmgr_info(opr_proc, &finfo);
-       MemoryContextSwitchTo(oldcontext);
+       fmgr_info_cxt(opr_proc, &finfo, TopMemoryContext);
 
        entry = (RI_OpreqHashEntry *) hash_search(ri_opreq_cache,
                                                  (void *) &typeid,
index d75d05309df38153ed2c9a58f8f2f440f17496c9..a294bfc9fff96c1a7de33d7f6ef9b1ad2fff32a2 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.18 2001/05/22 16:37:16 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.19 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,7 @@
 #include "catalog/pg_type.h"
 #include "utils/array.h"
 #include "utils/fmgroids.h"
+#include "utils/memutils.h"
 #include "utils/varbit.h"
 
 #define HEXDIG(z)   ((z)<10 ? ((z)+'0') : ((z)-10+'A'))
@@ -238,7 +239,7 @@ _bit(PG_FUNCTION_ARGS)
    static FmgrInfo bit_finfo;
 
    if (bit_finfo.fn_oid == InvalidOid)
-       fmgr_info(F_BIT, &bit_finfo);
+       fmgr_info_cxt(F_BIT, &bit_finfo, TopMemoryContext);
 
    MemSet(&locfcinfo, 0, sizeof(locfcinfo));
    locfcinfo.flinfo = &bit_finfo;
@@ -452,7 +453,7 @@ _varbit(PG_FUNCTION_ARGS)
    static FmgrInfo varbit_finfo;
 
    if (varbit_finfo.fn_oid == InvalidOid)
-       fmgr_info(F_VARBIT, &varbit_finfo);
+       fmgr_info_cxt(F_VARBIT, &varbit_finfo, TopMemoryContext);
 
    MemSet(&locfcinfo, 0, sizeof(locfcinfo));
    locfcinfo.flinfo = &varbit_finfo;
index 7ed56e7962f3712f6c2d48258cd9936f67189809..c963709ac8f6bddc35f21b40551b35b396a349b0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.83 2001/10/03 05:29:24 thomas Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.84 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -285,7 +285,7 @@ _bpchar(PG_FUNCTION_ARGS)
    static FmgrInfo bpchar_finfo;
 
    if (bpchar_finfo.fn_oid == InvalidOid)
-       fmgr_info(F_BPCHAR, &bpchar_finfo);
+       fmgr_info_cxt(F_BPCHAR, &bpchar_finfo, TopMemoryContext);
 
    MemSet(&locfcinfo, 0, sizeof(locfcinfo));
    locfcinfo.flinfo = &bpchar_finfo;
@@ -544,7 +544,7 @@ _varchar(PG_FUNCTION_ARGS)
    static FmgrInfo varchar_finfo;
 
    if (varchar_finfo.fn_oid == InvalidOid)
-       fmgr_info(F_VARCHAR, &varchar_finfo);
+       fmgr_info_cxt(F_VARCHAR, &varchar_finfo, TopMemoryContext);
 
    MemSet(&locfcinfo, 0, sizeof(locfcinfo));
    locfcinfo.flinfo = &varchar_finfo;
index 01896efdd338b4d3d8367b0cc087df240a72219c..5ac5a06827cb1fc01af67d5737f9b29e368f23ee 100644 (file)
@@ -4,7 +4,7 @@
 #    Makefile for utils/cache
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/utils/cache/Makefile,v 1.14 2000/08/31 16:10:46 petere Exp $
+#    $Header: /cvsroot/pgsql/src/backend/utils/cache/Makefile,v 1.15 2001/10/06 23:21:44 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -12,7 +12,7 @@ subdir = src/backend/utils/cache
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = catcache.o inval.o rel.o relcache.o syscache.o lsyscache.o \
+OBJS = catcache.o inval.o relcache.o syscache.o lsyscache.o \
    fcache.o temprel.o
 
 all: SUBSYS.o
index ce4363706b3513032f77440fffb63b787168ec33..77112a694e72fe1cc0c2ae447f8614085918fa1c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.82 2001/08/21 16:36:04 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.83 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -269,23 +269,10 @@ CatalogCacheInitializeCache(CatCache *cache)
         */
        cache->cc_skey[i].sk_procedure = EQPROC(keytype);
 
-       /*
-        * Note: to avoid any possible leakage of scan temporary data into
-        * the cache context, we do not switch into CacheMemoryContext while
-        * calling fmgr_info here.  Instead set fn_mcxt on return.  This
-        * would fail to work correctly if fmgr_info allocated any subsidiary
-        * data structures to attach to the FmgrInfo record; but it doesn't
-        * do so for built-in functions, and all the comparator functions
-        * for system caches should most assuredly be built-in functions.
-        * Currently there's no real need to fix fn_mcxt either, but let's do
-        * that anyway just to make sure it's not pointing to a dead context
-        * later on.
-        */
-
-       fmgr_info(cache->cc_skey[i].sk_procedure,
-                 &cache->cc_skey[i].sk_func);
-
-       cache->cc_skey[i].sk_func.fn_mcxt = CacheMemoryContext;
+       /* Do function lookup */
+       fmgr_info_cxt(cache->cc_skey[i].sk_procedure,
+                     &cache->cc_skey[i].sk_func,
+                     CacheMemoryContext);
 
        /* Initialize sk_attno suitably for HeapKeyTest() and heap scans */
        cache->cc_skey[i].sk_attno = cache->cc_key[i];
index bb1ac36f3efdf3715e438074fd7d2ca288804866..92cf46a036d85aa05b40b4aeaccc550bc6435148 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.40 2001/09/21 00:11:31 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.41 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 FunctionCachePtr
 init_fcache(Oid foid, int nargs, MemoryContext fcacheCxt)
 {
-   MemoryContext oldcontext;
    FunctionCachePtr retval;
 
    /* Safety check (should never fail, as parser should check sooner) */
    if (nargs > FUNC_MAX_ARGS)
        elog(ERROR, "init_fcache: too many arguments");
 
-   /* Switch to a context long-lived enough for the fcache entry */
-   oldcontext = MemoryContextSwitchTo(fcacheCxt);
-
-   retval = (FunctionCachePtr) palloc(sizeof(FunctionCache));
+   /* Create fcache entry in the desired context */
+   retval = (FunctionCachePtr) MemoryContextAlloc(fcacheCxt,
+                                                  sizeof(FunctionCache));
    MemSet(retval, 0, sizeof(FunctionCache));
 
    /* Set up the primary fmgr lookup information */
-   fmgr_info(foid, &(retval->func));
+   fmgr_info_cxt(foid, &(retval->func), fcacheCxt);
 
    /* Initialize additional info */
    retval->setArgsValid = false;
 
-   MemoryContextSwitchTo(oldcontext);
-
    return retval;
 }
diff --git a/src/backend/utils/cache/rel.c b/src/backend/utils/cache/rel.c
deleted file mode 100644 (file)
index 588566a..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * rel.c
- *   POSTGRES relation descriptor code.
- *
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/rel.c,v 1.9 2001/01/24 19:43:15 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres.h"
-#include "access/istrat.h"
-
-
-/*
- *     RelationIsValid is now a macro in rel.h -cim 4/27/91
- *
- *     All of the RelationGet...() functions are now macros in rel.h
- *             -mer 3/2/92
- */
-
-/*
- * RelationSetIndexSupport
- *     Sets index strategy and support info for a relation.
- *
- *     This routine saves two pointers -- one to the IndexStrategy, and
- *     one to the RegProcs that support the indexed access method.
- *
- * Note:
- *     Assumes relation descriptor is valid.
- *     Assumes index strategy is valid.  Assumes support is valid if non-
- *     NULL.
- */
-void
-RelationSetIndexSupport(Relation relation,
-                       IndexStrategy strategy,
-                       RegProcedure *support)
-{
-   Assert(PointerIsValid(relation));
-   Assert(IndexStrategyIsValid(strategy));
-
-   relation->rd_istrat = strategy;
-   relation->rd_support = support;
-}
index 8d8548713943a43e0ed33c08bb1f9ddc266a7611..c56d606076a48e86ae8e59fa2548a2a2b8b15f03 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.145 2001/10/05 17:28:12 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.146 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -249,7 +249,6 @@ static void build_tupdesc_ind(RelationBuildDescInfo buildinfo,
                  Relation relation);
 static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo,
                  Relation oldrelation);
-static void IndexedAccessMethodInitialize(Relation relation);
 static void AttrDefaultFetch(Relation relation);
 static void RelCheckFetch(Relation relation);
 static List *insert_ordered_oid(List *list, Oid datum);
@@ -1044,7 +1043,7 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
     * initialize index strategy and support information for this relation
     */
    if (OidIsValid(relam))
-       IndexedAccessMethodInitialize(relation);
+       RelationInitIndexAccessInfo(relation);
 
    /*
     * initialize the relation lock manager information
@@ -1087,41 +1086,75 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
    return relation;
 }
 
-static void
-IndexedAccessMethodInitialize(Relation relation)
+/*
+ * Initialize index-access-method support data for an index relation
+ */
+void
+RelationInitIndexAccessInfo(Relation relation)
 {
+   MemoryContext indexcxt;
    IndexStrategy strategy;
    RegProcedure *support;
+   FmgrInfo   *supportinfo;
    int         natts;
-   Size        stratSize;
-   Size        supportSize;
    uint16      amstrategies;
    uint16      amsupport;
+   Size        stratSize;
 
    natts = relation->rd_rel->relnatts;
    amstrategies = relation->rd_am->amstrategies;
    amsupport = relation->rd_am->amsupport;
 
+   /*
+    * Make the private context to hold index access info.  The reason
+    * we need a context, and not just a couple of pallocs, is so that
+    * we won't leak any subsidiary info attached to fmgr lookup records.
+    *
+    * Context parameters are set on the assumption that it'll probably not
+    * contain much data.
+    */
+   indexcxt = AllocSetContextCreate(CacheMemoryContext,
+                                    RelationGetRelationName(relation),
+                                    0,         /* minsize */
+                                    512,       /* initsize */
+                                    1024);     /* maxsize */
+   relation->rd_indexcxt = indexcxt;
+
+   /*
+    * Allocate arrays to hold data
+    */
    stratSize = AttributeNumberGetIndexStrategySize(natts, amstrategies);
-   strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
-                                                 stratSize);
+   strategy = (IndexStrategy) MemoryContextAlloc(indexcxt, stratSize);
 
    if (amsupport > 0)
    {
-       supportSize = natts * (amsupport * sizeof(RegProcedure));
-       support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
-                                                     supportSize);
+       int     nsupport = natts * amsupport;
+
+       support = (RegProcedure *)
+           MemoryContextAlloc(indexcxt, nsupport * sizeof(RegProcedure));
+       supportinfo = (FmgrInfo *)
+           MemoryContextAlloc(indexcxt, nsupport * sizeof(FmgrInfo));
+       MemSet(supportinfo, 0, nsupport * sizeof(FmgrInfo));
    }
    else
-       support = (RegProcedure *) NULL;
+   {
+       support = NULL;
+       supportinfo = NULL;
+   }
 
+   /*
+    * Fill the strategy map and the support RegProcedure arrays.
+    * (supportinfo is left as zeroes, and is filled on-the-fly when used)
+    */
    IndexSupportInitialize(strategy, support,
                           &relation->rd_uniqueindex,
                           RelationGetRelid(relation),
                           relation->rd_rel->relam,
                           amstrategies, amsupport, natts);
 
-   RelationSetIndexSupport(relation, strategy, support);
+   relation->rd_istrat = strategy;
+   relation->rd_support = support;
+   relation->rd_supportinfo = supportinfo;
 }
 
 /*
@@ -1595,11 +1628,9 @@ RelationClearRelation(Relation relation, bool rebuildIt)
        pfree(relation->rd_am);
    if (relation->rd_rel)
        pfree(relation->rd_rel);
-   if (relation->rd_istrat)
-       pfree(relation->rd_istrat);
-   if (relation->rd_support)
-       pfree(relation->rd_support);
    freeList(relation->rd_indexlist);
+   if (relation->rd_indexcxt)
+       MemoryContextDelete(relation->rd_indexcxt);
 
    /*
     * If we're really done with the relcache entry, blow it away. But if
@@ -2624,8 +2655,11 @@ init_irels(void)
    Relation    ird;
    Form_pg_am  am;
    Form_pg_class relform;
+   MemoryContext indexcxt;
    IndexStrategy strat;
    RegProcedure *support;
+   int         nstrategies,
+               nsupport;
    int         i;
    int         relno;
 
@@ -2646,6 +2680,13 @@ init_irels(void)
            return;
        }
 
+       /* safety check for incompatible relcache layout */
+       if (len != sizeof(RelationData))
+       {
+           write_irels();
+           return;
+       }
+
        ird = irel[relno] = (Relation) palloc(len);
        MemSet(ird, 0, len);
 
@@ -2659,6 +2700,7 @@ init_irels(void)
        /* reset transient fields */
        ird->rd_targblock = InvalidBlockNumber;
        ird->rd_fd = -1;
+       ird->rd_refcnt = 0;
 
        ird->rd_node.tblNode = MyDatabaseId;
 
@@ -2716,6 +2758,17 @@ init_irels(void)
            }
        }
 
+       /*
+        * prepare index info context --- parameters should match
+        * RelationInitIndexAccessInfo
+        */
+       indexcxt = AllocSetContextCreate(CacheMemoryContext,
+                                        RelationGetRelationName(ird),
+                                        0,         /* minsize */
+                                        512,       /* initsize */
+                                        1024);     /* maxsize */
+       ird->rd_indexcxt = indexcxt;
+
        /* next, read the index strategy map */
        if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
        {
@@ -2723,27 +2776,18 @@ init_irels(void)
            return;
        }
 
-       strat = (IndexStrategy) palloc(len);
+       strat = (IndexStrategy) MemoryContextAlloc(indexcxt, len);
        if ((nread = FileRead(fd, (char *) strat, len)) != len)
        {
            write_irels();
            return;
        }
 
-       /* oh, for god's sake... */
-#define SMD(i) strat->strategyMapData[i].entry[0]
-
-       /* have to reinit the function pointers in the strategy maps */
-       for (i = 0; i < am->amstrategies * relform->relnatts; i++)
-       {
-           fmgr_info(SMD(i).sk_procedure,
-                     &(SMD(i).sk_func));
-       }
+       /* have to invalidate any FmgrInfo data in the strategy maps */
+       nstrategies = am->amstrategies * relform->relnatts;
+       for (i = 0; i < nstrategies; i++)
+           strat->strategyMapData[i].entry[0].sk_func.fn_oid = InvalidOid;
 
-       /*
-        * use a real field called rd_istrat instead of the bogosity of
-        * hanging invisible fields off the end of a structure - jolly
-        */
        ird->rd_istrat = strat;
 
        /* finally, read the vector of support procedures */
@@ -2753,7 +2797,7 @@ init_irels(void)
            return;
        }
 
-       support = (RegProcedure *) palloc(len);
+       support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
        if ((nread = FileRead(fd, (char *) support, len)) != len)
        {
            write_irels();
@@ -2761,6 +2805,11 @@ init_irels(void)
        }
        ird->rd_support = support;
 
+       nsupport = relform->relnatts * am->amsupport;
+       ird->rd_supportinfo = (FmgrInfo *)
+           MemoryContextAlloc(indexcxt, nsupport * sizeof(FmgrInfo));
+       MemSet(ird->rd_supportinfo, 0, nsupport * sizeof(FmgrInfo));
+
        RelationInitLockInfo(ird);
 
        RelationCacheInsert(ird);
index f46d40c5c481764bef71cf56edfe7045133adf22..3085187d8a941f3c2344ecabc0040f1e6b5b3355 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.52 2001/10/04 19:13:55 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.53 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -55,14 +55,20 @@ static char * substitute_libpath_macro(const char * name);
 
 /*
  * Load the specified dynamic-link library file, and look for a function
- * named funcname in it.  If the function is not found, we raise an error
- * if signalNotFound is true, else return (PGFunction) NULL.  Note that
- * errors in loading the library will provoke elog regardless of
- * signalNotFound.
- */
+ * named funcname in it.  (funcname can be NULL to just load the file.)
+ *
+ * If the function is not found, we raise an error if signalNotFound is true,
+ * else return (PGFunction) NULL.  Note that errors in loading the library
+ * will provoke elog regardless of signalNotFound.
+ *
+ * If filehandle is not NULL, then *filehandle will be set to a handle
+ * identifying the library file.  The filehandle can be used with
+ * lookup_external_function to lookup additional functions in the same file
+ * at less cost than repeating load_external_function.
+  */
 PGFunction
 load_external_function(char *filename, char *funcname,
-                      bool signalNotFound)
+                      bool signalNotFound, void **filehandle)
 {
    DynamicFileList *file_scanner;
    PGFunction  retval;
@@ -130,6 +136,10 @@ load_external_function(char *filename, char *funcname,
        file_tail = file_scanner;
    }
 
+   /* Return handle if caller wants it. */
+   if (filehandle)
+       *filehandle = file_scanner->handle;
+
    /*
     * If funcname is NULL, we only wanted to load the file.
     */
@@ -201,11 +211,20 @@ load_file(char *filename)
        }
    }
 
-   load_external_function(fullname, (char *) NULL, false);
+   load_external_function(fullname, (char *) NULL, false, (void *) NULL);
 
    pfree(fullname);
 }
 
+/*
+ * Lookup a function whose library file is already loaded.
+ * Return (PGFunction) NULL if not found.
+ */
+PGFunction
+lookup_external_function(void *filehandle, char *funcname)
+{
+   return pg_dlsym(filehandle, funcname);
+}
 
 
 static bool
@@ -305,7 +324,7 @@ substitute_libpath_macro(const char * name)
 
    AssertArg(name != NULL);
 
-   if (strlen(name) == 0 || name[0] != '$')
+   if (name[0] != '$')
        return pstrdup(name);
 
    macroname_len = strcspn(name + 1, "/") + 1;
index 45ca532de249a9cf7d85737e699f1ece2f6b7672..5faa8a155c1b907ef1254292cde9b2d881c4bf9f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.54 2001/08/14 22:21:58 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.55 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -121,11 +121,21 @@ fmgr_lookupByName(const char *name)
  * will be allocated in that context.  The caller must ensure that this
  * context is at least as long-lived as the info struct itself.  This is
  * not a problem in typical cases where the info struct is on the stack or
- * in freshly-palloc'd space, but one must take extra care when the info
- * struct is in a long-lived table.
+ * in freshly-palloc'd space.  However, if one intends to store an info
+ * struct in a long-lived table, it's better to use fmgr_info_cxt.
  */
 void
 fmgr_info(Oid functionId, FmgrInfo *finfo)
+{
+   fmgr_info_cxt(functionId, finfo, CurrentMemoryContext);
+}
+
+/*
+ * Fill a FmgrInfo struct, specifying a memory context in which its
+ * subsidiary data should go.
+ */
+void
+fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
 {
    const FmgrBuiltin *fbp;
    HeapTuple   procedureTuple;
@@ -139,7 +149,7 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
     */
    finfo->fn_oid = InvalidOid;
    finfo->fn_extra = NULL;
-   finfo->fn_mcxt = CurrentMemoryContext;
+   finfo->fn_mcxt = mcxt;
 
    if ((fbp = fmgr_isbuiltin(functionId)) != NULL)
    {
@@ -228,6 +238,7 @@ fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
                probinattr;
    char       *prosrcstring,
               *probinstring;
+   void       *libraryhandle;
    PGFunction  user_fn;
    Pg_finfo_record *inforec;
    Oldstyle_fnextra *fnextra;
@@ -250,22 +261,19 @@ fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
    probinstring = DatumGetCString(DirectFunctionCall1(textout, probinattr));
 
    /* Look up the function itself */
-   user_fn = load_external_function(probinstring, prosrcstring, true);
+   user_fn = load_external_function(probinstring, prosrcstring, true,
+                                    &libraryhandle);
 
    /* Get the function information record (real or default) */
-   inforec = fetch_finfo_record(probinstring, prosrcstring);
+   inforec = fetch_finfo_record(libraryhandle, prosrcstring);
 
    switch (inforec->api_version)
    {
        case 0:
            /* Old style: need to use a handler */
            finfo->fn_addr = fmgr_oldstyle;
-
-           /*
-            * OK to use palloc here because fn_mcxt is
-            * CurrentMemoryContext
-            */
-           fnextra = (Oldstyle_fnextra *) palloc(sizeof(Oldstyle_fnextra));
+           fnextra = (Oldstyle_fnextra *)
+               MemoryContextAlloc(finfo->fn_mcxt, sizeof(Oldstyle_fnextra));
            finfo->fn_extra = (void *) fnextra;
            MemSet(fnextra, 0, sizeof(Oldstyle_fnextra));
            fnextra->func = (func_ptr) user_fn;
@@ -335,6 +343,8 @@ fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
 
 /*
  * Fetch and validate the information record for the given external function.
+ * The function is specified by a handle for the containing library
+ * (obtained from load_external_function) as well as the function name.
  *
  * If no info function exists for the given name, it is not an error.
  * Instead we return a default info record for a version-0 function.
@@ -346,7 +356,7 @@ fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
  * pg_proc.
  */
 Pg_finfo_record *
-fetch_finfo_record(char *filename, char *funcname)
+fetch_finfo_record(void *filehandle, char *funcname)
 {
    char       *infofuncname;
    PGFInfoFunction infofunc;
@@ -355,12 +365,12 @@ fetch_finfo_record(char *filename, char *funcname)
 
    /* Compute name of info func */
    infofuncname = (char *) palloc(strlen(funcname) + 10);
-   sprintf(infofuncname, "pg_finfo_%s", funcname);
+   strcpy(infofuncname, "pg_finfo_");
+   strcat(infofuncname, funcname);
 
    /* Try to look up the info function */
-   infofunc = (PGFInfoFunction) load_external_function(filename,
-                                                       infofuncname,
-                                                       false);
+   infofunc = (PGFInfoFunction) lookup_external_function(filehandle,
+                                                         infofuncname);
    if (infofunc == (PGFInfoFunction) NULL)
    {
        /* Not found --- assume version 0 */
@@ -391,6 +401,34 @@ fetch_finfo_record(char *filename, char *funcname)
 }
 
 
+/*
+ * Copy an FmgrInfo struct
+ *
+ * This is inherently somewhat bogus since we can't reliably duplicate
+ * language-dependent subsidiary info.  We cheat by zeroing fn_extra,
+ * instead, meaning that subsidiary info will have to be recomputed.
+ */
+void
+fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
+              MemoryContext destcxt)
+{
+   memcpy(dstinfo, srcinfo, sizeof(FmgrInfo));
+   dstinfo->fn_mcxt = destcxt;
+   if (dstinfo->fn_addr == fmgr_oldstyle)
+   {
+       /* For oldstyle functions we must copy fn_extra */
+       Oldstyle_fnextra *fnextra;
+
+       fnextra = (Oldstyle_fnextra *)
+           MemoryContextAlloc(destcxt, sizeof(Oldstyle_fnextra));
+       memcpy(fnextra, srcinfo->fn_extra, sizeof(Oldstyle_fnextra));
+       dstinfo->fn_extra = (void *) fnextra;
+   }
+   else
+       dstinfo->fn_extra = NULL;
+}
+
+
 /*
  * Specialized lookup routine for ProcedureCreate(): given the alleged name
  * of an internal function, return the OID of the function.
index db6795c0933e1bd554a53932e6ab13d32cbb895d..0a70691e770ac5cdf1bbcea03f1471bc826660f1 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: genam.h,v 1.26 2001/07/15 22:48:18 tgl Exp $
+ * $Id: genam.h,v 1.27 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,6 +56,8 @@ extern IndexBulkDeleteResult *index_bulk_delete(Relation relation,
 extern RegProcedure index_cost_estimator(Relation relation);
 extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
                uint16 procnum);
+extern struct FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum,
+                                         uint16 procnum);
 
 /* in genam.c */
 extern IndexScanDesc RelationGetIndexScan(Relation relation, bool scanFromEnd,
index 4e49f51afb1cc86b4178e589e5d35dc440726c03..304d5e4a46232f624b9f32bce39123e173533c98 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: skey.h,v 1.16 2001/06/09 18:16:59 tgl Exp $
+ * $Id: skey.h,v 1.17 2001/10/06 23:21:44 tgl Exp $
  *
  * Note:
  *     Needs more accessor/assignment routines.
@@ -44,5 +44,8 @@ typedef ScanKeyData *ScanKey;
 extern void ScanKeyEntrySetIllegal(ScanKey entry);
 extern void ScanKeyEntryInitialize(ScanKey entry, bits16 flags,
     AttrNumber attributeNumber, RegProcedure procedure, Datum argument);
+extern void ScanKeyEntryInitializeWithInfo(ScanKey entry, bits16 flags,
+    AttrNumber attributeNumber, FmgrInfo *finfo,
+    MemoryContext mcxt, Datum argument);
 
 #endif  /* SKEY_H */
index d3e3bae7048377e829dc9ff31eacfda265162eae..52956f807b3d6621634fc08c523dbf2121db74f8 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: index.h,v 1.39 2001/08/21 16:36:05 tgl Exp $
+ * $Id: index.h,v 1.40 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,10 +30,6 @@ typedef void (*IndexBuildCallback) (Relation index,
 extern Form_pg_am AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
                            MemoryContext resultCxt);
 
-extern void InitIndexStrategy(int numatts,
-                 Relation indexRelation,
-                 Oid accessMethodObjectId);
-
 extern Oid index_create(char *heapRelationName,
             char *indexRelationName,
             IndexInfo *indexInfo,
index 44641bdcb1829dab3f070500a4cb2655a51ebf5c..0acb966f683362987b176f30855844ba770d9915 100644 (file)
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: fmgr.h,v 1.14 2001/05/17 17:44:18 petere Exp $
+ * $Id: fmgr.h,v 1.15 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,7 +35,7 @@ typedef Datum (*PGFunction) (FunctionCallInfo fcinfo);
  * to be called multiple times, the lookup need be done only once and the
  * info struct saved for re-use.
  */
-typedef struct
+typedef struct FmgrInfo
 {
    PGFunction  fn_addr;        /* pointer to function or handler to be
                                 * called */
@@ -72,6 +72,20 @@ typedef struct FunctionCallInfoData
  */
 extern void fmgr_info(Oid functionId, FmgrInfo *finfo);
 
+/*
+ * Same, when the FmgrInfo struct is in a memory context longer-lived than
+ * CurrentMemoryContext.  The specified context will be set as fn_mcxt
+ * and used to hold all subsidiary data of finfo.
+ */
+extern void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo,
+                         MemoryContext mcxt);
+
+/*
+ * Copy an FmgrInfo struct
+ */
+extern void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
+                          MemoryContext destcxt);
+
 /*
  * This macro invokes a function given a filled-in FunctionCallInfoData
  * struct. The macro result is the returned Datum --- but note that
@@ -341,16 +355,18 @@ extern Datum OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
 /*
  * Routines in fmgr.c
  */
-extern Pg_finfo_record *fetch_finfo_record(char *filename, char *funcname);
+extern Pg_finfo_record *fetch_finfo_record(void *filehandle, char *funcname);
 extern Oid fmgr_internal_function(const char *proname);
 
 /*
  * Routines in dfmgr.c
  */
+extern char * Dynamic_library_path;
+
 extern PGFunction load_external_function(char *filename, char *funcname,
-                      bool signalNotFound);
+                      bool signalNotFound, void **filehandle);
+extern PGFunction lookup_external_function(void *filehandle, char *funcname);
 extern void load_file(char *filename);
-extern char * Dynamic_library_path;
 
 
 /*
index ef74317fda500ce5e769dbe2e45df58abb20253e..9cc7a2ecb47e02ceaed4ba590a433c113a90cbdd 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: rel.h,v 1.51 2001/06/27 23:31:40 tgl Exp $
+ * $Id: rel.h,v 1.52 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,8 +23,6 @@
 #include "storage/fd.h"
 #include "storage/relfilenode.h"
 
-/* added to prevent circular dependency.  bjm 1999/11/15 */
-extern char *get_temp_rel_by_physicalname(const char *relname);
 
 /*
  * LockRelId and LockInfo really belong to lmgr.h, but it's more convenient
@@ -115,7 +113,7 @@ typedef struct RelationData
    bool        rd_isnailed;    /* rel is nailed in cache */
    bool        rd_indexfound;  /* true if rd_indexlist is valid */
    bool        rd_uniqueindex; /* true if rel is a UNIQUE index */
-   Form_pg_am  rd_am;          /* AM tuple */
+   Form_pg_am  rd_am;          /* AM tuple (if an index) */
    Form_pg_class rd_rel;       /* RELATION tuple */
    Oid         rd_id;          /* relation's object id */
    List       *rd_indexlist;   /* list of OIDs of indexes on relation */
@@ -123,10 +121,16 @@ typedef struct RelationData
    TupleDesc   rd_att;         /* tuple descriptor */
    RuleLock   *rd_rules;       /* rewrite rules */
    MemoryContext rd_rulescxt;  /* private memory cxt for rd_rules, if any */
-   IndexStrategy rd_istrat;    /* info needed if rel is an index */
-   RegProcedure *rd_support;
    TriggerDesc *trigdesc;      /* Trigger info, or NULL if rel has none */
 
+   /* index access support info (used only for an index relation) */
+   MemoryContext rd_indexcxt;  /* private memory cxt for this stuff */
+   IndexStrategy rd_istrat;    /* operator strategy map */
+   RegProcedure *rd_support;   /* OIDs of support procedures */
+   struct FmgrInfo *rd_supportinfo; /* lookup info for support procedures */
+   /* "struct FmgrInfo" avoids need to include fmgr.h here */
+
+   /* statistics collection area */
    PgStat_Info pgstat_info;
 } RelationData;
 
@@ -228,13 +232,6 @@ typedef Relation *RelationPtr;
  */
 #define RelationGetIndexStrategy(relation) ((relation)->rd_istrat)
 
-/*
- * Routines in utils/cache/rel.c
- */
-extern void RelationSetIndexSupport(Relation relation,
-                       IndexStrategy strategy,
-                       RegProcedure *support);
-
 /*
  * Handle temp relations
  */
@@ -279,5 +276,7 @@ extern void RelationSetIndexSupport(Relation relation,
        RelationGetPhysicalRelationName(relation) \
 )
 
+/* added to prevent circular dependency.  bjm 1999/11/15 */
+extern char *get_temp_rel_by_physicalname(const char *relname);
 
 #endif  /* REL_H */
index 160ee0f47c721ce6e6f8f8b754f819f5ee348ce3..861185cea9e1772cde813a23239b48e85a249783 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: relcache.h,v 1.25 2001/06/29 21:08:25 tgl Exp $
+ * $Id: relcache.h,v 1.26 2001/10/06 23:21:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,6 +33,8 @@ extern void RelationClose(Relation relation);
  */
 extern List *RelationGetIndexList(Relation relation);
 
+extern void RelationInitIndexAccessInfo(Relation relation);
+
 /*
  * Routines for backend startup
  */
@@ -61,6 +63,7 @@ extern void RelationPurgeLocalRelation(bool xactComitted);
 extern void RelationCacheAbort(void);
 
 
+/* XLOG support */
 extern void CreateDummyCaches(void);
 extern void DestroyDummyCaches(void);
 
index cb733d7970763edcaea8992ee2f073bb82f6394d..b59486860e4509b9b10f2c179d3df74f2688f2d7 100644 (file)
@@ -33,7 +33,7 @@
  *   ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.22 2001/06/18 21:40:06 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.23 2001/10/06 23:21:44 tgl Exp $
  *
  **********************************************************************/
 
@@ -171,18 +171,14 @@ static void plperl_set_tuple_values(Tcl_Interp *interp, char *arrayname,
  * data structures such as fmgr info records therefore must live forever
  * as well.  A better implementation would store all this stuff in a per-
  * function memory context that could be reclaimed at need.  In the meantime,
- * fmgr_info must be called in TopMemoryContext so that whatever it might
- * allocate, and whatever the eventual function might allocate using fn_mcxt,
- * will live forever too.
+ * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever
+ * it might allocate, and whatever the eventual function might allocate using
+ * fn_mcxt, will live forever too.
  */
 static void
 perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
 {
-   MemoryContext   oldcontext;
-
-   oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-   fmgr_info(functionId, finfo);
-   MemoryContextSwitchTo(oldcontext);
+   fmgr_info_cxt(functionId, finfo, TopMemoryContext);
 }
 
 /**********************************************************************
index 2ab6632e336d6bb389b0797266c794de7aa17ea0..5c7e12ad19875196d6962f5718dea9289a0243be 100644 (file)
@@ -3,7 +3,7 @@
  *           procedural language
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.33 2001/07/12 17:42:07 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.34 2001/10/06 23:21:44 tgl Exp $
  *
  *   This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -92,18 +92,14 @@ PLpgSQL_function *plpgsql_curr_compile;
  * data structures such as fmgr info records therefore must live forever
  * as well.  A better implementation would store all this stuff in a per-
  * function memory context that could be reclaimed at need.  In the meantime,
- * fmgr_info must be called in TopMemoryContext so that whatever it might
- * allocate, and whatever the eventual function might allocate using fn_mcxt,
- * will live forever too.
+ * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever
+ * it might allocate, and whatever the eventual function might allocate using
+ * fn_mcxt, will live forever too.
  */
 static void
 perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
 {
-   MemoryContext   oldcontext;
-
-   oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-   fmgr_info(functionId, finfo);
-   MemoryContextSwitchTo(oldcontext);
+   fmgr_info_cxt(functionId, finfo, TopMemoryContext);
 }
 
 
index cd3486fa6d6c6c9f8863b4ef1da3705765cf9825..8dcfb1c970c8497dacc812a78e8568b30f77da9a 100644 (file)
@@ -29,7 +29,7 @@
  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.7 2001/10/04 15:45:49 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.8 2001/10/06 23:21:45 tgl Exp $
  *
  *********************************************************************
  */
@@ -308,18 +308,14 @@ volatile int func_leave_calls = 0;
  * data structures such as fmgr info records therefore must live forever
  * as well.  A better implementation would store all this stuff in a per-
  * function memory context that could be reclaimed at need.  In the meantime,
- * fmgr_info must be called in TopMemoryContext so that whatever it might
- * allocate, and whatever the eventual function might allocate using fn_mcxt,
- * will live forever too.
+ * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever
+ * it might allocate, and whatever the eventual function might allocate using
+ * fn_mcxt, will live forever too.
  */
 static void
 perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
 {
-   MemoryContext   oldcontext;
-
-   oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-   fmgr_info(functionId, finfo);
-   MemoryContextSwitchTo(oldcontext);
+   fmgr_info_cxt(functionId, finfo, TopMemoryContext);
 }
 
 
index 29d6559821bd473e10011fa0e4fd24d0cc52baee..38d7d4345010ba80c42d76c6315d8cc79cfb56e2 100644 (file)
@@ -31,7 +31,7 @@
  *   ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.42 2001/10/04 15:48:37 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.43 2001/10/06 23:21:45 tgl Exp $
  *
  **********************************************************************/
 
@@ -187,18 +187,14 @@ static int pltcl_SPI_lastoid(ClientData cdata, Tcl_Interp *interp,
  * data structures such as fmgr info records therefore must live forever
  * as well.  A better implementation would store all this stuff in a per-
  * function memory context that could be reclaimed at need.  In the meantime,
- * fmgr_info must be called in TopMemoryContext so that whatever it might
- * allocate, and whatever the eventual function might allocate using fn_mcxt,
- * will live forever too.
+ * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever
+ * it might allocate, and whatever the eventual function might allocate using
+ * fn_mcxt, will live forever too.
  */
 static void
 perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
 {
-   MemoryContext   oldcontext;
-
-   oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-   fmgr_info(functionId, finfo);
-   MemoryContextSwitchTo(oldcontext);
+   fmgr_info_cxt(functionId, finfo, TopMemoryContext);
 }
 
 /**********************************************************************