diff options
Diffstat (limited to 'src/backend/utils/fmgr')
| -rw-r--r-- | src/backend/utils/fmgr/dfmgr.c | 37 | ||||
| -rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 72 |
2 files changed, 83 insertions, 26 deletions
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index f46d40c5c4..3085187d8a 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.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; diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index 45ca532de2..5faa8a155c 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.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,12 +121,22 @@ 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; Form_pg_proc procedureStruct; @@ -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 */ @@ -392,6 +402,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. * If the name is not recognized, return InvalidOid. |
