]> begriffs open source - ai-pg/blob - full-docs/html/trigger-example.html
Include latest toc output
[ai-pg] / full-docs / html / trigger-example.html
1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>37.4. A Complete Trigger Example</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="trigger-interface.html" title="37.3. Writing Trigger Functions in C" /><link rel="next" href="event-triggers.html" title="Chapter 38. Event Triggers" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">37.4. A Complete Trigger Example</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="trigger-interface.html" title="37.3. Writing Trigger Functions in C">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="triggers.html" title="Chapter 37. Triggers">Up</a></td><th width="60%" align="center">Chapter 37. Triggers</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="event-triggers.html" title="Chapter 38. Event Triggers">Next</a></td></tr></table><hr /></div><div class="sect1" id="TRIGGER-EXAMPLE"><div class="titlepage"><div><div><h2 class="title" style="clear: both">37.4. A Complete Trigger Example <a href="#TRIGGER-EXAMPLE" class="id_link">#</a></h2></div></div></div><p>
3     Here is a very simple example of a trigger function written in C.
4     (Examples of triggers written in procedural languages can be found
5     in the documentation of the procedural languages.)
6    </p><p>
7     The function <code class="function">trigf</code> reports the number of rows in the
8     table <code class="structname">ttest</code> and skips the actual operation if the
9     command attempts to insert a null value into the column
10     <code class="structfield">x</code>. (So the trigger acts as a not-null constraint but
11     doesn't abort the transaction.)
12    </p><p>
13     First, the table definition:
14 </p><pre class="programlisting">
15 CREATE TABLE ttest (
16     x integer
17 );
18 </pre><p>
19    </p><p>
20     This is the source code of the trigger function:
21 </p><pre class="programlisting">
22 #include "postgres.h"
23 #include "fmgr.h"
24 #include "executor/spi.h"       /* this is what you need to work with SPI */
25 #include "commands/trigger.h"   /* ... triggers ... */
26 #include "utils/rel.h"          /* ... and relations */
27
28 PG_MODULE_MAGIC;
29
30 PG_FUNCTION_INFO_V1(trigf);
31
32 Datum
33 trigf(PG_FUNCTION_ARGS)
34 {
35     TriggerData *trigdata = (TriggerData *) fcinfo-&gt;context;
36     TupleDesc   tupdesc;
37     HeapTuple   rettuple;
38     char       *when;
39     bool        checknull = false;
40     bool        isnull;
41     int         ret, i;
42
43     /* make sure it's called as a trigger at all */
44     if (!CALLED_AS_TRIGGER(fcinfo))
45         elog(ERROR, "trigf: not called by trigger manager");
46
47     /* tuple to return to executor */
48     if (TRIGGER_FIRED_BY_UPDATE(trigdata-&gt;tg_event))
49         rettuple = trigdata-&gt;tg_newtuple;
50     else
51         rettuple = trigdata-&gt;tg_trigtuple;
52
53     /* check for null values */
54     if (!TRIGGER_FIRED_BY_DELETE(trigdata-&gt;tg_event)
55         &amp;&amp; TRIGGER_FIRED_BEFORE(trigdata-&gt;tg_event))
56         checknull = true;
57
58     if (TRIGGER_FIRED_BEFORE(trigdata-&gt;tg_event))
59         when = "before";
60     else
61         when = "after ";
62
63     tupdesc = trigdata-&gt;tg_relation-&gt;rd_att;
64
65     /* connect to SPI manager */
66     SPI_connect();
67
68     /* get number of rows in table */
69     ret = SPI_exec("SELECT count(*) FROM ttest", 0);
70
71     if (ret &lt; 0)
72         elog(ERROR, "trigf (fired %s): SPI_exec returned %d", when, ret);
73
74     /* count(*) returns int8, so be careful to convert */
75     i = DatumGetInt64(SPI_getbinval(SPI_tuptable-&gt;vals[0],
76                                     SPI_tuptable-&gt;tupdesc,
77                                     1,
78                                     &amp;isnull));
79
80     elog (INFO, "trigf (fired %s): there are %d rows in ttest", when, i);
81
82     SPI_finish();
83
84     if (checknull)
85     {
86         SPI_getbinval(rettuple, tupdesc, 1, &amp;isnull);
87         if (isnull)
88             rettuple = NULL;
89     }
90
91     return PointerGetDatum(rettuple);
92 }
93
94 </pre><p>
95    </p><p>
96     After you have compiled the source code (see <a class="xref" href="xfunc-c.html#DFUNC" title="36.10.5. Compiling and Linking Dynamically-Loaded Functions">Section 36.10.5</a>), declare the function and the triggers:
97 </p><pre class="programlisting">
98 CREATE FUNCTION trigf() RETURNS trigger
99     AS '<em class="replaceable"><code>filename</code></em>'
100     LANGUAGE C;
101
102 CREATE TRIGGER tbefore BEFORE INSERT OR UPDATE OR DELETE ON ttest
103     FOR EACH ROW EXECUTE FUNCTION trigf();
104
105 CREATE TRIGGER tafter AFTER INSERT OR UPDATE OR DELETE ON ttest
106     FOR EACH ROW EXECUTE FUNCTION trigf();
107 </pre><p>
108    </p><p>
109     Now you can test the operation of the trigger:
110 </p><pre class="screen">
111 =&gt; INSERT INTO ttest VALUES (NULL);
112 INFO:  trigf (fired before): there are 0 rows in ttest
113 INSERT 0 0
114
115 -- Insertion skipped and AFTER trigger is not fired
116
117 =&gt; SELECT * FROM ttest;
118  x
119 ---
120 (0 rows)
121
122 =&gt; INSERT INTO ttest VALUES (1);
123 INFO:  trigf (fired before): there are 0 rows in ttest
124 INFO:  trigf (fired after ): there are 1 rows in ttest
125                                        ^^^^^^^^
126                              remember what we said about visibility.
127 INSERT 167793 1
128 vac=&gt; SELECT * FROM ttest;
129  x
130 ---
131  1
132 (1 row)
133
134 =&gt; INSERT INTO ttest SELECT x * 2 FROM ttest;
135 INFO:  trigf (fired before): there are 1 rows in ttest
136 INFO:  trigf (fired after ): there are 2 rows in ttest
137                                        ^^^^^^
138                              remember what we said about visibility.
139 INSERT 167794 1
140 =&gt; SELECT * FROM ttest;
141  x
142 ---
143  1
144  2
145 (2 rows)
146
147 =&gt; UPDATE ttest SET x = NULL WHERE x = 2;
148 INFO:  trigf (fired before): there are 2 rows in ttest
149 UPDATE 0
150 =&gt; UPDATE ttest SET x = 4 WHERE x = 2;
151 INFO:  trigf (fired before): there are 2 rows in ttest
152 INFO:  trigf (fired after ): there are 2 rows in ttest
153 UPDATE 1
154 vac=&gt; SELECT * FROM ttest;
155  x
156 ---
157  1
158  4
159 (2 rows)
160
161 =&gt; DELETE FROM ttest;
162 INFO:  trigf (fired before): there are 2 rows in ttest
163 INFO:  trigf (fired before): there are 1 rows in ttest
164 INFO:  trigf (fired after ): there are 0 rows in ttest
165 INFO:  trigf (fired after ): there are 0 rows in ttest
166                                        ^^^^^^
167                              remember what we said about visibility.
168 DELETE 2
169 =&gt; SELECT * FROM ttest;
170  x
171 ---
172 (0 rows)
173 </pre><p>
174
175    </p><p>
176     There are more complex examples in
177     <code class="filename">src/test/regress/regress.c</code> and
178     in <a class="xref" href="contrib-spi.html" title="F.41. spi — Server Programming Interface features/examples">spi</a>.
179    </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="trigger-interface.html" title="37.3. Writing Trigger Functions in C">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="triggers.html" title="Chapter 37. Triggers">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="event-triggers.html" title="Chapter 38. Event Triggers">Next</a></td></tr><tr><td width="40%" align="left" valign="top">37.3. Writing Trigger Functions in C </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="40%" align="right" valign="top"> Chapter 38. Event Triggers</td></tr></table></div></body></html>