Support statement-level ON TRUNCATE triggers. Simon Riggs
This commit is contained in:
parent
107b3d0c23
commit
7692d8d5b7
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/plperl.sgml,v 2.67 2008/01/25 15:28:35 adunstan Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/plperl.sgml,v 2.68 2008/03/28 00:21:55 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="plperl">
|
<chapter id="plperl">
|
||||||
<title>PL/Perl - Perl Procedural Language</title>
|
<title>PL/Perl - Perl Procedural Language</title>
|
||||||
@ -17,12 +17,14 @@
|
|||||||
<ulink url="http://www.perl.com">Perl programming language</ulink>.
|
<ulink url="http://www.perl.com">Perl programming language</ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para> The usual advantage to using PL/Perl is that this allows use,
|
<para>
|
||||||
|
The main advantage to using PL/Perl is that this allows use,
|
||||||
within stored functions, of the manyfold <quote>string
|
within stored functions, of the manyfold <quote>string
|
||||||
munging</quote> operators and functions available for Perl. Parsing
|
munging</quote> operators and functions available for Perl. Parsing
|
||||||
complex strings might be easier using Perl than it is with the
|
complex strings might be easier using Perl than it is with the
|
||||||
string functions and control structures provided in PL/pgSQL.</para>
|
string functions and control structures provided in PL/pgSQL.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
To install PL/Perl in a particular database, use
|
To install PL/Perl in a particular database, use
|
||||||
<literal>createlang plperl <replaceable>dbname</></literal>.
|
<literal>createlang plperl <replaceable>dbname</></literal>.
|
||||||
@ -739,7 +741,8 @@ $$ LANGUAGE plperl;
|
|||||||
<term><literal>$_TD->{event}</literal></term>
|
<term><literal>$_TD->{event}</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Trigger event: <literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>, or <literal>UNKNOWN</>
|
Trigger event: <literal>INSERT</>, <literal>UPDATE</>,
|
||||||
|
<literal>DELETE</>, <literal>TRUNCATE</>, or <literal>UNKNOWN</>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -822,14 +825,14 @@ $$ LANGUAGE plperl;
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Triggers can return one of the following:
|
Row-level triggers can return one of the following:
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>return;</literal></term>
|
<term><literal>return;</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Execute the statement
|
Execute the operation
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -838,7 +841,7 @@ $$ LANGUAGE plperl;
|
|||||||
<term><literal>"SKIP"</literal></term>
|
<term><literal>"SKIP"</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Don't execute the statement
|
Don't execute the operation
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.124 2008/03/23 00:24:19 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.125 2008/03/28 00:21:55 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="plpgsql">
|
<chapter id="plpgsql">
|
||||||
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
|
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
|
||||||
@ -2785,9 +2785,9 @@ RAISE EXCEPTION 'Nonexistent ID --> %', user_id;
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Data type <type>text</type>; a string of
|
Data type <type>text</type>; a string of
|
||||||
<literal>INSERT</literal>, <literal>UPDATE</literal>, or
|
<literal>INSERT</literal>, <literal>UPDATE</literal>,
|
||||||
<literal>DELETE</literal> telling for which operation the
|
<literal>DELETE</literal>, or <literal>TRUNCATE</>
|
||||||
trigger was fired.
|
telling for which operation the trigger was fired.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.38 2007/02/01 00:28:17 momjian Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.39 2008/03/28 00:21:55 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="plpython">
|
<chapter id="plpython">
|
||||||
<title>PL/Python - Python Procedural Language</title>
|
<title>PL/Python - Python Procedural Language</title>
|
||||||
@ -381,31 +381,34 @@ $$ LANGUAGE plpythonu;
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
When a function is used as a trigger, the dictionary
|
When a function is used as a trigger, the dictionary
|
||||||
<literal>TD</literal> contains trigger-related values. The trigger
|
<literal>TD</literal> contains trigger-related values.
|
||||||
rows are in <literal>TD["new"]</> and/or <literal>TD["old"]</>
|
<literal>TD["event"]</> contains
|
||||||
depending on the trigger event. <literal>TD["event"]</> contains
|
|
||||||
the event as a string (<literal>INSERT</>, <literal>UPDATE</>,
|
the event as a string (<literal>INSERT</>, <literal>UPDATE</>,
|
||||||
<literal>DELETE</>, or <literal>UNKNOWN</>).
|
<literal>DELETE</>, <literal>TRUNCATE</>, or <literal>UNKNOWN</>).
|
||||||
<literal>TD["when"]</> contains one of <literal>BEFORE</>,
|
<literal>TD["when"]</> contains one of <literal>BEFORE</>,
|
||||||
<literal>AFTER</>, and <literal>UNKNOWN</>.
|
<literal>AFTER</>, or <literal>UNKNOWN</>.
|
||||||
<literal>TD["level"]</> contains one of <literal>ROW</>,
|
<literal>TD["level"]</> contains one of <literal>ROW</>,
|
||||||
<literal>STATEMENT</>, and <literal>UNKNOWN</>.
|
<literal>STATEMENT</>, or <literal>UNKNOWN</>.
|
||||||
|
For a row-level trigger, the trigger
|
||||||
|
rows are in <literal>TD["new"]</> and/or <literal>TD["old"]</>
|
||||||
|
depending on the trigger event.
|
||||||
<literal>TD["name"]</> contains the trigger name,
|
<literal>TD["name"]</> contains the trigger name,
|
||||||
<literal>TD["table_name"]</> contains the name of the table on which the trigger occurred,
|
<literal>TD["table_name"]</> contains the name of the table on which the trigger occurred,
|
||||||
<literal>TD["table_schema"]</> contains the schema of the table on which the trigger occurred,
|
<literal>TD["table_schema"]</> contains the schema of the table on which the trigger occurred,
|
||||||
<literal>TD["name"]</> contains the trigger name, and
|
and <literal>TD["relid"]</> contains the OID of the table on
|
||||||
<literal>TD["relid"]</> contains the OID of the table on
|
|
||||||
which the trigger occurred. If the <command>CREATE TRIGGER</> command
|
which the trigger occurred. If the <command>CREATE TRIGGER</> command
|
||||||
included arguments, they are available in <literal>TD["args"][0]</> to
|
included arguments, they are available in <literal>TD["args"][0]</> to
|
||||||
<literal>TD["args"][(<replaceable>n</>-1)]</>.
|
<literal>TD["args"][<replaceable>n</>-1]</>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If <literal>TD["when"]</literal> is <literal>BEFORE</>, you can
|
If <literal>TD["when"]</literal> is <literal>BEFORE</> and
|
||||||
|
<literal>TD["level"]</literal> is <literal>ROW</>, you can
|
||||||
return <literal>None</literal> or <literal>"OK"</literal> from the
|
return <literal>None</literal> or <literal>"OK"</literal> from the
|
||||||
Python function to indicate the row is unmodified,
|
Python function to indicate the row is unmodified,
|
||||||
<literal>"SKIP"</> to abort the event, or <literal>"MODIFY"</> to
|
<literal>"SKIP"</> to abort the event, or <literal>"MODIFY"</> to
|
||||||
indicate you've modified the row.
|
indicate you've modified the row.
|
||||||
|
Otherwise the return value is ignored.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.47 2007/12/03 23:49:50 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.48 2008/03/28 00:21:55 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="pltcl">
|
<chapter id="pltcl">
|
||||||
<title>PL/Tcl - Tcl Procedural Language</title>
|
<title>PL/Tcl - Tcl Procedural Language</title>
|
||||||
@ -569,7 +569,7 @@ SELECT 'doesn''t' AS ret
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The string <literal>BEFORE</> or <literal>AFTER</> depending on the
|
The string <literal>BEFORE</> or <literal>AFTER</> depending on the
|
||||||
type of trigger call.
|
type of trigger event.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -579,7 +579,7 @@ SELECT 'doesn''t' AS ret
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The string <literal>ROW</> or <literal>STATEMENT</> depending on the
|
The string <literal>ROW</> or <literal>STATEMENT</> depending on the
|
||||||
type of trigger call.
|
type of trigger event.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -588,8 +588,9 @@ SELECT 'doesn''t' AS ret
|
|||||||
<term><varname>$TG_op</varname></term>
|
<term><varname>$TG_op</varname></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The string <literal>INSERT</>, <literal>UPDATE</>, or
|
The string <literal>INSERT</>, <literal>UPDATE</>,
|
||||||
<literal>DELETE</> depending on the type of trigger call.
|
<literal>DELETE</>, or <literal>TRUNCATE</> depending on the type of
|
||||||
|
trigger event.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -602,6 +603,7 @@ SELECT 'doesn''t' AS ret
|
|||||||
row for <command>INSERT</> or <command>UPDATE</> actions, or
|
row for <command>INSERT</> or <command>UPDATE</> actions, or
|
||||||
empty for <command>DELETE</>. The array is indexed by column
|
empty for <command>DELETE</>. The array is indexed by column
|
||||||
name. Columns that are null will not appear in the array.
|
name. Columns that are null will not appear in the array.
|
||||||
|
This is not set for statement-level triggers.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -614,6 +616,7 @@ SELECT 'doesn''t' AS ret
|
|||||||
row for <command>UPDATE</> or <command>DELETE</> actions, or
|
row for <command>UPDATE</> or <command>DELETE</> actions, or
|
||||||
empty for <command>INSERT</>. The array is indexed by column
|
empty for <command>INSERT</>. The array is indexed by column
|
||||||
name. Columns that are null will not appear in the array.
|
name. Columns that are null will not appear in the array.
|
||||||
|
This is not set for statement-level triggers.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -644,6 +647,7 @@ SELECT 'doesn''t' AS ret
|
|||||||
only.) Needless to say that all this is only meaningful when the trigger
|
only.) Needless to say that all this is only meaningful when the trigger
|
||||||
is <literal>BEFORE</> and <command>FOR EACH ROW</>; otherwise the return value is ignored.
|
is <literal>BEFORE</> and <command>FOR EACH ROW</>; otherwise the return value is ignored.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Here's a little example trigger procedure that forces an integer value
|
Here's a little example trigger procedure that forces an integer value
|
||||||
in a table to keep track of the number of updates that are performed on the
|
in a table to keep track of the number of updates that are performed on the
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/create_trigger.sgml,v 1.47 2007/02/01 19:10:24 momjian Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/create_trigger.sgml,v 1.48 2008/03/28 00:21:55 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTE
|
|||||||
EXECUTE PROCEDURE <replaceable class="PARAMETER">funcname</replaceable> ( <replaceable class="PARAMETER">arguments</replaceable> )
|
EXECUTE PROCEDURE <replaceable class="PARAMETER">funcname</replaceable> ( <replaceable class="PARAMETER">arguments</replaceable> )
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Description</title>
|
<title>Description</title>
|
||||||
|
|
||||||
@ -65,6 +65,12 @@ CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTE
|
|||||||
EACH STATEMENT</literal> triggers).
|
EACH STATEMENT</literal> triggers).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In addition, triggers may be defined to fire for a
|
||||||
|
<command>TRUNCATE</command>, though only
|
||||||
|
<literal>FOR EACH STATEMENT</literal>.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If multiple triggers of the same kind are defined for the same event,
|
If multiple triggers of the same kind are defined for the same event,
|
||||||
they will be fired in alphabetical order by name.
|
they will be fired in alphabetical order by name.
|
||||||
@ -80,7 +86,7 @@ CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTE
|
|||||||
Refer to <xref linkend="triggers"> for more information about triggers.
|
Refer to <xref linkend="triggers"> for more information about triggers.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Parameters</title>
|
<title>Parameters</title>
|
||||||
|
|
||||||
@ -110,10 +116,10 @@ CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTE
|
|||||||
<term><replaceable class="parameter">event</replaceable></term>
|
<term><replaceable class="parameter">event</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
One of <command>INSERT</command>, <command>UPDATE</command>, or
|
One of <command>INSERT</command>, <command>UPDATE</command>,
|
||||||
<command>DELETE</command>; this specifies the event that will
|
<command>DELETE</command>, or <command>TRUNCATE</command>;
|
||||||
fire the trigger. Multiple events can be specified using
|
this specifies the event that will fire the trigger. Multiple
|
||||||
<literal>OR</literal>.
|
events can be specified using <literal>OR</literal>.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -179,6 +185,11 @@ CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTE
|
|||||||
<literal>TRIGGER</literal> privilege on the table.
|
<literal>TRIGGER</literal> privilege on the table.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Use <xref linkend="sql-droptrigger"
|
||||||
|
endterm="sql-droptrigger-title"> to remove a trigger.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
In <productname>PostgreSQL</productname> versions before 7.3, it was
|
In <productname>PostgreSQL</productname> versions before 7.3, it was
|
||||||
necessary to declare trigger functions as returning the placeholder
|
necessary to declare trigger functions as returning the placeholder
|
||||||
@ -187,11 +198,6 @@ CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTE
|
|||||||
declared as returning <type>opaque</>, but it will issue a notice and
|
declared as returning <type>opaque</>, but it will issue a notice and
|
||||||
change the function's declared return type to <type>trigger</>.
|
change the function's declared return type to <type>trigger</>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
Use <xref linkend="sql-droptrigger"
|
|
||||||
endterm="sql-droptrigger-title"> to remove a trigger.
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1 id="R1-SQL-CREATETRIGGER-2">
|
<refsect1 id="R1-SQL-CREATETRIGGER-2">
|
||||||
@ -204,7 +210,7 @@ CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTE
|
|||||||
|
|
||||||
<refsect1 id="SQL-CREATETRIGGER-compatibility">
|
<refsect1 id="SQL-CREATETRIGGER-compatibility">
|
||||||
<title>Compatibility</title>
|
<title>Compatibility</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <command>CREATE TRIGGER</command> statement in
|
The <command>CREATE TRIGGER</command> statement in
|
||||||
<productname>PostgreSQL</productname> implements a subset of the
|
<productname>PostgreSQL</productname> implements a subset of the
|
||||||
@ -267,6 +273,12 @@ CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTE
|
|||||||
<literal>OR</literal> is a <productname>PostgreSQL</> extension of
|
<literal>OR</literal> is a <productname>PostgreSQL</> extension of
|
||||||
the SQL standard.
|
the SQL standard.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The ability to fire triggers for <command>TRUNCATE</command> is a
|
||||||
|
<productname>PostgreSQL</> extension of the SQL standard.
|
||||||
|
</para>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/truncate.sgml,v 1.24 2007/05/11 19:40:08 neilc Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/truncate.sgml,v 1.25 2008/03/28 00:21:55 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ C
|
|||||||
operation. This is most useful on large tables.
|
operation. This is most useful on large tables.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Parameters</title>
|
<title>Parameters</title>
|
||||||
|
|
||||||
@ -91,8 +91,16 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ C
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<command>TRUNCATE</> will not run any <literal>ON DELETE</literal>
|
<command>TRUNCATE</> will not fire any <literal>ON DELETE</literal>
|
||||||
triggers that might exist for the tables.
|
triggers that might exist for the tables. But it will fire
|
||||||
|
<literal>ON TRUNCATE</literal> triggers.
|
||||||
|
If <literal>ON TRUNCATE</> triggers are defined for any of
|
||||||
|
the tables, then all <literal>BEFORE TRUNCATE</literal> triggers are
|
||||||
|
fired before any truncation happens, and all <literal>AFTER
|
||||||
|
TRUNCATE</literal> triggers are fired after the last truncation is
|
||||||
|
performed. The triggers will fire in the order that the tables are
|
||||||
|
to be processed (first those listed in the command, and then any
|
||||||
|
that were added due to cascading).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<warning>
|
<warning>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/trigger.sgml,v 1.51 2007/12/03 23:49:51 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/trigger.sgml,v 1.52 2008/03/28 00:21:55 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="triggers">
|
<chapter id="triggers">
|
||||||
<title>Triggers</title>
|
<title>Triggers</title>
|
||||||
@ -36,14 +36,15 @@
|
|||||||
performed. Triggers can be defined to execute either before or after any
|
performed. Triggers can be defined to execute either before or after any
|
||||||
<command>INSERT</command>, <command>UPDATE</command>, or
|
<command>INSERT</command>, <command>UPDATE</command>, or
|
||||||
<command>DELETE</command> operation, either once per modified row,
|
<command>DELETE</command> operation, either once per modified row,
|
||||||
or once per <acronym>SQL</acronym> statement.
|
or once per <acronym>SQL</acronym> statement. Triggers can also fire
|
||||||
If a trigger event occurs, the trigger's function is called
|
for <command>TRUNCATE</command> statements. If a trigger event occurs,
|
||||||
at the appropriate time to handle the event.
|
the trigger's function is called at the appropriate time to handle the
|
||||||
|
event.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The trigger function must be defined before the trigger itself can be
|
The trigger function must be defined before the trigger itself can be
|
||||||
created. The trigger function must be declared as a
|
created. The trigger function must be declared as a
|
||||||
function taking no arguments and returning type <literal>trigger</>.
|
function taking no arguments and returning type <literal>trigger</>.
|
||||||
(The trigger function receives its input through a specially-passed
|
(The trigger function receives its input through a specially-passed
|
||||||
<structname>TriggerData</> structure, not in the form of ordinary function
|
<structname>TriggerData</> structure, not in the form of ordinary function
|
||||||
@ -69,7 +70,8 @@
|
|||||||
in the execution of any applicable per-statement triggers. These
|
in the execution of any applicable per-statement triggers. These
|
||||||
two types of triggers are sometimes called <firstterm>row-level</>
|
two types of triggers are sometimes called <firstterm>row-level</>
|
||||||
triggers and <firstterm>statement-level</> triggers,
|
triggers and <firstterm>statement-level</> triggers,
|
||||||
respectively.
|
respectively. Triggers on <command>TRUNCATE</command> may only be
|
||||||
|
defined at statement-level.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -398,6 +400,15 @@ typedef struct TriggerData
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>TRIGGER_FIRED_BY_TRUNCATE(tg_event)</literal></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Returns true if the trigger was fired by a <command>TRUNCATE</command> command.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
@ -630,10 +641,10 @@ CREATE FUNCTION trigf() RETURNS trigger
|
|||||||
AS '<replaceable>filename</>'
|
AS '<replaceable>filename</>'
|
||||||
LANGUAGE C;
|
LANGUAGE C;
|
||||||
|
|
||||||
CREATE TRIGGER tbefore BEFORE INSERT OR UPDATE OR DELETE ON ttest
|
CREATE TRIGGER tbefore BEFORE INSERT OR UPDATE OR DELETE ON ttest
|
||||||
FOR EACH ROW EXECUTE PROCEDURE trigf();
|
FOR EACH ROW EXECUTE PROCEDURE trigf();
|
||||||
|
|
||||||
CREATE TRIGGER tafter AFTER INSERT OR UPDATE OR DELETE ON ttest
|
CREATE TRIGGER tafter AFTER INSERT OR UPDATE OR DELETE ON ttest
|
||||||
FOR EACH ROW EXECUTE PROCEDURE trigf();
|
FOR EACH ROW EXECUTE PROCEDURE trigf();
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.248 2008/03/27 03:57:33 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.249 2008/03/28 00:21:55 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -539,6 +539,9 @@ ExecuteTruncate(TruncateStmt *stmt)
|
|||||||
{
|
{
|
||||||
List *rels = NIL;
|
List *rels = NIL;
|
||||||
List *relids = NIL;
|
List *relids = NIL;
|
||||||
|
EState *estate;
|
||||||
|
ResultRelInfo *resultRelInfos;
|
||||||
|
ResultRelInfo *resultRelInfo;
|
||||||
ListCell *cell;
|
ListCell *cell;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -601,6 +604,45 @@ ExecuteTruncate(TruncateStmt *stmt)
|
|||||||
heap_truncate_check_FKs(rels, false);
|
heap_truncate_check_FKs(rels, false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Prepare to catch AFTER triggers. */
|
||||||
|
AfterTriggerBeginQuery();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To fire triggers, we'll need an EState as well as a ResultRelInfo
|
||||||
|
* for each relation.
|
||||||
|
*/
|
||||||
|
estate = CreateExecutorState();
|
||||||
|
resultRelInfos = (ResultRelInfo *)
|
||||||
|
palloc(list_length(rels) * sizeof(ResultRelInfo));
|
||||||
|
resultRelInfo = resultRelInfos;
|
||||||
|
foreach(cell, rels)
|
||||||
|
{
|
||||||
|
Relation rel = (Relation) lfirst(cell);
|
||||||
|
|
||||||
|
InitResultRelInfo(resultRelInfo,
|
||||||
|
rel,
|
||||||
|
0, /* dummy rangetable index */
|
||||||
|
CMD_DELETE, /* don't need any index info */
|
||||||
|
false);
|
||||||
|
resultRelInfo++;
|
||||||
|
}
|
||||||
|
estate->es_result_relations = resultRelInfos;
|
||||||
|
estate->es_num_result_relations = list_length(rels);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process all BEFORE STATEMENT TRUNCATE triggers before we begin
|
||||||
|
* truncating (this is because one of them might throw an error).
|
||||||
|
* Also, if we were to allow them to prevent statement execution,
|
||||||
|
* that would need to be handled here.
|
||||||
|
*/
|
||||||
|
resultRelInfo = resultRelInfos;
|
||||||
|
foreach(cell, rels)
|
||||||
|
{
|
||||||
|
estate->es_result_relation_info = resultRelInfo;
|
||||||
|
ExecBSTruncateTriggers(estate, resultRelInfo);
|
||||||
|
resultRelInfo++;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OK, truncate each table.
|
* OK, truncate each table.
|
||||||
*/
|
*/
|
||||||
@ -637,6 +679,23 @@ ExecuteTruncate(TruncateStmt *stmt)
|
|||||||
*/
|
*/
|
||||||
reindex_relation(heap_relid, true);
|
reindex_relation(heap_relid, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process all AFTER STATEMENT TRUNCATE triggers.
|
||||||
|
*/
|
||||||
|
resultRelInfo = resultRelInfos;
|
||||||
|
foreach(cell, rels)
|
||||||
|
{
|
||||||
|
estate->es_result_relation_info = resultRelInfo;
|
||||||
|
ExecASTruncateTriggers(estate, resultRelInfo);
|
||||||
|
resultRelInfo++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle queued AFTER triggers */
|
||||||
|
AfterTriggerEndQuery(estate);
|
||||||
|
|
||||||
|
/* We can clean up the EState now */
|
||||||
|
FreeExecutorState(estate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.230 2008/03/26 21:10:38 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.231 2008/03/28 00:21:55 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -179,6 +179,18 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid)
|
|||||||
errmsg("multiple UPDATE events specified")));
|
errmsg("multiple UPDATE events specified")));
|
||||||
TRIGGER_SETT_UPDATE(tgtype);
|
TRIGGER_SETT_UPDATE(tgtype);
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
if (TRIGGER_FOR_TRUNCATE(tgtype))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
|
errmsg("multiple TRUNCATE events specified")));
|
||||||
|
TRIGGER_SETT_TRUNCATE(tgtype);
|
||||||
|
/* Disallow ROW-level TRUNCATE triggers */
|
||||||
|
if (stmt->row)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "unrecognized trigger event: %d",
|
elog(ERROR, "unrecognized trigger event: %d",
|
||||||
(int) stmt->actions[i]);
|
(int) stmt->actions[i]);
|
||||||
@ -1299,6 +1311,15 @@ InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
|
|||||||
(*tp)[n[TRIGGER_EVENT_UPDATE]] = indx;
|
(*tp)[n[TRIGGER_EVENT_UPDATE]] = indx;
|
||||||
(n[TRIGGER_EVENT_UPDATE])++;
|
(n[TRIGGER_EVENT_UPDATE])++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TRIGGER_FOR_TRUNCATE(trigger->tgtype))
|
||||||
|
{
|
||||||
|
tp = &(t[TRIGGER_EVENT_TRUNCATE]);
|
||||||
|
if (*tp == NULL)
|
||||||
|
*tp = (int *) palloc(trigdesc->numtriggers * sizeof(int));
|
||||||
|
(*tp)[n[TRIGGER_EVENT_TRUNCATE]] = indx;
|
||||||
|
(n[TRIGGER_EVENT_TRUNCATE])++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2030,6 +2051,75 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
|
||||||
|
{
|
||||||
|
TriggerDesc *trigdesc;
|
||||||
|
int ntrigs;
|
||||||
|
int *tgindx;
|
||||||
|
int i;
|
||||||
|
TriggerData LocTriggerData;
|
||||||
|
|
||||||
|
trigdesc = relinfo->ri_TrigDesc;
|
||||||
|
|
||||||
|
if (trigdesc == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_TRUNCATE];
|
||||||
|
tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_TRUNCATE];
|
||||||
|
|
||||||
|
if (ntrigs == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LocTriggerData.type = T_TriggerData;
|
||||||
|
LocTriggerData.tg_event = TRIGGER_EVENT_TRUNCATE |
|
||||||
|
TRIGGER_EVENT_BEFORE;
|
||||||
|
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
|
||||||
|
LocTriggerData.tg_trigtuple = NULL;
|
||||||
|
LocTriggerData.tg_newtuple = NULL;
|
||||||
|
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
|
||||||
|
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
|
||||||
|
for (i = 0; i < ntrigs; i++)
|
||||||
|
{
|
||||||
|
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
|
||||||
|
HeapTuple newtuple;
|
||||||
|
|
||||||
|
if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
|
||||||
|
{
|
||||||
|
if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
|
||||||
|
trigger->tgenabled == TRIGGER_DISABLED)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else /* ORIGIN or LOCAL role */
|
||||||
|
{
|
||||||
|
if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
|
||||||
|
trigger->tgenabled == TRIGGER_DISABLED)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LocTriggerData.tg_trigger = trigger;
|
||||||
|
newtuple = ExecCallTriggerFunc(&LocTriggerData,
|
||||||
|
tgindx[i],
|
||||||
|
relinfo->ri_TrigFunctions,
|
||||||
|
relinfo->ri_TrigInstrument,
|
||||||
|
GetPerTupleMemoryContext(estate));
|
||||||
|
|
||||||
|
if (newtuple)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
|
||||||
|
errmsg("BEFORE STATEMENT trigger cannot return a value")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
|
||||||
|
{
|
||||||
|
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
|
||||||
|
|
||||||
|
if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_TRUNCATE] > 0)
|
||||||
|
AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_TRUNCATE,
|
||||||
|
false, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static HeapTuple
|
static HeapTuple
|
||||||
GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
|
GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
|
||||||
@ -3571,6 +3661,12 @@ AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
|
|||||||
if (afterTriggers == NULL)
|
if (afterTriggers == NULL)
|
||||||
elog(ERROR, "AfterTriggerSaveEvent() called outside of transaction");
|
elog(ERROR, "AfterTriggerSaveEvent() called outside of transaction");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* event is used both as a bitmask and an array offset,
|
||||||
|
* so make sure we don't walk off the edge of our arrays
|
||||||
|
*/
|
||||||
|
Assert(event >= 0 && event < TRIGGER_NUM_EVENT_CLASSES);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the CTID's of OLD and NEW
|
* Get the CTID's of OLD and NEW
|
||||||
*/
|
*/
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.304 2008/03/26 21:10:38 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.305 2008/03/28 00:21:55 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -66,11 +66,6 @@ typedef struct evalPlanQual
|
|||||||
|
|
||||||
/* decls for local routines only used within this module */
|
/* decls for local routines only used within this module */
|
||||||
static void InitPlan(QueryDesc *queryDesc, int eflags);
|
static void InitPlan(QueryDesc *queryDesc, int eflags);
|
||||||
static void initResultRelInfo(ResultRelInfo *resultRelInfo,
|
|
||||||
Relation resultRelationDesc,
|
|
||||||
Index resultRelationIndex,
|
|
||||||
CmdType operation,
|
|
||||||
bool doInstrument);
|
|
||||||
static void ExecEndPlan(PlanState *planstate, EState *estate);
|
static void ExecEndPlan(PlanState *planstate, EState *estate);
|
||||||
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
|
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
|
||||||
CmdType operation,
|
CmdType operation,
|
||||||
@ -525,7 +520,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
|||||||
|
|
||||||
resultRelationOid = getrelid(resultRelationIndex, rangeTable);
|
resultRelationOid = getrelid(resultRelationIndex, rangeTable);
|
||||||
resultRelation = heap_open(resultRelationOid, RowExclusiveLock);
|
resultRelation = heap_open(resultRelationOid, RowExclusiveLock);
|
||||||
initResultRelInfo(resultRelInfo,
|
InitResultRelInfo(resultRelInfo,
|
||||||
resultRelation,
|
resultRelation,
|
||||||
resultRelationIndex,
|
resultRelationIndex,
|
||||||
operation,
|
operation,
|
||||||
@ -860,8 +855,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
|||||||
/*
|
/*
|
||||||
* Initialize ResultRelInfo data for one result relation
|
* Initialize ResultRelInfo data for one result relation
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
initResultRelInfo(ResultRelInfo *resultRelInfo,
|
InitResultRelInfo(ResultRelInfo *resultRelInfo,
|
||||||
Relation resultRelationDesc,
|
Relation resultRelationDesc,
|
||||||
Index resultRelationIndex,
|
Index resultRelationIndex,
|
||||||
CmdType operation,
|
CmdType operation,
|
||||||
@ -997,11 +992,11 @@ ExecGetTriggerResultRel(EState *estate, Oid relid)
|
|||||||
/*
|
/*
|
||||||
* Make the new entry in the right context. Currently, we don't need any
|
* Make the new entry in the right context. Currently, we don't need any
|
||||||
* index information in ResultRelInfos used only for triggers, so tell
|
* index information in ResultRelInfos used only for triggers, so tell
|
||||||
* initResultRelInfo it's a DELETE.
|
* InitResultRelInfo it's a DELETE.
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
||||||
rInfo = makeNode(ResultRelInfo);
|
rInfo = makeNode(ResultRelInfo);
|
||||||
initResultRelInfo(rInfo,
|
InitResultRelInfo(rInfo,
|
||||||
rel,
|
rel,
|
||||||
0, /* dummy rangetable index */
|
0, /* dummy rangetable index */
|
||||||
CMD_DELETE,
|
CMD_DELETE,
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.610 2008/03/21 22:41:48 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.611 2008/03/28 00:21:55 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -2719,6 +2719,7 @@ TriggerOneEvent:
|
|||||||
INSERT { $$ = 'i'; }
|
INSERT { $$ = 'i'; }
|
||||||
| DELETE_P { $$ = 'd'; }
|
| DELETE_P { $$ = 'd'; }
|
||||||
| UPDATE { $$ = 'u'; }
|
| UPDATE { $$ = 'u'; }
|
||||||
|
| TRUNCATE { $$ = 't'; }
|
||||||
;
|
;
|
||||||
|
|
||||||
TriggerForSpec:
|
TriggerForSpec:
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.271 2008/03/26 21:10:39 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.272 2008/03/28 00:21:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -499,6 +499,13 @@ pg_get_triggerdef(PG_FUNCTION_ARGS)
|
|||||||
else
|
else
|
||||||
appendStringInfo(&buf, " UPDATE");
|
appendStringInfo(&buf, " UPDATE");
|
||||||
}
|
}
|
||||||
|
if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
|
||||||
|
{
|
||||||
|
if (findx > 0)
|
||||||
|
appendStringInfo(&buf, " OR TRUNCATE");
|
||||||
|
else
|
||||||
|
appendStringInfo(&buf, " TRUNCATE");
|
||||||
|
}
|
||||||
appendStringInfo(&buf, " ON %s ",
|
appendStringInfo(&buf, " ON %s ",
|
||||||
generate_relation_name(trigrec->tgrelid));
|
generate_relation_name(trigrec->tgrelid));
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* by PostgreSQL
|
* by PostgreSQL
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.485 2008/03/27 03:57:33 tgl Exp $
|
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.486 2008/03/28 00:21:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -9631,6 +9631,13 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
|
|||||||
else
|
else
|
||||||
appendPQExpBuffer(query, " UPDATE");
|
appendPQExpBuffer(query, " UPDATE");
|
||||||
}
|
}
|
||||||
|
if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
|
||||||
|
{
|
||||||
|
if (findx > 0)
|
||||||
|
appendPQExpBuffer(query, " OR TRUNCATE");
|
||||||
|
else
|
||||||
|
appendPQExpBuffer(query, " TRUNCATE");
|
||||||
|
}
|
||||||
appendPQExpBuffer(query, " ON %s\n",
|
appendPQExpBuffer(query, " ON %s\n",
|
||||||
fmtId(tbinfo->dobj.name));
|
fmtId(tbinfo->dobj.name));
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_trigger.h,v 1.31 2008/03/27 03:57:34 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_trigger.h,v 1.32 2008/03/28 00:21:56 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
@ -89,6 +89,7 @@ typedef FormData_pg_trigger *Form_pg_trigger;
|
|||||||
#define TRIGGER_TYPE_INSERT (1 << 2)
|
#define TRIGGER_TYPE_INSERT (1 << 2)
|
||||||
#define TRIGGER_TYPE_DELETE (1 << 3)
|
#define TRIGGER_TYPE_DELETE (1 << 3)
|
||||||
#define TRIGGER_TYPE_UPDATE (1 << 4)
|
#define TRIGGER_TYPE_UPDATE (1 << 4)
|
||||||
|
#define TRIGGER_TYPE_TRUNCATE (1 << 5)
|
||||||
|
|
||||||
/* Macros for manipulating tgtype */
|
/* Macros for manipulating tgtype */
|
||||||
#define TRIGGER_CLEAR_TYPE(type) ((type) = 0)
|
#define TRIGGER_CLEAR_TYPE(type) ((type) = 0)
|
||||||
@ -98,11 +99,13 @@ typedef FormData_pg_trigger *Form_pg_trigger;
|
|||||||
#define TRIGGER_SETT_INSERT(type) ((type) |= TRIGGER_TYPE_INSERT)
|
#define TRIGGER_SETT_INSERT(type) ((type) |= TRIGGER_TYPE_INSERT)
|
||||||
#define TRIGGER_SETT_DELETE(type) ((type) |= TRIGGER_TYPE_DELETE)
|
#define TRIGGER_SETT_DELETE(type) ((type) |= TRIGGER_TYPE_DELETE)
|
||||||
#define TRIGGER_SETT_UPDATE(type) ((type) |= TRIGGER_TYPE_UPDATE)
|
#define TRIGGER_SETT_UPDATE(type) ((type) |= TRIGGER_TYPE_UPDATE)
|
||||||
|
#define TRIGGER_SETT_TRUNCATE(type) ((type) |= TRIGGER_TYPE_TRUNCATE)
|
||||||
|
|
||||||
#define TRIGGER_FOR_ROW(type) ((type) & TRIGGER_TYPE_ROW)
|
#define TRIGGER_FOR_ROW(type) ((type) & TRIGGER_TYPE_ROW)
|
||||||
#define TRIGGER_FOR_BEFORE(type) ((type) & TRIGGER_TYPE_BEFORE)
|
#define TRIGGER_FOR_BEFORE(type) ((type) & TRIGGER_TYPE_BEFORE)
|
||||||
#define TRIGGER_FOR_INSERT(type) ((type) & TRIGGER_TYPE_INSERT)
|
#define TRIGGER_FOR_INSERT(type) ((type) & TRIGGER_TYPE_INSERT)
|
||||||
#define TRIGGER_FOR_DELETE(type) ((type) & TRIGGER_TYPE_DELETE)
|
#define TRIGGER_FOR_DELETE(type) ((type) & TRIGGER_TYPE_DELETE)
|
||||||
#define TRIGGER_FOR_UPDATE(type) ((type) & TRIGGER_TYPE_UPDATE)
|
#define TRIGGER_FOR_UPDATE(type) ((type) & TRIGGER_TYPE_UPDATE)
|
||||||
|
#define TRIGGER_FOR_TRUNCATE(type) ((type) & TRIGGER_TYPE_TRUNCATE)
|
||||||
|
|
||||||
#endif /* PG_TRIGGER_H */
|
#endif /* PG_TRIGGER_H */
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.66 2008/01/02 23:34:42 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.67 2008/03/28 00:21:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -38,11 +38,18 @@ typedef struct TriggerData
|
|||||||
Buffer tg_newtuplebuf;
|
Buffer tg_newtuplebuf;
|
||||||
} TriggerData;
|
} TriggerData;
|
||||||
|
|
||||||
/* TriggerEvent bit flags */
|
/*
|
||||||
|
* TriggerEvent bit flags
|
||||||
|
*
|
||||||
|
* Note that we assume different event types (INSERT/DELETE/UPDATE/TRUNCATE)
|
||||||
|
* can't be OR'd together in a single TriggerEvent. This is unlike the
|
||||||
|
* situation for pg_trigger rows, so pg_trigger.tgtype uses a different
|
||||||
|
* representation!
|
||||||
|
*/
|
||||||
#define TRIGGER_EVENT_INSERT 0x00000000
|
#define TRIGGER_EVENT_INSERT 0x00000000
|
||||||
#define TRIGGER_EVENT_DELETE 0x00000001
|
#define TRIGGER_EVENT_DELETE 0x00000001
|
||||||
#define TRIGGER_EVENT_UPDATE 0x00000002
|
#define TRIGGER_EVENT_UPDATE 0x00000002
|
||||||
|
#define TRIGGER_EVENT_TRUNCATE 0x00000003
|
||||||
#define TRIGGER_EVENT_OPMASK 0x00000003
|
#define TRIGGER_EVENT_OPMASK 0x00000003
|
||||||
#define TRIGGER_EVENT_ROW 0x00000004
|
#define TRIGGER_EVENT_ROW 0x00000004
|
||||||
#define TRIGGER_EVENT_BEFORE 0x00000008
|
#define TRIGGER_EVENT_BEFORE 0x00000008
|
||||||
@ -66,6 +73,10 @@ typedef struct TriggerData
|
|||||||
(((TriggerEvent) (event) & TRIGGER_EVENT_OPMASK) == \
|
(((TriggerEvent) (event) & TRIGGER_EVENT_OPMASK) == \
|
||||||
TRIGGER_EVENT_UPDATE)
|
TRIGGER_EVENT_UPDATE)
|
||||||
|
|
||||||
|
#define TRIGGER_FIRED_BY_TRUNCATE(event) \
|
||||||
|
(((TriggerEvent) (event) & TRIGGER_EVENT_OPMASK) == \
|
||||||
|
TRIGGER_EVENT_TRUNCATE)
|
||||||
|
|
||||||
#define TRIGGER_FIRED_FOR_ROW(event) \
|
#define TRIGGER_FIRED_FOR_ROW(event) \
|
||||||
((TriggerEvent) (event) & TRIGGER_EVENT_ROW)
|
((TriggerEvent) (event) & TRIGGER_EVENT_ROW)
|
||||||
|
|
||||||
@ -140,6 +151,10 @@ extern void ExecARUpdateTriggers(EState *estate,
|
|||||||
ResultRelInfo *relinfo,
|
ResultRelInfo *relinfo,
|
||||||
ItemPointer tupleid,
|
ItemPointer tupleid,
|
||||||
HeapTuple newtuple);
|
HeapTuple newtuple);
|
||||||
|
extern void ExecBSTruncateTriggers(EState *estate,
|
||||||
|
ResultRelInfo *relinfo);
|
||||||
|
extern void ExecASTruncateTriggers(EState *estate,
|
||||||
|
ResultRelInfo *relinfo);
|
||||||
|
|
||||||
extern void AfterTriggerBeginXact(void);
|
extern void AfterTriggerBeginXact(void);
|
||||||
extern void AfterTriggerBeginQuery(void);
|
extern void AfterTriggerBeginQuery(void);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.146 2008/01/01 19:45:57 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.147 2008/03/28 00:21:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -138,6 +138,11 @@ extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
|
|||||||
ScanDirection direction, long count);
|
ScanDirection direction, long count);
|
||||||
extern void ExecutorEnd(QueryDesc *queryDesc);
|
extern void ExecutorEnd(QueryDesc *queryDesc);
|
||||||
extern void ExecutorRewind(QueryDesc *queryDesc);
|
extern void ExecutorRewind(QueryDesc *queryDesc);
|
||||||
|
extern void InitResultRelInfo(ResultRelInfo *resultRelInfo,
|
||||||
|
Relation resultRelationDesc,
|
||||||
|
Index resultRelationIndex,
|
||||||
|
CmdType operation,
|
||||||
|
bool doInstrument);
|
||||||
extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);
|
extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);
|
||||||
extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
|
extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
|
||||||
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
|
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.104 2008/01/01 19:45:59 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.105 2008/03/28 00:21:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -71,9 +71,10 @@ typedef struct TriggerDesc
|
|||||||
/*
|
/*
|
||||||
* Index data to identify which triggers are which. Since each trigger
|
* Index data to identify which triggers are which. Since each trigger
|
||||||
* can appear in more than one class, for each class we provide a list of
|
* can appear in more than one class, for each class we provide a list of
|
||||||
* integer indexes into the triggers array.
|
* integer indexes into the triggers array. The class codes are defined
|
||||||
|
* by TRIGGER_EVENT_xxx macros in commands/trigger.h.
|
||||||
*/
|
*/
|
||||||
#define TRIGGER_NUM_EVENT_CLASSES 3
|
#define TRIGGER_NUM_EVENT_CLASSES 4
|
||||||
|
|
||||||
uint16 n_before_statement[TRIGGER_NUM_EVENT_CLASSES];
|
uint16 n_before_statement[TRIGGER_NUM_EVENT_CLASSES];
|
||||||
uint16 n_before_row[TRIGGER_NUM_EVENT_CLASSES];
|
uint16 n_before_row[TRIGGER_NUM_EVENT_CLASSES];
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* plperl.c - perl as a procedural language for PostgreSQL
|
* plperl.c - perl as a procedural language for PostgreSQL
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.138 2008/03/25 22:42:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.139 2008/03/28 00:21:56 tgl Exp $
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
@ -689,6 +689,8 @@ plperl_trigger_build_args(FunctionCallInfo fcinfo)
|
|||||||
tupdesc));
|
tupdesc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (TRIGGER_FIRED_BY_TRUNCATE(tdata->tg_event))
|
||||||
|
event = "TRUNCATE";
|
||||||
else
|
else
|
||||||
event = "UNKNOWN";
|
event = "UNKNOWN";
|
||||||
|
|
||||||
@ -1395,6 +1397,8 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
|
|||||||
retval = (Datum) trigdata->tg_newtuple;
|
retval = (Datum) trigdata->tg_newtuple;
|
||||||
else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
|
else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
|
||||||
retval = (Datum) trigdata->tg_trigtuple;
|
retval = (Datum) trigdata->tg_trigtuple;
|
||||||
|
else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event))
|
||||||
|
retval = (Datum) trigdata->tg_trigtuple;
|
||||||
else
|
else
|
||||||
retval = (Datum) 0; /* can this happen? */
|
retval = (Datum) 0; /* can this happen? */
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.206 2008/03/26 18:48:59 alvherre Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.207 2008/03/28 00:21:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -538,8 +538,10 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
|
|||||||
var->value = CStringGetTextDatum("UPDATE");
|
var->value = CStringGetTextDatum("UPDATE");
|
||||||
else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
|
else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
|
||||||
var->value = CStringGetTextDatum("DELETE");
|
var->value = CStringGetTextDatum("DELETE");
|
||||||
|
else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event))
|
||||||
|
var->value = CStringGetTextDatum("TRUNCATE");
|
||||||
else
|
else
|
||||||
elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, or UPDATE");
|
elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, UPDATE, or TRUNCATE");
|
||||||
var->isnull = false;
|
var->isnull = false;
|
||||||
var->freeval = true;
|
var->freeval = true;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* plpython.c - python as a procedural language for PostgreSQL
|
* plpython.c - python as a procedural language for PostgreSQL
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.107 2008/03/25 22:42:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.108 2008/03/28 00:21:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*********************************************************************
|
*********************************************************************
|
||||||
*/
|
*/
|
||||||
@ -714,6 +714,8 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc, HeapTuple *
|
|||||||
pltevent = PyString_FromString("DELETE");
|
pltevent = PyString_FromString("DELETE");
|
||||||
else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
|
else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
|
||||||
pltevent = PyString_FromString("UPDATE");
|
pltevent = PyString_FromString("UPDATE");
|
||||||
|
else if (TRIGGER_FIRED_BY_TRUNCATE(tdata->tg_event))
|
||||||
|
pltevent = PyString_FromString("TRUNCATE");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
|
elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* pltcl.c - PostgreSQL support for Tcl as
|
* pltcl.c - PostgreSQL support for Tcl as
|
||||||
* procedural language (PL)
|
* procedural language (PL)
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.118 2008/03/25 22:42:46 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.119 2008/03/28 00:21:56 tgl Exp $
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
@ -824,6 +824,8 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
|
|||||||
Tcl_DStringAppendElement(&tcl_cmd, "DELETE");
|
Tcl_DStringAppendElement(&tcl_cmd, "DELETE");
|
||||||
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||||
Tcl_DStringAppendElement(&tcl_cmd, "UPDATE");
|
Tcl_DStringAppendElement(&tcl_cmd, "UPDATE");
|
||||||
|
else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event))
|
||||||
|
Tcl_DStringAppendElement(&tcl_cmd, "TRUNCATE");
|
||||||
else
|
else
|
||||||
elog(ERROR, "unrecognized OP tg_event: %u", trigdata->tg_event);
|
elog(ERROR, "unrecognized OP tg_event: %u", trigdata->tg_event);
|
||||||
|
|
||||||
|
@ -145,3 +145,81 @@ NOTICE: drop cascades to constraint trunc_e_a_fkey on table trunc_e
|
|||||||
NOTICE: drop cascades to constraint trunc_b_a_fkey on table trunc_b
|
NOTICE: drop cascades to constraint trunc_b_a_fkey on table trunc_b
|
||||||
NOTICE: drop cascades to constraint trunc_e_b_fkey on table trunc_e
|
NOTICE: drop cascades to constraint trunc_e_b_fkey on table trunc_e
|
||||||
NOTICE: drop cascades to constraint trunc_d_a_fkey on table trunc_d
|
NOTICE: drop cascades to constraint trunc_d_a_fkey on table trunc_d
|
||||||
|
-- Test ON TRUNCATE triggers
|
||||||
|
CREATE TABLE trunc_trigger_test (f1 int, f2 text, f3 text);
|
||||||
|
CREATE TABLE trunc_trigger_log (tgop text, tglevel text, tgwhen text,
|
||||||
|
tgargv text, tgtable name, rowcount bigint);
|
||||||
|
CREATE FUNCTION trunctrigger() RETURNS trigger as $$
|
||||||
|
declare c bigint;
|
||||||
|
begin
|
||||||
|
execute 'select count(*) from ' || quote_ident(tg_table_name) into c;
|
||||||
|
insert into trunc_trigger_log values
|
||||||
|
(TG_OP, TG_LEVEL, TG_WHEN, TG_ARGV[0], tg_table_name, c);
|
||||||
|
return null;
|
||||||
|
end;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
-- basic before trigger
|
||||||
|
INSERT INTO trunc_trigger_test VALUES(1, 'foo', 'bar'), (2, 'baz', 'quux');
|
||||||
|
CREATE TRIGGER t
|
||||||
|
BEFORE TRUNCATE ON trunc_trigger_test
|
||||||
|
FOR EACH STATEMENT
|
||||||
|
EXECUTE PROCEDURE trunctrigger('before trigger truncate');
|
||||||
|
SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
|
||||||
|
Row count in test table
|
||||||
|
-------------------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM trunc_trigger_log;
|
||||||
|
tgop | tglevel | tgwhen | tgargv | tgtable | rowcount
|
||||||
|
------+---------+--------+--------+---------+----------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
TRUNCATE trunc_trigger_test;
|
||||||
|
SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
|
||||||
|
Row count in test table
|
||||||
|
-------------------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM trunc_trigger_log;
|
||||||
|
tgop | tglevel | tgwhen | tgargv | tgtable | rowcount
|
||||||
|
----------+-----------+--------+-------------------------+--------------------+----------
|
||||||
|
TRUNCATE | STATEMENT | BEFORE | before trigger truncate | trunc_trigger_test | 2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP TRIGGER t ON trunc_trigger_test;
|
||||||
|
truncate trunc_trigger_log;
|
||||||
|
-- same test with an after trigger
|
||||||
|
INSERT INTO trunc_trigger_test VALUES(1, 'foo', 'bar'), (2, 'baz', 'quux');
|
||||||
|
CREATE TRIGGER tt
|
||||||
|
AFTER TRUNCATE ON trunc_trigger_test
|
||||||
|
FOR EACH STATEMENT
|
||||||
|
EXECUTE PROCEDURE trunctrigger('after trigger truncate');
|
||||||
|
SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
|
||||||
|
Row count in test table
|
||||||
|
-------------------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM trunc_trigger_log;
|
||||||
|
tgop | tglevel | tgwhen | tgargv | tgtable | rowcount
|
||||||
|
------+---------+--------+--------+---------+----------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
TRUNCATE trunc_trigger_test;
|
||||||
|
SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
|
||||||
|
Row count in test table
|
||||||
|
-------------------------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM trunc_trigger_log;
|
||||||
|
tgop | tglevel | tgwhen | tgargv | tgtable | rowcount
|
||||||
|
----------+-----------+--------+------------------------+--------------------+----------
|
||||||
|
TRUNCATE | STATEMENT | AFTER | after trigger truncate | trunc_trigger_test | 0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP TABLE trunc_trigger_test;
|
||||||
|
DROP TABLE trunc_trigger_log;
|
||||||
|
DROP FUNCTION trunctrigger();
|
||||||
|
@ -77,3 +77,56 @@ SELECT * FROM truncate_a
|
|||||||
SELECT * FROM trunc_e;
|
SELECT * FROM trunc_e;
|
||||||
|
|
||||||
DROP TABLE truncate_a,trunc_c,trunc_b,trunc_d,trunc_e CASCADE;
|
DROP TABLE truncate_a,trunc_c,trunc_b,trunc_d,trunc_e CASCADE;
|
||||||
|
|
||||||
|
-- Test ON TRUNCATE triggers
|
||||||
|
|
||||||
|
CREATE TABLE trunc_trigger_test (f1 int, f2 text, f3 text);
|
||||||
|
CREATE TABLE trunc_trigger_log (tgop text, tglevel text, tgwhen text,
|
||||||
|
tgargv text, tgtable name, rowcount bigint);
|
||||||
|
|
||||||
|
CREATE FUNCTION trunctrigger() RETURNS trigger as $$
|
||||||
|
declare c bigint;
|
||||||
|
begin
|
||||||
|
execute 'select count(*) from ' || quote_ident(tg_table_name) into c;
|
||||||
|
insert into trunc_trigger_log values
|
||||||
|
(TG_OP, TG_LEVEL, TG_WHEN, TG_ARGV[0], tg_table_name, c);
|
||||||
|
return null;
|
||||||
|
end;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
-- basic before trigger
|
||||||
|
INSERT INTO trunc_trigger_test VALUES(1, 'foo', 'bar'), (2, 'baz', 'quux');
|
||||||
|
|
||||||
|
CREATE TRIGGER t
|
||||||
|
BEFORE TRUNCATE ON trunc_trigger_test
|
||||||
|
FOR EACH STATEMENT
|
||||||
|
EXECUTE PROCEDURE trunctrigger('before trigger truncate');
|
||||||
|
|
||||||
|
SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
|
||||||
|
SELECT * FROM trunc_trigger_log;
|
||||||
|
TRUNCATE trunc_trigger_test;
|
||||||
|
SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
|
||||||
|
SELECT * FROM trunc_trigger_log;
|
||||||
|
|
||||||
|
DROP TRIGGER t ON trunc_trigger_test;
|
||||||
|
|
||||||
|
truncate trunc_trigger_log;
|
||||||
|
|
||||||
|
-- same test with an after trigger
|
||||||
|
INSERT INTO trunc_trigger_test VALUES(1, 'foo', 'bar'), (2, 'baz', 'quux');
|
||||||
|
|
||||||
|
CREATE TRIGGER tt
|
||||||
|
AFTER TRUNCATE ON trunc_trigger_test
|
||||||
|
FOR EACH STATEMENT
|
||||||
|
EXECUTE PROCEDURE trunctrigger('after trigger truncate');
|
||||||
|
|
||||||
|
SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
|
||||||
|
SELECT * FROM trunc_trigger_log;
|
||||||
|
TRUNCATE trunc_trigger_test;
|
||||||
|
SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
|
||||||
|
SELECT * FROM trunc_trigger_log;
|
||||||
|
|
||||||
|
DROP TABLE trunc_trigger_test;
|
||||||
|
DROP TABLE trunc_trigger_log;
|
||||||
|
|
||||||
|
DROP FUNCTION trunctrigger();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user