⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trigger.sgml

📁 PostgreSQL7.4.6 for Linux
💻 SGML
📖 第 1 页 / 共 2 页
字号:
	  </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->rd_att</> (descriptor of the relation	tuples) and <literal>tg_relation->rd_rel->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	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>      <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       tgattr[FUNC_MAX_ARGS];    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>    </variablelist>   </para>   <para>    A trigger function must return either <symbol>NULL</> or a    <structname>HeapTuple</> pointer.  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 <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>    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->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->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;    /* connect to SPI manager */    if ((ret = SPI_connect()) < 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 < 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->vals[0],                                    SPI_tuptable->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>=> 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=> SELECT * FROM ttest; x---(0 rows)=> 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=> SELECT * FROM ttest; x--- 1(1 row)=> 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=> SELECT * FROM ttest; x--- 1 2(2 rows)=> UPDATE ttest SET x = NULL WHERE x = 2;INFO:  trigf (fired before): there are 2 rows in ttestUPDATE 0=> 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=> SELECT * FROM ttest; x--- 1 4(2 rows)=> DELETE FROM ttest;INFO:  trigf (fired before): there are 2 rows in ttestINFO:  trigf (fired after ): there are 1 rows in ttestINFO:  trigf (fired before): there are 1 rows in ttestINFO:  trigf (fired after ): there are 0 rows in ttest                                       ^^^^^^                             remember what we said about visibility.DELETE 2=> 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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -