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.
This commit is contained in:
Tom Lane 2000-11-20 20:36:57 +00:00
parent 99198ac6b8
commit 5bb2300b59
52 changed files with 571 additions and 328 deletions

View File

@ -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:

View File

@ -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)
{

View File

@ -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

View File

@ -1,3 +1,3 @@
create function fti() returns opaque as
'MODULE_PATHNAME'
language 'newC';
language 'C';

View File

@ -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)
{

View File

@ -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
--

View File

@ -16,6 +16,8 @@ extern Datum noup(PG_FUNCTION_ARGS);
* EXECUTE PROCEDURE noup ('col').
*/
PG_FUNCTION_INFO_V1(noup);
Datum
noup(PG_FUNCTION_ARGS)
{

View File

@ -3,5 +3,4 @@ DROP FUNCTION noup ();
CREATE FUNCTION noup ()
RETURNS opaque
AS 'MODULE_PATHNAME'
LANGUAGE 'newC'
;
LANGUAGE 'C';

View File

@ -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 <postgres.h>
@ -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)
{

View File

@ -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';

View File

@ -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 <stdio.h>
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 */

View File

@ -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';

View File

@ -5,6 +5,8 @@
extern Datum autoinc(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(autoinc);
Datum
autoinc(PG_FUNCTION_ARGS)
{

View File

@ -3,4 +3,4 @@ DROP FUNCTION autoinc();
CREATE FUNCTION autoinc()
RETURNS opaque
AS 'MODULE_PATHNAME'
LANGUAGE 'newC';
LANGUAGE 'C';

View File

@ -12,6 +12,8 @@
extern Datum insert_username(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(insert_username);
Datum
insert_username(PG_FUNCTION_ARGS)
{

View File

@ -3,4 +3,4 @@ DROP FUNCTION insert_username();
CREATE FUNCTION insert_username()
RETURNS opaque
AS 'MODULE_PATHNAME'
LANGUAGE 'newC';
LANGUAGE 'C';

View File

@ -17,6 +17,8 @@ OH, me, I'm Terry Mackintosh <terry@terrym.com>
extern Datum moddatetime(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(moddatetime);
Datum
moddatetime(PG_FUNCTION_ARGS)
{

View File

@ -3,4 +3,4 @@ DROP FUNCTION moddatetime();
CREATE FUNCTION moddatetime()
RETURNS opaque
AS 'MODULE_PATHNAME'
LANGUAGE 'newC';
LANGUAGE 'C';

View File

@ -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)
{

View File

@ -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';

View File

@ -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)
{

View File

@ -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);

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.19 2000/11/02 19:26:44 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.20 2000/11/20 20:36:46 tgl Exp $
Postgres documentation
-->
@ -119,8 +119,7 @@ CREATE FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceab
<listitem>
<para>
May be '<literal>sql</literal>',
'<literal>C</literal>', '<literal>newC</literal>',
'<literal>internal</literal>', '<literal>newinternal</literal>',
'<literal>C</literal>', '<literal>internal</literal>',
or '<replaceable class="parameter">plname</replaceable>',
where '<replaceable class="parameter">plname</replaceable>'
is the name of a created procedural language. See
@ -258,7 +257,7 @@ CREATE
</para>
<para>
Two <literal>internal</literal> or <literal>newinternal</literal>
Two <literal>internal</literal>
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

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_language.sgml,v 1.13 2000/11/04 21:04:54 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_language.sgml,v 1.14 2000/11/20 20:36:46 tgl Exp $
Postgres documentation
-->
@ -163,7 +163,8 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
<note>
<para>
In <productname>Postgres</productname> 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.
</para>
</note>
@ -180,7 +181,7 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
</para>
<para>
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 <replaceable class="parameter">funcname</replaceable
lanname | lanispl | lanpltrusted | lanplcallfoid | lancompiler
-------------+---------+--------------+---------------+-------------
internal | f | f | 0 | n/a
newinternal | f | f | 0 | n/a
C | f | f | 0 | /bin/cc
newC | f | f | 0 | /bin/cc
sql | f | f | 0 | postgres
</computeroutput>
</programlisting>
@ -279,8 +278,9 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
<para>
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.
</para>
<para>
@ -306,6 +306,8 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
PG_FUNCTION_INFO_V1(plsample_call_handler);
Datum
plsample_call_handler(PG_FUNCTION_ARGS)
{
@ -344,7 +346,7 @@ plsample_call_handler(PG_FUNCTION_ARGS)
<programlisting>
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';

View File

@ -22,7 +22,7 @@
<para>
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.
</para>
<para>
@ -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)
<programlisting>
create function trigf () returns opaque as
'...path_to_so' language 'newC';
'...path_to_so' language 'C';
create table ttest (x int4);
</programlisting>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.22 2000/10/23 00:46:06 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.23 2000/11/20 20:36:47 tgl Exp $
-->
<chapter id="xfunc">
@ -339,9 +339,9 @@ SELECT clean_EMP();
</para>
<para>
There are two procedural languages available with the standard
<productname>Postgres</productname> distribution (PLTCL and PLSQL), and other
languages can be defined.
There are currently three procedural languages available in the standard
<productname>Postgres</productname> distribution (PLSQL, PLTCL and
PLPERL), and other languages can be defined.
Refer to <xref linkend="xplang-title" endterm="xplang-title"> for
more information.
</para>
@ -366,12 +366,7 @@ SELECT clean_EMP();
<para>
Internal functions are declared in <command>CREATE FUNCTION</command>
with language name <literal>internal</literal> or
<literal>newinternal</literal>, 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
<literal>C</literal> and <literal>newC</literal> functions respectively;
see the next section for details.
with language name <literal>internal</literal>.
</para>
</sect1>
@ -404,9 +399,9 @@ SELECT clean_EMP();
<para>
The string which specifies the object file (the first string in the AS
clause) should be the <emphasis>full path</emphasis> 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 <command>nm</command> will print all of the link
symbols in a dynamically loadable object.
@ -422,11 +417,11 @@ SELECT clean_EMP();
<para>
Two different calling conventions are currently used for C functions.
The "old style" (pre-<productname>Postgres</productname>-7.1) method
is selected by writing language name '<literal>C</literal>' in the
<command>CREATE FUNCTION</command> command, while the "new style"
(7.1 and later) method is selecting by writing language name
'<literal>newC</literal>'. Old-style functions are now deprecated
The newer "version 1" 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
("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.
</para>
@ -484,7 +479,7 @@ SELECT clean_EMP();
<entry>include/postgres.h</entry>
</row>
<row>
<entry>char</entry>
<entry>"char"</entry>
<entry>char</entry>
<entry>N/A</entry>
</row>
@ -583,16 +578,6 @@ SELECT clean_EMP();
<entry>TimeInterval</entry>
<entry>utils/nabstime.h</entry>
</row>
<row>
<entry>uint2</entry>
<entry>uint16</entry>
<entry>include/c.h</entry>
</row>
<row>
<entry>uint4</entry>
<entry>uint32</entry>
<entry>include/c.h</entry>
</row>
<row>
<entry>xid</entry>
<entry>(XID *)</entry>
@ -694,7 +679,7 @@ typedef struct {
</para>
<para>
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 <acronym>C</acronym>. When manipulating
variable-length types, we must be careful to allocate
@ -721,12 +706,12 @@ memmove(destination-&gt;data, buffer, 40);
</sect2>
<sect2>
<title>Old-style Calling Conventions for C-Language Functions</title>
<title>Version-0 Calling Conventions for C-Language Functions</title>
<para>
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
</para>
<para>
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.
</para>
</sect2>
<sect2>
<title>New-style Calling Conventions for C-Language Functions</title>
<title>Version-1 Calling Conventions for C-Language Functions</title>
<para>
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
<programlisting>
Datum funcname(PG_FUNCTION_ARGS)
</programlisting>
Each actual argument is fetched using a PG_GETARG_xxx() macro that
In addition, the macro call
<programlisting>
PG_FUNCTION_INFO_V1(funcname);
</programlisting>
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
<emphasis>required</emphasis> for dynamically-loaded functions.
</para>
<para>
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.
</para>
@ -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)
<para>
The <command>CREATE FUNCTION</command> commands are the same as
for the old-style equivalents, except that the language is specified
as '<literal>newC</literal>' not '<literal>C</literal>'.
for the old-style equivalents.
</para>
<para>
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.)
</para>
<para>
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 &gt; 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)

View File

@ -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);
}
/*

View File

@ -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 */

View File

@ -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);

View File

@ -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);
}

View File

@ -9,7 +9,7 @@
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.17 2000/07/13 16:07:06 petere Exp $
# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.18 2000/11/20 20:36:48 tgl Exp $
#
#-------------------------------------------------------------------------
@ -82,7 +82,7 @@ trap 'echo "Caught signal." ; cleanup ; exit 1' 1 2 15
#
# Generate the file containing raw pg_proc tuple data
# (but only for "internal" and "newinternal" language procedures...).
# (but only for "internal" language procedures...).
#
# Unlike genbki.sh, which can run through cpp last, we have to
# deal with preprocessor statements first (before we sort the
@ -99,7 +99,6 @@ sed -e 's/^.*OID[^=]*=[^0-9]*//' \
-e 's/[ ]*).*$//' | \
$AWK '
/^#/ { print; next; }
$4 == "11" { print; next; }
$4 == "12" { print; next; }' > $CPPTMPFILE
if [ $? -ne 0 ]; then
@ -182,10 +181,6 @@ FuNkYfMgRsTuFf
# Generate fmgr's built-in-function table.
#
# Print out the function declarations, then the table that refers to them.
# NB: the function declarations are bogus in the case of old-style functions,
# although they should be correct for new-style. Therefore we need to compile
# this table definition as a separate C file that won't need to include any
# "real" declarations for those functions!
#
cat > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF
/*-------------------------------------------------------------------------
@ -205,10 +200,6 @@ cat > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF
* It has been GENERATED by $CMDNAME
* from $INFILE
*
* We lie here to cc about the return type and arguments of old-style
* builtin functions; all ld cares about is the fact that it
* will need to resolve an external function reference.
*
*-------------------------------------------------------------------------
*/
@ -237,13 +228,11 @@ FuNkYfMgRtAbStUfF
# conditional expression instead. Not all awks have conditional expressions.
$AWK 'BEGIN {
Strict["t"] = "true"
Strict["f"] = "false"
OldStyle["11"] = "true"
OldStyle["12"] = "false"
Bool["t"] = "true"
Bool["f"] = "false"
}
{ printf (" { %d, \"%s\", %d, %s, %s, %s },\n"), \
$1, $(NF-1), $9, Strict[$8], OldStyle[$4], $(NF-1)
$1, $(NF-1), $9, Bool[$8], Bool[$10], $(NF-1)
}' $RAWFILE >> "$$-$TABLEFILE"
if [ $? -ne 0 ]; then

