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 | |
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')
26 files changed, 449 insertions, 243 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; } diff --git a/src/bin/scripts/createlang.sh b/src/bin/scripts/createlang.sh index 3fc0a1b02fa..02c27aaf90b 100644 --- a/src/bin/scripts/createlang.sh +++ b/src/bin/scripts/createlang.sh @@ -8,7 +8,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createlang.sh,v 1.19 2000/11/13 23:37:53 momjian Exp $ +# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createlang.sh,v 1.20 2000/11/20 20:36:50 tgl Exp $ # #------------------------------------------------------------------------- @@ -259,7 +259,7 @@ fi # ---------- # Create the call handler and the language # ---------- -$PSQL "CREATE FUNCTION $handler () RETURNS OPAQUE AS '$PGLIB/${object}$DLSUFFIX' LANGUAGE 'newC'" +$PSQL "CREATE FUNCTION $handler () RETURNS OPAQUE AS '$PGLIB/${object}$DLSUFFIX' LANGUAGE 'C'" if [ $? -ne 0 ]; then echo "$CMDNAME: language installation failed" 1>&2 exit 1 diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index e3f4c6ff899..558feef575b 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: catversion.h,v 1.61 2000/11/20 05:18:40 vadim Exp $ + * $Id: catversion.h,v 1.62 2000/11/20 20:36:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200011191 +#define CATALOG_VERSION_NO 200011201 #endif diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h index 0d597d8c4da..423f2e94700 100644 --- a/src/include/catalog/pg_language.h +++ b/src/include/catalog/pg_language.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_language.h,v 1.11 2000/05/28 17:56:16 tgl Exp $ + * $Id: pg_language.h,v 1.12 2000/11/20 20:36:50 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -63,18 +63,12 @@ typedef FormData_pg_language *Form_pg_language; * ---------------- */ -DATA(insert OID = 11 ( internal f f 0 "n/a" )); -DESCR("old-style built-in functions"); -#define INTERNALlanguageId 11 -DATA(insert OID = 12 ( newinternal f f 0 "n/a" )); -DESCR("new-style built-in functions"); -#define NEWINTERNALlanguageId 12 +DATA(insert OID = 12 ( internal f f 0 "n/a" )); +DESCR("Built-in functions"); +#define INTERNALlanguageId 12 DATA(insert OID = 13 ( "C" f f 0 "/bin/cc" )); -DESCR("Dynamically-loaded old-style C functions"); +DESCR("Dynamically-loaded C functions"); #define ClanguageId 13 -DATA(insert OID = 10 ( "newC" f f 0 "/bin/cc" )); -DESCR("Dynamically-loaded new-style C functions"); -#define NEWClanguageId 10 DATA(insert OID = 14 ( "sql" f f 0 "postgres")); DESCR("SQL-language functions"); #define SQLlanguageId 14 diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 28634262bcc..08faf956299 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -11,7 +11,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: fmgr.h,v 1.10 2000/08/24 03:29:11 tgl Exp $ + * $Id: fmgr.h,v 1.11 2000/11/20 20:36:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -209,6 +209,43 @@ extern struct varlena * pg_detoast_datum_copy(struct varlena * datum); /*------------------------------------------------------------------------- + * Support for detecting call convention of dynamically-loaded functions + * + * Dynamically loaded functions may use either the version-1 ("new style") + * or version-0 ("old style") calling convention. Version 1 is the call + * convention defined in this header file; version 0 is the old "plain C" + * convention. A version-1 function must be accompanied by the macro call + * + * PG_FUNCTION_INFO_V1(function_name); + * + * Note that internal functions do not need this decoration since they are + * assumed to be version-1. + * + *------------------------------------------------------------------------- + */ + +typedef struct +{ + int api_version; /* specifies call convention version number */ + /* More fields may be added later, for version numbers > 1. */ +} Pg_finfo_record; + +/* Expected signature of an info function */ +typedef Pg_finfo_record * (*PGFInfoFunction) (void); + +/* Macro to build an info function associated with the given function name */ + +#define PG_FUNCTION_INFO_V1(funcname) \ +extern Pg_finfo_record * CppConcat(pg_finfo_,funcname) (void); \ +Pg_finfo_record * \ +CppConcat(pg_finfo_,funcname) (void) \ +{ \ + static Pg_finfo_record my_finfo = { 1 }; \ + return &my_finfo; \ +} + + +/*------------------------------------------------------------------------- * Support routines and macros for callers of fmgr-compatible functions *------------------------------------------------------------------------- */ @@ -297,13 +334,14 @@ extern Datum OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2, /* * Routines in fmgr.c */ -extern Oid fmgr_internal_language(const char *proname); +extern Pg_finfo_record *fetch_finfo_record(char *filename, char *funcname); +extern Oid fmgr_internal_function(const char *proname); /* * Routines in dfmgr.c */ -extern PGFunction fmgr_dynamic(Oid functionId); -extern PGFunction load_external_function(char *filename, char *funcname); +extern PGFunction load_external_function(char *filename, char *funcname, + bool signalNotFound); extern void load_file(char *filename); diff --git a/src/include/utils/fmgrtab.h b/src/include/utils/fmgrtab.h index e6cfe519650..9d46aeae694 100644 --- a/src/include/utils/fmgrtab.h +++ b/src/include/utils/fmgrtab.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: fmgrtab.h,v 1.13 2000/05/28 17:56:20 tgl Exp $ + * $Id: fmgrtab.h,v 1.14 2000/11/20 20:36:51 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,7 +28,7 @@ typedef struct const char *funcName; /* C name of the function */ short nargs; /* 0..FUNC_MAX_ARGS, or -1 if variable count */ bool strict; /* T if function is "strict" */ - bool oldstyle; /* T if function uses old fmgr interface */ + bool retset; /* T if function returns a set */ PGFunction func; /* pointer to compiled function */ } FmgrBuiltin; diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index f8547baa884..903e09aaf9c 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: lsyscache.h,v 1.27 2000/11/16 22:30:49 tgl Exp $ + * $Id: lsyscache.h,v 1.28 2000/11/20 20:36:51 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,6 +39,9 @@ extern char *get_rel_name(Oid relid); extern int16 get_typlen(Oid typid); extern bool get_typbyval(Oid typid); extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval); +extern char get_typstorage(Oid typid); extern Datum get_typdefault(Oid typid); +#define TypeIsToastable(typid) (get_typstorage(typid) != 'p') + #endif /* LSYSCACHE_H */ diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 81a4cd75d4b..0b2d7d4e425 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -33,7 +33,7 @@ * ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.15 2000/11/16 22:30:49 tgl Exp $ + * $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.16 2000/11/20 20:36:51 tgl Exp $ * **********************************************************************/ @@ -258,6 +258,7 @@ plperl_init_safe_interp(void) * call this function for execution of * perl procedures. **********************************************************************/ +PG_FUNCTION_INFO_V1(plperl_call_handler); /* keep non-static */ Datum diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 31788b07061..d9e208ee98b 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.5 2000/05/29 01:59:14 tgl Exp $ + * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.6 2000/11/20 20:36:52 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -66,6 +66,8 @@ static PLpgSQL_function *compiled_functions = NULL; * call this function for execution of PL/pgSQL procedures. * ---------- */ +PG_FUNCTION_INFO_V1(plpgsql_call_handler); + Datum plpgsql_call_handler(PG_FUNCTION_ARGS) { diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index 8658cac3065..94a67ef0433 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -31,7 +31,7 @@ * ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.29 2000/11/16 22:30:52 tgl Exp $ + * $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.30 2000/11/20 20:36:52 tgl Exp $ * **********************************************************************/ @@ -325,6 +325,7 @@ pltcl_init_load_unknown(void) * call this function for execution of * PL/Tcl procedures. **********************************************************************/ +PG_FUNCTION_INFO_V1(pltcl_call_handler); /* keep non-static */ Datum @@ -371,6 +372,12 @@ pltcl_call_handler(PG_FUNCTION_ARGS) return retval; } + +/* + * Alternate handler for unsafe functions + */ +PG_FUNCTION_INFO_V1(pltclu_call_handler); + /* keep non-static */ Datum pltclu_call_handler(PG_FUNCTION_ARGS) diff --git a/src/test/regress/input/create_function_1.source b/src/test/regress/input/create_function_1.source index 0f82a3bea40..6d91674cd56 100644 --- a/src/test/regress/input/create_function_1.source +++ b/src/test/regress/input/create_function_1.source @@ -15,30 +15,30 @@ CREATE FUNCTION widget_out(opaque) CREATE FUNCTION check_primary_key () RETURNS opaque AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION check_foreign_key () RETURNS opaque AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION autoinc () RETURNS opaque AS '@abs_builddir@/../../../contrib/spi/autoinc@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION funny_dup17 () RETURNS opaque AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION ttdummy () RETURNS opaque AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION set_ttdummy (int4) RETURNS int4 AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; diff --git a/src/test/regress/input/create_function_2.source b/src/test/regress/input/create_function_2.source index af6695764ac..b1c0eab1386 100644 --- a/src/test/regress/input/create_function_2.source +++ b/src/test/regress/input/create_function_2.source @@ -30,28 +30,33 @@ CREATE FUNCTION user_relns() CREATE FUNCTION pt_in_widget(point, widget) RETURNS bool AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION overpaid(emp) RETURNS bool AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION boxarea(box) RETURNS float8 AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION interpt_pp(path, path) RETURNS point AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION reverse_name(name) RETURNS name AS '@abs_builddir@/regress@DLSUFFIX@' LANGUAGE 'c'; +CREATE FUNCTION oldstyle_length(int4, text) + RETURNS int4 + AS '@abs_builddir@/regress@DLSUFFIX@' + LANGUAGE 'c'; + -- -- Function dynamic loading -- diff --git a/src/test/regress/input/misc.source b/src/test/regress/input/misc.source index 9e9ebdb75bc..dbb8df84709 100644 --- a/src/test/regress/input/misc.source +++ b/src/test/regress/input/misc.source @@ -216,6 +216,19 @@ SELECT user_relns() AS user_relns -- +-- check that old-style C functions work properly with TOASTed values +-- +create table oldstyle_test(i int4, t text); +insert into oldstyle_test values(null,null); +insert into oldstyle_test values(0,'12'); +insert into oldstyle_test values(1000,'12'); +insert into oldstyle_test values(0, repeat('x', 50000)); + +select i, length(t), octet_length(t), oldstyle_length(i,t) from oldstyle_test; + +drop table oldstyle_test; + +-- -- functional joins -- diff --git a/src/test/regress/output/create_function_1.source b/src/test/regress/output/create_function_1.source index d3815a9aadd..d075a61eb8a 100644 --- a/src/test/regress/output/create_function_1.source +++ b/src/test/regress/output/create_function_1.source @@ -13,24 +13,24 @@ CREATE FUNCTION widget_out(opaque) CREATE FUNCTION check_primary_key () RETURNS opaque AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION check_foreign_key () RETURNS opaque AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION autoinc () RETURNS opaque AS '@abs_builddir@/../../../contrib/spi/autoinc@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION funny_dup17 () RETURNS opaque AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION ttdummy () RETURNS opaque AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION set_ttdummy (int4) RETURNS int4 AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; diff --git a/src/test/regress/output/create_function_2.source b/src/test/regress/output/create_function_2.source index def359de90f..a5f39a00bb0 100644 --- a/src/test/regress/output/create_function_2.source +++ b/src/test/regress/output/create_function_2.source @@ -23,23 +23,27 @@ CREATE FUNCTION user_relns() CREATE FUNCTION pt_in_widget(point, widget) RETURNS bool AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION overpaid(emp) RETURNS bool AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION boxarea(box) RETURNS float8 AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION interpt_pp(path, path) RETURNS point AS '@abs_builddir@/regress@DLSUFFIX@' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION reverse_name(name) RETURNS name AS '@abs_builddir@/regress@DLSUFFIX@' LANGUAGE 'c'; +CREATE FUNCTION oldstyle_length(int4, text) + RETURNS int4 + AS '@abs_builddir@/regress@DLSUFFIX@' + LANGUAGE 'c'; -- -- Function dynamic loading -- diff --git a/src/test/regress/output/misc.source b/src/test/regress/output/misc.source index 144ad33f242..768dba5c3c7 100644 --- a/src/test/regress/output/misc.source +++ b/src/test/regress/output/misc.source @@ -657,6 +657,24 @@ SELECT user_relns() AS user_relns --SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name; -- +-- check that old-style C functions work properly with TOASTed values +-- +create table oldstyle_test(i int4, t text); +insert into oldstyle_test values(null,null); +insert into oldstyle_test values(0,'12'); +insert into oldstyle_test values(1000,'12'); +insert into oldstyle_test values(0, repeat('x', 50000)); +select i, length(t), octet_length(t), oldstyle_length(i,t) from oldstyle_test; + i | length | octet_length | oldstyle_length +------+--------+--------------+----------------- + | | | + 0 | 2 | 2 | 2 + 1000 | 2 | 2 | 1002 + 0 | 50000 | 581 | 50000 +(4 rows) + +drop table oldstyle_test; +-- -- functional joins -- -- diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index 479527fc3fc..bd65c4233da 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -1,5 +1,5 @@ /* - * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.44 2000/08/24 23:34:11 tgl Exp $ + * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.45 2000/11/20 20:36:53 tgl Exp $ */ #include <float.h> /* faked on sunos */ @@ -25,10 +25,13 @@ extern void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2); extern Datum overpaid(PG_FUNCTION_ARGS); extern Datum boxarea(PG_FUNCTION_ARGS); extern char *reverse_name(char *string); +extern int oldstyle_length(int n, text *t); /* ** Distance from a point to a path */ +PG_FUNCTION_INFO_V1(regress_dist_ptpath); + Datum regress_dist_ptpath(PG_FUNCTION_ARGS) { @@ -69,6 +72,8 @@ regress_dist_ptpath(PG_FUNCTION_ARGS) /* this essentially does a cartesian product of the lsegs in the two paths, and finds the min distance between any two lsegs */ +PG_FUNCTION_INFO_V1(regress_path_dist); + Datum regress_path_dist(PG_FUNCTION_ARGS) { @@ -129,6 +134,8 @@ POLYGON *poly; } /* return the point where two paths intersect, or NULL if no intersection. */ +PG_FUNCTION_INFO_V1(interpt_pp); + Datum interpt_pp(PG_FUNCTION_ARGS) { @@ -182,6 +189,8 @@ Point *pt2; lseg->m = point_sl(pt1, pt2); } +PG_FUNCTION_INFO_V1(overpaid); + Datum overpaid(PG_FUNCTION_ARGS) { @@ -254,6 +263,8 @@ WIDGET *widget; return result; } +PG_FUNCTION_INFO_V1(pt_in_widget); + Datum pt_in_widget(PG_FUNCTION_ARGS) { @@ -265,6 +276,8 @@ pt_in_widget(PG_FUNCTION_ARGS) #define ABS(X) ((X) >= 0 ? (X) : -(X)) +PG_FUNCTION_INFO_V1(boxarea); + Datum boxarea(PG_FUNCTION_ARGS) { @@ -278,8 +291,7 @@ boxarea(PG_FUNCTION_ARGS) } char * -reverse_name(string) -char *string; +reverse_name(char *string) { int i; int len; @@ -301,6 +313,20 @@ char *string; return new_string; } +/* This rather silly function is just to test that oldstyle functions + * work correctly on toast-able inputs. + */ +int +oldstyle_length(int n, text *t) +{ + int len = 0; + + if (t) + len = VARSIZE(t) - VARHDRSZ; + + return n + len; +} + #include "executor/spi.h" /* this is what you need to work with SPI */ #include "commands/trigger.h" /* -"- and triggers */ @@ -312,6 +338,8 @@ static bool fd17b_recursion = true; static bool fd17a_recursion = true; extern Datum funny_dup17(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(funny_dup17); + Datum funny_dup17(PG_FUNCTION_ARGS) { @@ -428,6 +456,8 @@ extern Datum set_ttdummy(PG_FUNCTION_ARGS); static void *splan = NULL; static bool ttoff = false; +PG_FUNCTION_INFO_V1(ttdummy); + Datum ttdummy(PG_FUNCTION_ARGS) { @@ -625,6 +655,8 @@ ttdummy(PG_FUNCTION_ARGS) return PointerGetDatum(rettuple); } +PG_FUNCTION_INFO_V1(set_ttdummy); + Datum set_ttdummy(PG_FUNCTION_ARGS) { diff --git a/src/test/regress/sql/drop.sql b/src/test/regress/sql/drop.sql index 254c62100dc..fc89483208e 100644 --- a/src/test/regress/sql/drop.sql +++ b/src/test/regress/sql/drop.sql @@ -38,6 +38,7 @@ DROP FUNCTION interpt_pp(path,path); DROP FUNCTION reverse_name(name); +DROP FUNCTION oldstyle_length(int4, text); -- -- OPERATOR REMOVAL diff --git a/src/tutorial/funcs_new.c b/src/tutorial/funcs_new.c index 0734e67a113..20f609d5d2d 100644 --- a/src/tutorial/funcs_new.c +++ b/src/tutorial/funcs_new.c @@ -30,6 +30,8 @@ Datum c_overpaid(PG_FUNCTION_ARGS); /* By Value */ +PG_FUNCTION_INFO_V1(add_one); + Datum add_one(PG_FUNCTION_ARGS) { @@ -40,6 +42,8 @@ add_one(PG_FUNCTION_ARGS) /* By Reference, Fixed Length */ +PG_FUNCTION_INFO_V1(add_one_float8); + Datum add_one_float8(PG_FUNCTION_ARGS) { @@ -49,6 +53,8 @@ add_one_float8(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(arg + 1.0); } +PG_FUNCTION_INFO_V1(makepoint); + Datum makepoint(PG_FUNCTION_ARGS) { @@ -64,6 +70,8 @@ makepoint(PG_FUNCTION_ARGS) /* By Reference, Variable Length */ +PG_FUNCTION_INFO_V1(copytext); + Datum copytext(PG_FUNCTION_ARGS) { @@ -82,6 +90,8 @@ copytext(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(new_t); } +PG_FUNCTION_INFO_V1(concat_text); + Datum concat_text(PG_FUNCTION_ARGS) { @@ -99,6 +109,8 @@ concat_text(PG_FUNCTION_ARGS) /* Composite types */ +PG_FUNCTION_INFO_V1(c_overpaid); + Datum c_overpaid(PG_FUNCTION_ARGS) { |