mirror of
https://github.com/postgres/postgres.git
synced 2025-11-13 16:22:44 +03:00
Rearrange fmgr.c and relcache so that it's possible to keep FmgrInfo
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.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
4
src/backend/utils/cache/Makefile
vendored
4
src/backend/utils/cache/Makefile
vendored
@@ -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
|
||||
|
||||
23
src/backend/utils/cache/catcache.c
vendored
23
src/backend/utils/cache/catcache.c
vendored
@@ -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];
|
||||
|
||||
14
src/backend/utils/cache/fcache.c
vendored
14
src/backend/utils/cache/fcache.c
vendored
@@ -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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -23,26 +23,22 @@
|
||||
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;
|
||||
}
|
||||
|
||||
49
src/backend/utils/cache/rel.c
vendored
49
src/backend/utils/cache/rel.c
vendored
@@ -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;
|
||||
}
|
||||
115
src/backend/utils/cache/relcache.c
vendored
115
src/backend/utils/cache/relcache.c
vendored
@@ -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 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;
|
||||
|
||||
/* 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));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user