Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1b7f3cc

Browse files
committed
This patch implements FOR EACH STATEMENT triggers, per my email to
-hackers a couple days ago. Notes/caveats: - added regression tests for the new functionality, all regression tests pass on my machine - added pg_dump support - updated PL/PgSQL to support per-statement triggers; didn't look at the other procedural languages. - there's (even) more code duplication in trigger.c than there was previously. Any suggestions on how to refactor the ExecXXXTriggers() functions to reuse more code would be welcome -- I took a brief look at it, but couldn't see an easy way to do it (there are several subtly-different versions of the code in question) - updated the documentation. I also took the liberty of removing a big chunk of duplicated syntax documentation in the Programmer's Guide on triggers, and moving that information to the CREATE TRIGGER reference page. - I also included some spelling fixes and similar small cleanups I noticed while making the changes. If you'd like me to split those into a separate patch, let me know. Neil Conway
1 parent ea29b32 commit 1b7f3cc

File tree

24 files changed

+702
-411
lines changed

24 files changed

+702
-411
lines changed

doc/src/sgml/plpgsql.sgml

Lines changed: 55 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v 1.11 2002/11/15 03:22:30 momjian Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v 1.12 2002/11/23 03:59:05 momjian Exp $
33
-->
44

55
<chapter id="plpgsql">
@@ -674,24 +674,25 @@ RENAME this_var TO that_var;
674674
<title>Expressions</title>
675675

676676
<para>
677-
All expressions used in <application>PL/pgSQL</application> statements
678-
are processed using the server's regular SQL executor. Expressions that
679-
appear to contain
680-
constants may in fact require run-time evaluation
681-
(e.g. <literal>'now'</literal> for the
682-
<type>timestamp</type> type) so
683-
it is impossible for the <application>PL/pgSQL</application> parser
684-
to identify real constant values other than the NULL keyword. All
685-
expressions are evaluated internally by executing a query
677+
All expressions used in <application>PL/pgSQL</application>
678+
statements are processed using the server's regular
679+
<acronym>SQL</acronym> executor. Expressions that appear to
680+
contain constants may in fact require run-time evaluation
681+
(e.g. <literal>'now'</literal> for the <type>timestamp</type>
682+
type) so it is impossible for the
683+
<application>PL/pgSQL</application> parser to identify real
684+
constant values other than the NULL keyword. All expressions are
685+
evaluated internally by executing a query
686686
<synopsis>
687687
SELECT <replaceable>expression</replaceable>
688688
</synopsis>
689-
using the <acronym>SPI</acronym> manager. In the expression, occurrences
690-
of <application>PL/pgSQL</application> variable
689+
using the <acronym>SPI</acronym> manager. In the expression,
690+
occurrences of <application>PL/pgSQL</application> variable
691691
identifiers are replaced by parameters and the actual values from
692692
the variables are passed to the executor in the parameter array.
693-
This allows the query plan for the SELECT to be prepared just once
694-
and then re-used for subsequent evaluations.
693+
This allows the query plan for the <command>SELECT</command> to
694+
be prepared just once and then re-used for subsequent
695+
evaluations.
695696
</para>
696697