View File

@ -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
*

View File

@ -8,20 +8,17 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.45 2000/11/16 22:30:34 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.46 2000/11/20 20:36:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <sys/types.h>
#include <sys/stat.h>
#include "postgres.h"
#include "catalog/pg_proc.h"
#include "dynloader.h"
#include "utils/dynamic_loader.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
/*
@ -46,55 +43,16 @@ static DynamicFileList *file_tail = (DynamicFileList *) NULL;
#define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device)
/*
* Load the specified dynamic-link library file, and look for a function
* named funcname in it. If the function is not found, we raise an error
* if signalNotFound is true, else return (PGFunction) NULL. Note that
* errors in loading the library will provoke elog regardless of
* signalNotFound.
*/
PGFunction
fmgr_dynamic(Oid functionId)
{
HeapTuple procedureTuple;
Form_pg_proc procedureStruct;
char *proname,
*prosrcstring,
*probinstring;
Datum prosrcattr,
probinattr;
PGFunction user_fn;
bool isnull;
procedureTuple = SearchSysCache(PROCOID,
ObjectIdGetDatum(functionId),
0, 0, 0);
if (!HeapTupleIsValid(procedureTuple))
elog(ERROR, "fmgr_dynamic: function %u: cache lookup failed",
functionId);
procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
proname = NameStr(procedureStruct->proname);
prosrcattr = SysCacheGetAttr(PROCOID, procedureTuple,
Anum_pg_proc_prosrc, &isnull);
if (isnull)
elog(ERROR, "fmgr: Could not extract prosrc for %u from pg_proc",
functionId);
prosrcstring = DatumGetCString(DirectFunctionCall1(textout, prosrcattr));
probinattr = SysCacheGetAttr(PROCOID, procedureTuple,
Anum_pg_proc_probin, &isnull);
if (isnull)
elog(ERROR, "fmgr: Could not extract probin for %u from pg_proc",
functionId);
probinstring = DatumGetCString(DirectFunctionCall1(textout, probinattr));
user_fn = load_external_function(probinstring, prosrcstring);
pfree(prosrcstring);
pfree(probinstring);
ReleaseSysCache(procedureTuple);
return user_fn;
}
PGFunction
load_external_function(char *filename, char *funcname)
load_external_function(char *filename, char *funcname,
bool signalNotFound)
{
DynamicFileList *file_scanner;
PGFunction retval;
@ -164,7 +122,7 @@ load_external_function(char *filename, char *funcname)
retval = pg_dlsym(file_scanner->handle, funcname);
if (retval == (PGFunction) NULL)
if (retval == (PGFunction) NULL && signalNotFound)
elog(ERROR, "Can't find function %s in file %s", funcname, filename);
return retval;
@ -217,5 +175,5 @@ load_file(char *filename)
}
}
load_external_function(filename, (char *) NULL);
load_external_function(filename, (char *) NULL, false);
}

