2 37.4. A Complete Trigger Example #
4 Here is a very simple example of a trigger function written in C.
5 (Examples of triggers written in procedural languages can be found in
6 the documentation of the procedural languages.)
8 The function trigf reports the number of rows in the table ttest and
9 skips the actual operation if the command attempts to insert a null
10 value into the column x. (So the trigger acts as a not-null constraint
11 but doesn't abort the transaction.)
13 First, the table definition:
18 This is the source code of the trigger function:
21 #include "executor/spi.h" /* this is what you need to work with SPI */
22 #include "commands/trigger.h" /* ... triggers ... */
23 #include "utils/rel.h" /* ... and relations */
27 PG_FUNCTION_INFO_V1(trigf);
30 trigf(PG_FUNCTION_ARGS)
32 TriggerData *trigdata = (TriggerData *) fcinfo->context;
36 bool checknull = false;
40 /* make sure it's called as a trigger at all */
41 if (!CALLED_AS_TRIGGER(fcinfo))
42 elog(ERROR, "trigf: not called by trigger manager");
44 /* tuple to return to executor */
45 if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
46 rettuple = trigdata->tg_newtuple;
48 rettuple = trigdata->tg_trigtuple;
50 /* check for null values */
51 if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)
52 && TRIGGER_FIRED_BEFORE(trigdata->tg_event))
55 if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
60 tupdesc = trigdata->tg_relation->rd_att;
62 /* connect to SPI manager */
65 /* get number of rows in table */
66 ret = SPI_exec("SELECT count(*) FROM ttest", 0);
69 elog(ERROR, "trigf (fired %s): SPI_exec returned %d", when, ret);
71 /* count(*) returns int8, so be careful to convert */
72 i = DatumGetInt64(SPI_getbinval(SPI_tuptable->vals[0],
73 SPI_tuptable->tupdesc,
77 elog (INFO, "trigf (fired %s): there are %d rows in ttest", when, i);
83 SPI_getbinval(rettuple, tupdesc, 1, &isnull);
88 return PointerGetDatum(rettuple);
92 After you have compiled the source code (see Section 36.10.5), declare
93 the function and the triggers:
94 CREATE FUNCTION trigf() RETURNS trigger
98 CREATE TRIGGER tbefore BEFORE INSERT OR UPDATE OR DELETE ON ttest
99 FOR EACH ROW EXECUTE FUNCTION trigf();
101 CREATE TRIGGER tafter AFTER INSERT OR UPDATE OR DELETE ON ttest
102 FOR EACH ROW EXECUTE FUNCTION trigf();
104 Now you can test the operation of the trigger:
105 => INSERT INTO ttest VALUES (NULL);
106 INFO: trigf (fired before): there are 0 rows in ttest
109 -- Insertion skipped and AFTER trigger is not fired
111 => SELECT * FROM ttest;
116 => INSERT INTO ttest VALUES (1);
117 INFO: trigf (fired before): there are 0 rows in ttest
118 INFO: trigf (fired after ): there are 1 rows in ttest
120 remember what we said about visibility.
122 vac=> SELECT * FROM ttest;
128 => INSERT INTO ttest SELECT x * 2 FROM ttest;
129 INFO: trigf (fired before): there are 1 rows in ttest
130 INFO: trigf (fired after ): there are 2 rows in ttest
132 remember what we said about visibility.
134 => SELECT * FROM ttest;
141 => UPDATE ttest SET x = NULL WHERE x = 2;
142 INFO: trigf (fired before): there are 2 rows in ttest
144 => UPDATE ttest SET x = 4 WHERE x = 2;
145 INFO: trigf (fired before): there are 2 rows in ttest
146 INFO: trigf (fired after ): there are 2 rows in ttest
148 vac=> SELECT * FROM ttest;
155 => DELETE FROM ttest;
156 INFO: trigf (fired before): there are 2 rows in ttest
157 INFO: trigf (fired before): there are 1 rows in ttest
158 INFO: trigf (fired after ): there are 0 rows in ttest
159 INFO: trigf (fired after ): there are 0 rows in ttest
161 remember what we said about visibility.
163 => SELECT * FROM ttest;
168 There are more complex examples in src/test/regress/regress.c and in