Remove support for version-0 calling conventions.
authorAndres Freund <andres@anarazel.de>
Wed, 29 Mar 2017 20:16:49 +0000 (13:16 -0700)
committerAndres Freund <andres@anarazel.de>
Thu, 30 Mar 2017 13:25:46 +0000 (06:25 -0700)
The V0 convention is failure prone because we've so far assumed that a
function is V0 if PG_FUNCTION_INFO_V1 is missing, leading to crashes
if a function was coded against the V1 interface.  V0 doesn't allow
proper NULL, SRF and toast handling.  V0 doesn't offer features that
V1 doesn't.

Thus remove V0 support and obsolete fmgr README contents relating to
it.

Author: Andres Freund, with contributions by Peter Eisentraut & Craig Ringer
Reviewed-By: Peter Eisentraut, Craig Ringer
Discussion: https://postgr.es/m/20161208213441.k3mbno4twhg2qf7g@alap3.anarazel.de

contrib/earthdistance/earthdistance.c
doc/src/sgml/xfunc.sgml
src/backend/utils/fmgr/README
src/backend/utils/fmgr/fmgr.c
src/include/fmgr.h
src/test/regress/input/create_function_2.source
src/test/regress/input/misc.source
src/test/regress/output/create_function_2.source
src/test/regress/output/misc.source
src/test/regress/regress.c

index 861b1663739bf7f9a4265ccf05bf499397aa3471..6ad6d87ce8c25ef9fcb17923d4a0f3fcc86b5db1 100644 (file)
@@ -88,16 +88,8 @@ geo_distance_internal(Point *pt1, Point *pt2)
  *
  * returns: float8
  *  distance between the points in miles on earth's surface
- *
- * If float8 is passed-by-value, the oldstyle version-0 calling convention
- * is unportable, so we use version-1.  However, if it's passed-by-reference,
- * continue to use oldstyle.  This is just because we'd like earthdistance
- * to serve as a canary for any unintentional breakage of version-0 functions
- * with float8 results.
  ******************************************************/
 
-#ifdef USE_FLOAT8_BYVAL
-
 PG_FUNCTION_INFO_V1(geo_distance);
 
 Datum
@@ -110,17 +102,3 @@ geo_distance(PG_FUNCTION_ARGS)
    result = geo_distance_internal(pt1, pt2);
    PG_RETURN_FLOAT8(result);
 }
-#else                          /* !USE_FLOAT8_BYVAL */
-
-double    *geo_distance(Point *pt1, Point *pt2);
-
-double *
-geo_distance(Point *pt1, Point *pt2)
-{
-   double     *resultp = palloc(sizeof(double));
-
-   *resultp = geo_distance_internal(pt1, pt2);
-   return resultp;
-}
-
-#endif   /* USE_FLOAT8_BYVAL */
index 94a7ad747daa3da36870f3a73d0a3e3782f3eea9..e6313ddd59da2a12a6e67547c88bb7d7976a7d6e 100644 (file)
@@ -1610,14 +1610,10 @@ CREATE FUNCTION square_root(double precision) RETURNS double precision
    </para>
 
    <para>
-    Two different calling conventions are currently used for C functions.
-    The newer <quote>version 1</quote> calling convention is indicated by writing
-    a <literal>PG_FUNCTION_INFO_V1()</literal> macro call for the function,
-    as illustrated below.  Lack of such a macro indicates an old-style
-    (<quote>version 0</quote>) function.  The language name specified in <command>CREATE FUNCTION</command>
-    is <literal>C</literal> in either case.  Old-style functions are now deprecated
-    because of portability problems and lack of functionality, but they
-    are still supported for compatibility reasons.
+    Currently only one calling convention is used for C functions
+    (<quote>version 1</quote>). Support for that calling convention is
+    indicated by writing a <literal>PG_FUNCTION_INFO_V1()</literal> macro
+    call for the function, as illustrated below.
    </para>
 
   <sect2 id="xfunc-c-dynload">
@@ -2137,160 +2133,6 @@ memcpy(destination->data, buffer, 40);
     </para>
    </sect2>
 
-   <sect2>
-    <title>Version 0 Calling Conventions</title>
-
-    <para>
-     We present the <quote>old style</quote> calling convention first &mdash; although
-     this approach is now deprecated, it's easier to get a handle on
-     initially.  In the version-0 method, the arguments and result
-     of the C function are just declared in normal C style, but being
-     careful to use the C representation of each SQL data type as shown
-     above.
-    </para>
-
-    <para>
-     Here are some examples:
-
-<programlisting><![CDATA[
-#include "postgres.h"
-#include <string.h>
-#include "utils/geo_decls.h"
-
-#ifdef PG_MODULE_MAGIC
-PG_MODULE_MAGIC;
-#endif
-
-/* by value */
-
-int
-add_one(int arg)
-{
-    return arg + 1;
-}
-
-/* by reference, fixed length */
-
-float8 *
-add_one_float8(float8 *arg)
-{
-    float8    *result = (float8 *) palloc(sizeof(float8));
-
-    *result = *arg + 1.0;
-
-    return result;
-}
-
-Point *
-makepoint(Point *pointx, Point *pointy)
-{
-    Point     *new_point = (Point *) palloc(sizeof(Point));
-
-    new_point->x = pointx->x;
-    new_point->y = pointy->y;
-
-    return new_point;
-}
-
-/* by reference, variable length */
-
-text *
-copytext(text *t)
-{
-    /*
-     * VARSIZE is the total size of the struct in bytes.
-     */
-    text *new_t = (text *) palloc(VARSIZE(t));
-    SET_VARSIZE(new_t, VARSIZE(t));
-    /*
-     * VARDATA is a pointer to the data region of the struct.
-     */
-    memcpy((void *) VARDATA(new_t), /* destination */
-           (void *) VARDATA(t),     /* source */
-           VARSIZE(t) - VARHDRSZ);  /* how many bytes */
-    return new_t;
-}
-
-text *
-concat_text(text *arg1, text *arg2)
-{
-    int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
-    text *new_text = (text *) palloc(new_text_size);
-
-    SET_VARSIZE(new_text, new_text_size);
-    memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1) - VARHDRSZ);
-    memcpy(VARDATA(new_text) + (VARSIZE(arg1) - VARHDRSZ),
-           VARDATA(arg2), VARSIZE(arg2) - VARHDRSZ);
-    return new_text;
-}
-]]>
-</programlisting>
-    </para>
-
-    <para>
-     Supposing that the above code has been prepared in file
-     <filename>funcs.c</filename> and compiled into a shared object,
-     we could define the functions to <productname>PostgreSQL</productname>
-     with commands like this:
-
-<programlisting>
-CREATE FUNCTION add_one(integer) RETURNS integer
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one'
-     LANGUAGE C STRICT;
-
--- note overloading of SQL function name "add_one"
-CREATE FUNCTION add_one(double precision) RETURNS double precision
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one_float8'
-     LANGUAGE C STRICT;
-
-CREATE FUNCTION makepoint(point, point) RETURNS point
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'makepoint'
-     LANGUAGE C STRICT;
-
-CREATE FUNCTION copytext(text) RETURNS text
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'copytext'
-     LANGUAGE C STRICT;
-
-CREATE FUNCTION concat_text(text, text) RETURNS text
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'concat_text'
-     LANGUAGE C STRICT;
-</programlisting>
-    </para>
-
-    <para>
-     Here, <replaceable>DIRECTORY</replaceable> stands for the
-     directory of the shared library file (for instance the
-     <productname>PostgreSQL</productname> tutorial directory, which
-     contains the code for the examples used in this section).
-     (Better style would be to use just <literal>'funcs'</> in the
-     <literal>AS</> clause, after having added
-     <replaceable>DIRECTORY</replaceable> to the search path.  In any
-     case, we can omit the system-specific extension for a shared
-     library, commonly <literal>.so</literal> or
-     <literal>.sl</literal>.)
-    </para>
-
-    <para>
-     Notice that we have specified the functions as <quote>strict</quote>,
-     meaning that
-     the system should automatically assume a null result if any input
-     value is null.  By doing this, we avoid having to check for null inputs
-     in the function code.  Without this, we'd have to check for null values
-     explicitly, by checking for a null pointer for each
-     pass-by-reference argument.  (For pass-by-value arguments, we don't
-     even have a way to check!)
-    </para>
-
-    <para>
-     Although this calling convention is simple to use,
-     it is not very portable; on some architectures there are problems
-     with passing data types that are smaller than <type>int</type> this way.  Also, there is
-     no simple way to return a null result, nor to cope with null arguments
-     in any way other than making the function strict.  The version-1
-     convention, presented next, overcomes these objections.
-    </para>
-   </sect2>
-
    <sect2>
     <title>Version 1 Calling Conventions</title>
 
@@ -2316,8 +2158,10 @@ PG_FUNCTION_INFO_V1(funcname);
     <para>
      In a version-1 function, each actual argument is fetched using a
      <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>
-     macro that corresponds to the argument's data type, and the
-     result is returned using a
+     macro that corresponds to the argument's data type.  In non-strict
+     functions there needs to be a previous check about argument null-ness
+     using <function>PG_ARGNULL_<replaceable>xxx</replaceable>()</function>.
+     The result is returned using a
      <function>PG_RETURN_<replaceable>xxx</replaceable>()</function>
      macro for the return type.
      <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>
