Commit 22ae53d4 authored by Peter Eisentraut's avatar Peter Eisentraut

Move the "how to write a PL call handler" parts from the CREATE LANGUAGE

man page to the Programmer's Guide.
parent f25ed23c
This diff is collapsed.
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.33 2001/08/28 14:20:26 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.34 2001/09/06 10:28:39 petere Exp $
-->
<chapter id="xfunc">
......@@ -337,11 +337,11 @@ SELECT clean_EMP();
</para>
<para>
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"> for
more information.
There are currently four procedural languages available in the
standard <productname>PostgreSQL</productname> distribution:
PL/pgSQL, PL/Tcl, PL/Perl, and PL/Python. Other languages can be
defined by users. Refer to <xref linkend="xplang"> for more
information.
</para>
</sect1>
......@@ -1357,6 +1357,173 @@ LANGUAGE 'c';
</sect3>
</sect2>
</sect1>
<sect1 id="xfunc-plhandler">
<title>Procedural Language Handlers</title>
<para>
All calls to functions that are written in a language other than
the current <quote>version 1</quote> interface for compiled
languages, in particular in user-defined procedural languages, but
also functions written in SQL or the version 0 compiled language
interface, go through a <firstterm>call handler</firstterm>
function for the specific language. It is the responsibility of
the call handler to execute the function in a meaningful way, such
as by interpreting the supplied source text. This section
describes how a language call handler can be written. This is not
a common task, in fact, it has only been done a handful of times
in the history of <productname>PostgreSQL</productname>, but the
topic naturally belongs in this chapter, and the material might
give some insight into the extensible nature of the
<productname>PostgreSQL</productname> system.
</para>
<para>
The call handler for a procedural language is a
<quote>normal</quote> function, which must be written in a
compiled language such as C and registered with
<productname>PostgreSQL</productname> as taking no arguments and
returning the <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 to the handler when a
function in the language offered by the handler is to be
executed.)
</para>
<note>
<para>
In <productname>PostgreSQL</productname> 7.1 and later, call
handlers must adhere to the <quote>version 1</quote> function
manager interface, not the old-style interface.
</para>
</note>
<para>
The call handler is called in the same way as any other function:
It receives a pointer to a
<structname>FunctionCallInfoData</structname> struct containing
argument values and information about the called function, and it
is expected to return a <type>Datum</type> result (and possibly
set the <structfield>isnull</structfield> field of the
<structname>FunctionCallInfoData</structname> struct, if it wishes
to return an SQL NULL result). The difference between a call
handler and an ordinary callee function is that the
<structfield>flinfo-&gt;fn_oid</structfield> field of the
<structname>FunctionCallInfoData</structname> struct will contain
the OID of the actual 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 function,
not of the call handler.
</para>
<para>
It's up to the call handler to fetch the
<classname>pg_proc</classname> entry and to analyze the argument
and return types of the called procedure. The AS clause from the
<command>CREATE FUNCTION</command> of the procedure will be found
in the <literal>prosrc</literal> attribute of the
<classname>pg_proc</classname> table entry. This may be the source
text in the procedural language itself (like for PL/Tcl), a
pathname to a 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
<structfield>flinfo-&gt;fn_extra</structfield> 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
<structfield>flinfo-&gt;fn_extra</structfield> is already non-NULL
then it can be used and the information lookup step skipped. The
call handler must be careful that
<structfield>flinfo-&gt;fn_extra</structfield> is made to point at
memory that will live at least until the end of the current query,
since an <structname>FmgrInfo</structname> data structure could be
kept that long. One way to do this is to allocate the extra data
in the memory context specified by
<structfield>flinfo-&gt;fn_mcxt</structfield>; such data will
normally have the same lifespan as the
<structname>FmgrInfo</structname> itself. But the handler could
also choose to use a longer-lived context so that it can cache
function definition information across queries.
</para>
<para>
When a PL function is invoked as a trigger, no explicit arguments
are passed, but the
<structname>FunctionCallInfoData</structname>'s
<structfield>context</structfield> field points at a
<structname>TriggerData</structname> node, rather than being NULL
as it is in a plain function call. A language handler should
provide mechanisms for PL functions to get at the trigger
information.
</para>
<para>
This is a template for a PL handler written in C:
<programlisting>
#include "postgres.h"
#include "executor/spi.h"
#include "commands/trigger.h"
#include "utils/elog.h"
#include "fmgr.h"
#include "access/heapam.h"
#include "utils/syscache.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
PG_FUNCTION_INFO_V1(plsample_call_handler);
Datum
plsample_call_handler(PG_FUNCTION_ARGS)
{
Datum retval;
if (CALLED_AS_TRIGGER(fcinfo))
{
/*
* Called as a trigger procedure
*/
TriggerData *trigdata = (TriggerData *) fcinfo->context;
retval = ...
}
else {
/*
* Called as a function
*/
retval = ...
}
return retval;
}
</programlisting>
</para>
<para>
Only a few thousand lines of code have to be added instead of the
dots to complete the call handler. See <xref linkend="xfunc-c">
for information on how to compile it into a loadable module.
</para>
<para>
The following commands then register the sample procedural
language:
<programlisting>
CREATE FUNCTION plsample_call_handler () RETURNS opaque
AS '/usr/local/pgsql/lib/plsample.so'
LANGUAGE C;
CREATE LANGUAGE plsample
HANDLER plsample_call_handler;
</programlisting>
</para>
</sect1>
</chapter>
<!-- Keep this comment at the end of the file
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment