postgresql/doc/src/sgml/trigger.sgml

586 lines
18 KiB
Plaintext
Raw Normal View History

<!--
$Header: /cvsroot/pgsql/doc/src/sgml/trigger.sgml,v 1.29 2003/08/10 01:20:34 tgl Exp $
-->
<chapter id="triggers">
<title>Triggers</title>
<para>
2003-04-11 20:41:20 +02:00
This chapter describes how to write trigger functions. In
particular, it describes the C-language interface for trigger
functions. The trigger interfaces in most procedural languages
work analogously. (Trigger functions cannot be written in SQL.)
</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>
<sect1 id="trigger-definition">
<title>Trigger Definition</title>
<para>
2003-04-11 20:41:20 +02:00
If a trigger event occurs, the trigger manager is called by the
executor. It sets up an information structure of type
<structname>TriggerData</> (described below) and calls the trigger
function to handle the event.
</para>
<para>
The trigger function must be defined before the trigger itself can be
created. The trigger function must be declared as a
function taking no arguments and returning type <literal>trigger</>.
2002-09-21 20:32:54 +02:00
(The trigger function receives its input through a <structname>TriggerData</>
structure, not in the form of ordinary function arguments.)
If the function is written in C, it must use the <quote>version 1</>
function manager interface.
</para>
<para>
The syntax for creating triggers is described in
<xref linkend="sql-createtrigger" endterm="sql-createtrigger-title">.
</para>
<para>
2003-04-11 20:41:20 +02:00
Trigger functions return a value of type <structname>HeapTuple</>,
which represents a table row, to the calling executor. The return
value is ignored for triggers fired after an operation, but a
triggers fired before an operation has the following choices:
<itemizedlist>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
It can return a <symbol>NULL</> pointer to skip the operation
for the current row (and so the row will not be
2002-09-21 20:32:54 +02:00
inserted/updated/deleted).
</para>
</listitem>
<listitem>
<para>
For <command>INSERT</command> and <command>UPDATE</command>
2003-04-11 20:41:20 +02:00
triggers only, the returned row becomes the row that will
be inserted or will replace the row being updated. This
allows the trigger function to modify the row being inserted or
updated.
</para>
</listitem>
</itemizedlist>
2003-04-11 20:41:20 +02:00
A before trigger that does not intend to cause either of these
behaviors must be careful to return the same row that was passed
in as the new row (see below).
</para>
<para>
2002-09-21 20:32:54 +02:00
If more than one trigger is defined for the same event on the same
relation, the triggers will be fired in alphabetical order by
2003-04-11 20:41:20 +02:00
name. In the case of before triggers, the possibly-modified row
2002-09-21 20:32:54 +02:00
returned by each trigger becomes the input to the next trigger.
2003-04-11 20:41:20 +02:00
If any before trigger returns a <symbol>NULL</> pointer, the
operation is abandoned and subsequent triggers are not fired.
</para>
<para>
2003-04-11 20:41:20 +02:00
If a trigger function executes SQL commands (using SPI) then these
commands may fire triggers again. This is known as cascading
triggers. There is no direct limitation on the number of cascade
2003-04-11 20:41:20 +02:00
levels. It is possible for cascades to cause a recursive invocation
of the same trigger; for example, an <command>INSERT</command>
trigger might execute a command that inserts an additional row
into the same table, causing the <command>INSERT</command> trigger
to be fired again. It is the trigger programmer's responsibility
to avoid infinite recursion in such scenarios.
</para>
<para>
2003-04-11 20:41:20 +02:00
When a trigger is being defined, arguments can be specified for
it. The purpose of including arguments in the trigger definition
is to allow different triggers with similar requirements to call
the same function. As an example, there could be a generalized
trigger function that takes as its arguments two column names and
puts the current user in one and the current time stamp in the
other. Properly written, this trigger function would be
independent of the specific table it is triggering on. So the
same function could be used for <command>INSERT</command> events
on any table with suitable columns, to automatically track creation
of records in a transaction table for example. It could also be
used to track last-update events if defined as an
<command>UPDATE</command> trigger.
</para>
</sect1>
<sect1 id="trigger-manager">
<title>Interaction with the Trigger Manager</title>
<para>
This section describes the low-level details of the interface to a
trigger function. This information is only needed when writing a
2003-04-11 20:41:20 +02:00
trigger function in C. If you are using a higher-level
language then these details are handled for you.
</para>
<para>
When a function is called by the trigger manager, it is not passed
2003-04-11 20:41:20 +02:00
any normal arguments, but it is passed a <quote>context</>
pointer pointing to a <structname>TriggerData</> structure. C
functions can check whether they were called from the trigger
manager or not by executing the macro
2003-04-11 20:41:20 +02:00
<programlisting>
CALLED_AS_TRIGGER(fcinfo)
</programlisting>
which expands to
2002-09-21 20:32:54 +02:00
<programlisting>
((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
</programlisting>
If this returns true, then it is safe to cast
<literal>fcinfo->context</> to type <literal>TriggerData
*</literal> and make use of the pointed-to
<structname>TriggerData</> structure. The function must
<emphasis>not</emphasis> alter the <structname>TriggerData</>
structure or any of the data it points to.
</para>
<para>
2002-03-22 20:20:45 +01:00
<structname>struct TriggerData</structname> is defined in
<filename>commands/trigger.h</filename>:
2002-03-22 20:20:45 +01:00
<programlisting>
1998-03-01 09:16:16 +01:00
typedef struct TriggerData
{
NodeTag type;
TriggerEvent tg_event;
Relation tg_relation;
HeapTuple tg_trigtuple;
HeapTuple tg_newtuple;
Trigger *tg_trigger;
1998-03-01 09:16:16 +01:00
} TriggerData;
2002-03-22 20:20:45 +01:00
</programlisting>
where the members are defined as follows:
<variablelist>
<varlistentry>
2002-09-21 20:32:54 +02:00
<term><structfield>type</></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
Always <literal>T_TriggerData</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
2002-09-21 20:32:54 +02:00
<term><structfield>tg_event</></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
Describes the event for which the function is called. You may use the
following macros to examine <literal>tg_event</literal>:
<variablelist>
<varlistentry>
2003-04-11 20:41:20 +02:00
<term><literal>TRIGGER_FIRED_BEFORE(tg_event)</literal></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
Returns true if the trigger fired before the operation.
</para>
</listitem>
</varlistentry>
<varlistentry>
2003-04-11 20:41:20 +02:00
<term><literal>TRIGGER_FIRED_AFTER(tg_event)</literal></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
Returns true if the trigger fired after the operation.
</para>
</listitem>
</varlistentry>
<varlistentry>
2003-04-11 20:41:20 +02:00
<term><literal>TRIGGER_FIRED_FOR_ROW(tg_event)</literal></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
Returns true if the trigger fired for a row-level event.
</para>
</listitem>
</varlistentry>
<varlistentry>
2003-04-11 20:41:20 +02:00
<term><literal>TRIGGER_FIRED_FOR_STATEMENT(tg_event)</literal></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
Returns true if the trigger fired for a statement-level event.
</para>
</listitem>
</varlistentry>
<varlistentry>
2003-04-11 20:41:20 +02:00
<term><literal>TRIGGER_FIRED_BY_INSERT(tg_event)</literal></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
Returns true if the trigger was fired by an <command>INSERT</command> command.
</para>
</listitem>
</varlistentry>
<varlistentry>
2003-04-11 20:41:20 +02:00
<term><literal>TRIGGER_FIRED_BY_UPDATE(tg_event)</literal></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
Returns true if the trigger was fired by an <command>UPDATE</command> command.
</para>
</listitem>
</varlistentry>
<varlistentry>
2003-04-11 20:41:20 +02:00
<term><literal>TRIGGER_FIRED_BY_DELETE(tg_event)</literal></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
Returns true if the trigger was fired by a <command>DELETE</command> command.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</listitem>
</varlistentry>
<varlistentry>
2002-09-21 20:32:54 +02:00
<term><structfield>tg_relation</></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
A pointer to a structure describing the relation that the trigger fired for.
Look at <filename>utils/rel.h</> for details about
2002-09-21 20:32:54 +02:00
this structure. The most interesting things are
<literal>tg_relation->rd_att</> (descriptor of the relation
tuples) and <literal>tg_relation->rd_rel->relname</>
2003-04-11 20:41:20 +02:00
(relation name; the type is not <type>char*</> but
<type>NameData</>; use
<literal>SPI_getrelname(tg_relation)</> to get a <type>char*</> if you
2002-09-21 20:32:54 +02:00
need a copy of the name).
</para>
</listitem>
</varlistentry>
<varlistentry>
2002-09-21 20:32:54 +02:00
<term><structfield>tg_trigtuple</></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
A pointer to the row for which the trigger was fired. This is
the row being inserted, updated, or deleted. If this trigger
was fired for an <command>INSERT</command> or
<command>DELETE</command> then this is what you should return
to from the function if you don't want to replace the row with
a different one (in the case of <command>INSERT</command>) or
skip the operation.
</para>
</listitem>
</varlistentry>
<varlistentry>
2002-09-21 20:32:54 +02:00
<term><structfield>tg_newtuple</></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
A pointer to the new version of the row, if the trigger was
fired for an <command>UPDATE</command>, and <symbol>NULL</> if
it is for an <command>INSERT</command> or a
<command>DELETE</command>. This is what you have to return
from the function if the event is an <command>UPDATE</command>
and you don't want to replace this row by a different one or
skip the operation.
</para>
</listitem>
</varlistentry>
<varlistentry>
2002-09-21 20:32:54 +02:00
<term><structfield>tg_trigger</></term>
<listitem>
<para>
2003-04-11 20:41:20 +02:00
A pointer to a structure of type <structname>Trigger</>,
defined in <filename>utils/rel.h</>:
2002-09-21 20:32:54 +02:00
<programlisting>
1998-03-01 09:16:16 +01:00
typedef struct Trigger
{
2000-01-11 06:37:11 +01:00
Oid tgoid;
char *tgname;
Oid tgfoid;
int16 tgtype;
bool tgenabled;
bool tgisconstraint;
Oid tgconstrrelid;
2000-01-11 06:37:11 +01:00
bool tgdeferrable;
bool tginitdeferred;
int16 tgnargs;
int16 tgattr[FUNC_MAX_ARGS];
char **tgargs;
1998-03-01 09:16:16 +01:00
} Trigger;
2002-09-21 20:32:54 +02:00
</programlisting>
2002-09-21 20:32:54 +02:00
where <structfield>tgname</> is the trigger's name,
<structfield>tgnargs</> is number of arguments in
2003-04-11 20:41:20 +02:00
<structfield>tgargs</>, and <structfield>tgargs</> is an array of
pointers to the arguments specified in the <command>CREATE
2003-04-11 20:41:20 +02:00
TRIGGER</command> statement. The other members are for internal use
only.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</sect1>
<sect1 id="trigger-datachanges">
<title>Visibility of Data Changes</title>
<para>
2003-04-11 20:41:20 +02:00
If you are using the SPI interface to execute SQL commands in your
trigger functions written in C (or you are using a different
language and execute SQL commands in some way, which internally
goes through SPI as well), be sure to read <xref
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:
2003-04-11 20:41:20 +02:00
<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>
2003-04-11 20:41:20 +02:00
<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>
2003-04-11 20:41:20 +02:00
<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>
2003-04-11 20:41:20 +02:00
The next section contains a demonstration of these rules applied.
</para>
</sect1>
2003-04-11 20:41:20 +02:00
<sect1 id="trigger-example">
<title>A Complete Example</title>
<para>
2003-04-11 20:41:20 +02:00
Here is a very simple example of a trigger function written in C.
The function <function>trigf</> reports the number of rows in the
table <literal>ttest</> and skips the actual operation if the
command attempts to insert a null value into the column
<literal>x</>. (So the trigger acts as a not-null constraint but
doesn't abort the transaction.)
</para>
<para>
2003-04-11 20:41:20 +02:00
First, the table definition:
<programlisting>
CREATE TABLE ttest (
x integer
);
</programlisting>
</para>
2003-04-11 20:41:20 +02:00
<para>
This is the source code of the trigger function:
2002-09-21 20:32:54 +02:00
<programlisting>
2003-04-11 20:41:20 +02:00
#include "postgres.h"
2002-09-21 20:32:54 +02:00
#include "executor/spi.h" /* this is what you need to work with SPI */
2003-04-11 20:41:20 +02:00
#include "commands/trigger.h" /* ... and triggers */
1998-03-01 09:16:16 +01:00
extern Datum trigf(PG_FUNCTION_ARGS);
1998-03-01 09:16:16 +01:00
PG_FUNCTION_INFO_V1(trigf);
Datum
trigf(PG_FUNCTION_ARGS)
1998-03-01 09:16:16 +01:00
{
2002-09-21 20:32:54 +02:00
TriggerData *trigdata = (TriggerData *) fcinfo->context;
TupleDesc tupdesc;
HeapTuple rettuple;
char *when;
bool checknull = false;
bool isnull;
int ret, i;
2003-04-11 20:41:20 +02:00
/* make sure it's called as a trigger at all */
2002-09-21 20:32:54 +02:00
if (!CALLED_AS_TRIGGER(fcinfo))
2003-04-11 20:41:20 +02:00
elog(ERROR, "trigf: not called by trigger manager");
2002-09-21 20:32:54 +02:00
2003-04-11 20:41:20 +02:00
/* tuple to return to executor */
2002-09-21 20:32:54 +02:00
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
rettuple = trigdata->tg_newtuple;
else
rettuple = trigdata->tg_trigtuple;
/* check for null values */
if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)
&& TRIGGER_FIRED_BEFORE(trigdata->tg_event))
checknull = true;
if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
when = "before";
else
when = "after ";
tupdesc = trigdata->tg_relation->rd_att;
2003-04-11 20:41:20 +02:00
/* connect to SPI manager */
2002-09-21 20:32:54 +02:00
if ((ret = SPI_connect()) < 0)
elog(INFO, "trigf (fired %s): SPI_connect returned %d", when, ret);
2003-04-11 20:41:20 +02:00
/* get number of rows in table */
2002-09-21 20:32:54 +02:00
ret = SPI_exec("SELECT count(*) FROM ttest", 0);
if (ret < 0)
elog(NOTICE, "trigf (fired %s): SPI_exec returned %d", when, ret);
2003-04-11 20:41:20 +02:00
/* count(*) returns int8, so be careful to convert */
i = DatumGetInt64(SPI_getbinval(SPI_tuptable->vals[0],
SPI_tuptable->tupdesc,
1,
&amp;isnull));
2002-09-21 20:32:54 +02:00
2003-04-11 20:41:20 +02:00
elog (INFO, "trigf (fired %s): there are %d rows in ttest", when, i);
2002-09-21 20:32:54 +02:00
SPI_finish();
if (checknull)
{
2003-04-11 20:41:20 +02:00
SPI_getbinval(rettuple, tupdesc, 1, &amp;isnull);
2002-09-21 20:32:54 +02:00
if (isnull)
rettuple = NULL;
}
return PointerGetDatum(rettuple);
1998-03-01 09:16:16 +01:00
}
2002-09-21 20:32:54 +02:00
</programlisting>
</para>
1998-03-01 09:16:16 +01:00
<para>
2003-04-11 20:41:20 +02:00
After you have compiled the source code, declare the function and
the triggers:
2002-09-21 20:32:54 +02:00
<programlisting>
2003-04-11 20:41:20 +02:00
CREATE FUNCTION trigf() RETURNS trigger
AS '<replaceable>filename</>'
LANGUAGE C;
CREATE TRIGGER tbefore BEFORE INSERT OR UPDATE OR DELETE ON ttest
FOR EACH ROW EXECUTE PROCEDURE trigf();
2003-04-11 20:41:20 +02:00
CREATE TRIGGER tafter AFTER INSERT OR UPDATE OR DELETE ON ttest
FOR EACH ROW EXECUTE PROCEDURE trigf();
2002-09-21 20:32:54 +02:00
</programlisting>
2003-04-11 20:41:20 +02:00
</para>
1998-03-01 09:16:16 +01:00
2003-04-11 20:41:20 +02:00
<para>
Now you can test the operation of the trigger:
<screen>
=> INSERT INTO ttest VALUES (NULL);
INFO: trigf (fired before): there are 0 rows in ttest
1998-03-01 09:16:16 +01:00
INSERT 0 0
-- Insertion skipped and AFTER trigger is not fired
2003-04-11 20:41:20 +02:00
=> SELECT * FROM ttest;
2002-09-21 20:32:54 +02:00
x
---
1998-03-01 09:16:16 +01:00
(0 rows)
2003-04-11 20:41:20 +02:00
=> INSERT INTO ttest VALUES (1);
INFO: trigf (fired before): there are 0 rows in ttest
INFO: trigf (fired after ): there are 1 rows in ttest
1998-03-01 09:16:16 +01:00
^^^^^^^^
remember what we said about visibility.
INSERT 167793 1
2001-10-13 01:32:34 +02:00
vac=> SELECT * FROM ttest;
2002-09-21 20:32:54 +02:00
x
---
1
1998-03-01 09:16:16 +01:00
(1 row)
2003-04-11 20:41:20 +02:00
=> INSERT INTO ttest SELECT x * 2 FROM ttest;
INFO: trigf (fired before): there are 1 rows in ttest
INFO: trigf (fired after ): there are 2 rows in ttest
^^^^^^
1998-03-01 09:16:16 +01:00
remember what we said about visibility.
INSERT 167794 1
2003-04-11 20:41:20 +02:00
=> SELECT * FROM ttest;
2002-09-21 20:32:54 +02:00
x
---
1
2
1998-03-01 09:16:16 +01:00
(2 rows)
2003-04-11 20:41:20 +02:00
=> UPDATE ttest SET x = NULL WHERE x = 2;
INFO: trigf (fired before): there are 2 rows in ttest
1998-03-01 09:16:16 +01:00
UPDATE 0
2003-04-11 20:41:20 +02:00
=> UPDATE ttest SET x = 4 WHERE x = 2;
INFO: trigf (fired before): there are 2 rows in ttest
INFO: trigf (fired after ): there are 2 rows in ttest
1998-03-01 09:16:16 +01:00
UPDATE 1
2001-10-13 01:32:34 +02:00
vac=> SELECT * FROM ttest;
2002-09-21 20:32:54 +02:00
x
---
1
4
1998-03-01 09:16:16 +01:00
(2 rows)
2003-04-11 20:41:20 +02:00
=> DELETE FROM ttest;
INFO: trigf (fired before): there are 2 rows in ttest
INFO: trigf (fired after ): there are 1 rows in ttest
INFO: trigf (fired before): there are 1 rows in ttest
INFO: trigf (fired after ): there are 0 rows in ttest
^^^^^^
1998-03-01 09:16:16 +01:00
remember what we said about visibility.
DELETE 2
2003-04-11 20:41:20 +02:00
=> SELECT * FROM ttest;
2002-09-21 20:32:54 +02:00
x
---
1998-03-01 09:16:16 +01:00
(0 rows)
2003-04-11 20:41:20 +02:00
</screen>
</para>
2003-04-11 20:41:20 +02:00
<para>
There are more complex examples in
<filename>src/test/regress/regress.c</filename> and
in <filename>contrib/spi</filename>.
</para>
</sect1>
</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:
-->