697698
<para>
@@ -1100,41 +1101,43 @@ GET DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replace
11001101
<itemizedlist>
11011102
<listitem>
11021103
<para>
1103-
A SELECT INTO statement sets <literal>FOUND</literal>
1104-
true if it returns a row, false if no row is returned.
1104+
A <command>SELECT INTO</command> statement sets
1105+
<literal>FOUND</literal> true if it returns a row, false if no
1106+
row is returned.
11051107
</para>
11061108
</listitem>
11071109
<listitem>
11081110
<para>
1109-
A PERFORM statement sets <literal>FOUND</literal>
1111+
A <command>PERFORM</> statement sets <literal>FOUND</literal>
11101112
true if it produces (discards) a row, false if no row is
11111113
produced.
11121114
</para>
11131115
</listitem>
11141116
<listitem>
11151117
<para>
1116-
UPDATE, INSERT, and DELETE statements set
1117-
<literal>FOUND</literal> true if at least one row is
1118-
affected, false if no row is affected.
1118+
<command>UPDATE</>, <command>INSERT</>, and <command>DELETE</>
1119+
statements set <literal>FOUND</literal> true if at least one
1120+
row is affected, false if no row is affected.
11191121
</para>
11201122
</listitem>
11211123
<listitem>
11221124
<para>
1123-
A FETCH statement sets <literal>FOUND</literal>
1125+
A <command>FETCH</> statement sets <literal>FOUND</literal>
11241126
true if it returns a row, false if no row is returned.
11251127
</para>
11261128
</listitem>
11271129
<listitem>
11281130
<para>
1129-
A FOR statement sets <literal>FOUND</literal>
1130-
true if it iterates one or more times, else false.
1131-
This applies to all three variants of the FOR statement
1132-
(integer FOR loops, record-set FOR loops, and dynamic
1133-
record-set FOR loops). <literal>FOUND</literal> is only set
1134-
when the FOR loop exits: inside the execution of the loop,
1135-
<literal>FOUND</literal> is not modified by the FOR statement,
1136-
although it may be changed by the execution of other
1137-
statements within the loop body.
1131+
A <command>FOR</> statement sets <literal>FOUND</literal> true
1132+
if it iterates one or more times, else false. This applies to
1133+
all three variants of the <command>FOR</> statement (integer
1134+
<command>FOR</> loops, record-set <command>FOR</> loops, and
1135+
dynamic record-set <command>FOR</>
1136+
loops). <literal>FOUND</literal> is only set when the
1137+
<command>FOR</> loop exits: inside the execution of the loop,
1138+
<literal>FOUND</literal> is not modified by the
1139+
<command>FOR</> statement, although it may be changed by the
1140+
execution of other statements within the loop body.
11381141
</para>
11391142
</listitem>
11401143
</itemizedlist>
@@ -1975,7 +1978,7 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
19751978
<application>PL/pgSQL</application> can be used to define trigger
19761979
procedures. A trigger procedure is created with the
19771980
<command>CREATE FUNCTION</> command as a function with no
1978-
arguments and a return type of <type>TRIGGER</type>. Note that
1981+
arguments and a return type of <type>trigger</type>. Note that
19791982
the function must be declared with no arguments even if it expects
19801983
to receive arguments specified in <command>CREATE TRIGGER</> ---
19811984
trigger arguments are passed via <varname>TG_ARGV</>, as described
@@ -1992,8 +1995,9 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
19921995
<term><varname>NEW</varname></term>
19931996
<listitem>
19941997
<para>
1995-
Data type <type>RECORD</type>; variable holding the new database row for INSERT/UPDATE
1996-
operations in ROW level triggers.
1998+
Data type <type>RECORD</type>; variable holding the new
1999+
database row for INSERT/UPDATE operations in ROW level
2000+
triggers. This variable is NULL in STATEMENT level triggers.
19972001
</para>
19982002
</listitem>
19992003
</varlistentry>
@@ -2002,8 +2006,9 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
20022006
<term><varname>OLD</varname></term>
20032007
<listitem>
20042008
<para>
2005-
Data type <type>RECORD</type>; variable holding the old database row for UPDATE/DELETE
2006-
operations in ROW level triggers.
2009+
Data type <type>RECORD</type>; variable holding the old
2010+
database row for UPDATE/DELETE operations in ROW level
2011+
triggers. This variable is NULL in STATEMENT level triggers.
20072012
</para>
20082013
</listitem>
20092014
</varlistentry>
@@ -2098,22 +2103,23 @@ RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
20982103

20992104
<para>
21002105
A trigger function must return either NULL or a record/row value
2101-
having exactly the structure of the table the trigger was fired for.
2102-
Triggers fired BEFORE may return NULL to signal the trigger manager
2103-
to skip the rest of the operation for this row (ie, subsequent triggers
2104-
are not fired, and the INSERT/UPDATE/DELETE does not occur for this
2105-
row). If a non-NULL value is returned then the operation proceeds with
2106-
that row value. Note that returning a row value different from the
2107-
original value of NEW alters the row that will be inserted or updated.
2108-
It is possible to replace single values directly
2109-
in NEW and return that, or to build a complete new record/row to
2110-
return.
2106+
having exactly the structure of the table the trigger was fired
2107+
for. The return value of a BEFORE or AFTER STATEMENT level
2108+
trigger, or an AFTER ROW level trigger is ignored; it may as well
2109+
return NULL. However, any of these types of triggers can still
2110+
abort the entire trigger operation by raising an error.
21112111
</para>
21122112

21132113
<para>
2114-
The return value of a trigger fired AFTER is ignored; it may as well
2115-
always return a NULL value. But an AFTER trigger can still abort the
2116-
operation by raising an error.
2114+
ROW level triggers fired BEFORE may return NULL to signal the
2115+
trigger manager to skip the rest of the operation for this row
2116+
(ie, subsequent triggers are not fired, and the
2117+
INSERT/UPDATE/DELETE does not occur for this row). If a non-NULL
2118+
value is returned then the operation proceeds with that row value.
2119+
Note that returning a row value different from the original value
2120+
of NEW alters the row that will be inserted or updated. It is
2121+
possible to replace single values directly in NEW and return that,
2122+
or to build a complete new record/row to return.
21172123
</para>
21182124

21192125
<example>
@@ -2143,7 +2149,7 @@ CREATE FUNCTION emp_stamp () RETURNS TRIGGER AS '
21432149
RAISE EXCEPTION ''% cannot have NULL salary'', NEW.empname;
21442150
END IF;
21452151

2146-
-- Who works for us when she must pay for?
2152+
-- Who works for us when she must pay for it?
21472153
IF NEW.salary < 0 THEN
21482154
RAISE EXCEPTION ''% cannot have a negative salary'', NEW.empname;
21492155
END IF;

doc/src/sgml/ref/alter_trigger.sgml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ ALTER TRIGGER emp_stamp ON emp RENAME TO emp_track_chgs;
153153
</refsect2info>
154154
<title>SQL92</title>
155155
<para>
156-
The clause to rename triggers is a
157-
<productname>PostgreSQL</productname> extension from SQL92.
156+
<command>ALTER TRIGGER</command> is a <productname>PostgreSQL</>
157+
extension of SQL92.
158158
</para>
159159
</refsect2>
160160
</refsect1>

doc/src/sgml/ref/create_trigger.sgml

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_trigger.sgml,v 1.29 2002/11/21 23:34:43 petere Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_trigger.sgml,v 1.30 2002/11/23 03:59:06 momjian Exp $
33
PostgreSQL documentation
44
-->
55

@@ -21,8 +21,9 @@ PostgreSQL documentation
2121
<date>2000-03-25</date>
2222
</refsynopsisdivinfo>
2323
<synopsis>
24-
CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTER } { <replaceable class="PARAMETER">event</replaceable> [OR ...] }
25-
ON <replaceable class="PARAMETER">table</replaceable> FOR EACH { ROW | STATEMENT }
24+
CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> {
25+
BEFORE | AFTER } { <replaceable class="PARAMETER">event</replaceable> [ OR ... ] }
26+
ON <replaceable class="PARAMETER">table</replaceable> [ FOR EACH { ROW | STATEMENT } ]
2627
EXECUTE PROCEDURE <replaceable class="PARAMETER">func</replaceable> ( <replaceable class="PARAMETER">arguments</replaceable> )
2728
</synopsis>
2829

@@ -45,22 +46,53 @@ CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTE
4546
</para>
4647
</listitem>
4748
</varlistentry>
49+
50+
<varlistentry>
51+
<term>BEFORE</term>
52+
<term>AFTER</term>
53+
<listitem>
54+
<para>
55+
Determines whether the function is called before or after the
56+
event.
57+
</para>
58+
</listitem>
59+
</varlistentry>
60+
4861
<varlistentry>
4962
<term><replaceable class="parameter">event</replaceable></term>
5063
<listitem>
5164
<para>
52-
One of INSERT, DELETE or UPDATE.
65+
One of <command>INSERT</command>, <command>DELETE</command> or
66+
<command>UPDATE</command>; this specifies the event that will
67+
fire the trigger. Multiple events can be specified using
68+
<literal>OR</literal>.
5369
</para>
5470
</listitem>
5571
</varlistentry>
5672
<varlistentry>
5773
<term><replaceable class="parameter">table</replaceable></term>
5874
<listitem>
5975
<para>
60-
The name (optionally schema-qualified) of the table the trigger is for.
76+
The name (optionally schema-qualified) of the table the
77+
trigger is for.
6178
</para>
6279
</listitem>
6380
</varlistentry>
81+
82+
<varlistentry>
83+
<term>FOR EACH ROW</term>
84+
<term>FOR EACH STATEMENT</term>
85+
86+
<listitem>
87+
<para>
88+
This specifies whether the trigger procedure should be fired
89+
once for every row affected by the trigger event, or just once
90+
per SQL statement. If neither is specified, <literal>FOR EACH
91+
STATEMENT</literal> is the default.
92+
</para>
93+
</listitem>
94+
</varlistentry>
95+
6496
<varlistentry>
6597
<term><replaceable class="parameter">func</replaceable></term>
6698
<listitem>
@@ -74,11 +106,15 @@ CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTE
74106
<term><replaceable class="parameter">arguments</replaceable></term>
75107
<listitem>
76108
<para>
77-
An optional comma-separated list of arguments to be provided to the
78-
function when the trigger is executed, along with the standard trigger
79-
data such as old and new tuple contents. The arguments are literal
80-
string constants. Simple names and numeric constants may be written
81-
here too, but they will all be converted to strings.
109+
An optional comma-separated list of arguments to be provided to
110+
the function when the trigger is executed, along with the standard
111+
trigger data such as old and new tuple contents. The arguments
112+
are literal string constants. Simple names and numeric constants
113+
may be written here too, but they will all be converted to
114+
strings. Note that these arguments are not provided as normal
115+
function parameters (since a trigger procedure must be declared to
116+
take zero parameters), but are instead accessed through the
117+
<literal>TG_ARGV</literal> array.
82118
</para>
83119
</listitem>
84120
</varlistentry>
@@ -121,7 +157,7 @@ CREATE TRIGGER
121157

