PG_MODULE_MAGIC;
#endif
-bool
-c_overpaid(HeapTupleHeader t, /* the current row of emp */
- int32 limit)
-{
- bool isnull;
- int32 salary;
-
- salary = DatumGetInt32(GetAttributeByName(t, "salary", &isnull));
- if (isnull)
- return false;
- return salary > limit;
-}
-]]>
-
-
- In version-1 coding, the above would look like this:
-
-
-#include "postgres.h"
-#include "executor/executor.h" /* for GetAttributeByName() */
-
-#ifdef PG_MODULE_MAGIC
-PG_MODULE_MAGIC;
-#endif
-
PG_FUNCTION_INFO_V1(c_overpaid);
Datum
Function Manager
================
-Proposal For Function-Manager Redesign 19-Nov-2000
---------------------------------------
-
-We know that the existing mechanism for calling Postgres functions needs
-to be redesigned. It has portability problems because it makes
-assumptions about parameter passing that violate ANSI C; it fails to
-handle NULL arguments and results cleanly; and "function handlers" that
-support a class of functions (such as fmgr_pl) can only be done via a
-really ugly, non-reentrant kluge. (Global variable set during every
-function call, forsooth.) Here is a proposal for fixing these problems.
-
-In the past, the major objections to redoing the function-manager
-interface have been (a) it'll be quite tedious to implement, since every
-built-in function and everyplace that calls such functions will need to
-be touched; (b) such wide-ranging changes will be difficult to make in
-parallel with other development work; (c) it will break existing
-user-written loadable modules that define "C language" functions. While
-I have no solution to the "tedium" aspect, I believe I see an answer to
-the other problems: by use of function handlers, we can support both old
-and new interfaces in parallel for both callers and callees, at some
-small efficiency cost for the old styles. That way, most of the changes
-can be done on an incremental file-by-file basis --- we won't need a
-"big bang" where everything changes at once. Support for callees
-written in the old style can be left in place indefinitely, to provide
-backward compatibility for user-written C functions.
-
-
-Changes In pg_proc (System Data About a Function)
--------------------------------------------------
-
-A new column "proisstrict" will be added to the system pg_proc table.
-This is a boolean value which will be TRUE if the function is "strict",
-that is it always returns NULL when any of its inputs are NULL. The
-function manager will check this field and skip calling the function when
-it's TRUE and there are NULL inputs. This allows us to remove explicit
-NULL-value tests from many functions that currently need them (not to
-mention fixing many more that need them but don't have them). A function
-that is not marked "strict" is responsible for checking whether its inputs
-are NULL or not. Most builtin functions will be marked "strict".
-
-An optional WITH parameter will be added to CREATE FUNCTION to allow
-specification of whether user-defined functions are strict or not. I am
-inclined to make the default be "not strict", since that seems to be the
-more useful case for functions expressed in SQL or a PL language, but
-am open to arguments for the other choice.
-
-
-The New Function-Manager Interface
-----------------------------------
-
-The core of the new design is revised data structures for representing
-the result of a function lookup and for representing the parameters
-passed to a specific function invocation. (We want to keep function
-lookup separate from function call, since many parts of the system apply
-the same function over and over; the lookup overhead should be paid once
-per query, not once per tuple.)
+[This file originally explained the transition from the V0 to the V1
+interface. Now it just explains some internals and rationale for the V1
+interface, while the V0 interface has been removed.]
+
+The V1 Function-Manager Interface
+---------------------------------
+
+The core of the design is data structures for representing the result of a
+function lookup and for representing the parameters passed to a specific
+function invocation. (We want to keep function lookup separate from
+function call, since many parts of the system apply the same function over
+and over; the lookup overhead should be paid once per query, not once per
+tuple.)
When a function is looked up in pg_proc, the result is represented as
Function Coding Conventions
---------------------------
-As an example, int4 addition goes from old-style
-
-int32
-int4pl(int32 arg1, int32 arg2)
-{
- return arg1 + arg2;
-}
-
-to new-style
-
-Datum
-int4pl(FunctionCallInfo fcinfo)
-{
- /* we assume the function is marked "strict", so we can ignore
- * NULL-value handling */
-
- return Int32GetDatum(DatumGetInt32(fcinfo->arg[0]) +
- DatumGetInt32(fcinfo->arg[1]));
-}
-
-This is, of course, much uglier than the old-style code, but we can
-improve matters with some well-chosen macros for the boilerplate parts.
-I propose below macros that would make the code look like
-
-Datum
-int4pl(PG_FUNCTION_ARGS)
-{
- int32 arg1 = PG_GETARG_INT32(0);
- int32 arg2 = PG_GETARG_INT32(1);
-
- PG_RETURN_INT32( arg1 + arg2 );
-}
-
-This is still more code than before, but it's fairly readable, and it's
-also amenable to machine processing --- for example, we could probably
-write a script that scans code like this and extracts argument and result
-type info for comparison to the pg_proc table.
-
-For the standard data types float4, float8, and int8, these macros should hide
-whether the types are pass-by-value or pass-by reference, by incorporating
-indirection and space allocation if needed. This will offer a considerable
-gain in readability, and it also opens up the opportunity to make these types
-be pass-by-value on machines where it's feasible to do so.
-
Here are the proposed macros and coding conventions:
The definition of an fmgr-callable function will always look like
syntactic-sugar macros for these cases is useful.
-Call-Site Coding Conventions
-----------------------------
-
-There are many places in the system that call either a specific function
-(for example, the parser invokes "textin" by name in places) or a
-particular group of functions that have a common argument list (for
-example, the optimizer invokes selectivity estimation functions with
-a fixed argument list). These places will need to change, but we should
-try to avoid making them significantly uglier than before.
-
-Places that invoke an arbitrary function with an arbitrary argument list
-can simply be changed to fill a FunctionCallInfoData structure directly;
-that'll be no worse and possibly cleaner than what they do now.
-
-When invoking a specific built-in function by name, we have generally
-just written something like
- result = textin ( ... args ... )
-which will not work after textin() is converted to the new call style.
-I suggest that code like this be converted to use "helper" functions
-that will create and fill in a FunctionCallInfoData struct. For
-example, if textin is being called with one argument, it'd look
-something like
- result = DirectFunctionCall1(textin, PointerGetDatum(argument));
-These helper routines will have declarations like
- Datum DirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2);
-Note it will be the caller's responsibility to convert to and from
-Datum; appropriate conversion macros should be used.
-
-The DirectFunctionCallN routines will not bother to fill in
-fcinfo->flinfo (indeed cannot, since they have no idea about an OID for
-the target function); they will just set it NULL. This is unlikely to
-bother any built-in function that could be called this way. Note also
-that this style of coding cannot pass a NULL input value nor cope with
-a NULL result (it couldn't before, either!). We can make the helper
-routines ereport an error if they see that the function returns a NULL.
-
-When invoking a function that has a known argument signature, we have
-usually written either
- result = fmgr(targetfuncOid, ... args ... );
-or
- result = fmgr_ptr(FmgrInfo *finfo, ... args ... );
-depending on whether an FmgrInfo lookup has been done yet or not.
-This kind of code can be recast using helper routines, in the same
-style as above:
- result = OidFunctionCall1(funcOid, PointerGetDatum(argument));
- result = FunctionCall2(funcCallInfo,
- PointerGetDatum(argument),
- Int32GetDatum(argument));
-Again, this style of coding does not allow for expressing NULL inputs
-or receiving a NULL result.
-
-As with the callee-side situation, I propose adding argument conversion
-macros that hide whether int8, float4, and float8 are pass-by-value or
-pass-by-reference.
-
-The existing helper functions fmgr(), fmgr_c(), etc will be left in
-place until all uses of them are gone. Of course their internals will
-have to change in the first step of implementation, but they can
-continue to support the same external appearance.
-
-
Support for TOAST-Able Data Types
---------------------------------
CurrentMemoryContext at the time the FmgrInfo structure was created;
in any case it is required to be a context at least as long-lived as the
FmgrInfo itself.
-
-
-Telling the Difference Between Old- and New-Style Functions
------------------------------------------------------------
-
-During the conversion process, we carried two different pg_language
-entries, "internal" and "newinternal", for internal functions. The
-function manager used the language code to distinguish which calling
-convention to use. (Old-style internal functions were supported via
-a function handler.) As of Nov. 2000, no old-style internal functions
-remain, so we can drop support for them. We will remove the old "internal"
-pg_language entry and rename "newinternal" to "internal".
-
-The interim solution for dynamically-loaded compiled functions has been
-similar: two pg_language entries "C" and "newC". This naming convention
-is not desirable for the long run, and yet we cannot stop supporting
-old-style user functions. Instead, it seems better to use just one
-pg_language entry "C", and require the dynamically-loaded library to
-provide additional information that identifies new-style functions.
-This avoids compatibility problems --- for example, existing dump
-scripts will identify PL language handlers as being in language "C",
-which would be wrong under the "newC" convention. Also, this approach
-should generalize more conveniently for future extensions to the function
-interface specification.
-
-Given a dynamically loaded function named "foo" (note that the name being
-considered here is the link-symbol name, not the SQL-level function name),
-the function manager will look for another function in the same dynamically
-loaded library named "pg_finfo_foo". If this second function does not
-exist, then foo is assumed to be called old-style, thus ensuring backwards
-compatibility with existing libraries. If the info function does exist,
-it is expected to have the signature
-
- Pg_finfo_record * pg_finfo_foo (void);
-
-The info function will be called by the fmgr, and must return a pointer
-to a Pg_finfo_record struct. (The returned struct will typically be a
-statically allocated constant in the dynamic-link library.) The current
-definition of the struct is just
-
- typedef struct {
- int api_version;
- } Pg_finfo_record;
-
-where api_version is 0 to indicate old-style or 1 to indicate new-style
-calling convention. In future releases, additional fields may be defined
-after api_version, but these additional fields will only be used if
-api_version is greater than 1.
-
-These details will be hidden from the author of a dynamically loaded
-function by using a macro. To define a new-style dynamically loaded
-function named foo, write
-
- PG_FUNCTION_INFO_V1(foo);
-
- Datum
- foo(PG_FUNCTION_ARGS)
- {
- ...
- }
-
-The function itself is written using the same conventions as for new-style
-internal functions; you just need to add the PG_FUNCTION_INFO_V1() macro.
-Note that old-style and new-style functions can be intermixed in the same
-library, depending on whether or not you write a PG_FUNCTION_INFO_V1() for
-each one.
-
-The SQL declaration for a dynamically-loaded function is CREATE FUNCTION
-foo ... LANGUAGE C regardless of whether it is old- or new-style.
-
-New-style dynamic functions will be invoked directly by fmgr, and will
-therefore have the same performance as internal functions after the initial
-pg_proc lookup overhead. Old-style dynamic functions will be invoked via
-a handler, and will therefore have a small performance penalty.
-
-To allow old-style dynamic functions to work safely on toastable datatypes,
-the handler for old-style functions will automatically detoast toastable
-arguments before passing them to the old-style function. A new-style
-function is expected to take care of toasted arguments by using the
-standard argument access macros defined above.
PGDLLIMPORT needs_fmgr_hook_type needs_fmgr_hook = NULL;
PGDLLIMPORT fmgr_hook_type fmgr_hook = NULL;
-/*
- * Declaration for old-style function pointer type. This is now used only
- * in fmgr_oldstyle() and is no longer exported.
- *
- * The m68k SVR4 ABI defines that pointers are returned in %a0 instead of
- * %d0. So if a function pointer is declared to return a pointer, the
- * compiler may look only into %a0, but if the called function was declared
- * to return an integer type, it puts its value only into %d0. So the
- * caller doesn't pick up the correct return value. The solution is to
- * declare the function pointer to return int, so the compiler picks up the
- * return value from %d0. (Functions returning pointers put their value
- * *additionally* into %d0 for compatibility.) The price is that there are
- * some warnings about int->pointer conversions ... which we can suppress
- * with suitably ugly casts in fmgr_oldstyle().
- */
-#if (defined(__mc68000__) || (defined(__m68k__))) && defined(__ELF__)
-typedef int32 (*func_ptr) ();
-#else
-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;
-
/*
* Hashtable for fast lookup of external C functions
*/
static CFuncHashTabEntry *lookup_C_func(HeapTuple procedureTuple);
static void record_C_func(HeapTuple procedureTuple,
PGFunction user_fn, const Pg_finfo_record *inforec);
-static Datum fmgr_oldstyle(PG_FUNCTION_ARGS);
static Datum fmgr_security_definer(PG_FUNCTION_ARGS);
static void
fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
{
- Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
CFuncHashTabEntry *hashentry;
PGFunction user_fn;
const Pg_finfo_record *inforec;
- Oldstyle_fnextra *fnextra;
bool isnull;
- int i;
/*
* See if we have the function address cached already
switch (inforec->api_version)
{
- case 0:
- /* Old style: need to use a handler */
- finfo->fn_addr = fmgr_oldstyle;
- fnextra = (Oldstyle_fnextra *)
- MemoryContextAllocZero(finfo->fn_mcxt,
- sizeof(Oldstyle_fnextra));
- finfo->fn_extra = (void *) fnextra;
- fnextra->func = (func_ptr) user_fn;
- for (i = 0; i < procedureStruct->pronargs; i++)
- {
- fnextra->arg_toastable[i] =
- TypeIsToastable(procedureStruct->proargtypes.values[i]);
- }
- break;
case 1:
/* New style: call directly */
finfo->fn_addr = user_fn;
CurrentMemoryContext, true);
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, "language %u has old-style handler", language);
-
ReleaseSysCache(languageTuple);
}
* 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.
- * We want to raise an error here only if the info function returns
- * something bogus.
+ * If no info function exists for the given name an error is raised.
*
* This function is broken out of fmgr_info_C_lang so that fmgr_c_validator
* can validate the information record for a function not yet entered into
char *infofuncname;
PGFInfoFunction infofunc;
const Pg_finfo_record *inforec;
- static Pg_finfo_record default_inforec = {0};
infofuncname = psprintf("pg_finfo_%s", funcname);
infofuncname);
if (infofunc == NULL)
{
- /* Not found --- assume version 0 */
- pfree(infofuncname);
- return &default_inforec;
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not find function information for function \"%s\"",
+ funcname),
+ errhint("SQL-callable functions need an accompanying PG_FUNCTION_INFO_V1(funcname).")));
+ return NULL; /* silence compiler */
}
/* Found, so call it */
elog(ERROR, "null result from info function \"%s\"", infofuncname);
switch (inforec->api_version)
{
- case 0:
case 1:
/* OK, no additional fields to validate */
break;
{
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;
+ dstinfo->fn_extra = NULL;
}
}
-/*
- * Handler for old-style "C" language functions
- */
-static Datum
-fmgr_oldstyle(PG_FUNCTION_ARGS)
-{
- 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, "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++)
- {
- 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 = fnextra->func;
-
- switch (n_arguments)
- {
- case 0:
- returnValue = (char *) (*user_fn) ();
- break;
- case 1:
-
- /*
- * nullvalue() used to use isNull to check if arg is NULL; perhaps
- * there are other functions still out there that also rely on
- * this undocumented hack?
- */
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- &fcinfo->isnull);
- break;
- case 2:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1]);
- break;
- case 3:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2]);
- break;
- case 4:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3]);
- break;
- case 5:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4]);
- break;
- case 6:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4],
- fcinfo->arg[5]);
- break;
- case 7:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4],
- fcinfo->arg[5],
- fcinfo->arg[6]);
- break;
- case 8:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4],
- fcinfo->arg[5],
- fcinfo->arg[6],
- fcinfo->arg[7]);
- break;
- case 9:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4],
- fcinfo->arg[5],
- fcinfo->arg[6],
- fcinfo->arg[7],
- fcinfo->arg[8]);
- break;
- case 10:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4],
- fcinfo->arg[5],
- fcinfo->arg[6],
- fcinfo->arg[7],
- fcinfo->arg[8],
- fcinfo->arg[9]);
- break;
- case 11:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4],
- fcinfo->arg[5],
- fcinfo->arg[6],
- fcinfo->arg[7],
- fcinfo->arg[8],
- fcinfo->arg[9],
- fcinfo->arg[10]);
- break;
- case 12:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4],
- fcinfo->arg[5],
- fcinfo->arg[6],
- fcinfo->arg[7],
- fcinfo->arg[8],
- fcinfo->arg[9],
- fcinfo->arg[10],
- fcinfo->arg[11]);
- break;
- case 13:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4],
- fcinfo->arg[5],
- fcinfo->arg[6],
- fcinfo->arg[7],
- fcinfo->arg[8],
- fcinfo->arg[9],
- fcinfo->arg[10],
- fcinfo->arg[11],
- fcinfo->arg[12]);
- break;
- case 14:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4],
- fcinfo->arg[5],
- fcinfo->arg[6],
- fcinfo->arg[7],
- fcinfo->arg[8],
- fcinfo->arg[9],
- fcinfo->arg[10],
- fcinfo->arg[11],
- fcinfo->arg[12],
- fcinfo->arg[13]);
- break;
- case 15:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4],
- fcinfo->arg[5],
- fcinfo->arg[6],
- fcinfo->arg[7],
- fcinfo->arg[8],
- fcinfo->arg[9],
- fcinfo->arg[10],
- fcinfo->arg[11],
- fcinfo->arg[12],
- fcinfo->arg[13],
- fcinfo->arg[14]);
- break;
- case 16:
- returnValue = (char *) (*user_fn) (fcinfo->arg[0],
- fcinfo->arg[1],
- fcinfo->arg[2],
- fcinfo->arg[3],
- fcinfo->arg[4],
- fcinfo->arg[5],
- fcinfo->arg[6],
- fcinfo->arg[7],
- fcinfo->arg[8],
- fcinfo->arg[9],
- fcinfo->arg[10],
- fcinfo->arg[11],
- fcinfo->arg[12],
- fcinfo->arg[13],
- fcinfo->arg[14],
- fcinfo->arg[15]);
- break;
- default:
-
- /*
- * Increasing FUNC_MAX_ARGS doesn't automatically add cases to the
- * above code, so mention the actual value in this error not
- * FUNC_MAX_ARGS. You could add cases to the above if you needed
- * to support old-style functions with many arguments, but making
- * 'em be new-style is probably a better idea.
- */
- ereport(ERROR,
- (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
- errmsg("function %u has too many arguments (%d, maximum is %d)",
- fcinfo->flinfo->fn_oid, n_arguments, 16)));
- returnValue = NULL; /* keep compiler quiet */
- break;
- }
-
- return PointerGetDatum(returnValue);
-}
-
-
/*
* Support for security-definer and proconfig-using functions. We support
* both of these features using the same call handler, because they are
}
-/*
- * !!! OLD INTERFACE !!!
- *
- * fmgr() is the only remaining vestige of the old-style caller support
- * functions. It's no longer used anywhere in the Postgres distribution,
- * but we should leave it around for a release or two to ease the transition
- * for user-supplied C functions. OidFunctionCallN() replaces it for new
- * code.
- *
- * DEPRECATED, DO NOT USE IN NEW CODE
- */
-char *
-fmgr(Oid procedureId,...)
-{
- FmgrInfo flinfo;
- FunctionCallInfoData fcinfo;
- int n_arguments;
- Datum result;
-
- fmgr_info(procedureId, &flinfo);
-
- MemSet(&fcinfo, 0, sizeof(fcinfo));
- fcinfo.flinfo = &flinfo;
- fcinfo.nargs = flinfo.fn_nargs;
- n_arguments = fcinfo.nargs;
-
- if (n_arguments > 0)
- {
- va_list pvar;
- int i;
-
- if (n_arguments > FUNC_MAX_ARGS)
- ereport(ERROR,
- (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
- errmsg("function %u has too many arguments (%d, maximum is %d)",
- flinfo.fn_oid, n_arguments, FUNC_MAX_ARGS)));
- va_start(pvar, procedureId);
- for (i = 0; i < n_arguments; i++)
- fcinfo.arg[i] = PointerGetDatum(va_arg(pvar, char *));
- va_end(pvar);
- }
-
- result = FunctionCallInvoke(&fcinfo);
-
- /* Check for null result, since caller is clearly not expecting one */
- if (fcinfo.isnull)
- elog(ERROR, "function %u returned NULL", flinfo.fn_oid);
-
- return DatumGetPointer(result);
-}
-
-
/*-------------------------------------------------------------------------
* Support routines for standard maybe-pass-by-reference datatypes
*
/*-------------------------------------------------------------------------
* 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
+ * Dynamically loaded functions currently can only use the version-1 ("new
+ * style") calling convention. Version-0 ("old style") is not supported
+ * anymore. Version 1 is the call convention defined in this header file, and
+ * must be accompanied by the macro call
*
* PG_FUNCTION_INFO_V1(function_name);
*
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT;
-CREATE FUNCTION oldstyle_length(int4, text)
- RETURNS int4
- AS '@libdir@/regress@DLSUFFIX@'
- LANGUAGE C; -- intentionally not strict
-
--
-- Function dynamic loading
--
SELECT *, (equipment(CAST((h.*) AS hobbies_r))).name FROM hobbies_r h;
---
--- 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
--
RETURNS name
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT;
-CREATE FUNCTION oldstyle_length(int4, text)
- RETURNS int4
- AS '@libdir@/regress@DLSUFFIX@'
- LANGUAGE C; -- intentionally not strict
--
-- Function dynamic loading
--
skywalking | | guts
(7 rows)
---
--- 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 | 50000 | 50000
-(4 rows)
-
-drop table oldstyle_test;
--
-- functional joins
--
extern PATH *poly2path(POLYGON *poly);
extern void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-extern char *reverse_name(char *string);
-extern int oldstyle_length(int n, text *t);
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
double radius;
} WIDGET;
-WIDGET *widget_in(char *str);
-char *widget_out(WIDGET *widget);
+PG_FUNCTION_INFO_V1(widget_in);
+PG_FUNCTION_INFO_V1(widget_out);
#define NARGS 3
-WIDGET *
-widget_in(char *str)
+Datum
+widget_in(PG_FUNCTION_ARGS)
{
+ char *str = PG_GETARG_CSTRING(0);
char *p,
*coord[NARGS];
int i;
result->center.y = atof(coord[1]);
result->radius = atof(coord[2]);
- return result;
+ PG_RETURN_POINTER(result);
}
-char *
-widget_out(WIDGET *widget)
+Datum
+widget_out(PG_FUNCTION_ARGS)
{
- return psprintf("(%g,%g,%g)",
- widget->center.x, widget->center.y, widget->radius);
+ WIDGET *widget = (WIDGET *) PG_GETARG_POINTER(0);
+ char *str = psprintf("(%g,%g,%g)",
+ widget->center.x, widget->center.y, widget->radius);
+ PG_RETURN_CSTRING(str);
}
PG_FUNCTION_INFO_V1(pt_in_widget);
PG_RETURN_FLOAT8(width * height);
}
-char *
-reverse_name(char *string)
+PG_FUNCTION_INFO_V1(reverse_name);
+
+Datum
+reverse_name(PG_FUNCTION_ARGS)
{
+ char *string = PG_GETARG_CSTRING(0);
int i;
int len;
char *new_string;
len = i;
for (; i >= 0; --i)
new_string[len - i] = string[i];
- 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;
+ PG_RETURN_CSTRING(new_string);
}