diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2000-11-20 20:36:57 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2000-11-20 20:36:57 +0000 |
commit | 5bb2300b59b74cdc7c8e3f0bf3c8d31c27657670 (patch) | |
tree | 8a0e76a6742884477e5bb50639e9a7ab9ba42872 /src/backend | |
parent | 99198ac6b8d2003949a02a148f4483e2f95e7dd4 (diff) | |
download | postgresql-5bb2300b59b74cdc7c8e3f0bf3c8d31c27657670.tar.gz postgresql-5bb2300b59b74cdc7c8e3f0bf3c8d31c27657670.zip |
Revise handling of oldstyle/newstyle functions per recent discussions
in pghackers list. Support for oldstyle internal functions is gone
(no longer needed, since conversion is complete) and pg_language entry
'internal' now implies newstyle call convention. pg_language entry
'newC' is gone; both old and newstyle dynamically loaded C functions
are now called language 'C'. A newstyle function must be identified
by an associated info routine. See src/backend/utils/fmgr/README.
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/pg_proc.c | 29 | ||||
-rw-r--r-- | src/backend/commands/define.c | 21 | ||||
-rw-r--r-- | src/backend/commands/remove.c | 5 | ||||
-rw-r--r-- | src/backend/commands/trigger.c | 11 | ||||
-rw-r--r-- | src/backend/utils/Gen_fmgrtab.sh | 21 | ||||
-rw-r--r-- | src/backend/utils/cache/lsyscache.c | 23 | ||||
-rw-r--r-- | src/backend/utils/fmgr/dfmgr.c | 70 | ||||
-rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 286 |
8 files changed, 271 insertions, 195 deletions
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 9d3ce5c50d6..5d63ebf1616 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.50 2000/11/16 22:30:17 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.51 2000/11/20 20:36:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -229,50 +229,35 @@ ProcedureCreate(char *procedureName, * FUNCTION xyz AS '' LANGUAGE 'internal'. To preserve some modicum * of backwards compatibility, accept an empty 'prosrc' value as * meaning the supplied SQL function name. - * - * XXX: we could treat "internal" and "newinternal" language specs - * as equivalent, and take the actual language ID from the table of - * known builtin functions. Is that a better idea than making the - * user specify the right thing? Not sure. */ - if (languageObjectId == INTERNALlanguageId || - languageObjectId == NEWINTERNALlanguageId) + if (languageObjectId == INTERNALlanguageId) { - Oid actualLangID; - if (strlen(prosrc) == 0) prosrc = procedureName; - actualLangID = fmgr_internal_language(prosrc); - if (actualLangID == InvalidOid) + if (fmgr_internal_function(prosrc) == InvalidOid) elog(ERROR, "ProcedureCreate: there is no builtin function named \"%s\"", prosrc); - if (actualLangID != languageObjectId) - elog(ERROR, - "ProcedureCreate: \"%s\" is not %s internal function", - prosrc, - ((languageObjectId == INTERNALlanguageId) ? - "an old-style" : "a new-style")); } /* * If this is a dynamically loadable procedure, make sure that the * library file exists, is loadable, and contains the specified link - * symbol. + * symbol. Also check for a valid function information record. * * We used to perform these checks only when the function was first * called, but it seems friendlier to verify the library's validity * at CREATE FUNCTION time. */ - if (languageObjectId == ClanguageId || - languageObjectId == NEWClanguageId) + if (languageObjectId == ClanguageId) { /* If link symbol is specified as "-", substitute procedure name */ if (strcmp(prosrc, "-") == 0) prosrc = procedureName; - (void) load_external_function(probin, prosrc); + (void) load_external_function(probin, prosrc, true); + (void) fetch_finfo_record(probin, prosrc); } /* diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index 9d681a4a50f..63ccf32543f 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.48 2000/11/16 22:30:18 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.49 2000/11/20 20:36:47 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -66,7 +66,7 @@ case_translate_language_name(const char *input, char *output) { /*------------------------------------------------------------------------- Translate the input language name to lower case, except if it's "C", - translate to upper case, or "newC", translate to that spelling. + translate to upper case. --------------------------------------------------------------------------*/ int i; @@ -77,8 +77,6 @@ case_translate_language_name(const char *input, char *output) if (strcmp(output, "c") == 0) output[0] = 'C'; - else if (strcmp(output, "newc") == 0) - output[3] = 'C'; } @@ -183,8 +181,7 @@ interpret_AS_clause(const char *languageName, const List *as, { Assert(as != NIL); - if (strcmp(languageName, "C") == 0 || - strcmp(languageName, "newC") == 0) + if (strcmp(languageName, "C") == 0) { /* @@ -230,8 +227,8 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) char languageName[NAMEDATALEN]; /* - * name of language of function, with case adjusted: "C", "newC", - * "internal", "newinternal", "sql", etc. + * name of language of function, with case adjusted: "C", + * "internal", "sql", etc. */ bool returnsSet; @@ -255,9 +252,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) * Apply appropriate security checks depending on language. */ if (strcmp(languageName, "C") == 0 || - strcmp(languageName, "newC") == 0 || - strcmp(languageName, "internal") == 0 || - strcmp(languageName, "newinternal") == 0) + strcmp(languageName, "internal") == 0) { if (!superuser()) elog(ERROR, @@ -283,8 +278,8 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) if (!HeapTupleIsValid(languageTuple)) elog(ERROR, "Unrecognized language specified in a CREATE FUNCTION: " - "'%s'.\n\tRecognized languages are sql, C, newC, " - "internal, newinternal, and created procedural languages.", + "'%s'.\n\tRecognized languages are sql, C, " + "internal, and created procedural languages.", languageName); /* Check that this language is a PL */ diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c index fdcd0e7e744..cb11b47a37c 100644 --- a/src/backend/commands/remove.c +++ b/src/backend/commands/remove.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.55 2000/11/16 22:30:18 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.56 2000/11/20 20:36:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -344,8 +344,7 @@ RemoveFunction(char *functionName, /* function name to be removed */ if (!HeapTupleIsValid(tup)) func_error("RemoveFunction", functionName, nargs, argList, NULL); - if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId || - ((Form_pg_proc) GETSTRUCT(tup))->prolang == NEWINTERNALlanguageId) + if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId) { /* "Helpful" notice when removing a builtin function ... */ elog(NOTICE, "Removing built-in function \"%s\"", functionName); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 22dfcac0524..cc31a0eb48b 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.80 2000/11/16 22:30:18 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.81 2000/11/20 20:36:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -169,10 +169,7 @@ CreateTrigger(CreateTrigStmt *stmt) funclang = ((Form_pg_proc) GETSTRUCT(tuple))->prolang; ReleaseSysCache(tuple); - if (funclang != ClanguageId && - funclang != NEWClanguageId && - funclang != INTERNALlanguageId && - funclang != NEWINTERNALlanguageId) + if (funclang != ClanguageId && funclang != INTERNALlanguageId) { HeapTuple langTup; @@ -180,10 +177,10 @@ CreateTrigger(CreateTrigStmt *stmt) ObjectIdGetDatum(funclang), 0, 0, 0); if (!HeapTupleIsValid(langTup)) - elog(ERROR, "CreateTrigger: cache lookup for PL %u failed", + elog(ERROR, "CreateTrigger: cache lookup for language %u failed", funclang); if (((Form_pg_language) GETSTRUCT(langTup))->lanispl == false) - elog(ERROR, "CreateTrigger: only builtin, C and PL functions are supported"); + elog(ERROR, "CreateTrigger: only internal, C and PL functions are supported"); ReleaseSysCache(langTup); } diff --git a/src/backend/utils/Gen_fmgrtab.sh b/src/backend/utils/Gen_fmgrtab.sh index 41a0bc3d712..00f12e3e1f1 100644 --- a/src/backend/utils/Gen_fmgrtab.sh +++ b/src/backend/utils/Gen_fmgrtab.sh @@ -9,7 +9,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.17 2000/07/13 16:07:06 petere Exp $ +# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.18 2000/11/20 20:36:48 tgl Exp $ # #------------------------------------------------------------------------- @@ -82,7 +82,7 @@ trap 'echo "Caught signal." ; cleanup ; exit 1' 1 2 15 # # Generate the file containing raw pg_proc tuple data -# (but only for "internal" and "newinternal" language procedures...). +# (but only for "internal" language procedures...). # # Unlike genbki.sh, which can run through cpp last, we have to # deal with preprocessor statements first (before we sort the @@ -99,7 +99,6 @@ sed -e 's/^.*OID[^=]*=[^0-9]*//' \ -e 's/[ ]*).*$//' | \ $AWK ' /^#/ { print; next; } -$4 == "11" { print; next; } $4 == "12" { print; next; }' > $CPPTMPFILE if [ $? -ne 0 ]; then @@ -182,10 +181,6 @@ FuNkYfMgRsTuFf # Generate fmgr's built-in-function table. # # Print out the function declarations, then the table that refers to them. -# NB: the function declarations are bogus in the case of old-style functions, -# although they should be correct for new-style. Therefore we need to compile -# this table definition as a separate C file that won't need to include any -# "real" declarations for those functions! # cat > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF /*------------------------------------------------------------------------- @@ -205,10 +200,6 @@ cat > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF * It has been GENERATED by $CMDNAME * from $INFILE * - * We lie here to cc about the return type and arguments of old-style - * builtin functions; all ld cares about is the fact that it - * will need to resolve an external function reference. - * *------------------------------------------------------------------------- */ @@ -237,13 +228,11 @@ FuNkYfMgRtAbStUfF # conditional expression instead. Not all awks have conditional expressions. $AWK 'BEGIN { - Strict["t"] = "true" - Strict["f"] = "false" - OldStyle["11"] = "true" - OldStyle["12"] = "false" + Bool["t"] = "true" + Bool["f"] = "false" } { printf (" { %d, \"%s\", %d, %s, %s, %s },\n"), \ - $1, $(NF-1), $9, Strict[$8], OldStyle[$4], $(NF-1) + $1, $(NF-1), $9, Bool[$8], Bool[$10], $(NF-1) }' $RAWFILE >> "$$-$TABLEFILE" if [ $? -ne 0 ]; then diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index e07445837a5..24b2cbada95 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.47 2000/11/16 22:30:33 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.48 2000/11/20 20:36:49 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -731,6 +731,27 @@ get_typalign(Oid typid) #endif +char +get_typstorage(Oid typid) +{ + HeapTuple tp; + + tp = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typid), + 0, 0, 0); + if (HeapTupleIsValid(tp)) + { + Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); + char result; + + result = typtup->typstorage; + ReleaseSysCache(tp); + return result; + } + else + return 'p'; +} + /* * get_typdefault * diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index 2dfddebd0a8..ae8eb6785e5 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -8,20 +8,17 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.45 2000/11/16 22:30:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.46 2000/11/20 20:36:49 tgl Exp $ * *------------------------------------------------------------------------- */ +#include "postgres.h" + #include <sys/types.h> #include <sys/stat.h> -#include "postgres.h" - -#include "catalog/pg_proc.h" #include "dynloader.h" #include "utils/dynamic_loader.h" -#include "utils/builtins.h" -#include "utils/syscache.h" /* @@ -46,55 +43,16 @@ static DynamicFileList *file_tail = (DynamicFileList *) NULL; #define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device) +/* + * 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. + */ PGFunction -fmgr_dynamic(Oid functionId) -{ - HeapTuple procedureTuple; - Form_pg_proc procedureStruct; - char *proname, - *prosrcstring, - *probinstring; - Datum prosrcattr, - probinattr; - PGFunction user_fn; - bool isnull; - - procedureTuple = SearchSysCache(PROCOID, - ObjectIdGetDatum(functionId), - 0, 0, 0); - if (!HeapTupleIsValid(procedureTuple)) - elog(ERROR, "fmgr_dynamic: function %u: cache lookup failed", - functionId); - procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple); - - proname = NameStr(procedureStruct->proname); - - prosrcattr = SysCacheGetAttr(PROCOID, procedureTuple, - Anum_pg_proc_prosrc, &isnull); - if (isnull) - elog(ERROR, "fmgr: Could not extract prosrc for %u from pg_proc", - functionId); - prosrcstring = DatumGetCString(DirectFunctionCall1(textout, prosrcattr)); - - probinattr = SysCacheGetAttr(PROCOID, procedureTuple, - Anum_pg_proc_probin, &isnull); - if (isnull) - elog(ERROR, "fmgr: Could not extract probin for %u from pg_proc", - functionId); - probinstring = DatumGetCString(DirectFunctionCall1(textout, probinattr)); - - user_fn = load_external_function(probinstring, prosrcstring); - - pfree(prosrcstring); - pfree(probinstring); - - ReleaseSysCache(procedureTuple); - - return user_fn; -} - -PGFunction -load_external_function(char *filename, char *funcname) +load_external_function(char *filename, char *funcname, + bool signalNotFound) { DynamicFileList *file_scanner; PGFunction retval; @@ -164,7 +122,7 @@ load_external_function(char *filename, char *funcname) retval = pg_dlsym(file_scanner->handle, funcname); - if (retval == (PGFunction) NULL) + if (retval == (PGFunction) NULL && signalNotFound) elog(ERROR, "Can't find function %s in file %s", funcname, filename); return retval; @@ -217,5 +175,5 @@ load_file(char *filename) } } - load_external_function(filename, (char *) NULL); + load_external_function(filename, (char *) NULL, false); } diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index 5287615eea0..d4353a48246 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.47 2000/11/16 22:30:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.48 2000/11/20 20:36:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,6 +20,7 @@ #include "executor/functions.h" #include "utils/builtins.h" #include "utils/fmgrtab.h" +#include "utils/lsyscache.h" #include "utils/syscache.h" /* @@ -42,7 +43,19 @@ typedef int32 ((*func_ptr) ()); typedef char *((*func_ptr) ()); #endif +/* + * For an oldstyle function, fn_extra points to a record like this: + */ +typedef struct +{ + func_ptr func; /* Address of the oldstyle function */ + bool arg_toastable[FUNC_MAX_ARGS]; /* is n'th arg of a toastable + * datatype? */ +} Oldstyle_fnextra; + +static void fmgr_info_C_lang(FmgrInfo *finfo, HeapTuple procedureTuple); +static void fmgr_info_other_lang(FmgrInfo *finfo, HeapTuple procedureTuple); static Datum fmgr_oldstyle(PG_FUNCTION_ARGS); static Datum fmgr_untrusted(PG_FUNCTION_ARGS); @@ -104,9 +117,6 @@ fmgr_info(Oid functionId, FmgrInfo *finfo) const FmgrBuiltin *fbp; HeapTuple procedureTuple; Form_pg_proc procedureStruct; - HeapTuple languageTuple; - Form_pg_language languageStruct; - Oid language; char *prosrc; finfo->fn_oid = functionId; @@ -120,16 +130,8 @@ fmgr_info(Oid functionId, FmgrInfo *finfo) */ finfo->fn_nargs = fbp->nargs; finfo->fn_strict = fbp->strict; - finfo->fn_retset = false; /* assume no builtins return sets! */ - if (fbp->oldstyle) - { - finfo->fn_addr = fmgr_oldstyle; - finfo->fn_extra = (void *) fbp->func; - } - else - { - finfo->fn_addr = fbp->func; - } + finfo->fn_retset = fbp->retset; + finfo->fn_addr = fbp->func; return; } @@ -148,16 +150,15 @@ fmgr_info(Oid functionId, FmgrInfo *finfo) if (!procedureStruct->proistrusted) { + /* This isn't really supported anymore... */ finfo->fn_addr = fmgr_untrusted; ReleaseSysCache(procedureTuple); return; } - language = procedureStruct->prolang; - switch (language) + switch (procedureStruct->prolang) { case INTERNALlanguageId: - case NEWINTERNALlanguageId: /* * For an ordinary builtin function, we should never get * here because the isbuiltin() search above will have @@ -175,24 +176,12 @@ fmgr_info(Oid functionId, FmgrInfo *finfo) elog(ERROR, "fmgr_info: function %s not in internal table", prosrc); pfree(prosrc); - if (fbp->oldstyle) - { - finfo->fn_addr = fmgr_oldstyle; - finfo->fn_extra = (void *) fbp->func; - } - else - { - finfo->fn_addr = fbp->func; - } + /* Should we check that nargs, strict, retset match the table? */ + finfo->fn_addr = fbp->func; break; case ClanguageId: - finfo->fn_addr = fmgr_oldstyle; - finfo->fn_extra = (void *) fmgr_dynamic(functionId); - break; - - case NEWClanguageId: - finfo->fn_addr = fmgr_dynamic(functionId); + fmgr_info_C_lang(finfo, procedureTuple); break; case SQLlanguageId: @@ -200,92 +189,234 @@ fmgr_info(Oid functionId, FmgrInfo *finfo) break; default: - /* - * Might be a created procedural language; try to look it up. - */ - languageTuple = SearchSysCache(LANGOID, - ObjectIdGetDatum(language), - 0, 0, 0); - if (!HeapTupleIsValid(languageTuple)) - elog(ERROR, "fmgr_info: cache lookup for language %u failed", - language); - languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); - if (languageStruct->lanispl) - { - FmgrInfo plfinfo; - - fmgr_info(languageStruct->lanplcallfoid, &plfinfo); - finfo->fn_addr = plfinfo.fn_addr; - /* - * If lookup of the PL handler function produced nonnull - * fn_extra, complain --- it must be an oldstyle function! - * We no longer support oldstyle PL handlers. - */ - if (plfinfo.fn_extra != NULL) - elog(ERROR, "fmgr_info: language %u has old-style handler", - language); - } - else + fmgr_info_other_lang(finfo, procedureTuple); + break; + } + + ReleaseSysCache(procedureTuple); +} + +/* + * Special fmgr_info processing for C-language functions + */ +static void +fmgr_info_C_lang(FmgrInfo *finfo, HeapTuple procedureTuple) +{ + Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple); + Datum prosrcattr, + probinattr; + char *prosrcstring, + *probinstring; + PGFunction user_fn; + Pg_finfo_record *inforec; + Oldstyle_fnextra *fnextra; + bool isnull; + int i; + + /* Get prosrc and probin strings (link symbol and library filename) */ + prosrcattr = SysCacheGetAttr(PROCOID, procedureTuple, + Anum_pg_proc_prosrc, &isnull); + if (isnull) + elog(ERROR, "fmgr: Could not extract prosrc for %u from pg_proc", + finfo->fn_oid); + prosrcstring = DatumGetCString(DirectFunctionCall1(textout, prosrcattr)); + + probinattr = SysCacheGetAttr(PROCOID, procedureTuple, + Anum_pg_proc_probin, &isnull); + if (isnull) + elog(ERROR, "fmgr: Could not extract probin for %u from pg_proc", + finfo->fn_oid); + probinstring = DatumGetCString(DirectFunctionCall1(textout, probinattr)); + + /* Look up the function itself */ + user_fn = load_external_function(probinstring, prosrcstring, true); + + /* Get the function information record (real or default) */ + inforec = fetch_finfo_record(probinstring, 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)); + finfo->fn_extra = (void *) fnextra; + MemSet(fnextra, 0, sizeof(Oldstyle_fnextra)); + fnextra->func = (func_ptr) user_fn; + for (i = 0; i < procedureStruct->pronargs; i++) { - elog(ERROR, "fmgr_info: function %u: unsupported language %u", - functionId, language); + fnextra->arg_toastable[i] = + TypeIsToastable(procedureStruct->proargtypes[i]); } - ReleaseSysCache(languageTuple); + break; + case 1: + /* New style: call directly */ + finfo->fn_addr = user_fn; + break; + default: + /* Shouldn't get here if fetch_finfo_record did its job */ + elog(ERROR, "Unknown function API version %d", + inforec->api_version); break; } - ReleaseSysCache(procedureTuple); + pfree(prosrcstring); + pfree(probinstring); } +/* + * Special fmgr_info processing for other-language functions + */ +static void +fmgr_info_other_lang(FmgrInfo *finfo, HeapTuple procedureTuple) +{ + Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple); + Oid language = procedureStruct->prolang; + HeapTuple languageTuple; + Form_pg_language languageStruct; + + languageTuple = SearchSysCache(LANGOID, + ObjectIdGetDatum(language), + 0, 0, 0); + if (!HeapTupleIsValid(languageTuple)) + elog(ERROR, "fmgr_info: cache lookup for language %u failed", + language); + languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); + if (languageStruct->lanispl) + { + FmgrInfo plfinfo; + + fmgr_info(languageStruct->lanplcallfoid, &plfinfo); + finfo->fn_addr = plfinfo.fn_addr; + /* + * If lookup of the PL handler function produced nonnull + * fn_extra, complain --- it must be an oldstyle function! + * We no longer support oldstyle PL handlers. + */ + if (plfinfo.fn_extra != NULL) + elog(ERROR, "fmgr_info: language %u has old-style handler", + language); + } + else + { + elog(ERROR, "fmgr_info: function %u: unsupported language %u", + finfo->fn_oid, language); + } + ReleaseSysCache(languageTuple); +} /* - * Specialized lookup routine for pg_proc.c: given the alleged name of - * an internal function, return the OID of the function's language. - * If the name is not known, return InvalidOid. + * Fetch and validate the information record for the given external function. + * + * 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. + * We want to raise an error here only if the info function returns + * something bogus. + * + * This function is broken out of fmgr_info_C_lang() so that ProcedureCreate() + * can validate the information record for a function not yet entered into + * pg_proc. + */ +Pg_finfo_record * +fetch_finfo_record(char *filename, char *funcname) +{ + char *infofuncname; + PGFInfoFunction infofunc; + Pg_finfo_record *inforec; + static Pg_finfo_record default_inforec = { 0 }; + + /* Compute name of info func */ + infofuncname = (char *) palloc(strlen(funcname) + 10); + sprintf(infofuncname, "pg_finfo_%s", funcname); + + /* Try to look up the info function */ + infofunc = (PGFInfoFunction) load_external_function(filename, + infofuncname, + false); + if (infofunc == (PGFInfoFunction) NULL) + { + /* Not found --- assume version 0 */ + pfree(infofuncname); + return &default_inforec; + } + + /* Found, so call it */ + inforec = (*infofunc)(); + + /* Validate result as best we can */ + if (inforec == NULL) + elog(ERROR, "Null result from %s", infofuncname); + switch (inforec->api_version) + { + case 0: + case 1: + /* OK, no additional fields to validate */ + break; + default: + elog(ERROR, "Unknown version %d reported by %s", + inforec->api_version, infofuncname); + break; + } + + pfree(infofuncname); + return inforec; +} + + +/* + * 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. */ Oid -fmgr_internal_language(const char *proname) +fmgr_internal_function(const char *proname) { const FmgrBuiltin *fbp = fmgr_lookupByName(proname); if (fbp == NULL) return InvalidOid; - return fbp->oldstyle ? INTERNALlanguageId : NEWINTERNALlanguageId; + return fbp->foid; } /* - * Handler for old-style internal and "C" language functions - * - * We expect fmgr_info to have placed the old-style function's address - * in fn_extra of *flinfo. This is a bit of a hack since fn_extra is really - * void * which might be a different size than a pointer to function, but - * it will work on any machine that our old-style call interface works on... + * Handler for old-style "C" language functions */ static Datum fmgr_oldstyle(PG_FUNCTION_ARGS) { - char *returnValue = NULL; + Oldstyle_fnextra *fnextra; int n_arguments = fcinfo->nargs; int i; bool isnull; func_ptr user_fn; + char *returnValue; if (fcinfo->flinfo == NULL || fcinfo->flinfo->fn_extra == NULL) - elog(ERROR, "Internal error: fmgr_oldstyle received NULL function pointer"); + elog(ERROR, "Internal error: fmgr_oldstyle received NULL pointer"); + fnextra = (Oldstyle_fnextra *) fcinfo->flinfo->fn_extra; /* * Result is NULL if any argument is NULL, but we still call the function * (peculiar, but that's the way it worked before, and after all this is * a backwards-compatibility wrapper). Note, however, that we'll never * get here with NULL arguments if the function is marked strict. + * + * We also need to detoast any TOAST-ed inputs, since it's unlikely that + * an old-style function knows about TOASTing. */ isnull = false; for (i = 0; i < n_arguments; i++) - isnull |= PG_ARGISNULL(i); + { + if (PG_ARGISNULL(i)) + isnull = true; + else if (fnextra->arg_toastable[i]) + fcinfo->arg[i] = PointerGetDatum(PG_DETOAST_DATUM(fcinfo->arg[i])); + } fcinfo->isnull = isnull; - user_fn = (func_ptr) fcinfo->flinfo->fn_extra; + user_fn = fnextra->func; switch (n_arguments) { @@ -411,6 +542,7 @@ fmgr_oldstyle(PG_FUNCTION_ARGS) */ elog(ERROR, "fmgr_oldstyle: function %u: too many arguments (%d > %d)", fcinfo->flinfo->fn_oid, n_arguments, 16); + returnValue = NULL; /* keep compiler quiet */ break; } |