122158
<para>
123159
<command>CREATE TRIGGER</command> will enter a new trigger into the current
124-
data base. The trigger will be associated with the relation
160+
database. The trigger will be associated with the relation
125161
<replaceable class="parameter">table</replaceable> and will execute
126162
the specified function <replaceable class="parameter">func</replaceable>.
127163
</para>
@@ -141,15 +177,27 @@ CREATE TRIGGER
141177
or deletion, are <quote>visible</quote> to the trigger.
142178
</para>
143179

180+
<para>
181+
A trigger that executes <literal>FOR EACH ROW</literal> of the
182+
specified operation is called once for every row that the operation
183+
modifies. For example, a <command>DELETE</command> that affects 10
184+
rows will cause any <literal>ON DELETE</literal> triggers on the
185+
target relation to be called 10 separate times, once for each
186+
deleted tuple. In contrast, a trigger that executes <literal>FOR
187+
EACH STATEMENT</literal> of the specified operation only executes
188+
once for any given operation, regardless of how many rows it
189+
modifies.
190+
</para>
191+
144192
<para>
145193
If multiple triggers of the same kind are defined for the same event,
146194
they will be fired in alphabetical order by name.
147195
</para>
148196

149197
<para>
150-
<command>SELECT</command> does not modify any rows so you can not
151-
create <command>SELECT</command> triggers. Rules and views are more
152-
appropriate in such cases.
198+
<command>SELECT</command> does not modify any rows so you can not
199+
create <command>SELECT</command> triggers. Rules and views are more
200+
appropriate in such cases.
153201
</para>
154202

155203
<para>
@@ -176,10 +224,6 @@ CREATE TRIGGER
176224
change the function's declared return type to <type>trigger</>.
177225
</para>
178226

179-
<para>
180-
As of the current release, <literal>STATEMENT</literal> triggers are not implemented.
181-
</para>
182-
183227
<para>
184228
Refer to the <xref linkend="sql-droptrigger" endterm="sql-droptrigger-title"> command for
185229
information on how to remove triggers.
@@ -268,13 +312,6 @@ CREATE TABLE distributors (
268312
</para>
269313
</listitem>
270314

271-
<listitem>
272-
<para>
273-
<productname>PostgreSQL</productname> only has row-level
274-
triggers, no statement-level triggers.
275-
</para>
276-
</listitem>
277-
278315
<listitem>
279316
<para>
280317
<productname>PostgreSQL</productname> only allows the

doc/src/sgml/release.sgml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.166 2002/11/23 02:41:03 tgl Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.167 2002/11/23 03:59:06 momjian Exp $
33
-->
44

55
<appendix id="release">
@@ -4619,7 +4619,7 @@ Enhancements
46194619
* pg_dump now output the schema and/or the data, with many fixes to
46204620
enhance completeness.
46214621
* psql used in place of monitor in administration shell scripts.
4622-
monitor to be depreciated in next release.
4622+
monitor to be deprecated in next release.
46234623
* date/time functions enhanced
46244624
* NULL insert/update/comparison fixed/enhanced
46254625
* TCL/TK lib and shell fixed to work with both tck7.4/tk4.0 and tcl7.5/tk4.1

0 commit comments

Comments
 (0)