mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Move docs about index cost estimation functions and writing a procedural
language handler to the 'Internals' area, per my proposal of yesterday. Clean up the trigger documentation a bit. Push SPI chapter to the end of its part, and reorder the Internals chapters into what seems a more sensible order (at the moment anyway).
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/filelist.sgml,v 1.31 2003/10/17 18:57:01 tgl Exp $ -->
|
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/filelist.sgml,v 1.32 2003/10/22 22:28:10 tgl Exp $ -->
|
||||||
|
|
||||||
<!entity history SYSTEM "history.sgml">
|
<!entity history SYSTEM "history.sgml">
|
||||||
<!entity info SYSTEM "info.sgml">
|
<!entity info SYSTEM "info.sgml">
|
||||||
@ -7,8 +7,6 @@
|
|||||||
<!entity notation SYSTEM "notation.sgml">
|
<!entity notation SYSTEM "notation.sgml">
|
||||||
<!entity problems SYSTEM "problems.sgml">
|
<!entity problems SYSTEM "problems.sgml">
|
||||||
|
|
||||||
<!entity bookindex SYSTEM "bookindex.sgml">
|
|
||||||
|
|
||||||
<!-- tutorial -->
|
<!-- tutorial -->
|
||||||
<!entity advanced SYSTEM "advanced.sgml">
|
<!entity advanced SYSTEM "advanced.sgml">
|
||||||
<!entity query SYSTEM "query.sgml">
|
<!entity query SYSTEM "query.sgml">
|
||||||
@ -20,27 +18,16 @@
|
|||||||
<!-- user's guide -->
|
<!-- user's guide -->
|
||||||
<!entity array SYSTEM "array.sgml">
|
<!entity array SYSTEM "array.sgml">
|
||||||
<!entity datatype SYSTEM "datatype.sgml">
|
<!entity datatype SYSTEM "datatype.sgml">
|
||||||
<!entity datetime SYSTEM "datetime.sgml">
|
|
||||||
<!entity ddl SYSTEM "ddl.sgml">
|
<!entity ddl SYSTEM "ddl.sgml">
|
||||||
<!entity dml SYSTEM "dml.sgml">
|
<!entity dml SYSTEM "dml.sgml">
|
||||||
<!entity errcodes SYSTEM "errcodes.sgml">
|
|
||||||
<!entity features SYSTEM "features.sgml">
|
|
||||||
<!entity func SYSTEM "func.sgml">
|
<!entity func SYSTEM "func.sgml">
|
||||||
<!entity indices SYSTEM "indices.sgml">
|
<!entity indices SYSTEM "indices.sgml">
|
||||||
<!entity keywords SYSTEM "keywords.sgml">
|
|
||||||
<!entity mvcc SYSTEM "mvcc.sgml">
|
<!entity mvcc SYSTEM "mvcc.sgml">
|
||||||
<!entity perform SYSTEM "perform.sgml">
|
<!entity perform SYSTEM "perform.sgml">
|
||||||
<!entity queries SYSTEM "queries.sgml">
|
<!entity queries SYSTEM "queries.sgml">
|
||||||
<!entity syntax SYSTEM "syntax.sgml">
|
<!entity syntax SYSTEM "syntax.sgml">
|
||||||
<!entity typeconv SYSTEM "typeconv.sgml">
|
<!entity typeconv SYSTEM "typeconv.sgml">
|
||||||
|
|
||||||
<!entity features-supported SYSTEM "features-supported.sgml">
|
|
||||||
<!entity features-unsupported SYSTEM "features-unsupported.sgml">
|
|
||||||
|
|
||||||
<!-- reference pages -->
|
|
||||||
<!entity % allfiles SYSTEM "ref/allfiles.sgml">
|
|
||||||
%allfiles;
|
|
||||||
|
|
||||||
<!-- administrator's guide -->
|
<!-- administrator's guide -->
|
||||||
<!entity backup SYSTEM "backup.sgml">
|
<!entity backup SYSTEM "backup.sgml">
|
||||||
<!entity charset SYSTEM "charset.sgml">
|
<!entity charset SYSTEM "charset.sgml">
|
||||||
@ -52,7 +39,6 @@
|
|||||||
<!entity manage-ag SYSTEM "manage-ag.sgml">
|
<!entity manage-ag SYSTEM "manage-ag.sgml">
|
||||||
<!entity monitoring SYSTEM "monitoring.sgml">
|
<!entity monitoring SYSTEM "monitoring.sgml">
|
||||||
<!entity regress SYSTEM "regress.sgml">
|
<!entity regress SYSTEM "regress.sgml">
|
||||||
<!entity release SYSTEM "release.sgml">
|
|
||||||
<!entity runtime SYSTEM "runtime.sgml">
|
<!entity runtime SYSTEM "runtime.sgml">
|
||||||
<!entity user-manag SYSTEM "user-manag.sgml">
|
<!entity user-manag SYSTEM "user-manag.sgml">
|
||||||
<!entity wal SYSTEM "wal.sgml">
|
<!entity wal SYSTEM "wal.sgml">
|
||||||
@ -62,8 +48,6 @@
|
|||||||
<!entity ecpg SYSTEM "ecpg.sgml">
|
<!entity ecpg SYSTEM "ecpg.sgml">
|
||||||
<!entity extend SYSTEM "extend.sgml">
|
<!entity extend SYSTEM "extend.sgml">
|
||||||
<!entity func-ref SYSTEM "func-ref.sgml">
|
<!entity func-ref SYSTEM "func-ref.sgml">
|
||||||
<!entity gist SYSTEM "gist.sgml">
|
|
||||||
<!entity indexcost SYSTEM "indexcost.sgml">
|
|
||||||
<!entity infoschema SYSTEM "information_schema.sgml">
|
<!entity infoschema SYSTEM "information_schema.sgml">
|
||||||
<!entity jdbc SYSTEM "jdbc.sgml">
|
<!entity jdbc SYSTEM "jdbc.sgml">
|
||||||
<!entity libpgeasy SYSTEM "libpgeasy.sgml">
|
<!entity libpgeasy SYSTEM "libpgeasy.sgml">
|
||||||
@ -85,21 +69,40 @@
|
|||||||
<!entity plsql SYSTEM "plpgsql.sgml">
|
<!entity plsql SYSTEM "plpgsql.sgml">
|
||||||
<!entity pltcl SYSTEM "pltcl.sgml">
|
<!entity pltcl SYSTEM "pltcl.sgml">
|
||||||
|
|
||||||
|
<!-- reference pages -->
|
||||||
|
<!entity % allfiles SYSTEM "ref/allfiles.sgml">
|
||||||
|
%allfiles;
|
||||||
|
|
||||||
<!-- developer's guide -->
|
<!-- developer's guide -->
|
||||||
<!entity arch-dev SYSTEM "arch-dev.sgml">
|
<!entity arch-dev SYSTEM "arch-dev.sgml">
|
||||||
<!entity biblio SYSTEM "biblio.sgml">
|
|
||||||
<!entity bki SYSTEM "bki.sgml">
|
<!entity bki SYSTEM "bki.sgml">
|
||||||
<!entity catalogs SYSTEM "catalogs.sgml">
|
<!entity catalogs SYSTEM "catalogs.sgml">
|
||||||
<!entity compiler SYSTEM "compiler.sgml">
|
<!entity compiler SYSTEM "compiler.sgml">
|
||||||
<!entity contacts SYSTEM "contacts.sgml">
|
|
||||||
<!entity cvs SYSTEM "cvs.sgml">
|
|
||||||
<!entity docguide SYSTEM "docguide.sgml">
|
|
||||||
<!entity geqo SYSTEM "geqo.sgml">
|
<!entity geqo SYSTEM "geqo.sgml">
|
||||||
<!entity index SYSTEM "index.sgml">
|
<!entity gist SYSTEM "gist.sgml">
|
||||||
|
<!entity indexcost SYSTEM "indexcost.sgml">
|
||||||
|
<!entity nls SYSTEM "nls.sgml">
|
||||||
<!entity page SYSTEM "page.sgml">
|
<!entity page SYSTEM "page.sgml">
|
||||||
|
<!entity plhandler SYSTEM "plhandler.sgml">
|
||||||
<!entity protocol SYSTEM "protocol.sgml">
|
<!entity protocol SYSTEM "protocol.sgml">
|
||||||
<!entity sources SYSTEM "sources.sgml">
|
<!entity sources SYSTEM "sources.sgml">
|
||||||
<!entity nls SYSTEM "nls.sgml">
|
|
||||||
|
<!-- appendixes -->
|
||||||
|
<!entity contacts SYSTEM "contacts.sgml">
|
||||||
|
<!entity cvs SYSTEM "cvs.sgml">
|
||||||
|
<!entity datetime SYSTEM "datetime.sgml">
|
||||||
|
<!entity docguide SYSTEM "docguide.sgml">
|
||||||
|
<!entity errcodes SYSTEM "errcodes.sgml">
|
||||||
|
<!entity features SYSTEM "features.sgml">
|
||||||
|
<!entity keywords SYSTEM "keywords.sgml">
|
||||||
|
<!entity release SYSTEM "release.sgml">
|
||||||
|
|
||||||
|
<!entity features-supported SYSTEM "features-supported.sgml">
|
||||||
|
<!entity features-unsupported SYSTEM "features-unsupported.sgml">
|
||||||
|
|
||||||
|
<!-- back matter -->
|
||||||
|
<!entity biblio SYSTEM "biblio.sgml">
|
||||||
|
<!entity bookindex SYSTEM "bookindex.sgml">
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Some parts of the documentation are also source for some plain-text
|
Some parts of the documentation are also source for some plain-text
|
||||||
|
174
doc/src/sgml/plhandler.sgml
Normal file
174
doc/src/sgml/plhandler.sgml
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
<!--
|
||||||
|
$Header: /cvsroot/pgsql/doc/src/sgml/plhandler.sgml,v 1.1 2003/10/22 22:28:10 tgl Exp $
|
||||||
|
-->
|
||||||
|
|
||||||
|
<chapter id="plhandler">
|
||||||
|
<title>Writing A Procedural Language Handler</title>
|
||||||
|
|
||||||
|
<indexterm zone="plhandler">
|
||||||
|
<primary>procedural language</primary>
|
||||||
|
<secondary>handler for</secondary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
All calls to functions that are written in a language other than
|
||||||
|
the current <quote>version 1</quote> interface for compiled
|
||||||
|
languages (this includes functions in user-defined procedural languages,
|
||||||
|
functions written in SQL, and functions using 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 chapter outlines
|
||||||
|
how a new procedural language's call handler can be written.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The call handler for a procedural language is a
|
||||||
|
<quote>normal</quote> function that must be written in a compiled
|
||||||
|
language such as C, using the version-1 interface, and registered
|
||||||
|
with <productname>PostgreSQL</productname> as taking no arguments
|
||||||
|
and returning the type <type>language_handler</type>. This
|
||||||
|
special pseudotype identifies the function as a call handler and
|
||||||
|
prevents it from being called directly in SQL commands.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The call handler is called in the same way as any other function:
|
||||||
|
It receives a pointer to a
|
||||||
|
<structname>FunctionCallInfoData</structname> <type>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> structure, 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->fn_oid</structfield> field of the
|
||||||
|
<structname>FunctionCallInfoData</structname> structure 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 entry of the function from the
|
||||||
|
system table
|
||||||
|
<classname>pg_proc</classname> and to analyze the argument
|
||||||
|
and return types of the called function. The <literal>AS</> clause from the
|
||||||
|
<command>CREATE FUNCTION</command> of the function will be found
|
||||||
|
in the <literal>prosrc</literal> column of the
|
||||||
|
<classname>pg_proc</classname> row. This may be the source
|
||||||
|
text in the procedural language itself (like for PL/Tcl), a
|
||||||
|
path name 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->fn_extra</structfield> field. This will
|
||||||
|
initially be <symbol>NULL</>, but can be set by the call handler to point at
|
||||||
|
information about the called function. On subsequent calls, if
|
||||||
|
<structfield>flinfo->fn_extra</structfield> is already non-<symbol>NULL</>
|
||||||
|
then it can be used and the information lookup step skipped. The
|
||||||
|
call handler must make sure that
|
||||||
|
<structfield>flinfo->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->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 memory context so that it can cache
|
||||||
|
function definition information across queries.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When a procedural-language function is invoked as a trigger, no arguments
|
||||||
|
are passed in the usual way, but the
|
||||||
|
<structname>FunctionCallInfoData</structname>'s
|
||||||
|
<structfield>context</structfield> field points at a
|
||||||
|
<structname>TriggerData</structname> structure, rather than being <symbol>NULL</>
|
||||||
|
as it is in a plain function call. A language handler should
|
||||||
|
provide mechanisms for procedural-language functions to get at the trigger
|
||||||
|
information.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This is a template for a procedural-language handler written in C:
|
||||||
|
<programlisting>
|
||||||
|
#include "postgres.h"
|
||||||
|
#include "executor/spi.h"
|
||||||
|
#include "commands/trigger.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>
|
||||||
|
Only a few thousand lines of code have to be added instead of the
|
||||||
|
dots to complete the call handler.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
After having compiled the handler function into a loadable module
|
||||||
|
(see <xref linkend="dfunc">), the following commands then
|
||||||
|
register the sample procedural language:
|
||||||
|
<programlisting>
|
||||||
|
CREATE FUNCTION plsample_call_handler() RETURNS language_handler
|
||||||
|
AS '<replaceable>filename</replaceable>'
|
||||||
|
LANGUAGE C;
|
||||||
|
CREATE LANGUAGE plsample
|
||||||
|
HANDLER plsample_call_handler;
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<!-- Keep this comment at the end of the file
|
||||||
|
Local variables:
|
||||||
|
mode:sgml
|
||||||
|
sgml-omittag:nil
|
||||||
|
sgml-shorttag:t
|
||||||
|
sgml-minimize-attributes:nil
|
||||||
|
sgml-always-quote-attributes:t
|
||||||
|
sgml-indent-step:1
|
||||||
|
sgml-indent-data:t
|
||||||
|
sgml-parent-document:nil
|
||||||
|
sgml-default-dtd-file:"./reference.ced"
|
||||||
|
sgml-exposed-tags:nil
|
||||||
|
sgml-local-catalogs:("/usr/lib/sgml/catalog")
|
||||||
|
sgml-local-ecat-files:nil
|
||||||
|
End:
|
||||||
|
-->
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/postgres.sgml,v 1.57 2003/10/17 18:57:01 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/postgres.sgml,v 1.58 2003/10/22 22:28:10 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [
|
||||||
@ -203,10 +203,8 @@ $Header: /cvsroot/pgsql/doc/src/sgml/postgres.sgml,v 1.57 2003/10/17 18:57:01 tg
|
|||||||
</partintro>
|
</partintro>
|
||||||
|
|
||||||
&extend;
|
&extend;
|
||||||
&indexcost;
|
|
||||||
&rules;
|
&rules;
|
||||||
&trigger;
|
&trigger;
|
||||||
&spi;
|
|
||||||
|
|
||||||
&xplang;
|
&xplang;
|
||||||
&plsql;
|
&plsql;
|
||||||
@ -214,6 +212,8 @@ $Header: /cvsroot/pgsql/doc/src/sgml/postgres.sgml,v 1.57 2003/10/17 18:57:01 tg
|
|||||||
&plperl;
|
&plperl;
|
||||||
&plpython;
|
&plpython;
|
||||||
|
|
||||||
|
&spi;
|
||||||
|
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
&reference;
|
&reference;
|
||||||
@ -231,13 +231,15 @@ $Header: /cvsroot/pgsql/doc/src/sgml/postgres.sgml,v 1.57 2003/10/17 18:57:01 tg
|
|||||||
&arch-dev;
|
&arch-dev;
|
||||||
&catalogs;
|
&catalogs;
|
||||||
&protocol;
|
&protocol;
|
||||||
&page;
|
|
||||||
&geqo;
|
|
||||||
&gist;
|
|
||||||
&bki;
|
|
||||||
&sources;
|
&sources;
|
||||||
&compiler;
|
|
||||||
&nls;
|
&nls;
|
||||||
|
&plhandler;
|
||||||
|
&geqo;
|
||||||
|
&indexcost;
|
||||||
|
&gist;
|
||||||
|
&page;
|
||||||
|
&bki;
|
||||||
|
&compiler;
|
||||||
|
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/spi.sgml,v 1.27 2003/08/31 17:32:20 petere Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/spi.sgml,v 1.28 2003/10/22 22:28:10 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="spi">
|
<chapter id="spi">
|
||||||
@ -11,18 +11,28 @@ $Header: /cvsroot/pgsql/doc/src/sgml/spi.sgml,v 1.27 2003/08/31 17:32:20 petere
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <firstterm>Server Programming Interface</firstterm>
|
The <firstterm>Server Programming Interface</firstterm>
|
||||||
(<acronym>SPI</acronym>) gives users the ability to run
|
(<acronym>SPI</acronym>) gives writers of user-defined
|
||||||
<acronym>SQL</acronym> commands inside user-defined
|
<acronym>C</acronym> functions the ability to run
|
||||||
<acronym>C</acronym> functions. <acronym>SPI</acronym> is a set of
|
<acronym>SQL</acronym> commands inside their functions.
|
||||||
|
<acronym>SPI</acronym> is a set of
|
||||||
interface functions to simplify access to the parser, planner,
|
interface functions to simplify access to the parser, planner,
|
||||||
optimizer, and executor. <acronym>SPI</acronym> also does some
|
optimizer, and executor. <acronym>SPI</acronym> also does some
|
||||||
memory management.
|
memory management.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
The available procedural languages provide various means to
|
||||||
|
execute SQL commands from procedures. Some of these are based on or
|
||||||
|
modelled after SPI, so this documentation might be of use for users
|
||||||
|
of those languages as well.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
To avoid misunderstanding we'll use the term <quote>function</quote>
|
To avoid misunderstanding we'll use the term <quote>function</quote>
|
||||||
when we speak of <acronym>SPI</acronym> interface functions and
|
when we speak of <acronym>SPI</acronym> interface functions and
|
||||||
<quote>procedure</quote> for user-defined C-functions, which may be
|
<quote>procedure</quote> for a user-defined C-function that is
|
||||||
using <acronym>SPI</acronym>.
|
using <acronym>SPI</acronym>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@ -50,15 +60,6 @@ $Header: /cvsroot/pgsql/doc/src/sgml/spi.sgml,v 1.27 2003/08/31 17:32:20 petere
|
|||||||
<filename>executor/spi.h</filename>.
|
<filename>executor/spi.h</filename>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
|
||||||
<para>
|
|
||||||
The available procedural languages provide different means to
|
|
||||||
execute SQL commands from procedures. Some of these are modelled
|
|
||||||
after SPI, so this documentation might be of use for those users as
|
|
||||||
well.
|
|
||||||
</para>
|
|
||||||
</note>
|
|
||||||
|
|
||||||
|
|
||||||
<sect1 id="spi-interface">
|
<sect1 id="spi-interface">
|
||||||
<title>Interface Functions</title>
|
<title>Interface Functions</title>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/trigger.sgml,v 1.30 2003/08/31 17:32:20 petere Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/trigger.sgml,v 1.31 2003/10/22 22:28:10 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="triggers">
|
<chapter id="triggers">
|
||||||
@ -10,49 +10,44 @@ $Header: /cvsroot/pgsql/doc/src/sgml/trigger.sgml,v 1.30 2003/08/31 17:32:20 pet
|
|||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
This chapter describes how to write trigger functions. In
|
This chapter describes how to write trigger functions. Trigger
|
||||||
particular, it describes the C-language interface for trigger
|
functions can be written in C or in some of the available procedural
|
||||||
functions. The trigger interfaces in most procedural languages
|
languages. It is not currently possible to write a SQL-language
|
||||||
work analogously. (Trigger functions cannot be written in SQL.)
|
trigger function.
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
A trigger function can execute before or after a
|
|
||||||
<command>INSERT</command>, <command>UPDATE</command>, or
|
|
||||||
<command>DELETE</command>, either once per modified row, or once
|
|
||||||
per <acronym>SQL</acronym> statement.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<sect1 id="trigger-definition">
|
<sect1 id="trigger-definition">
|
||||||
<title>Trigger Definition</title>
|
<title>Overview of Trigger Behavior</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If a trigger event occurs, the trigger manager is called by the
|
A trigger can be defined to execute before or after an
|
||||||
executor. It sets up an information structure of type
|
<command>INSERT</command>, <command>UPDATE</command>, or
|
||||||
<structname>TriggerData</> (described below) and calls the trigger
|
<command>DELETE</command> operation, either once per modified row,
|
||||||
function to handle the event.
|
or once per <acronym>SQL</acronym> statement.
|
||||||
|
If a trigger event occurs, the trigger's function is called
|
||||||
|
at the appropriate time to handle the event.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The trigger function must be defined before the trigger itself can be
|
The trigger function must be defined before the trigger itself can be
|
||||||
created. The trigger function must be declared as a
|
created. The trigger function must be declared as a
|
||||||
function taking no arguments and returning type <literal>trigger</>.
|
function taking no arguments and returning type <literal>trigger</>.
|
||||||
(The trigger function receives its input through a <structname>TriggerData</>
|
(The trigger function receives its input through a specially-passed
|
||||||
structure, not in the form of ordinary function arguments.)
|
<structname>TriggerData</> structure, not in the form of ordinary function
|
||||||
If the function is written in C, it must use the <quote>version 1</>
|
arguments.)
|
||||||
function manager interface.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The syntax for creating triggers is described in
|
Once a suitable trigger function has been created, the trigger is
|
||||||
|
established with
|
||||||
<xref linkend="sql-createtrigger" endterm="sql-createtrigger-title">.
|
<xref linkend="sql-createtrigger" endterm="sql-createtrigger-title">.
|
||||||
|
The same trigger function can be used for multiple triggers.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Trigger functions return a value of type <structname>HeapTuple</>,
|
Trigger functions return a table row (a value of type
|
||||||
which represents a table row, to the calling executor. The return
|
<structname>HeapTuple</>) to the calling executor.
|
||||||
value is ignored for triggers fired after an operation, but a
|
A trigger fired before an operation has the following choices:
|
||||||
triggers fired before an operation has the following choices:
|
|
||||||
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -75,13 +70,19 @@ $Header: /cvsroot/pgsql/doc/src/sgml/trigger.sgml,v 1.30 2003/08/31 17:32:20 pet
|
|||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
A before trigger that does not intend to cause either of these
|
A before trigger that does not intend to cause either of these
|
||||||
behaviors must be careful to return the same row that was passed
|
behaviors must be careful to return as its result the same row that was
|
||||||
in as the new row (see below).
|
passed in.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The return
|
||||||
|
value is ignored for triggers fired after an operation, and so
|
||||||
|
they may as well return <symbol>NULL</>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If more than one trigger is defined for the same event on the same
|
If more than one trigger is defined for the same event on the same
|
||||||
relation, the triggers will be fired in alphabetical order by
|
relation, the triggers will be fired in alphabetical order by trigger
|
||||||
name. In the case of before triggers, the possibly-modified row
|
name. In the case of before triggers, the possibly-modified row
|
||||||
returned by each trigger becomes the input to the next trigger.
|
returned by each trigger becomes the input to the next trigger.
|
||||||
If any before trigger returns a <symbol>NULL</> pointer, the
|
If any before trigger returns a <symbol>NULL</> pointer, the
|
||||||
@ -89,7 +90,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/trigger.sgml,v 1.30 2003/08/31 17:32:20 pet
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If a trigger function executes SQL commands (using SPI) then these
|
If a trigger function executes SQL commands then these
|
||||||
commands may fire triggers again. This is known as cascading
|
commands may fire triggers again. This is known as cascading
|
||||||
triggers. There is no direct limitation on the number of cascade
|
triggers. There is no direct limitation on the number of cascade
|
||||||
levels. It is possible for cascades to cause a recursive invocation
|
levels. It is possible for cascades to cause a recursive invocation
|
||||||
@ -120,10 +121,57 @@ $Header: /cvsroot/pgsql/doc/src/sgml/trigger.sgml,v 1.30 2003/08/31 17:32:20 pet
|
|||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="trigger-manager">
|
<sect1 id="trigger-datachanges">
|
||||||
<title>Interaction with the Trigger Manager</title>
|
<title>Visibility of Data Changes</title>
|
||||||
|
|
||||||
<indexterm zone="trigger-manager">
|
<para>
|
||||||
|
If you execute SQL commands in your trigger function, and these
|
||||||
|
commands access the table that the trigger is for, then
|
||||||
|
you need to be aware of the data visibility rules, because they determine
|
||||||
|
whether these SQL commands will see the data change that the trigger
|
||||||
|
is fired for. Briefly:
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The data change (insertion, update, or deletion) causing the trigger
|
||||||
|
to fire is naturally
|
||||||
|
<emphasis>not</emphasis> visible to SQL commands executed in a
|
||||||
|
before trigger, because it hasn't happened yet.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
However, SQL commands executed in a before trigger
|
||||||
|
<emphasis>will</emphasis> see the effects of data changes
|
||||||
|
for rows previously processed in the same outer command. This
|
||||||
|
requires caution, since the ordering of these change events
|
||||||
|
is not in general predictable; a SQL command that affects
|
||||||
|
multiple rows may visit the rows in any order.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
When an after trigger is fired, all data changes made by the outer
|
||||||
|
command are already complete, and are visible to executed SQL commands.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Further information about data visibility rules can be found in
|
||||||
|
<xref linkend="spi-visibility">. The example in <xref
|
||||||
|
linkend="trigger-example"> contains a demonstration of these rules.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="trigger-interface">
|
||||||
|
<title>Writing Trigger Functions in C</title>
|
||||||
|
|
||||||
|
<indexterm zone="trigger-interface">
|
||||||
<primary>trigger</primary>
|
<primary>trigger</primary>
|
||||||
<secondary>in C</secondary>
|
<secondary>in C</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
@ -132,7 +180,14 @@ $Header: /cvsroot/pgsql/doc/src/sgml/trigger.sgml,v 1.30 2003/08/31 17:32:20 pet
|
|||||||
This section describes the low-level details of the interface to a
|
This section describes the low-level details of the interface to a
|
||||||
trigger function. This information is only needed when writing a
|
trigger function. This information is only needed when writing a
|
||||||
trigger function in C. If you are using a higher-level
|
trigger function in C. If you are using a higher-level
|
||||||
language then these details are handled for you.
|
language then these details are handled for you. The documentation
|
||||||
|
of each procedural language explains how to write a trigger in that
|
||||||
|
language.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Trigger functions must use the <quote>version 1</> function manager
|
||||||
|
interface.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -342,49 +397,12 @@ typedef struct Trigger
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1 id="trigger-datachanges">
|
|
||||||
<title>Visibility of Data Changes</title>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If you are using the SPI interface to execute SQL commands in your
|
A trigger function must return either <symbol>NULL</> or a
|
||||||
trigger functions written in C (or you are using a different
|
<structname>HeapTuple</> pointer. Be careful to return either
|
||||||
language and execute SQL commands in some way, which internally
|
<structfield>tg_trigtuple</> or <structfield>tg_newtuple</>,
|
||||||
goes through SPI as well), be sure to read <xref
|
as appropriate, if you don't want to modify the row being operated on.
|
||||||
linkend="spi-visibility"> so that you know which data is visible
|
|
||||||
at which point during the execution of a trigger. For triggers,
|
|
||||||
the most important consequences of the data visibility rules are:
|
|
||||||
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
The row being inserted (<structfield>tg_trigtuple</>) is
|
|
||||||
<emphasis>not</emphasis> visible to SQL commands executed in a
|
|
||||||
before trigger.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
The row being inserted (<structfield>tg_trigtuple</>)
|
|
||||||
<emphasis>is</emphasis> visible to SQL commands executed in an
|
|
||||||
after trigger (because it was just inserted).
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
A just-inserted row is visible to all SQL commands executed
|
|
||||||
within any trigger that is fired later in the execution of the
|
|
||||||
outer command (e.g., for the next row).
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The next section contains a demonstration of these rules applied.
|
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -393,6 +411,11 @@ typedef struct Trigger
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Here is a very simple example of a trigger function written in C.
|
Here is a very simple example of a trigger function written in C.
|
||||||
|
(Examples of triggers written in procedural languages may be found
|
||||||
|
in the documentation of the procedural languages.)
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
The function <function>trigf</> reports the number of rows in the
|
The function <function>trigf</> reports the number of rows in the
|
||||||
table <literal>ttest</> and skips the actual operation if the
|
table <literal>ttest</> and skips the actual operation if the
|
||||||
command attempts to insert a null value into the column
|
command attempts to insert a null value into the column
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.75 2003/09/12 22:17:24 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.76 2003/10/22 22:28:10 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<sect1 id="xfunc">
|
<sect1 id="xfunc">
|
||||||
@ -58,6 +58,8 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.75 2003/09/12 22:17:24 tgl E
|
|||||||
<para>
|
<para>
|
||||||
It's easiest to define <acronym>SQL</acronym>
|
It's easiest to define <acronym>SQL</acronym>
|
||||||
functions, so we'll start by discussing those.
|
functions, so we'll start by discussing those.
|
||||||
|
Most of the concepts presented for <acronym>SQL</acronym> functions
|
||||||
|
will carry over to the other types of functions.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -66,7 +68,8 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.75 2003/09/12 22:17:24 tgl E
|
|||||||
understand the examples better.
|
understand the examples better.
|
||||||
Some examples from this chapter
|
Some examples from this chapter
|
||||||
can be found in <filename>funcs.sql</filename>
|
can be found in <filename>funcs.sql</filename>
|
||||||
and <filename>funcs.c</filename> in the tutorial directory.
|
and <filename>funcs.c</filename> in the <filename>src/tutorial</>
|
||||||
|
directory in the <productname>PostgreSQL</productname> source distribution.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -597,19 +600,23 @@ DETAIL: A function returning ANYARRAY or ANYELEMENT must have at least one argu
|
|||||||
<title>Procedural Language Functions</title>
|
<title>Procedural Language Functions</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Procedural languages aren't built into the <productname>PostgreSQL</productname> server; they are offered
|
Procedural languages aren't built into the
|
||||||
|
<productname>PostgreSQL</productname> server; they are offered
|
||||||
by loadable modules. Please refer to the documentation of the
|
by loadable modules. Please refer to the documentation of the
|
||||||
procedural language in question for details about the syntax and how the function body
|
procedural language in question for details about the syntax and how the
|
||||||
is interpreted for each language.
|
function body is interpreted for each language.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There are currently four procedural languages available in the
|
There are currently four procedural languages available in the
|
||||||
standard <productname>PostgreSQL</productname> distribution:
|
standard <productname>PostgreSQL</productname> distribution:
|
||||||
<application>PL/pgSQL</application>, <application>PL/Tcl</application>,
|
<application>PL/pgSQL</application>, <application>PL/Tcl</application>,
|
||||||
<application>PL/Perl</application>, and <application>PL/Python</application>. Other languages can be
|
<application>PL/Perl</application>, and
|
||||||
defined by users. Refer to <xref linkend="xplang"> for more
|
<application>PL/Python</application>.
|
||||||
information. The basics of developing a new procedural language are covered in <xref linkend="xfunc-plhandler">.
|
Refer to <xref linkend="xplang"> for more information.
|
||||||
|
Other languages can be defined by users.
|
||||||
|
The basics of developing a new procedural language are covered in <xref
|
||||||
|
linkend="plhandler">.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -1478,7 +1485,7 @@ concat_text(PG_FUNCTION_ARGS)
|
|||||||
to return set results (<xref linkend="xfunc-c-return-set">) and
|
to return set results (<xref linkend="xfunc-c-return-set">) and
|
||||||
implement trigger functions (<xref linkend="triggers">) and
|
implement trigger functions (<xref linkend="triggers">) and
|
||||||
procedural-language call handlers (<xref
|
procedural-language call handlers (<xref
|
||||||
linkend="xfunc-plhandler">). Version-1 code is also more
|
linkend="plhandler">). Version-1 code is also more
|
||||||
portable than version-0, because it does not break restrictions
|
portable than version-0, because it does not break restrictions
|
||||||
on function call protocol in the C standard. For more details
|
on function call protocol in the C standard. For more details
|
||||||
see <filename>src/backend/utils/fmgr/README</filename> in the
|
see <filename>src/backend/utils/fmgr/README</filename> in the
|
||||||
@ -2247,163 +2254,6 @@ CREATE FUNCTION test(int, int) RETURNS int
|
|||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="xfunc-plhandler">
|
|
||||||
<title>Procedural Language Handlers</title>
|
|
||||||
|
|
||||||
<indexterm zone="xfunc-plhandler">
|
|
||||||
<primary>procedural language</primary>
|
|
||||||
<secondary>handler for</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
All calls to functions that are written in a language other than
|
|
||||||
the current <quote>version 1</quote> interface for compiled
|
|
||||||
languages (this includes functions in user-defined procedural languages,
|
|
||||||
functions written in SQL, and functions using 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 that must be written in a compiled
|
|
||||||
language such as C, using the version-1 interface, and registered
|
|
||||||
with <productname>PostgreSQL</productname> as taking no arguments
|
|
||||||
and returning the type <type>language_handler</type>. This
|
|
||||||
special pseudotype identifies the function as a call handler and
|
|
||||||
prevents it from being called directly in SQL commands.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The call handler is called in the same way as any other function:
|
|
||||||
It receives a pointer to a
|
|
||||||
<structname>FunctionCallInfoData</structname> <type>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> structure, 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->fn_oid</structfield> field of the
|
|
||||||
<structname>FunctionCallInfoData</structname> structure 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 entry of the function from the system table
|
|
||||||
<classname>pg_proc</classname> and to analyze the argument
|
|
||||||
and return types of the called function. The <literal>AS</> clause from the
|
|
||||||
<command>CREATE FUNCTION</command> of the function will be found
|
|
||||||
in the <literal>prosrc</literal> column of the
|
|
||||||
<classname>pg_proc</classname> row. This may be the source
|
|
||||||
text in the procedural language itself (like for PL/Tcl), a
|
|
||||||
path name 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->fn_extra</structfield> field. This will
|
|
||||||
initially be <symbol>NULL</>, but can be set by the call handler to point at
|
|
||||||
information about the called function. On subsequent calls, if
|
|
||||||
<structfield>flinfo->fn_extra</structfield> is already non-<symbol>NULL</>
|
|
||||||
then it can be used and the information lookup step skipped. The
|
|
||||||
call handler must make sure that
|
|
||||||
<structfield>flinfo->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->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 memory context so that it can cache
|
|
||||||
function definition information across queries.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
When a procedural-language function is invoked as a trigger, no arguments
|
|
||||||
are passed in the usual way, but the
|
|
||||||
<structname>FunctionCallInfoData</structname>'s
|
|
||||||
<structfield>context</structfield> field points at a
|
|
||||||
<structname>TriggerData</structname> structure, rather than being <symbol>NULL</>
|
|
||||||
as it is in a plain function call. A language handler should
|
|
||||||
provide mechanisms for procedural-language functions to get at the trigger
|
|
||||||
information.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This is a template for a procedural-language handler written in C:
|
|
||||||
<programlisting>
|
|
||||||
#include "postgres.h"
|
|
||||||
#include "executor/spi.h"
|
|
||||||
#include "commands/trigger.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>
|
|
||||||
Only a few thousand lines of code have to be added instead of the
|
|
||||||
dots to complete the call handler.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
After having compiled the handler function into a loadable module
|
|
||||||
(see <xref linkend="dfunc">), the following commands then
|
|
||||||
register the sample procedural language:
|
|
||||||
<programlisting>
|
|
||||||
CREATE FUNCTION plsample_call_handler() RETURNS language_handler
|
|
||||||
AS '<replaceable>filename</replaceable>'
|
|
||||||
LANGUAGE C;
|
|
||||||
CREATE LANGUAGE plsample
|
|
||||||
HANDLER plsample_call_handler;
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<!-- Keep this comment at the end of the file
|
<!-- Keep this comment at the end of the file
|
||||||
Local variables:
|
Local variables:
|
||||||
mode:sgml
|
mode:sgml
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/xplang.sgml,v 1.24 2003/09/20 20:12:05 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/xplang.sgml,v 1.25 2003/10/22 22:28:10 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="xplang">
|
<chapter id="xplang">
|
||||||
@ -28,7 +28,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xplang.sgml,v 1.24 2003/09/20 20:12:05 tgl
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Writing a handler for a new procedural language is described in
|
Writing a handler for a new procedural language is described in
|
||||||
<xref linkend="xfunc-plhandler">. Several procedural languages are
|
<xref linkend="plhandler">. Several procedural languages are
|
||||||
available in the standard <productname>PostgreSQL</productname>
|
available in the standard <productname>PostgreSQL</productname>
|
||||||
distribution, which can serve as examples.
|
distribution, which can serve as examples.
|
||||||
</para>
|
</para>
|
||||||
|
Reference in New Issue
Block a user