@@ -2328,7 +2172,7 @@ PG_FUNCTION_INFO_V1(funcname);
     </para>
 
     <para>
-     Here we show the same functions as above, coded in version-1 style:
+     Here are some examples using the version-1 calling convention:
 
 <programlisting><![CDATA[
 #include "postgres.h"
@@ -2427,27 +2271,67 @@ concat_text(PG_FUNCTION_ARGS)
 }
 ]]>
 </programlisting>
+
+    <para>
+     Supposing that the above code has been prepared in file
+     <filename>funcs.c</filename> and compiled into a shared object,
+     we could define the functions to <productname>PostgreSQL</productname>
+     with commands like this:
+
+<programlisting>
+CREATE FUNCTION add_one(integer) RETURNS integer
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one'
+     LANGUAGE C STRICT;
+
+-- note overloading of SQL function name "add_one"
+CREATE FUNCTION add_one(double precision) RETURNS double precision
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one_float8'
+     LANGUAGE C STRICT;
+
+CREATE FUNCTION makepoint(point, point) RETURNS point
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'makepoint'
+     LANGUAGE C STRICT;
+
+CREATE FUNCTION copytext(text) RETURNS text
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'copytext'
+     LANGUAGE C STRICT;
+
+CREATE FUNCTION concat_text(text, text) RETURNS text
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'concat_text'
+     LANGUAGE C STRICT;
+</programlisting>
+
+    <para>
+     Here, <replaceable>DIRECTORY</replaceable> stands for the
+     directory of the shared library file (for instance the
+     <productname>PostgreSQL</productname> tutorial directory, which
+     contains the code for the examples used in this section).
+     (Better style would be to use just <literal>'funcs'</> in the
+     <literal>AS</> clause, after having added
+     <replaceable>DIRECTORY</replaceable> to the search path.  In any
+     case, we can omit the system-specific extension for a shared
+     library, commonly <literal>.so</literal>.)
     </para>
 
     <para>
-     The <command>CREATE FUNCTION</command> commands are the same as
-     for the version-0 equivalents.
+     Notice that we have specified the functions as <quote>strict</quote>,
+     meaning that
+     the system should automatically assume a null result if any input
+     value is null.  By doing this, we avoid having to check for null inputs
+     in the function code.  Without this, we'd have to check for null values
+     explicitly, using PG_ARGISNULL().
     </para>
 
     <para>
-     At first glance, the version-1 coding conventions might appear to
-     be just pointless obscurantism.  They do, however, offer a number
-     of improvements, because the macros can hide unnecessary detail.
-     An example is that in coding <function>add_one_float8</>, we no longer need to
-     be aware that <type>float8</type> is a pass-by-reference type.  Another
-     example is that the <literal>GETARG</> macros for variable-length types allow
-     for more efficient fetching of <quote>toasted</quote> (compressed or
+     At first glance, the version-1 coding conventions might appear to be just
+     pointless obscurantism, over using plain <literal>C</> calling
+     conventions.  They do however allow to deal with <literal>NULL</>able
+     arguments/return values, and <quote>toasted</quote> (compressed or
      out-of-line) values.
     </para>
 
     <para>
-     One big improvement in version-1 functions is better handling of null
-     inputs and results.  The macro <function>PG_ARGISNULL(<replaceable>n</>)</function>
+     The macro <function>PG_ARGISNULL(<replaceable>n</>)</function>
      allows a function to test whether each input is null.  (Of course, doing
      this is only necessary in functions not declared <quote>strict</>.)
      As with the
@@ -2461,7 +2345,7 @@ concat_text(PG_FUNCTION_ARGS)
     </para>
 
     <para>
-     Other options provided in the new-style interface are two
+     Other options provided by the version-1 interface are two
      variants of the
      <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>
      macros. The first of these,
@@ -2493,9 +2377,7 @@ concat_text(PG_FUNCTION_ARGS)
      to return set results (<xref linkend="xfunc-c-return-set">) and
      implement trigger functions (<xref linkend="triggers">) and
      procedural-language call handlers (<xref
-     linkend="plhandler">).  Version-1 code is also more
-     portable than version-0, because it does not break restrictions
-     on function call protocol in the C standard.  For more details
+     linkend="plhandler">).  For more details
      see <filename>src/backend/utils/fmgr/README</filename> in the
      source distribution.
     </para>
@@ -2630,7 +2512,7 @@ SELECT name, c_overpaid(emp, 1500) AS overpaid
     WHERE name = 'Bill' OR name = 'Sam';
 </programlisting>
 
