mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Second round of fmgr changes: triggers are now invoked in new style,
CurrentTriggerData is history.
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_language.sgml,v 1.9 2000/03/26 18:32:27 petere Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_language.sgml,v 1.10 2000/05/29 01:59:06 tgl Exp $
|
||||
Postgres documentation
|
||||
-->
|
||||
|
||||
@ -160,44 +160,42 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
|
||||
<title>
|
||||
Writing PL handlers
|
||||
</title>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
In <productname>Postgres</productname> 7.1 and later, call handlers
|
||||
must adhere to the "new style" function manager interface.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The call handler for a procedural language must be written
|
||||
in a compiler language such as 'C' and registered with
|
||||
in a compiled language such as 'C' and registered with
|
||||
<productname>Postgres</productname> as a function taking
|
||||
no arguments and returning the
|
||||
<type>opaque</type> type, a placeholder for unspecified or undefined types..
|
||||
<type>opaque</type> type, a placeholder for unspecified or undefined types.
|
||||
This prevents the call handler from being
|
||||
called directly as a function from queries.
|
||||
(However, arguments may be supplied in the actual call when a
|
||||
PL function in the language offered by the handler is to be executed.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
However, arguments must be supplied on the actual call when a
|
||||
PL function or trigger
|
||||
procedure in the language offered by the handler is to be
|
||||
executed.
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
When called from the trigger manager, the only argument is
|
||||
the object ID from the procedure's <filename>pg_proc</filename>
|
||||
entry. All other
|
||||
information from the trigger manager is found in the
|
||||
global <structname>CurrentTriggerData</structname> pointer.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
When called from the function manager, the arguments are
|
||||
the object ID of the procedure's <filename>pg_proc</filename>
|
||||
entry, the number
|
||||
of arguments given to the PL function, the arguments in a
|
||||
<structname>FmgrValues</structname> structure and a pointer
|
||||
to a boolean where the
|
||||
function tells the caller if the return value is the SQL
|
||||
NULL value.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
The call handler is called in the same way as any other new-style
|
||||
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
|
||||
<literal>isnull</literal> field of the FunctionCallInfoData struct,
|
||||
if it wishes to return an SQL NULL result). The difference between
|
||||
a call handler and an ordinary callee function is that the
|
||||
<literal>flinfo->fn_oid</literal> field of the FunctionCallInfoData
|
||||
struct will contain the OID of the PL function to be called, not of
|
||||
the call handler itself. The call handler must use this field to
|
||||
determine which function to execute. Also, the passed argument list
|
||||
has been set up according to the declaration of the target PL function,
|
||||
not of the call handler.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
It's up to the call handler to fetch the
|
||||
<filename>pg_proc</filename> entry and
|
||||
@ -212,6 +210,28 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
|
||||
file or anything else that tells the call handler what to
|
||||
do in detail.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Often, the same function is called many times per SQL statement.
|
||||
A call handler can avoid repeated lookups of information about the
|
||||
called function by using the <literal>flinfo->fn_extra</literal> field.
|
||||
This will initially be NULL, but can be set by the call handler to
|
||||
point at information about the PL function. On subsequent calls,
|
||||
if <literal>flinfo->fn_extra</literal> is already non-NULL then it
|
||||
can be used and the information lookup step skipped. The call handler
|
||||
must be careful that <literal>flinfo->fn_extra</literal> is made to
|
||||
point at memory that will live at least until the end of the current
|
||||
query, since an FmgrInfo data structure could be kept that long.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When a PL function is invoked as a trigger, no explicit arguments
|
||||
are passed, but the FunctionCallInfoData's
|
||||
<literal>context</literal> field points at a TriggerData node,
|
||||
rather than being NULL as it is in a plain function call.
|
||||
A PL handler should provide mechanisms for PL functions to get
|
||||
at the trigger information.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id="R2-SQL-CREATELANGUAGE-4">
|
||||
@ -275,39 +295,33 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
|
||||
#include "executor/spi.h"
|
||||
#include "commands/trigger.h"
|
||||
#include "utils/elog.h"
|
||||
#include "fmgr.h" /* for FmgrValues struct */
|
||||
#include "fmgr.h"
|
||||
#include "access/heapam.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_type.h"
|
||||
|
||||
Datum
|
||||
plsample_call_handler(
|
||||
Oid prooid,
|
||||
int pronargs,
|
||||
FmgrValues *proargs,
|
||||
bool *isNull)
|
||||
plsample_call_handler(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum retval;
|
||||
TriggerData *trigdata;
|
||||
|
||||
if (CurrentTriggerData == NULL) {
|
||||
if (CALLED_AS_TRIGGER(fcinfo))
|
||||
{
|
||||
/*
|
||||
* Called as a trigger procedure
|
||||
*/
|
||||
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||
|
||||
retval = ...
|
||||
} else {
|
||||
/*
|
||||
* Called as a function
|
||||
*/
|
||||
|
||||
retval = ...
|
||||
} else {
|
||||
/*
|
||||
* Called as a trigger procedure
|
||||
*/
|
||||
trigdata = CurrentTriggerData;
|
||||
CurrentTriggerData = NULL;
|
||||
|
||||
retval = ...
|
||||
}
|
||||
|
||||
*isNull = false;
|
||||
return retval;
|
||||
}
|
||||
</programlisting>
|
||||
@ -325,7 +339,7 @@ plsample_call_handler(
|
||||
<programlisting>
|
||||
CREATE FUNCTION plsample_call_handler () RETURNS opaque
|
||||
AS '/usr/local/pgsql/lib/plsample.so'
|
||||
LANGUAGE 'C';
|
||||
LANGUAGE 'newC';
|
||||
CREATE PROCEDURAL LANGUAGE 'plsample'
|
||||
HANDLER plsample_call_handler
|
||||
LANCOMPILER 'PL/Sample';
|
||||
|
Reference in New Issue
Block a user