trigger.sgml

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· SGML 代码 · 共 735 行 · 第 1/2 页

SGML
735
字号
          <term><literal>TRIGGER_FIRED_FOR_STATEMENT(tg_event)</literal></term>          <listitem>           <para>            Returns true if the trigger fired for a statement-level event.           </para>          </listitem>         </varlistentry>         <varlistentry>          <term><literal>TRIGGER_FIRED_BY_INSERT(tg_event)</literal></term>          <listitem>           <para>            Returns true if the trigger was fired by an <command>INSERT</command> command.           </para>          </listitem>         </varlistentry>         <varlistentry>          <term><literal>TRIGGER_FIRED_BY_UPDATE(tg_event)</literal></term>          <listitem>           <para>            Returns true if the trigger was fired by an <command>UPDATE</command> command.           </para>          </listitem>         </varlistentry>         <varlistentry>          <term><literal>TRIGGER_FIRED_BY_DELETE(tg_event)</literal></term>          <listitem>           <para>            Returns true if the trigger was fired by a <command>DELETE</command> command.           </para>          </listitem>         </varlistentry>        </variablelist>       </para>      </listitem>     </varlistentry>     <varlistentry>      <term><structfield>tg_relation</></term>      <listitem>       <para>        A pointer to a structure describing the relation that the trigger fired for.        Look at <filename>utils/rel.h</> for details about        this structure.  The most interesting things are        <literal>tg_relation-&gt;rd_att</> (descriptor of the relation        tuples) and <literal>tg_relation-&gt;rd_rel-&gt;relname</>        (relation name; the type is not <type>char*</> but        <type>NameData</>; use        <literal>SPI_getrelname(tg_relation)</> to get a <type>char*</> if you        need a copy of the name).       </para>      </listitem>     </varlistentry>     <varlistentry>      <term><structfield>tg_trigtuple</></term>      <listitem>       <para>        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        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>      <term><structfield>tg_newtuple</></term>      <listitem>       <para>        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>      <term><structfield>tg_trigger</></term>      <listitem>       <para>        A pointer to a structure of type <structname>Trigger</>,        defined in <filename>utils/rel.h</>:<programlisting>typedef struct Trigger{    Oid         tgoid;    char       *tgname;    Oid         tgfoid;    int16       tgtype;    bool        tgenabled;    bool        tgisconstraint;    Oid         tgconstrrelid;    bool        tgdeferrable;    bool        tginitdeferred;    int16       tgnargs;    int16       tgnattr;    int16      *tgattr;    char      **tgargs;} Trigger;</programlisting>       where <structfield>tgname</> is the trigger's name,       <structfield>tgnargs</> is number of arguments in       <structfield>tgargs</>, and <structfield>tgargs</> is an array of       pointers to the arguments specified in the <command>CREATE       TRIGGER</command> statement. The other members are for internal use       only.       </para>      </listitem>     </varlistentry>     <varlistentry>      <term><structfield>tg_trigtuplebuf</></term>      <listitem>       <para>        The buffer containing <structfield>tg_trigtuple</structfield>, or <symbol>InvalidBuffer</symbol> if there        is no such tuple or it is not stored in a disk buffer.       </para>      </listitem>     </varlistentry>     <varlistentry>      <term><structfield>tg_newtuplebuf</></term>      <listitem>       <para>        The buffer containing <structfield>tg_newtuple</structfield>, or <symbol>InvalidBuffer</symbol> if there        is no such tuple or it is not stored in a disk buffer.       </para>      </listitem>     </varlistentry>    </variablelist>   </para>   <para>    A trigger function must return either a    <structname>HeapTuple</> pointer or a <symbol>NULL</> pointer    (<emphasis>not</> an SQL null value, that is, do not set <parameter>isNull</parameter> true).    Be careful to return either    <structfield>tg_trigtuple</> or <structfield>tg_newtuple</>,    as appropriate, if you don't want to modify the row being operated on.   </para>  </sect1>  <sect1 id="trigger-example">   <title>A Complete Example</title>   <para>    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    table <structname>ttest</> and skips the actual operation if the    command attempts to insert a null value into the column    <structfield>x</>. (So the trigger acts as a not-null constraint but    doesn't abort the transaction.)   </para>   <para>    First, the table definition:<programlisting>CREATE TABLE ttest (    x integer);</programlisting>   </para>   <para>    This is the source code of the trigger function:<programlisting>#include "postgres.h"#include "executor/spi.h"       /* this is what you need to work with SPI */#include "commands/trigger.h"   /* ... and triggers */extern Datum trigf(PG_FUNCTION_ARGS);PG_FUNCTION_INFO_V1(trigf);Datumtrigf(PG_FUNCTION_ARGS){    TriggerData *trigdata = (TriggerData *) fcinfo-&gt;context;    TupleDesc   tupdesc;    HeapTuple   rettuple;    char       *when;    bool        checknull = false;    bool        isnull;    int         ret, i;    /* make sure it's called as a trigger at all */    if (!CALLED_AS_TRIGGER(fcinfo))        elog(ERROR, "trigf: not called by trigger manager");    /* tuple to return to executor */    if (TRIGGER_FIRED_BY_UPDATE(trigdata-&gt;tg_event))        rettuple = trigdata-&gt;tg_newtuple;    else        rettuple = trigdata-&gt;tg_trigtuple;    /* check for null values */    if (!TRIGGER_FIRED_BY_DELETE(trigdata-&gt;tg_event)        && TRIGGER_FIRED_BEFORE(trigdata-&gt;tg_event))        checknull = true;    if (TRIGGER_FIRED_BEFORE(trigdata-&gt;tg_event))        when = "before";    else        when = "after ";    tupdesc = trigdata-&gt;tg_relation-&gt;rd_att;    /* connect to SPI manager */    if ((ret = SPI_connect()) &lt; 0)        elog(INFO, "trigf (fired %s): SPI_connect returned %d", when, ret);    /* get number of rows in table */    ret = SPI_exec("SELECT count(*) FROM ttest", 0);    if (ret &lt; 0)        elog(NOTICE, "trigf (fired %s): SPI_exec returned %d", when, ret);    /* count(*) returns int8, so be careful to convert */    i = DatumGetInt64(SPI_getbinval(SPI_tuptable-&gt;vals[0],                                    SPI_tuptable-&gt;tupdesc,                                    1,                                    &amp;isnull));    elog (INFO, "trigf (fired %s): there are %d rows in ttest", when, i);    SPI_finish();    if (checknull)    {        SPI_getbinval(rettuple, tupdesc, 1, &amp;isnull);        if (isnull)            rettuple = NULL;    }    return PointerGetDatum(rettuple);}</programlisting>   </para>   <para>    After you have compiled the source code, declare the function and    the triggers:<programlisting>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();CREATE TRIGGER tafter AFTER INSERT OR UPDATE OR DELETE ON ttest     FOR EACH ROW EXECUTE PROCEDURE trigf();</programlisting>   </para>   <para>    Now you can test the operation of the trigger:<screen>=&gt; INSERT INTO ttest VALUES (NULL);INFO:  trigf (fired before): there are 0 rows in ttestINSERT 0 0-- Insertion skipped and AFTER trigger is not fired=&gt; SELECT * FROM ttest; x---(0 rows)=&gt; INSERT INTO ttest VALUES (1);INFO:  trigf (fired before): there are 0 rows in ttestINFO:  trigf (fired after ): there are 1 rows in ttest                                       ^^^^^^^^                             remember what we said about visibility.INSERT 167793 1vac=&gt; SELECT * FROM ttest; x--- 1(1 row)=&gt; INSERT INTO ttest SELECT x * 2 FROM ttest;INFO:  trigf (fired before): there are 1 rows in ttestINFO:  trigf (fired after ): there are 2 rows in ttest                                       ^^^^^^                             remember what we said about visibility.INSERT 167794 1=&gt; SELECT * FROM ttest; x--- 1 2(2 rows)=&gt; UPDATE ttest SET x = NULL WHERE x = 2;INFO:  trigf (fired before): there are 2 rows in ttestUPDATE 0=&gt; UPDATE ttest SET x = 4 WHERE x = 2;INFO:  trigf (fired before): there are 2 rows in ttestINFO:  trigf (fired after ): there are 2 rows in ttestUPDATE 1vac=&gt; SELECT * FROM ttest; x--- 1 4(2 rows)=&gt; DELETE FROM ttest;INFO:  trigf (fired before): there are 2 rows in ttestINFO:  trigf (fired before): there are 1 rows in ttestINFO:  trigf (fired after ): there are 0 rows in ttestINFO:  trigf (fired after ): there are 0 rows in ttest                                       ^^^^^^                             remember what we said about visibility.DELETE 2=&gt; SELECT * FROM ttest; x---(0 rows)</screen>   </para>   <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 fileLocal variables:mode:sgmlsgml-omittag:nilsgml-shorttag:tsgml-minimize-attributes:nilsgml-always-quote-attributes:tsgml-indent-step:1sgml-indent-data:tsgml-parent-document:nilsgml-default-dtd-file:"./reference.ced"sgml-exposed-tags:nilsgml-local-catalogs:("/usr/lib/sgml/catalog")sgml-local-ecat-files:nilEnd:-->

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?