-     Using call conventions version 0, we can define
+     Using the version-1 calling conventions, we can define
      <function>c_overpaid</> as:
 
 <programlisting><![CDATA[
@@ -2641,31 +2523,6 @@ SELECT name, c_overpaid(emp, 1500) AS overpaid
 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;
-}
-]]>
-</programlisting>
-
-     In version-1 coding, the above would look like this:
-
-<programlisting><![CDATA[
-#include "postgres.h"
-#include "executor/executor.h"  /* for GetAttributeByName() */
-
-#ifdef PG_MODULE_MAGIC
-PG_MODULE_MAGIC;
-#endif
-
 PG_FUNCTION_INFO_V1(c_overpaid);
 
 Datum
index e7e7ae9c6e862548ae9cb28f3b3d14dfa167b431..5a2331ff159844b55000ee7413efb13ec6e6f1fa 100644 (file)
@@ -3,62 +3,19 @@ src/backend/utils/fmgr/README
 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
@@ -183,50 +140,6 @@ should have no portability or optimization problems.
 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
@@ -291,67 +204,6 @@ fields of FunctionCallInfo, it should just do it.  I doubt that providing
 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
 ---------------------------------
 
@@ -474,83 +326,3 @@ context.  fn_mcxt normally points at the context that was
 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.
index 9fb695279bb87dbc27ff03ca60c8adb6f7c71bd1..68d2110890aadea93caa86d1172fb16d52e6999d 100644 (file)
 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
  */
@@ -90,7 +59,6 @@ static void fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple proc
 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);
 
 
@@ -304,13 +272,10 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
 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
@@ -362,20 +327,6 @@ fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
 
    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;
@@ -415,14 +366,6 @@ fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
                           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);
 }
 
@@ -431,10 +374,7 @@ fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
  * 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
@@ -446,7 +386,6 @@ fetch_finfo_record(void *filehandle, char *funcname)
    char       *infofuncname;
    PGFInfoFunction infofunc;
    const Pg_finfo_record *inforec;
-   static Pg_finfo_record default_inforec = {0};
 
    infofuncname = psprintf("pg_finfo_%s", funcname);
 
@@ -455,9 +394,12 @@ fetch_finfo_record(void *filehandle, char *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 */
@@ -468,7 +410,6 @@ fetch_finfo_record(void *filehandle, char *funcname)
        elog(ERROR, "null result from info function \"%s\"", infofuncname);
    switch (inforec->api_version)
    {
-       case 0:
        case 1:
            /* OK, no additional fields to validate */
            break;
@@ -585,18 +526,7 @@ fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
 {
    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;
 }
 
 
@@ -616,245 +546,6 @@ fmgr_internal_function(const char *proname)
 }
 
 
-/*
- * 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
@@ -2081,58 +1772,6 @@ OidSendFunctionCall(Oid functionId, Datum val)
 }
 
 
-/*
- * !!! 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
  *
index 6128752ab19e8f690adbdd3460b312ed4d79563d..0c695e246a5f70ff99afd88a8a16d125a64e6acd 100644 (file)
@@ -336,10 +336,10 @@ extern struct varlena *pg_detoast_datum_packed(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
+ * 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);
  *
index 3c26b2fec6ac7051d1979d4128c10be47d21c7e4..b167c8ac6d80e0955e2b1cbe8b98d7df7d2aa598 100644 (file)
@@ -87,11 +87,6 @@ CREATE FUNCTION reverse_name(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
 --
index dd2d1b203373b8bd67856ad3bbd6e05a54c94905..b1dbc573c9b1fc22552304dac49539aa98b2b10c 100644 (file)
@@ -249,19 +249,6 @@ SELECT *, name(equipment(h.*)) FROM hobbies_r h;
 
 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
 --
index bdd1b1bec56244873d80d761ddd832063b8bd2b7..8f28bff298ab707ef6b45ea60d38ce6a1ef58d3a 100644 (file)
@@ -67,10 +67,6 @@ CREATE FUNCTION reverse_name(name)
    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
 --
index 574ef0d2e34df240ac3ae88ffe0b12098afb2908..b9595cc2391ea635d0aad19c19933bb3bce768a5 100644 (file)
@@ -681,24 +681,6 @@ SELECT *, (equipment(CAST((h.*) AS hobbies_r))).name FROM hobbies_r h;
  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
 --
index 986d54ce2fa63b0eb1c580ca8dc9c2c03ae8c11a..d7fb8498d86f19f418835719d45fc38eea7c9dda 100644 (file)
@@ -45,8 +45,6 @@
 
 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;
@@ -240,14 +238,15 @@ typedef struct
    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;
@@ -270,14 +269,16 @@ widget_in(char *str)
    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);
@@ -305,9 +306,12 @@ boxarea(PG_FUNCTION_ARGS)
    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;
@@ -320,22 +324,7 @@ reverse_name(char *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);
 }