View File

@ -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
{
elog(ERROR, "fmgr_info: function %u: unsupported language %u",
functionId, language);
}
ReleaseSysCache(languageTuple);
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++)
{
fnextra->arg_toastable[i] =
TypeIsToastable(procedureStruct->proargtypes[i]);
}
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;
}
pfree(prosrcstring);
pfree(probinstring);
}
/*
* 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.
* 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);
}
/*
* 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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 $
*
*-------------------------------------------------------------------------
*/
@ -208,6 +208,43 @@ extern struct varlena * pg_detoast_datum_copy(struct varlena * datum);
#define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
/*-------------------------------------------------------------------------
* 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);

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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)
{

View File

@ -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)

View File

@ -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';

View File

@ -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
--

View File

@ -215,6 +215,19 @@ 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;
drop table oldstyle_test;
--
-- functional joins
--

View File

@ -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';

View File

@ -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
--

View File

@ -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
--
--

View File

@ -1,5 +1,5 @@
/*
* $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.44 2000/08/24 23:34:11 tgl Exp $
* $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.45 2000/11/20 20:36:53 tgl Exp $
*/
#include <float.h> /* faked on sunos */
@ -25,10 +25,13 @@ extern void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
extern Datum overpaid(PG_FUNCTION_ARGS);
extern Datum boxarea(PG_FUNCTION_ARGS);
extern char *reverse_name(char *string);
extern int oldstyle_length(int n, text *t);
/*
** Distance from a point to a path
*/
PG_FUNCTION_INFO_V1(regress_dist_ptpath);
Datum
regress_dist_ptpath(PG_FUNCTION_ARGS)
{
@ -69,6 +72,8 @@ regress_dist_ptpath(PG_FUNCTION_ARGS)
/* this essentially does a cartesian product of the lsegs in the
two paths, and finds the min distance between any two lsegs */
PG_FUNCTION_INFO_V1(regress_path_dist);
Datum
regress_path_dist(PG_FUNCTION_ARGS)
{
@ -129,6 +134,8 @@ POLYGON *poly;
}
/* return the point where two paths intersect, or NULL if no intersection. */
PG_FUNCTION_INFO_V1(interpt_pp);
Datum
interpt_pp(PG_FUNCTION_ARGS)
{
@ -182,6 +189,8 @@ Point *pt2;
lseg->m = point_sl(pt1, pt2);
}
PG_FUNCTION_INFO_V1(overpaid);
Datum
overpaid(PG_FUNCTION_ARGS)
{
@ -254,6 +263,8 @@ WIDGET *widget;
return result;
}
PG_FUNCTION_INFO_V1(pt_in_widget);
Datum
pt_in_widget(PG_FUNCTION_ARGS)
{
@ -265,6 +276,8 @@ pt_in_widget(PG_FUNCTION_ARGS)
#define ABS(X) ((X) >= 0 ? (X) : -(X))
PG_FUNCTION_INFO_V1(boxarea);
Datum
boxarea(PG_FUNCTION_ARGS)
{
@ -278,8 +291,7 @@ boxarea(PG_FUNCTION_ARGS)
}
char *
reverse_name(string)
char *string;
reverse_name(char *string)
{
int i;
int len;
@ -301,6 +313,20 @@ char *string;
return new_string;
}
/* This rather silly function is just to test that oldstyle functions
* work correctly on toast-able inputs.
*/
int
oldstyle_length(int n, text *t)
{
int len = 0;
if (t)
len = VARSIZE(t) - VARHDRSZ;
return n + len;
}
#include "executor/spi.h" /* this is what you need to work with SPI */
#include "commands/trigger.h" /* -"- and triggers */
@ -312,6 +338,8 @@ static bool fd17b_recursion = true;
static bool fd17a_recursion = true;
extern Datum funny_dup17(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(funny_dup17);
Datum
funny_dup17(PG_FUNCTION_ARGS)
{
@ -428,6 +456,8 @@ extern Datum set_ttdummy(PG_FUNCTION_ARGS);
static void *splan = NULL;
static bool ttoff = false;
PG_FUNCTION_INFO_V1(ttdummy);
Datum
ttdummy(PG_FUNCTION_ARGS)
{
@ -625,6 +655,8 @@ ttdummy(PG_FUNCTION_ARGS)
return PointerGetDatum(rettuple);
}
PG_FUNCTION_INFO_V1(set_ttdummy);
Datum
set_ttdummy(PG_FUNCTION_ARGS)
{

View File

@ -38,6 +38,7 @@ DROP FUNCTION interpt_pp(path,path);
DROP FUNCTION reverse_name(name);
DROP FUNCTION oldstyle_length(int4, text);
--
-- OPERATOR REMOVAL

View File

@ -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)
{