From 5bb2300b59b74cdc7c8e3f0bf3c8d31c27657670 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 20 Nov 2000 20:36:57 +0000 Subject: [PATCH] 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. --- contrib/fulltextindex/README.fti | 2 +- contrib/fulltextindex/fti.c | 4 +- contrib/fulltextindex/fti.pl | 2 +- contrib/fulltextindex/fti.sql.in | 2 +- contrib/lo/lo.c | 4 +- contrib/lo/lo.sql.in | 4 +- contrib/noupdate/noup.c | 2 + contrib/noupdate/noup.sql.in | 3 +- contrib/pgcrypto/pgcrypto.c | 6 +- contrib/pgcrypto/pgcrypto.sql.in | 4 +- contrib/soundex/soundex.c | 11 +- contrib/soundex/soundex.sql.in | 4 +- contrib/spi/autoinc.c | 2 + contrib/spi/autoinc.sql.in | 2 +- contrib/spi/insert_username.c | 2 + contrib/spi/insert_username.sql.in | 2 +- contrib/spi/moddatetime.c | 2 + contrib/spi/moddatetime.sql.in | 2 +- contrib/spi/refint.c | 4 + contrib/spi/refint.sql.in | 6 +- contrib/spi/timetravel.c | 4 + contrib/spi/timetravel.sql.in | 4 +- doc/src/sgml/ref/create_function.sgml | 7 +- doc/src/sgml/ref/create_language.sgml | 16 +- doc/src/sgml/trigger.sgml | 6 +- doc/src/sgml/xfunc.sgml | 98 ++++---- src/backend/catalog/pg_proc.c | 29 +-- src/backend/commands/define.c | 21 +- src/backend/commands/remove.c | 5 +- src/backend/commands/trigger.c | 11 +- src/backend/utils/Gen_fmgrtab.sh | 21 +- src/backend/utils/cache/lsyscache.c | 23 +- src/backend/utils/fmgr/dfmgr.c | 70 ++---- src/backend/utils/fmgr/fmgr.c | 286 +++++++++++++++++------ src/bin/scripts/createlang.sh | 4 +- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_language.h | 16 +- src/include/fmgr.h | 46 +++- src/include/utils/fmgrtab.h | 4 +- src/include/utils/lsyscache.h | 5 +- src/pl/plperl/plperl.c | 3 +- src/pl/plpgsql/src/pl_handler.c | 4 +- src/pl/tcl/pltcl.c | 9 +- src/test/regress/input/create_function_1.source | 12 +- src/test/regress/input/create_function_2.source | 13 +- src/test/regress/input/misc.source | 13 ++ src/test/regress/output/create_function_1.source | 12 +- src/test/regress/output/create_function_2.source | 12 +- src/test/regress/output/misc.source | 18 ++ src/test/regress/regress.c | 38 ++- src/test/regress/sql/drop.sql | 1 + src/tutorial/funcs_new.c | 12 + 52 files changed, 570 insertions(+), 327 deletions(-) diff --git a/contrib/fulltextindex/README.fti b/contrib/fulltextindex/README.fti index fdb6fcf3b1..10838db691 100644 --- a/contrib/fulltextindex/README.fti +++ b/contrib/fulltextindex/README.fti @@ -57,7 +57,7 @@ sub-string will fit. The create the function that contains the trigger:: create function fti() returns opaque as - '/path/to/fti.so' language 'newC'; + '/path/to/fti.so' language 'C'; And finally define the trigger on the 'cds' table: diff --git a/contrib/fulltextindex/fti.c b/contrib/fulltextindex/fti.c index a98fcd47dc..bb4636ff3e 100644 --- a/contrib/fulltextindex/fti.c +++ b/contrib/fulltextindex/fti.c @@ -17,7 +17,7 @@ Example: create function fti() returns opaque as -'/home/boekhold/src/postgresql-6.2/contrib/fti/fti.so' language 'newC'; +'/home/boekhold/src/postgresql-6.2/contrib/fti/fti.so' language 'C'; create table title_fti (string varchar(25), id oid); create index title_fti_idx on title_fti (string); @@ -93,6 +93,8 @@ static int nDeletePlans = 0; static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans); /***********************************************************************/ +PG_FUNCTION_INFO_V1(fti); + Datum fti(PG_FUNCTION_ARGS) { diff --git a/contrib/fulltextindex/fti.pl b/contrib/fulltextindex/fti.pl index 6b6d68e490..02bf057e94 100644 --- a/contrib/fulltextindex/fti.pl +++ b/contrib/fulltextindex/fti.pl @@ -29,7 +29,7 @@ # # create function fti() returns opaque as # '/path/to/fti/file/fti.so' -# language 'newC'; +# language 'C'; # # create trigger my_fti_trigger after update or insert or delete # on mytable diff --git a/contrib/fulltextindex/fti.sql.in b/contrib/fulltextindex/fti.sql.in index c0b3662ae5..e0da2353c5 100644 --- a/contrib/fulltextindex/fti.sql.in +++ b/contrib/fulltextindex/fti.sql.in @@ -1,3 +1,3 @@ create function fti() returns opaque as 'MODULE_PATHNAME' - language 'newC'; \ No newline at end of file + language 'C'; \ No newline at end of file diff --git a/contrib/lo/lo.c b/contrib/lo/lo.c index 386c2c2d2f..5de00ad5ca 100644 --- a/contrib/lo/lo.c +++ b/contrib/lo/lo.c @@ -1,7 +1,7 @@ /* * PostgreSQL type definitions for managed LargeObjects. * - * $Id: lo.c,v 1.4 2000/06/09 01:10:58 tgl Exp $ + * $Id: lo.c,v 1.5 2000/11/20 20:36:55 tgl Exp $ * */ @@ -140,6 +140,8 @@ lo(Oid oid) /* * This handles the trigger that protects us from orphaned large objects */ +PG_FUNCTION_INFO_V1(lo_manage); + Datum lo_manage(PG_FUNCTION_ARGS) { diff --git a/contrib/lo/lo.sql.in b/contrib/lo/lo.sql.in index 4aa75a60fe..9b340b196f 100644 --- a/contrib/lo/lo.sql.in +++ b/contrib/lo/lo.sql.in @@ -1,7 +1,7 @@ -- -- PostgreSQL code for LargeObjects -- --- $Id: lo.sql.in,v 1.4 2000/06/19 13:53:42 momjian Exp $ +-- $Id: lo.sql.in,v 1.5 2000/11/20 20:36:55 tgl Exp $ -- -- -- Create the data type @@ -44,7 +44,7 @@ create function lo(oid) create function lo_manage() returns opaque as 'MODULE_PATHNAME' - language 'newC'; + language 'C'; -- This allows us to map lo to oid -- diff --git a/contrib/noupdate/noup.c b/contrib/noupdate/noup.c index 5035e127be..af857c41f6 100644 --- a/contrib/noupdate/noup.c +++ b/contrib/noupdate/noup.c @@ -16,6 +16,8 @@ extern Datum noup(PG_FUNCTION_ARGS); * EXECUTE PROCEDURE noup ('col'). */ +PG_FUNCTION_INFO_V1(noup); + Datum noup(PG_FUNCTION_ARGS) { diff --git a/contrib/noupdate/noup.sql.in b/contrib/noupdate/noup.sql.in index cc1e6fa146..abf92837d1 100644 --- a/contrib/noupdate/noup.sql.in +++ b/contrib/noupdate/noup.sql.in @@ -3,5 +3,4 @@ DROP FUNCTION noup (); CREATE FUNCTION noup () RETURNS opaque AS 'MODULE_PATHNAME' - LANGUAGE 'newC' -; + LANGUAGE 'C'; diff --git a/contrib/pgcrypto/pgcrypto.c b/contrib/pgcrypto/pgcrypto.c index 4897edb9d2..e4978dea2d 100644 --- a/contrib/pgcrypto/pgcrypto.c +++ b/contrib/pgcrypto/pgcrypto.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: pgcrypto.c,v 1.1 2000/10/31 13:11:28 petere Exp $ + * $Id: pgcrypto.c,v 1.2 2000/11/20 20:36:56 tgl Exp $ */ #include @@ -59,6 +59,8 @@ find_digest(pg_digest *hbuf, text *name, int silent); /* SQL function: hash(text, text) returns text */ +PG_FUNCTION_INFO_V1(digest); + Datum digest(PG_FUNCTION_ARGS) { @@ -95,6 +97,8 @@ digest(PG_FUNCTION_ARGS) } /* check if given hash exists */ +PG_FUNCTION_INFO_V1(digest_exists); + Datum digest_exists(PG_FUNCTION_ARGS) { diff --git a/contrib/pgcrypto/pgcrypto.sql.in b/contrib/pgcrypto/pgcrypto.sql.in index a30b3116e5..2059c0d8e5 100644 --- a/contrib/pgcrypto/pgcrypto.sql.in +++ b/contrib/pgcrypto/pgcrypto.sql.in @@ -4,9 +4,9 @@ CREATE FUNCTION digest(text, text) RETURNS text AS '@MODULE_FILENAME@', - 'digest' LANGUAGE 'newC'; + 'digest' LANGUAGE 'C'; CREATE FUNCTION digest_exists(text) RETURNS bool AS '@MODULE_FILENAME@', - 'digest_exists' LANGUAGE 'newC'; + 'digest_exists' LANGUAGE 'C'; diff --git a/contrib/soundex/soundex.c b/contrib/soundex/soundex.c index f2acba4036..f66cb21f24 100644 --- a/contrib/soundex/soundex.c +++ b/contrib/soundex/soundex.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/contrib/soundex/Attic/soundex.c,v 1.7 2000/10/04 19:25:34 petere Exp $ */ +/* $Header: /cvsroot/pgsql/contrib/soundex/Attic/soundex.c,v 1.8 2000/11/20 20:36:57 tgl Exp $ */ #include "postgres.h" #include "fmgr.h" #include "utils/builtins.h" @@ -7,11 +7,9 @@ #include -Datum -text_soundex(PG_FUNCTION_ARGS); +Datum text_soundex(PG_FUNCTION_ARGS); -static void -soundex(const char *instr, char *outstr); +static void soundex(const char *instr, char *outstr); #define SOUNDEX_LEN 4 @@ -24,6 +22,8 @@ soundex(const char *instr, char *outstr); /* * SQL function: text_soundex(text) returns text */ +PG_FUNCTION_INFO_V1(text_soundex); + Datum text_soundex(PG_FUNCTION_ARGS) { @@ -36,6 +36,7 @@ text_soundex(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(_textin(outstr)); } + #endif /* not SOUNDEX_TEST */ diff --git a/contrib/soundex/soundex.sql.in b/contrib/soundex/soundex.sql.in index 4cb0ad0e4d..4805694f9a 100644 --- a/contrib/soundex/soundex.sql.in +++ b/contrib/soundex/soundex.sql.in @@ -1,5 +1,5 @@ CREATE FUNCTION text_soundex(text) RETURNS text - AS '@MODULE_FILENAME@', 'text_soundex' LANGUAGE 'newC'; + AS '@MODULE_FILENAME@', 'text_soundex' LANGUAGE 'C'; CREATE FUNCTION soundex(text) RETURNS text - AS '@MODULE_FILENAME@', 'text_soundex' LANGUAGE 'newC'; + AS '@MODULE_FILENAME@', 'text_soundex' LANGUAGE 'C'; diff --git a/contrib/spi/autoinc.c b/contrib/spi/autoinc.c index f8b86217e7..8592ea7ed9 100644 --- a/contrib/spi/autoinc.c +++ b/contrib/spi/autoinc.c @@ -5,6 +5,8 @@ extern Datum autoinc(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(autoinc); + Datum autoinc(PG_FUNCTION_ARGS) { diff --git a/contrib/spi/autoinc.sql.in b/contrib/spi/autoinc.sql.in index d587b567b3..3676742943 100644 --- a/contrib/spi/autoinc.sql.in +++ b/contrib/spi/autoinc.sql.in @@ -3,4 +3,4 @@ DROP FUNCTION autoinc(); CREATE FUNCTION autoinc() RETURNS opaque AS 'MODULE_PATHNAME' - LANGUAGE 'newC'; + LANGUAGE 'C'; diff --git a/contrib/spi/insert_username.c b/contrib/spi/insert_username.c index 978a873ec9..6bc3144420 100644 --- a/contrib/spi/insert_username.c +++ b/contrib/spi/insert_username.c @@ -12,6 +12,8 @@ extern Datum insert_username(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(insert_username); + Datum insert_username(PG_FUNCTION_ARGS) { diff --git a/contrib/spi/insert_username.sql.in b/contrib/spi/insert_username.sql.in index d60aebc1b0..436fc88b73 100644 --- a/contrib/spi/insert_username.sql.in +++ b/contrib/spi/insert_username.sql.in @@ -3,4 +3,4 @@ DROP FUNCTION insert_username(); CREATE FUNCTION insert_username() RETURNS opaque AS 'MODULE_PATHNAME' - LANGUAGE 'newC'; + LANGUAGE 'C'; diff --git a/contrib/spi/moddatetime.c b/contrib/spi/moddatetime.c index 0229eb8f15..73b1518518 100644 --- a/contrib/spi/moddatetime.c +++ b/contrib/spi/moddatetime.c @@ -17,6 +17,8 @@ OH, me, I'm Terry Mackintosh extern Datum moddatetime(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(moddatetime); + Datum moddatetime(PG_FUNCTION_ARGS) { diff --git a/contrib/spi/moddatetime.sql.in b/contrib/spi/moddatetime.sql.in index cfb7c3c508..d497900ecf 100644 --- a/contrib/spi/moddatetime.sql.in +++ b/contrib/spi/moddatetime.sql.in @@ -3,4 +3,4 @@ DROP FUNCTION moddatetime(); CREATE FUNCTION moddatetime() RETURNS opaque AS 'MODULE_PATHNAME' - LANGUAGE 'newC'; + LANGUAGE 'C'; diff --git a/contrib/spi/refint.c b/contrib/spi/refint.c index 4bbe761573..d7a8d73c8e 100644 --- a/contrib/spi/refint.c +++ b/contrib/spi/refint.c @@ -36,6 +36,8 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans); * check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2'). */ +PG_FUNCTION_INFO_V1(check_primary_key); + Datum check_primary_key(PG_FUNCTION_ARGS) { @@ -216,6 +218,8 @@ check_primary_key(PG_FUNCTION_ARGS) * 'Ftable1', 'Fkey11', 'Fkey12', 'Ftable2', 'Fkey21', 'Fkey22'). */ +PG_FUNCTION_INFO_V1(check_foreign_key); + Datum check_foreign_key(PG_FUNCTION_ARGS) { diff --git a/contrib/spi/refint.sql.in b/contrib/spi/refint.sql.in index 91448e8a2e..d193319d9d 100644 --- a/contrib/spi/refint.sql.in +++ b/contrib/spi/refint.sql.in @@ -4,11 +4,9 @@ DROP FUNCTION check_foreign_key (); CREATE FUNCTION check_primary_key () RETURNS opaque AS 'MODULE_PATHNAME' - LANGUAGE 'newC' -; + LANGUAGE 'C'; CREATE FUNCTION check_foreign_key () RETURNS opaque AS 'MODULE_PATHNAME' - LANGUAGE 'newC' -; + LANGUAGE 'C'; diff --git a/contrib/spi/timetravel.c b/contrib/spi/timetravel.c index cd50cd8489..41e7b092b3 100644 --- a/contrib/spi/timetravel.c +++ b/contrib/spi/timetravel.c @@ -47,6 +47,8 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans); * timetravel ('date_on', 'date_off'). */ +PG_FUNCTION_INFO_V1(timetravel); + Datum timetravel(PG_FUNCTION_ARGS) { @@ -326,6 +328,8 @@ timetravel(PG_FUNCTION_ARGS) * set_timetravel (relname, on) -- * turn timetravel for specified relation ON/OFF */ +PG_FUNCTION_INFO_V1(set_timetravel); + Datum set_timetravel(PG_FUNCTION_ARGS) { diff --git a/contrib/spi/timetravel.sql.in b/contrib/spi/timetravel.sql.in index 0de680cb39..46912abf6d 100644 --- a/contrib/spi/timetravel.sql.in +++ b/contrib/spi/timetravel.sql.in @@ -4,9 +4,9 @@ DROP FUNCTION set_timetravel(name, int4); CREATE FUNCTION timetravel() RETURNS opaque AS 'MODULE_PATHNAME' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE FUNCTION set_timetravel(name, int4) RETURNS int4 AS 'MODULE_PATHNAME' - LANGUAGE 'newC' WITH (isStrict); + LANGUAGE 'C' WITH (isStrict); diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml index 20a7b6f8b0..bb733b8df2 100644 --- a/doc/src/sgml/ref/create_function.sgml +++ b/doc/src/sgml/ref/create_function.sgml @@ -1,5 +1,5 @@ @@ -119,8 +119,7 @@ CREATE FUNCTION name ( [ May be 'sql', - 'C', 'newC', - 'internal', 'newinternal', + 'C', 'internal', or 'plname', where 'plname' is the name of a created procedural language. See @@ -258,7 +257,7 @@ CREATE - Two internal or newinternal + Two internal functions cannot have the same C name without causing errors at link time. To get around that, give them different C names (for example, use the argument types as part of the C names), then diff --git a/doc/src/sgml/ref/create_language.sgml b/doc/src/sgml/ref/create_language.sgml index 934b6cbaf9..f5e1c6ffa9 100644 --- a/doc/src/sgml/ref/create_language.sgml +++ b/doc/src/sgml/ref/create_language.sgml @@ -1,5 +1,5 @@ @@ -163,7 +163,8 @@ ERROR: PL handler function funcname In Postgres 7.1 and later, call handlers - must adhere to the "new style" function manager interface. + must adhere to the "version 1" function manager interface, not the + old-style interface. @@ -180,7 +181,7 @@ ERROR: PL handler function funcname - The call handler is called in the same way as any other new-style + The call handler is called in the same way as any other function: it receives a pointer to a FunctionCallInfoData struct containing argument values and information about the called function, and it is expected to return a Datum result (and possibly set the @@ -269,9 +270,7 @@ ERROR: PL handler function funcname @@ -279,8 +278,9 @@ ERROR: PL handler function funcname The call handler for a procedural language must normally be written - in C and registered as 'newinternal' or 'newC' language, depending + in C and registered as 'internal' or 'C' language, depending on whether it is linked into the backend or dynamically loaded. + The call handler cannot use the old-style 'C' function interface. @@ -306,6 +306,8 @@ ERROR: PL handler function funcname CREATE FUNCTION plsample_call_handler () RETURNS opaque AS '/usr/local/pgsql/lib/plsample.so' - LANGUAGE 'newC'; + LANGUAGE 'C'; CREATE PROCEDURAL LANGUAGE 'plsample' HANDLER plsample_call_handler LANCOMPILER 'PL/Sample'; diff --git a/doc/src/sgml/trigger.sgml b/doc/src/sgml/trigger.sgml index 0b3442517c..d248887a59 100644 --- a/doc/src/sgml/trigger.sgml +++ b/doc/src/sgml/trigger.sgml @@ -22,7 +22,7 @@ The trigger function must be created before the trigger is created as a function taking no arguments and returning opaque. If the function is - written in C, it must follow the "new style" function manager interface. + written in C, it must use the "version 1" function manager interface. @@ -447,6 +447,8 @@ execution of Q) or after Q is done. extern Datum trigf(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(trigf); + Datum trigf(PG_FUNCTION_ARGS) { @@ -513,7 +515,7 @@ trigf(PG_FUNCTION_ARGS) create function trigf () returns opaque as -'...path_to_so' language 'newC'; +'...path_to_so' language 'C'; create table ttest (x int4); diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index d02718d53a..f2dc298174 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -1,5 +1,5 @@ @@ -339,9 +339,9 @@ SELECT clean_EMP(); - There are two procedural languages available with the standard - Postgres distribution (PLTCL and PLSQL), and other - languages can be defined. + There are currently three procedural languages available in the standard + Postgres distribution (PLSQL, PLTCL and + PLPERL), and other languages can be defined. Refer to for more information. @@ -366,12 +366,7 @@ SELECT clean_EMP(); Internal functions are declared in CREATE FUNCTION - with language name internal or - newinternal, depending on whether they follow the - old (pre-7.1) or new (7.1 and later) function call conventions. - The details of the call conventions are the same as for - C and newC functions respectively; - see the next section for details. + with language name internal. @@ -404,9 +399,9 @@ SELECT clean_EMP(); The string which specifies the object file (the first string in the AS clause) should be the full path of the object - code file for the function, bracketed by quotation marks. If a + code file for the function, bracketed by single quote marks. If a link symbol is given in the AS clause, the link symbol should also be - bracketed by single quotation marks, and should be exactly the + bracketed by single quote marks, and should be exactly the same as the name of the function in the C source code. On Unix systems the command nm will print all of the link symbols in a dynamically loadable object. @@ -422,11 +417,11 @@ SELECT clean_EMP(); Two different calling conventions are currently used for C functions. - The "old style" (pre-Postgres-7.1) method - is selected by writing language name 'C' in the - CREATE FUNCTION command, while the "new style" - (7.1 and later) method is selecting by writing language name - 'newC'. Old-style functions are now deprecated + The newer "version 1" calling convention is indicated by writing + a PG_FUNCTION_INFO_V1() macro call for the function, + as illustrated below. Lack of such a macro indicates an old-style + ("version 0") function. The language name specified in CREATE FUNCTION + is 'C' 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. @@ -484,7 +479,7 @@ SELECT clean_EMP(); include/postgres.h - char + "char" char N/A @@ -584,16 +579,6 @@ SELECT clean_EMP(); utils/nabstime.h - uint2 - uint16 - include/c.h - - - uint4 - uint32 - include/c.h - - xid (XID *) include/postgres.h @@ -694,7 +679,7 @@ typedef struct { - Obviously, the data field is not long enough to hold + Obviously, the data field shown here is not long enough to hold all possible strings; it's impossible to declare such a structure in C. When manipulating variable-length types, we must be careful to allocate @@ -721,12 +706,12 @@ memmove(destination->data, buffer, 40); - Old-style Calling Conventions for C-Language Functions + Version-0 Calling Conventions for C-Language Functions We present the "old style" calling convention first --- although this approach is now deprecated, it's easier to get a handle on - initially. In the "old style" method, the arguments and result + 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. @@ -854,26 +839,39 @@ CREATE FUNCTION concat_text(text, text) RETURNS text - Although this old-style calling convention is simple to use, + Although this calling convention is simple to use, it is not very portable; on some architectures there are problems with passing smaller-than-int data types 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 new-style + in any way other than making the function strict. The version-1 convention, presented next, overcomes these objections. - New-style Calling Conventions for C-Language Functions + Version-1 Calling Conventions for C-Language Functions - The new-style calling convention relies on macros to suppress most + The version-1 calling convention relies on macros to suppress most of the complexity of passing arguments and results. The C declaration - of a new-style function is always + of a version-1 function is always Datum funcname(PG_FUNCTION_ARGS) - Each actual argument is fetched using a PG_GETARG_xxx() macro that + In addition, the macro call + + PG_FUNCTION_INFO_V1(funcname); + + must appear in the same source file (conventionally it's written + just before the function itself). This macro call is not needed + for "internal"-language functions, since Postgres currently assumes + all internal functions are version-1. However, it is + required for dynamically-loaded functions. + + + + In a version-1 function, + each actual argument is fetched using a PG_GETARG_xxx() macro that corresponds to the argument's datatype, and the result is returned using a PG_RETURN_xxx() macro for the return type. @@ -887,6 +885,8 @@ CREATE FUNCTION concat_text(text, text) RETURNS text #include "fmgr.h" /* By Value */ + +PG_FUNCTION_INFO_V1(add_one); Datum add_one(PG_FUNCTION_ARGS) @@ -898,6 +898,8 @@ add_one(PG_FUNCTION_ARGS) /* By Reference, Fixed Length */ +PG_FUNCTION_INFO_V1(add_one_float8); + Datum add_one_float8(PG_FUNCTION_ARGS) { @@ -907,6 +909,8 @@ add_one_float8(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(arg + 1.0); } +PG_FUNCTION_INFO_V1(makepoint); + Datum makepoint(PG_FUNCTION_ARGS) { @@ -922,6 +926,8 @@ makepoint(PG_FUNCTION_ARGS) /* By Reference, Variable Length */ +PG_FUNCTION_INFO_V1(copytext); + Datum copytext(PG_FUNCTION_ARGS) { @@ -940,6 +946,8 @@ copytext(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(new_t); } +PG_FUNCTION_INFO_V1(concat_text); + Datum concat_text(PG_FUNCTION_ARGS) { @@ -959,12 +967,11 @@ concat_text(PG_FUNCTION_ARGS) The CREATE FUNCTION commands are the same as - for the old-style equivalents, except that the language is specified - as 'newC' not 'C'. + for the old-style equivalents. - At first glance, the new-style coding conventions may appear to be + At first glance, the version-1 coding conventions may appear to be just pointless obscurantism. However, they do offer a number of improvements, because the macros can hide unnecessary detail. An example is that in coding add_one_float8, we no longer need to @@ -973,11 +980,14 @@ concat_text(PG_FUNCTION_ARGS) to deal with fetching "toasted" (compressed or out-of-line) values. The old-style copytext and concat_text functions shown above are actually wrong in the presence of toasted values, because they don't - call pg_detoast_datum() on their inputs. + call pg_detoast_datum() on their inputs. (The handler for old-style + dynamically-loaded functions currently takes care of this detail, + but it does so less efficiently than is possible for a version-1 + function.) - The new-style function call conventions also make it possible to + The version-1 function call conventions also make it possible to test for NULL inputs to a non-strict function, return a NULL result (from either strict or non-strict functions), return "set" results, and implement trigger functions and procedural-language call handlers. @@ -1026,7 +1036,9 @@ c_overpaid(TupleTableSlot *t, /* the current instance of EMP */ return salary > limit; } -/* In new-style coding, the above would look like this: */ +/* In version-1 coding, the above would look like this: */ + +PG_FUNCTION_INFO_V1(c_overpaid); Datum c_overpaid(PG_FUNCTION_ARGS) diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 9d3ce5c50d..5d63ebf161 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 9d681a4a50..63ccf32543 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 fdcd0e7e74..cb11b47a37 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 22dfcac052..cc31a0eb48 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 41a0bc3d71..00f12e3e1f 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" < "$$-$TABLEFILE" <> "$$-$TABLEFILE" if [ $? -ne 0 ]; then diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index e07445837a..24b2cbada9 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 2dfddebd0a..ae8eb6785e 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 #include -#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 5287615eea..d4353a4824 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 3fc0a1b02f..02c27aaf90 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 e3f4c6ff89..558feef575 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 0d597d8c4d..423f2e9470 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 28634262bc..08faf95629 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 e6cfe51965..9d46aeae69 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 f8547baa88..903e09aaf9 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 81a4cd75d4..0b2d7d4e42 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 31788b0706..d9e208ee98 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 8658cac306..94a67ef043 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 0f82a3bea4..6d91674cd5 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 af6695764a..b1c0eab138 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 9e9ebdb75b..dbb8df8470 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 d3815a9aad..d075a61eb8 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 def359de90..a5f39a00bb 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 144ad33f24..768dba5c3c 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 479527fc3f..bd65c4233d 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 /* 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 254c62100d..fc89483208 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 0734e67a11..20f609d5d2 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) { -- 2.11.0