summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Paquier2012-09-06 04:55:05 +0000
committerMichael Paquier2012-09-06 04:55:05 +0000
commitc1b86b2c885e0f18e15169cb2d8088c3f5276249 (patch)
tree26f3777f8c4c38b3c4e693b2beef6c3f8c5ef517
parent63013850114cd690fda43c278f9558801e199993 (diff)
Support for trigger shippability evaluation and statement triggers
This commit adds support for triggers using FOR EACH STATEMENT. An XC specific infrastructure is added to evaluate if a trigger on a relation is shippable to a remote node or not. This needs to be considered as a first step targetting a complete support of triggers and constraints in Postgres-XC. The second step of the implementation will be to improve the synergy of constraints and triggers for XC-specific features regarding their shippability to remote nodes. In vanilla, constraints and triggers use the same structure and are fired during DML execution step if necessary. However, constraints are implemented in such a way in XC that only the constraints that can be locally enforced on Datanodes can be created. For example, a simple restriction is the case of a primary on a hash distributed table, the primary key must contain the distribution column to allow its check on remote nodes. Well, this lacks of extensibility because we need to be able to check constraint validity and fire triggers also on local Coordinators to allow all possible types of operations including foreign keys or fancier things in cluster. For example, in the case of triggers it is necessary to fire triggers using a non-shippable volatile function on local Coordinator to insure database integrity. Once those extensions are in place, a real support for FOR EACH ROW trigger and more global constraints will be possible by allowing constraints and triggers to be fired also on Coordinators safely. This will need a proper row-based fetch mechanism though. By the way, row-based triggers are disabled for the time being. Documentation is cleaned up and CREATE/ALTER/DROP TRIGGER commands are re-allowed. Some test cases for different types of triggers are added with a new regression test xc_triggers.
-rw-r--r--doc-xc/src/sgml/intro.sgmlin10
-rw-r--r--doc-xc/src/sgml/ref/alter_trigger.sgmlin11
-rw-r--r--doc-xc/src/sgml/ref/create_trigger.sgmlin18
-rw-r--r--doc-xc/src/sgml/ref/drop_trigger.sgmlin11
-rw-r--r--doc-xc/src/sgml/trigger.sgmlin45
-rw-r--r--src/backend/commands/tablecmds.c41
-rw-r--r--src/backend/commands/trigger.c265
-rw-r--r--src/backend/optimizer/util/pgxcship.c12
-rw-r--r--src/backend/tcop/utility.c73
-rw-r--r--src/bin/psql/tab-complete.c15
-rw-r--r--src/include/commands/tablecmds.h4
-rw-r--r--src/include/commands/trigger.h5
-rw-r--r--src/test/regress/expected/copy2_1.out4
-rw-r--r--src/test/regress/expected/drop_if_exists.out2
-rw-r--r--src/test/regress/expected/plpgsql_1.out76
-rw-r--r--src/test/regress/expected/rangefuncs_1.out2
-rw-r--r--src/test/regress/expected/triggers_1.out242
-rw-r--r--src/test/regress/expected/tsearch_1.out2
-rw-r--r--src/test/regress/expected/with.out7
-rw-r--r--src/test/regress/expected/xc_triggers.out305
-rw-r--r--src/test/regress/parallel_schedule2
-rw-r--r--src/test/regress/serial_schedule1
-rw-r--r--src/test/regress/sql/xc_triggers.sql231
23 files changed, 1082 insertions, 302 deletions
diff --git a/doc-xc/src/sgml/intro.sgmlin b/doc-xc/src/sgml/intro.sgmlin
index 3df8cebd47..af214273d4 100644
--- a/doc-xc/src/sgml/intro.sgmlin
+++ b/doc-xc/src/sgml/intro.sgmlin
@@ -358,16 +358,6 @@ from applications, which is known as "master" server in general. In Postgres-XC,
</simpara>
</listitem>
<listitem>
- <simpara>
- triggers
- <footnote>
- <para>
- <productname>Postgres-XC</productname> does not support trigger in the current version. This may be supported in the future releases.
- </para>
- </footnote>
- </simpara>
- </listitem>
- <listitem>
<simpara>views</simpara>
</listitem>
<!## PG>
diff --git a/doc-xc/src/sgml/ref/alter_trigger.sgmlin b/doc-xc/src/sgml/ref/alter_trigger.sgmlin
index c4ea6c117e..2f943ee9c2 100644
--- a/doc-xc/src/sgml/ref/alter_trigger.sgmlin
+++ b/doc-xc/src/sgml/ref/alter_trigger.sgmlin
@@ -28,16 +28,6 @@ ALTER TRIGGER <replaceable class="PARAMETER">name</replaceable> ON <replaceable
<refsect1>
<title>Description</title>
-<!## XC>
-&xconly;
- <para>
- <command>ALTER TRIGGERXS</> statement has not been supported
- in <productname>Postgres-XC</> yet.
- </para>
-<!## end>
-
-<!## PG>
-
<para>
<command>ALTER TRIGGER</command> changes properties of an existing
trigger. The <literal>RENAME</literal> clause changes the name of
@@ -113,7 +103,6 @@ ALTER TRIGGER emp_stamp ON emp RENAME TO emp_track_chgs;
<command>ALTER TRIGGER</command> is a <productname>PostgreSQL</>
extension of the SQL standard.
</para>
-<!## end>
</refsect1>
<refsect1>
diff --git a/doc-xc/src/sgml/ref/create_trigger.sgmlin b/doc-xc/src/sgml/ref/create_trigger.sgmlin
index be6f06e3a2..dc867be4bf 100644
--- a/doc-xc/src/sgml/ref/create_trigger.sgmlin
+++ b/doc-xc/src/sgml/ref/create_trigger.sgmlin
@@ -41,16 +41,6 @@ CREATE [ CONSTRAINT ] TRIGGER <replaceable class="PARAMETER">name</replaceable>
<refsect1>
<title>Description</title>
-<!## XC>
-&xconly;
- <para>
- <command>CREATE TRIGGER</> statement has not been supported
- in <productname>Postgres-XC</> yet.
- </para>
-<!## end>
-
-<!## PG>
-
<para>
<command>CREATE TRIGGER</command> creates a new trigger. The
trigger will be associated with the specified table or view and will
@@ -58,6 +48,13 @@ CREATE [ CONSTRAINT ] TRIGGER <replaceable class="PARAMETER">name</replaceable>
class="parameter">function_name</replaceable> when certain events occur.
</para>
+<!## XC>
+&xconly;
+ <para>
+ <literal>FOR EACH ROW</literal> is not supported by <productname>Postgres-XC</> yet.
+ </para>
+<!## end>
+
<para>
The trigger can be specified to fire before the
operation is attempted on a row (before constraints are checked and
@@ -560,7 +557,6 @@ CREATE TRIGGER view_insert
<productname>PostgreSQL</productname> extension of the <acronym>SQL</>
standard.
</para>
-<!## end>
</refsect1>
<refsect1>
diff --git a/doc-xc/src/sgml/ref/drop_trigger.sgmlin b/doc-xc/src/sgml/ref/drop_trigger.sgmlin
index 1a904665ce..9a9b8c286e 100644
--- a/doc-xc/src/sgml/ref/drop_trigger.sgmlin
+++ b/doc-xc/src/sgml/ref/drop_trigger.sgmlin
@@ -28,16 +28,6 @@ DROP TRIGGER [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON
<refsect1>
<title>Description</title>
-<!## XC>
-&xconly;
- <para>
- <command>DROP TRIGGER</> statement has not been supported
- in <productname>Postgres-XC</> yet.
- </para>
-<!## end>
-
-<!## PG>
-
<para>
<command>DROP TRIGGER</command> removes an existing
trigger definition. To execute this command, the current
@@ -124,7 +114,6 @@ DROP TRIGGER if_dist_exists ON films;
<replaceable>name</replaceable></literal>.
</para>
-<!## end>
</refsect1>
<refsect1>
diff --git a/doc-xc/src/sgml/trigger.sgmlin b/doc-xc/src/sgml/trigger.sgmlin
index 07789e1e5a..db776d80a0 100644
--- a/doc-xc/src/sgml/trigger.sgmlin
+++ b/doc-xc/src/sgml/trigger.sgmlin
@@ -7,14 +7,6 @@
<primary>trigger</primary>
</indexterm>
-<!## XC>
-&xconly;
- <para>
- The trigger will be supported in the future. The document will be supported then.
- </para>
-<!## end>
-
-<!## PG>
<para>
This chapter provides general information about writing trigger functions.
Trigger functions can be written in most of the available procedural
@@ -34,18 +26,10 @@
It is not currently possible to write a trigger function in the
plain SQL function language.
</para>
-<!## end>
<sect1 id="trigger-definition">
<title>Overview of Trigger Behavior</title>
-<!## XC>
-&xconly;
- <para>
- The trigger will be supported in the future. The document will be supported then.
- </para>
-<!## end>
-<!## PG>
<para>
A trigger is a specification that the database should automatically
execute a particular function whenever a certain type of operation is
@@ -291,21 +275,11 @@
Statement-level triggers do not currently have any way to examine the
individual row(s) modified by the statement.
</para>
-<!## end>
</sect1>
<sect1 id="trigger-datachanges">
<title>Visibility of Data Changes</title>
-<!## XC>
-&xconly;
- <para>
- The trigger will be supported in the future. The document will be supported then.
- </para>
-<!## end>
-
-<!## PG>
-
<para>
If you execute SQL commands in your trigger function, and these
commands access the table that the trigger is for, then
@@ -377,7 +351,6 @@
<xref linkend="spi-visibility">. The example in <xref
linkend="trigger-example"> contains a demonstration of these rules.
</para>
-<!## end>
</sect1>
<sect1 id="trigger-interface">
@@ -388,14 +361,6 @@
<secondary>in C</secondary>
</indexterm>
-<!## XC>
-&xconly;
- <para>
- The trigger will be supported in the future. The document will be supported then.
- </para>
-<!## end>
-
-<!## PG>
<para>
This section describes the low-level details of the interface to a
trigger function. This information is only needed when writing
@@ -672,20 +637,11 @@ typedef struct Trigger
<structfield>tg_trigtuple</> or <structfield>tg_newtuple</>,
as appropriate, if you don't want to modify the row being operated on.
</para>
-<!## end>
</sect1>
<sect1 id="trigger-example">
<title>A Complete Trigger Example</title>
-<!## XC>
-&xconly;
- <para>
- The trigger will be supported in the future. The document will be supported then.
- </para>
-<!## end>
-
-<!## PG>
<para>
Here is a very simple example of a trigger function written in C.
(Examples of triggers written in procedural languages can be found
@@ -880,6 +836,5 @@ DELETE 2
<filename>src/test/regress/regress.c</filename> and
in <xref linkend="contrib-spi">.
</para>
-<!## end>
</sect1>
</chapter>
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 101df04602..e00f8d0684 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -977,8 +977,13 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
* internal to the group that's being truncated. Finally all the relations
* are truncated and reindexed.
*/
+#ifdef PGXC
+void
+ExecuteTruncate(TruncateStmt *stmt, const char *sql_statement)
+#else
void
ExecuteTruncate(TruncateStmt *stmt)
+#endif
{
List *rels = NIL;
List *relids = NIL;
@@ -1240,6 +1245,42 @@ ExecuteTruncate(TruncateStmt *stmt)
resultRelInfo++;
}
+#ifdef PGXC
+ /*
+ * In Postgres-XC, TRUNCATE needs to be launched to remote nodes before the
+ * AFTER triggers are launched. This insures that the triggers are being fired
+ * by correct events.
+ */
+ if (IS_PGXC_COORDINATOR && !IsConnFromCoord())
+ {
+ bool is_temp = false;
+ RemoteQuery *step = makeNode(RemoteQuery);
+
+ foreach(cell, stmt->relations)
+ {
+ Oid relid;
+ RangeVar *rel = (RangeVar *) lfirst(cell);
+
+ relid = RangeVarGetRelid(rel, NoLock, false);
+ if (IsTempTable(relid))
+ {
+ is_temp = true;
+ break;
+ }
+ }
+
+ step->combine_type = COMBINE_TYPE_SAME;
+ step->exec_nodes = NULL;
+ step->sql_statement = pstrdup(sql_statement);
+ step->force_autocommit = false;
+ step->exec_type = EXEC_ON_DATANODES;
+ step->is_temp = is_temp;
+ ExecRemoteUtility(step);
+ pfree(step->sql_statement);
+ pfree(step);
+ }
+#endif
+
/* Handle queued AFTER triggers */
AfterTriggerEndQuery(estate);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 3f98d8c1f5..04e2cc1acb 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -56,6 +56,7 @@
#include "utils/tqual.h"
#ifdef PGXC
#include "pgxc/pgxc.h"
+#include "optimizer/pgxcship.h"
#endif
@@ -89,6 +90,10 @@ static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
int event, bool row_trigger,
HeapTuple oldtup, HeapTuple newtup,
List *recheckIndexes, Bitmapset *modifiedCols);
+#ifdef PGXC
+static bool pgxc_is_trigger_shippable(Trigger *trigger);
+static bool pgxc_is_trigger_firable(Trigger *trigger);
+#endif
/*
@@ -1927,6 +1932,12 @@ ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
NULL, NULL, NULL))
continue;
+#ifdef PGXC
+ /* Fire the trigger if authorized */
+ if (!pgxc_is_trigger_firable(trigger))
+ continue;
+#endif
+
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
i,
@@ -1982,6 +1993,12 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
NULL, NULL, newtuple))
continue;
+#ifdef PGXC
+ /* Fire the trigger if authorized */
+ if (!pgxc_is_trigger_firable(trigger))
+ continue;
+#endif
+
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
@@ -2057,6 +2074,12 @@ ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
NULL, NULL, newtuple))
continue;
+#ifdef PGXC
+ /* Fire the trigger if authorized */
+ if (!pgxc_is_trigger_firable(trigger))
+ continue;
+#endif
+
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
@@ -2126,6 +2149,12 @@ ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
NULL, NULL, NULL))
continue;
+#ifdef PGXC
+ /* Fire the trigger if authorized */
+ if (!pgxc_is_trigger_firable(trigger))
+ continue;
+#endif
+
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
i,
@@ -2188,6 +2217,12 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
NULL, trigtuple, NULL))
continue;
+#ifdef PGXC
+ /* Fire the trigger if authorized */
+ if (!pgxc_is_trigger_firable(trigger))
+ continue;
+#endif
+
LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
@@ -2255,6 +2290,12 @@ ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
NULL, trigtuple, NULL))
continue;
+#ifdef PGXC
+ /* Fire the trigger if authorized */
+ if (!pgxc_is_trigger_firable(trigger))
+ continue;
+#endif
+
LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
@@ -2310,6 +2351,12 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
modifiedCols, NULL, NULL))
continue;
+#ifdef PGXC
+ /* Fire the trigger if authorized */
+ if (!pgxc_is_trigger_firable(trigger))
+ continue;
+#endif
+
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
i,
@@ -2394,6 +2441,12 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
modifiedCols, trigtuple, newtuple))
continue;
+#ifdef PGXC
+ /* Fire the trigger if authorized */
+ if (!pgxc_is_trigger_firable(trigger))
+ continue;
+#endif
+
LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_newtuple = oldtuple = newtuple;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
@@ -2481,6 +2534,12 @@ ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
NULL, trigtuple, newtuple))
continue;
+#ifdef PGXC
+ /* Fire the trigger if authorized */
+ if (!pgxc_is_trigger_firable(trigger))
+ continue;
+#endif
+
LocTriggerData.tg_trigtuple = trigtuple;
LocTriggerData.tg_newtuple = oldtuple = newtuple;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
@@ -2552,6 +2611,12 @@ ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
NULL, NULL, NULL))
continue;
+#ifdef PGXC
+ /* Fire the trigger if authorized */
+ if (!pgxc_is_trigger_firable(trigger))
+ continue;
+#endif
+
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
i,
@@ -4618,6 +4683,12 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
modifiedCols, oldtup, newtup))
continue;
+#ifdef PGXC
+ /* Fire the trigger if authorized */
+ if (!pgxc_is_trigger_firable(trigger))
+ continue;
+#endif
+
/*
* If this is an UPDATE of a PK table or FK table that does not change
* the PK or FK respectively, we can skip queuing the event: there is
@@ -4695,3 +4766,197 @@ pg_trigger_depth(PG_FUNCTION_ARGS)
{
PG_RETURN_INT32(MyTriggerDepth);
}
+
+
+#ifdef PGXC
+/*
+ * pgxc_check_triggers_shippability
+ * Check if given relation can be shipped entirely based on its potential
+ * triggers actions. If at least one trigger is not shippable then the given
+ * relation cannot be shipped completely to remote nodes for given command
+ * type.
+ */
+bool
+pgxc_check_triggers_shippability(Oid relid, CmdType commandType)
+{
+ Relation rel = relation_open(relid, AccessShareLock);
+ bool res = true;
+ int i;
+ TriggerDesc *trigdesc;
+
+ /* Relation has no triggers, can safely return */
+ if (!rel->rd_rel->relhastriggers)
+ goto finish;
+
+ /* Rebuild trigger list if necessary */
+ if (rel->rd_rel->relhastriggers && rel->trigdesc == NULL)
+ RelationBuildTriggers(rel);
+
+ /* Definitely no triggers for this relation */
+ if (rel->trigdesc == NULL)
+ goto finish;
+
+ trigdesc = rel->trigdesc;
+
+ /*
+ * Check if there are any triggers related to given command
+ * If there are any, we need to scan the triggers to be sure
+ * that they are safe.
+ */
+ switch (commandType)
+ {
+ case CMD_INSERT:
+ if (!trigdesc->trig_insert_before_row &&
+ !trigdesc->trig_insert_after_row &&
+ !trigdesc->trig_insert_instead_row &&
+ !trigdesc->trig_insert_before_statement &&
+ !trigdesc->trig_insert_after_statement)
+ goto finish;
+ break;
+ case CMD_UPDATE:
+ if (!trigdesc->trig_update_before_row &&
+ !trigdesc->trig_update_after_row &&
+ !trigdesc->trig_update_instead_row &&
+ !trigdesc->trig_update_before_statement &&
+ !trigdesc->trig_update_after_statement)
+ goto finish;
+ break;
+ case CMD_DELETE:
+ if (!trigdesc->trig_delete_before_row &&
+ !trigdesc->trig_delete_after_row &&
+ !trigdesc->trig_delete_instead_row &&
+ !trigdesc->trig_delete_before_statement &&
+ !trigdesc->trig_delete_after_statement)
+ goto finish;
+ break;
+ case CMD_UTILITY:
+ /* Trigger might be based on an event */
+ if (!trigdesc->trig_truncate_before_statement &&
+ !trigdesc->trig_truncate_after_statement)
+ goto finish;
+ break;
+ case CMD_SELECT:
+ default:
+ Assert(0); /* Shouldn't come here */
+ }
+
+ /*
+ * By being here, it is sure that there are triggers on this relation
+ * that are based on events based on the command type invocated.
+ * So let's scan each potential trigger and be such that it is shippable.
+ */
+ for (i = 0; i < trigdesc->numtriggers; i++)
+ {
+ Trigger *trigger = &trigdesc->triggers[i];
+ int16 tgtype = trigger->tgtype;
+
+ switch (commandType)
+ {
+ case CMD_INSERT:
+ /* Don't mind if trigger is not involved in INSERT */
+ if (!TRIGGER_FOR_INSERT(tgtype))
+ continue;
+ break;
+ case CMD_UPDATE:
+ /* Don't mind if trigger is not involved in UPDATE */
+ if (!TRIGGER_FOR_UPDATE(tgtype))
+ continue;
+ break;
+ case CMD_DELETE:
+ /* Don't mind if trigger is not involved in UPDATE */
+ if (!TRIGGER_FOR_DELETE(tgtype))
+ continue;
+ break;
+ /* Trigger might be on a truncate */
+ case CMD_UTILITY:
+ /* Don't mind if trigger is not involved in TRUNCATE */
+ if (!TRIGGER_FOR_TRUNCATE(tgtype))
+ continue;
+ break;
+ case CMD_SELECT:
+ default:
+ Assert(0); /* Shouldn't come here */
+ continue;
+ }
+
+ /* Check trigger shippability */
+ res = pgxc_is_trigger_shippable(trigger);
+
+ /* Leave if trigger is not shippable */
+ if (!res)
+ goto finish;
+ }
+
+finish:
+ relation_close(rel, AccessShareLock);
+ return res;
+}
+
+
+/*
+ * pgxc_is_trigger_shippable
+ * Depending on the node type where this trigger is evaluated and
+ * its shippability, determine if the trigger can be fired or not.
+ */
+static bool
+pgxc_is_trigger_firable(Trigger *trigger)
+{
+ bool is_shippable = pgxc_is_trigger_shippable(trigger);
+
+ /*
+ * If trigger is based on a constraint or is internal, enforce its launch
+ * whatever the node type where we are for the time being.
+ * PGXCTODO: we need to remove this condition once constraints and triggers
+ * are better implemented within Postgres-XC as a constraint can be locally
+ * evaluated on remote nodes depending on the distribution type of the table
+ * on which it is defined or on its parent/child distribution types.
+ */
+ if (trigger->tgisinternal)
+ return true;
+
+ /* A non-shippable trigger can be fired safely on a local Coordinator */
+ if (!is_shippable && IS_PGXC_COORDINATOR && !IsConnFromCoord())
+ return true;
+
+ /* A shippable trigger can be fired safely on a remote node */
+ if (is_shippable && IsConnFromCoord())
+ return true;
+
+ return false;
+}
+
+
+/*
+ * pgxc_is_trigger_shippable
+ * Check if trigger is shippable to a remote node
+ */
+static bool
+pgxc_is_trigger_shippable(Trigger *trigger)
+{
+ bool res = true;
+
+ /*
+ * If trigger is based on a constraint or is internal, enforce its launch
+ * whatever the node type where we are for the time being.
+ * PGXCTODO: we need to remove this condition once constraints and triggers
+ * are better implemented within Postgres-XC as a constraint can be locally
+ * evaluated on remote nodes depending on the distribution type of the table
+ * on which it is defined or on its parent/child distribution types.
+ */
+ if (trigger->tgisinternal)
+ return true;
+
+ /*
+ * INSTEAD OF triggers can only be defined on views, which are defined
+ * only on Coordinators, so they cannot be shipped.
+ */
+ if (TRIGGER_FOR_INSTEAD(trigger->tgtype))
+ res = false;
+
+ /* Finally check if function called is shippable */
+ if (!pgxc_is_func_shippable(trigger->tgfoid))
+ res = false;
+
+ return res;
+}
+#endif
diff --git a/src/backend/optimizer/util/pgxcship.c b/src/backend/optimizer/util/pgxcship.c
index e71e7359db..4dd79f726e 100644
--- a/src/backend/optimizer/util/pgxcship.c
+++ b/src/backend/optimizer/util/pgxcship.c
@@ -21,6 +21,7 @@
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "catalog/pgxc_node.h"
+#include "commands/trigger.h"
#include "nodes/nodeFuncs.h"
#include "nodes/relation.h"
#include "optimizer/clauses.h"
@@ -823,6 +824,17 @@ pgxc_shippability_walker(Node *node, Shippability_context *sc_context)
if (sc_context->sc_max_varlevelsup != 0)
pgxc_set_shippability_reason(sc_context, SS_VARLEVEL);
+ /* Check shippability of triggers on this query */
+ if (query->commandType == CMD_UPDATE ||
+ query->commandType == CMD_INSERT ||
+ query->commandType == CMD_DELETE)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) list_nth(query->rtable, query->resultRelation - 1);
+
+ if (!pgxc_check_triggers_shippability(rte->relid, query->commandType))
+ pgxc_set_shippability_reason(sc_context, SS_UNSHIPPABLE_EXPR);
+ }
+
/*
* Walk the RangeTableEntries of the query and find the
* Datanodes needed for evaluating this query
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 49209120b1..a202d8d018 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -885,34 +885,15 @@ standard_ProcessUtility(Node *parsetree,
break;
case T_TruncateStmt:
- ExecuteTruncate((TruncateStmt *) parsetree);
#ifdef PGXC
/*
- * Check details of the object being truncated.
- * If at least one temporary table is truncated truncate cannot use 2PC
- * at commit.
+ * In Postgres-XC, TRUNCATE needs to be launched to remote nodes
+ * before AFTER triggers. As this needs an internal control it is
+ * managed by this function internally.
*/
- if (IS_PGXC_COORDINATOR && !IsConnFromCoord())
- {
- bool is_temp = false;
- ListCell *cell;
- TruncateStmt *stmt = (TruncateStmt *) parsetree;
-
- foreach(cell, stmt->relations)
- {
- Oid relid;
- RangeVar *rel = (RangeVar *) lfirst(cell);
-
- relid = RangeVarGetRelid(rel, NoLock, false);
- if (IsTempTable(relid))
- {
- is_temp = true;
- break;
- }
- }
-
- ExecUtilityStmtOnNodes(queryString, NULL, sentToRemote, false, EXEC_ON_DATANODES, is_temp);
- }
+ ExecuteTruncate((TruncateStmt *) parsetree, queryString);
+#else
+ ExecuteTruncate((TruncateStmt *) parsetree);
#endif
break;
@@ -1713,14 +1694,25 @@ standard_ProcessUtility(Node *parsetree,
(void) CreateTrigger((CreateTrigStmt *) parsetree, queryString,
InvalidOid, InvalidOid, false);
#ifdef PGXC
- /* Postgres-XC does not support yet triggers */
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("Postgres-XC does not support TRIGGER yet"),
- errdetail("The feature is not currently supported")));
-
if (IS_PGXC_COORDINATOR)
- ExecUtilityStmtOnNodes(queryString, NULL, sentToRemote, false, EXEC_ON_ALL_NODES, false);
+ {
+ CreateTrigStmt *stmt = (CreateTrigStmt *) parsetree;
+ RemoteQueryExecType exec_type;
+ bool is_temp;
+
+ /* Postgres-XC does not support yet FOR EACH ROW yet */
+ if (stmt->row)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support ROW TRIGGER yet"),
+ errdetail("The feature is not currently supported")));
+
+ exec_type = ExecUtilityFindNodes(OBJECT_TABLE,
+ RangeVarGetRelid(stmt->relation, NoLock, false),
+ &is_temp);
+
+ ExecUtilityStmtOnNodes(queryString, NULL, sentToRemote, false, exec_type, is_temp);
+ }
#endif
break;
@@ -2069,7 +2061,9 @@ ExecUtilityFindNodes(ObjectType object_type,
exec_type = EXEC_ON_ALL_NODES;
break;
+ /* Triggers are evaluated based on the relation they are defined on */
case OBJECT_TABLE:
+ case OBJECT_TRIGGER:
/* Do the check on relation kind */
exec_type = ExecUtilityFindNodesRelkind(object_id, is_temp);
break;
@@ -3774,17 +3768,18 @@ DropStmtPreTreatment(DropStmt *stmt, const char *queryString, bool sentToRemote,
}
break;
+ /*
+ * Those objects are dropped depending on the nature of the relationss
+ * they are defined on. This evaluation uses the temporary behavior
+ * and the relkind of the relation used.
+ */
case OBJECT_RULE:
+ case OBJECT_TRIGGER:
{
- /*
- * In the case of a rule we need to find the object on
- * which the rule is dependent and define if this rule
- * has a dependency with a temporary object or not.
- */
List *objname = linitial(stmt->objects);
Relation relation = NULL;
- get_object_address(OBJECT_RULE,
+ get_object_address(stmt->removeType,
objname, NIL,
&relation,
AccessExclusiveLock,
@@ -3792,7 +3787,7 @@ DropStmtPreTreatment(DropStmt *stmt, const char *queryString, bool sentToRemote,
/* Do nothing if no relation */
if (relation && OidIsValid(relation->rd_id))
- res_exec_type = ExecUtilityFindNodes(OBJECT_RULE,
+ res_exec_type = ExecUtilityFindNodes(stmt->removeType,
relation->rd_id,
&res_is_temp);
else
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 216b3e796a..63052c5f0c 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -700,10 +700,7 @@ static const pgsql_thing_t words_after_create[] = {
{"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */
{"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
{"TEXT SEARCH", NULL, NULL},
-#ifndef PGXC
- /* PGXCTODO: This should be re-enabled once TRIGGER is supported */
{"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
-#endif
{"TYPE", NULL, &Query_for_list_of_datatypes},
{"UNIQUE", NULL, NULL, THING_NO_DROP}, /* for CREATE UNIQUE INDEX ... */
{"UNLOGGED", NULL, NULL, THING_NO_DROP}, /* for CREATE UNLOGGED TABLE
@@ -790,7 +787,7 @@ psql_completion(char *text, int start, int end)
static const char *const sql_commands[] = {
#ifdef PGXC
- /*
+ /*
* Added "CLEAN" and "EXECUTE DIRECT"
* Removed LISTEN, NOTIFY, RELEASE, SAVEPOINT and UNLISTEN
*/
@@ -889,13 +886,13 @@ psql_completion(char *text, int start, int end)
/*
* Added: "NODE" (NODE NAME cannot be altered).
* Removed: "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "LARGE OBJECT",
- * "SERVER", "TRIGGER", "USER MAPPING FOR".
+ * "SERVER", "USER MAPPING FOR".
*/
{"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
"EXTENSION", "FUNCTION",
"GROUP", "INDEX", "LANGUAGE", "NODE", "NODE GROUP", "OPERATOR",
"ROLE", "SCHEMA", "SEQUENCE", "TABLE",
- "TABLESPACE", "TEXT SEARCH", "TYPE",
+ "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
"USER", "VIEW", NULL};
#else
{"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
@@ -1264,8 +1261,6 @@ psql_completion(char *text, int start, int end)
COMPLETE_WITH_LIST(list_ALTERVIEW);
}
-#ifndef PGXC
- /* PGXCTODO: This should be re-enabled once TRIGGER is supported */
/* ALTER TRIGGER <name>, add ON */
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
@@ -1290,7 +1285,6 @@ psql_completion(char *text, int start, int end)
else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
pg_strcasecmp(prev2_wd, "ON") == 0)
COMPLETE_WITH_CONST("RENAME TO");
-#endif
/*
* If we detect ALTER TABLE <name>, suggest sub commands
@@ -2087,8 +2081,6 @@ psql_completion(char *text, int start, int end)
pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
COMPLETE_WITH_CONST("(");
-#ifndef PGXC
- /* PGXCTODO: This should be re-enabled once TRIGGER is supported */
/* CREATE TRIGGER */
/* complete CREATE TRIGGER <name> with BEFORE,AFTER */
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
@@ -2155,7 +2147,6 @@ psql_completion(char *text, int start, int end)
prev2_wd[0] != '\0')
COMPLETE_WITH_CONST("PROCEDURE");
-#endif
/* CREATE ROLE,USER,GROUP <name> */
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
!(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
index e262a1d8d3..7d25bf3a31 100644
--- a/src/include/commands/tablecmds.h
+++ b/src/include/commands/tablecmds.h
@@ -42,7 +42,11 @@ extern void AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
extern void CheckTableNotInUse(Relation rel, const char *stmt);
+#ifdef PGXC
+extern void ExecuteTruncate(TruncateStmt *stmt, const char *sql_statement);
+#else
extern void ExecuteTruncate(TruncateStmt *stmt);
+#endif
extern void SetRelationHasSubclass(Oid relationId, bool relhassubclass);
diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
index 1f7ba47466..8e5499e4c5 100644
--- a/src/include/commands/trigger.h
+++ b/src/include/commands/trigger.h
@@ -210,4 +210,9 @@ extern int RI_FKey_trigger_type(Oid tgfoid);
extern Datum pg_trigger_depth(PG_FUNCTION_ARGS);
+#ifdef PGXC
+/* Postgres-XC related functions for triggers */
+extern bool pgxc_check_triggers_shippability(Oid relid, CmdType commandType);
+#endif
+
#endif /* TRIGGER_H */
diff --git a/src/test/regress/expected/copy2_1.out b/src/test/regress/expected/copy2_1.out
index 24ac6b9b83..e0be20714f 100644
--- a/src/test/regress/expected/copy2_1.out
+++ b/src/test/regress/expected/copy2_1.out
@@ -22,11 +22,11 @@ CREATE FUNCTION fn_x_after () RETURNS TRIGGER AS '
' LANGUAGE plpgsql;
CREATE TRIGGER trg_x_after AFTER INSERT ON x
FOR EACH ROW EXECUTE PROCEDURE fn_x_after();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
CREATE TRIGGER trg_x_before BEFORE INSERT ON x
FOR EACH ROW EXECUTE PROCEDURE fn_x_before();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
COPY x (a, b, c, d, e) from stdin;
COPY x (b, d) from stdin;
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index 871ee08813..3b0ad8bd11 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -177,7 +177,7 @@ ERROR: relation "no_such_table" does not exist
CREATE TRIGGER test_trigger_exists
BEFORE UPDATE ON test_exists
FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
DROP TRIGGER test_trigger_exists ON test_exists;
ERROR: trigger "test_trigger_exists" for table "test_exists" does not exist
diff --git a/src/test/regress/expected/plpgsql_1.out b/src/test/regress/expected/plpgsql_1.out
index 4e3240fe00..894f6ffbeb 100644
--- a/src/test/regress/expected/plpgsql_1.out
+++ b/src/test/regress/expected/plpgsql_1.out
@@ -103,7 +103,7 @@ end;
' language plpgsql;
create trigger tg_room_au after update
on Room for each row execute procedure tg_room_au();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * AFTER DELETE on Room
@@ -117,7 +117,7 @@ end;
' language plpgsql;
create trigger tg_room_ad after delete
on Room for each row execute procedure tg_room_ad();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE INSERT or UPDATE on WSlot
@@ -133,7 +133,7 @@ end;
$$ language plpgsql;
create trigger tg_wslot_biu before insert or update
on WSlot for each row execute procedure tg_wslot_biu();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * AFTER UPDATE on PField
@@ -149,7 +149,7 @@ end;
' language plpgsql;
create trigger tg_pfield_au after update
on PField for each row execute procedure tg_pfield_au();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * AFTER DELETE on PField
@@ -163,7 +163,7 @@ end;
' language plpgsql;
create trigger tg_pfield_ad after delete
on PField for each row execute procedure tg_pfield_ad();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE INSERT or UPDATE on PSlot
@@ -183,7 +183,7 @@ end;
$proc$ language plpgsql;
create trigger tg_pslot_biu before insert or update
on PSlot for each row execute procedure tg_pslot_biu();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * AFTER UPDATE on System
@@ -199,7 +199,7 @@ end;
' language plpgsql;
create trigger tg_system_au after update
on System for each row execute procedure tg_system_au();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE INSERT or UPDATE on IFace
@@ -226,7 +226,7 @@ end;
$$ language plpgsql;
create trigger tg_iface_biu before insert or update
on IFace for each row execute procedure tg_iface_biu();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * AFTER INSERT or UPDATE or DELETE on Hub
@@ -256,7 +256,7 @@ end;
' language plpgsql;
create trigger tg_hub_a after insert or update or delete
on Hub for each row execute procedure tg_hub_a();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * Support function to add/remove slots of Hub
@@ -320,7 +320,7 @@ end;
' language plpgsql;
create trigger tg_hslot_biu before insert or update
on HSlot for each row execute procedure tg_hslot_biu();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE DELETE on HSlot
@@ -342,7 +342,7 @@ end;
' language plpgsql;
create trigger tg_hslot_bd before delete
on HSlot for each row execute procedure tg_hslot_bd();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE INSERT on all slots
@@ -358,23 +358,23 @@ end;
' language plpgsql;
create trigger tg_chkslotname before insert
on PSlot for each row execute procedure tg_chkslotname('PS');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_chkslotname before insert
on WSlot for each row execute procedure tg_chkslotname('WS');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_chkslotname before insert
on PLine for each row execute procedure tg_chkslotname('PL');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_chkslotname before insert
on IFace for each row execute procedure tg_chkslotname('IF');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_chkslotname before insert
on PHone for each row execute procedure tg_chkslotname('PH');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE INSERT or UPDATE on all slots with slotlink
@@ -390,23 +390,23 @@ end;
' language plpgsql;
create trigger tg_chkslotlink before insert or update
on PSlot for each row execute procedure tg_chkslotlink();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_chkslotlink before insert or update
on WSlot for each row execute procedure tg_chkslotlink();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_chkslotlink before insert or update
on IFace for each row execute procedure tg_chkslotlink();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_chkslotlink before insert or update
on HSlot for each row execute procedure tg_chkslotlink();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_chkslotlink before insert or update
on PHone for each row execute procedure tg_chkslotlink();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE INSERT or UPDATE on all slots with backlink
@@ -422,15 +422,15 @@ end;
' language plpgsql;
create trigger tg_chkbacklink before insert or update
on PSlot for each row execute procedure tg_chkbacklink();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_chkbacklink before insert or update
on WSlot for each row execute procedure tg_chkbacklink();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_chkbacklink before insert or update
on PLine for each row execute procedure tg_chkbacklink();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE UPDATE on PSlot
@@ -458,7 +458,7 @@ end;
' language plpgsql;
create trigger tg_pslot_bu before update
on PSlot for each row execute procedure tg_pslot_bu();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE UPDATE on WSlot
@@ -486,7 +486,7 @@ end;
' language plpgsql;
create trigger tg_wslot_bu before update
on WSlot for each row execute procedure tg_Wslot_bu();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE UPDATE on PLine
@@ -514,7 +514,7 @@ end;
' language plpgsql;
create trigger tg_pline_bu before update
on PLine for each row execute procedure tg_pline_bu();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE UPDATE on IFace
@@ -542,7 +542,7 @@ end;
' language plpgsql;
create trigger tg_iface_bu before update
on IFace for each row execute procedure tg_iface_bu();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE UPDATE on HSlot
@@ -570,7 +570,7 @@ end;
' language plpgsql;
create trigger tg_hslot_bu before update
on HSlot for each row execute procedure tg_hslot_bu();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * BEFORE UPDATE on PHone
@@ -596,7 +596,7 @@ end;
' language plpgsql;
create trigger tg_phone_bu before update
on PHone for each row execute procedure tg_phone_bu();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * AFTER INSERT or UPDATE or DELETE on slot with backlink
@@ -637,15 +637,15 @@ end;
' language plpgsql;
create trigger tg_backlink_a after insert or update or delete
on PSlot for each row execute procedure tg_backlink_a('PS');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_backlink_a after insert or update or delete
on WSlot for each row execute procedure tg_backlink_a('WS');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_backlink_a after insert or update or delete
on PLine for each row execute procedure tg_backlink_a('PL');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * Support function to set the opponents backlink field
@@ -785,23 +785,23 @@ end;
' language plpgsql;
create trigger tg_slotlink_a after insert or update or delete
on PSlot for each row execute procedure tg_slotlink_a('PS');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_slotlink_a after insert or update or delete
on WSlot for each row execute procedure tg_slotlink_a('WS');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_slotlink_a after insert or update or delete
on IFace for each row execute procedure tg_slotlink_a('IF');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_slotlink_a after insert or update or delete
on HSlot for each row execute procedure tg_slotlink_a('HS');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger tg_slotlink_a after insert or update or delete
on PHone for each row execute procedure tg_slotlink_a('PH');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- ************************************************************
-- * Support function to set the opponents slotlink field
diff --git a/src/test/regress/expected/rangefuncs_1.out b/src/test/regress/expected/rangefuncs_1.out
index 860b8ea214..2a19f0c888 100644
--- a/src/test/regress/expected/rangefuncs_1.out
+++ b/src/test/regress/expected/rangefuncs_1.out
@@ -643,7 +643,7 @@ begin
end $$ language plpgsql;
create trigger tnoticetrigger after insert on tt for each row
execute procedure noticetrigger();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
select insert_tt2('foolme','barme') limit 1;
ERROR: RETURNING clause not yet supported
diff --git a/src/test/regress/expected/triggers_1.out b/src/test/regress/expected/triggers_1.out
index 2fd167457e..8c9ae67deb 100644
--- a/src/test/regress/expected/triggers_1.out
+++ b/src/test/regress/expected/triggers_1.out
@@ -24,13 +24,13 @@ create trigger check_fkeys_pkey_exist
for each row
execute procedure
check_primary_key ('fkey1', 'fkey2', 'pkeys', 'pkey1', 'pkey2');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger check_fkeys_pkey2_exist
before insert or update on fkeys
for each row
execute procedure check_primary_key ('fkey3', 'fkeys2', 'pkey23');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
--
-- For fkeys2:
@@ -41,7 +41,7 @@ create trigger check_fkeys2_pkey_exist
for each row
execute procedure
check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
-- Test comments
COMMENT ON TRIGGER check_fkeys2_pkey_bad ON fkeys2 IS 'wrong';
@@ -61,7 +61,7 @@ create trigger check_pkeys_fkey_cascade
execute procedure
check_foreign_key (2, 'cascade', 'pkey1', 'pkey2',
'fkeys', 'fkey1', 'fkey2', 'fkeys2', 'fkey21', 'fkey22');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
--
-- For fkeys2:
@@ -72,7 +72,7 @@ create trigger check_fkeys2_fkey_restrict
before delete or update on fkeys2
for each row
execute procedure check_foreign_key (1, 'restrict', 'pkey23', 'fkeys', 'fkey3');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
insert into fkeys2 values (10, '1', 1);
insert into fkeys2 values (30, '3', 2);
@@ -143,14 +143,14 @@ create trigger ttdummy
for each row
execute procedure
ttdummy (price_on, price_off);
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger ttserial
before insert or update on tttest
for each row
execute procedure
autoinc (price_on, ttdummy_seq);
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
insert into tttest values (1, 1, null);
insert into tttest values (2, 2, null);
@@ -273,25 +273,21 @@ BEGIN
END;';
CREATE TRIGGER before_ins_stmt_trig BEFORE INSERT ON main_table
FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func('before_ins_stmt');
-ERROR: Postgres-XC does not support TRIGGER yet
-DETAIL: The feature is not currently supported
CREATE TRIGGER after_ins_stmt_trig AFTER INSERT ON main_table
FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func('after_ins_stmt');
-ERROR: Postgres-XC does not support TRIGGER yet
-DETAIL: The feature is not currently supported
--
-- if neither 'FOR EACH ROW' nor 'FOR EACH STATEMENT' was specified,
-- CREATE TRIGGER should default to 'FOR EACH STATEMENT'
--
CREATE TRIGGER after_upd_stmt_trig AFTER UPDATE ON main_table
EXECUTE PROCEDURE trigger_func('after_upd_stmt');
-ERROR: Postgres-XC does not support TRIGGER yet
-DETAIL: The feature is not currently supported
CREATE TRIGGER after_upd_row_trig AFTER UPDATE ON main_table
FOR EACH ROW EXECUTE PROCEDURE trigger_func('after_upd_row');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
INSERT INTO main_table DEFAULT VALUES;
+NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+NOTICE: trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
UPDATE main_table SET a = a + 1 WHERE b < 30;
ERROR: Partition column can't be updated in current version
-- UPDATE that effects zero rows should still call per-statement trigger
@@ -299,6 +295,8 @@ UPDATE main_table SET a = a + 2 WHERE b > 100;
ERROR: Partition column can't be updated in current version
-- COPY should fire per-row and per-statement INSERT triggers
COPY main_table (a, b) FROM stdin;
+NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+NOTICE: trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
SELECT * FROM main_table ORDER BY a, b;
a | b
----+----
@@ -317,31 +315,34 @@ SELECT * FROM main_table ORDER BY a, b;
--
CREATE TRIGGER modified_a BEFORE UPDATE OF a ON main_table
FOR EACH ROW WHEN (OLD.a <> NEW.a) EXECUTE PROCEDURE trigger_func('modified_a');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
CREATE TRIGGER modified_any BEFORE UPDATE OF a ON main_table
FOR EACH ROW WHEN (OLD.* IS DISTINCT FROM NEW.*) EXECUTE PROCEDURE trigger_func('modified_any');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
CREATE TRIGGER insert_a AFTER INSERT ON main_table
FOR EACH ROW WHEN (NEW.a = 123) EXECUTE PROCEDURE trigger_func('insert_a');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
CREATE TRIGGER delete_a AFTER DELETE ON main_table
FOR EACH ROW WHEN (OLD.a = 123) EXECUTE PROCEDURE trigger_func('delete_a');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
CREATE TRIGGER insert_when BEFORE INSERT ON main_table
FOR EACH STATEMENT WHEN (true) EXECUTE PROCEDURE trigger_func('insert_when');
-ERROR: Postgres-XC does not support TRIGGER yet
-DETAIL: The feature is not currently supported
CREATE TRIGGER delete_when AFTER DELETE ON main_table
FOR EACH STATEMENT WHEN (true) EXECUTE PROCEDURE trigger_func('delete_when');
-ERROR: Postgres-XC does not support TRIGGER yet
-DETAIL: The feature is not currently supported
INSERT INTO main_table (a) VALUES (123), (456);
+NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+NOTICE: trigger_func(insert_when) called: action = INSERT, when = BEFORE, level = STATEMENT
+NOTICE: trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
COPY main_table FROM stdin;
+NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+NOTICE: trigger_func(insert_when) called: action = INSERT, when = BEFORE, level = STATEMENT
+NOTICE: trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
DELETE FROM main_table WHERE a IN (123, 456);
+NOTICE: trigger_func(delete_when) called: action = DELETE, when = AFTER, level = STATEMENT
UPDATE main_table SET a = 50, b = 60;
ERROR: Partition column can't be updated in current version
SELECT * FROM main_table ORDER BY a, b;
@@ -381,32 +382,26 @@ ERROR: trigger "insert_a" for table "main_table" does not exist
DROP TRIGGER delete_a ON main_table;
ERROR: trigger "delete_a" for table "main_table" does not exist
DROP TRIGGER insert_when ON main_table;
-ERROR: trigger "insert_when" for table "main_table" does not exist
DROP TRIGGER delete_when ON main_table;
-ERROR: trigger "delete_when" for table "main_table" does not exist
-- Test column-level triggers
DROP TRIGGER after_upd_row_trig ON main_table;
ERROR: trigger "after_upd_row_trig" for table "main_table" does not exist
CREATE TRIGGER before_upd_a_row_trig BEFORE UPDATE OF a ON main_table
FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_upd_a_row');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
CREATE TRIGGER after_upd_b_row_trig AFTER UPDATE OF b ON main_table
FOR EACH ROW EXECUTE PROCEDURE trigger_func('after_upd_b_row');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
CREATE TRIGGER after_upd_a_b_row_trig AFTER UPDATE OF a, b ON main_table
FOR EACH ROW EXECUTE PROCEDURE trigger_func('after_upd_a_b_row');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
CREATE TRIGGER before_upd_a_stmt_trig BEFORE UPDATE OF a ON main_table
FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func('before_upd_a_stmt');
-ERROR: Postgres-XC does not support TRIGGER yet
-DETAIL: The feature is not currently supported
CREATE TRIGGER after_upd_b_stmt_trig AFTER UPDATE OF b ON main_table
FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func('after_upd_b_stmt');
-ERROR: Postgres-XC does not support TRIGGER yet
-DETAIL: The feature is not currently supported
SELECT pg_get_triggerdef(oid) FROM pg_trigger WHERE tgrelid = 'main_table'::regclass AND tgname = 'after_upd_a_b_row_trig';
pg_get_triggerdef
-------------------
@@ -415,6 +410,8 @@ SELECT pg_get_triggerdef(oid) FROM pg_trigger WHERE tgrelid = 'main_table'::regc
UPDATE main_table SET a = 50;
ERROR: Partition column can't be updated in current version
UPDATE main_table SET b = 10;
+NOTICE: trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+NOTICE: trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
--
-- Test case for bug with BEFORE trigger followed by AFTER trigger with WHEN
--
@@ -428,17 +425,17 @@ END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER some_trig_before BEFORE UPDATE ON some_t FOR EACH ROW
EXECUTE PROCEDURE dummy_update_func('before');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
CREATE TRIGGER some_trig_aftera AFTER UPDATE ON some_t FOR EACH ROW
WHEN (NOT OLD.some_col AND NEW.some_col)
EXECUTE PROCEDURE dummy_update_func('aftera');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
CREATE TRIGGER some_trig_afterb AFTER UPDATE ON some_t FOR EACH ROW
WHEN (NOT NEW.some_col)
EXECUTE PROCEDURE dummy_update_func('afterb');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
INSERT INTO some_t VALUES (TRUE);
UPDATE some_t SET some_col = TRUE;
@@ -488,6 +485,9 @@ LINE 2: FOR EACH STATEMENT WHEN (OLD.* IS DISTINCT FROM NEW.*)
^
-- check dependency restrictions
ALTER TABLE main_table DROP COLUMN b;
+ERROR: cannot drop table main_table column b because other objects depend on it
+DETAIL: trigger after_upd_b_stmt_trig on table main_table depends on table main_table column b
+HINT: Use DROP ... CASCADE to drop the dependent objects too.
-- this should succeed, but we'll roll it back to keep the triggers around
begin;
DROP TRIGGER after_upd_a_b_row_trig ON main_table;
@@ -512,32 +512,33 @@ begin
end;$$ language plpgsql;
create trigger trigtest_b_row_tg before insert or update or delete on trigtest
for each row execute procedure trigtest();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger trigtest_a_row_tg after insert or update or delete on trigtest
for each row execute procedure trigtest();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create trigger trigtest_b_stmt_tg before insert or update or delete on trigtest
for each statement execute procedure trigtest();
-ERROR: Postgres-XC does not support TRIGGER yet
-DETAIL: The feature is not currently supported
create trigger trigtest_a_stmt_tg after insert or update or delete on trigtest
for each statement execute procedure trigtest();
-ERROR: Postgres-XC does not support TRIGGER yet
-DETAIL: The feature is not currently supported
insert into trigtest default values;
+NOTICE: trigtest INSERT BEFORE STATEMENT
+NOTICE: trigtest INSERT AFTER STATEMENT
alter table trigtest disable trigger trigtest_b_row_tg;
ERROR: trigger "trigtest_b_row_tg" for table "trigtest" does not exist
insert into trigtest default values;
+NOTICE: trigtest INSERT BEFORE STATEMENT
+NOTICE: trigtest INSERT AFTER STATEMENT
alter table trigtest disable trigger user;
insert into trigtest default values;
alter table trigtest enable trigger trigtest_a_stmt_tg;
-ERROR: trigger "trigtest_a_stmt_tg" for table "trigtest" does not exist
insert into trigtest default values;
+NOTICE: trigtest INSERT AFTER STATEMENT
insert into trigtest2 values(1);
insert into trigtest2 values(2);
delete from trigtest where i=2;
+NOTICE: trigtest DELETE AFTER STATEMENT
select * from trigtest2 order by 1;
i
---
@@ -623,7 +624,7 @@ $$;
CREATE TRIGGER show_trigger_data_trig
BEFORE INSERT OR UPDATE OR DELETE ON trigger_test
FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
insert into trigger_test values(1,'insert');
update trigger_test set v = 'update' where i = 1;
@@ -649,7 +650,7 @@ end$$;
CREATE TRIGGER t
BEFORE UPDATE ON trigger_test
FOR EACH ROW EXECUTE PROCEDURE mytrigger();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
INSERT INTO trigger_test VALUES(1, 'foo', 'bar');
INSERT INTO trigger_test VALUES(2, 'baz', 'quux');
@@ -690,7 +691,7 @@ CREATE TABLE serializable_update_tab (
);
CREATE TRIGGER serializable_update_trig BEFORE UPDATE ON serializable_update_tab
FOR EACH ROW EXECUTE PROCEDURE serializable_update_trig();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
INSERT INTO serializable_update_tab SELECT a, repeat('xyzxz', 100), 'new'
FROM generate_series(1, 50) a;
@@ -720,12 +721,12 @@ INSERT INTO min_updates_test_oids VALUES ('a',1,2),('b','2',null);
CREATE TRIGGER z_min_update
BEFORE UPDATE ON min_updates_test
FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
CREATE TRIGGER z_min_update
BEFORE UPDATE ON min_updates_test_oids
FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
\set QUIET false
UPDATE min_updates_test SET f1 = f1;
@@ -761,27 +762,20 @@ DROP TABLE min_updates_test_oids;
-- Test triggers on views
--
CREATE VIEW main_view AS SELECT a, b FROM main_table;
-ERROR: column "b" does not exist
-LINE 1: CREATE VIEW main_view AS SELECT a, b FROM main_table;
- ^
-- Updates should fail without rules or triggers
INSERT INTO main_view VALUES (1,2);
-ERROR: relation "main_view" does not exist
-LINE 1: INSERT INTO main_view VALUES (1,2);
- ^
+ERROR: cannot insert into view "main_view"
+HINT: You need an unconditional ON INSERT DO INSTEAD rule or an INSTEAD OF INSERT trigger.
UPDATE main_view SET b = 20 WHERE a = 50;
-ERROR: relation "main_view" does not exist
-LINE 1: UPDATE main_view SET b = 20 WHERE a = 50;
- ^
+ERROR: cannot update view "main_view"
+HINT: You need an unconditional ON UPDATE DO INSTEAD rule or an INSTEAD OF UPDATE trigger.
DELETE FROM main_view WHERE a = 50;
-ERROR: relation "main_view" does not exist
-LINE 1: DELETE FROM main_view WHERE a = 50;
- ^
+ERROR: cannot delete from view "main_view"
+HINT: You need an unconditional ON DELETE DO INSTEAD rule or an INSTEAD OF DELETE trigger.
-- Should fail even when there are no matching rows
DELETE FROM main_view WHERE a = 51;
-ERROR: relation "main_view" does not exist
-LINE 1: DELETE FROM main_view WHERE a = 51;
- ^
+ERROR: cannot delete from view "main_view"
+HINT: You need an unconditional ON DELETE DO INSTEAD rule or an INSTEAD OF DELETE trigger.
-- VIEW trigger function
CREATE OR REPLACE FUNCTION view_trigger() RETURNS trigger
LANGUAGE plpgsql AS $$
@@ -825,30 +819,38 @@ $$;
-- Before row triggers aren't allowed on views
CREATE TRIGGER invalid_trig BEFORE INSERT ON main_view
FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_ins_row');
-ERROR: relation "main_view" does not exist
+ERROR: "main_view" is a view
+DETAIL: Views cannot have row-level BEFORE or AFTER triggers.
CREATE TRIGGER invalid_trig BEFORE UPDATE ON main_view
FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_upd_row');
-ERROR: relation "main_view" does not exist
+ERROR: "main_view" is a view
+DETAIL: Views cannot have row-level BEFORE or AFTER triggers.
CREATE TRIGGER invalid_trig BEFORE DELETE ON main_view
FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_del_row');
-ERROR: relation "main_view" does not exist
+ERROR: "main_view" is a view
+DETAIL: Views cannot have row-level BEFORE or AFTER triggers.
-- After row triggers aren't allowed on views
CREATE TRIGGER invalid_trig AFTER INSERT ON main_view
FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_ins_row');
-ERROR: relation "main_view" does not exist
+ERROR: "main_view" is a view
+DETAIL: Views cannot have row-level BEFORE or AFTER triggers.
CREATE TRIGGER invalid_trig AFTER UPDATE ON main_view
FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_upd_row');
-ERROR: relation "main_view" does not exist
+ERROR: "main_view" is a view
+DETAIL: Views cannot have row-level BEFORE or AFTER triggers.
CREATE TRIGGER invalid_trig AFTER DELETE ON main_view
FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_del_row');
-ERROR: relation "main_view" does not exist
+ERROR: "main_view" is a view
+DETAIL: Views cannot have row-level BEFORE or AFTER triggers.
-- Truncate triggers aren't allowed on views
CREATE TRIGGER invalid_trig BEFORE TRUNCATE ON main_view
EXECUTE PROCEDURE trigger_func('before_tru_row');
-ERROR: relation "main_view" does not exist
+ERROR: "main_view" is a view
+DETAIL: Views cannot have TRUNCATE triggers.
CREATE TRIGGER invalid_trig AFTER TRUNCATE ON main_view
EXECUTE PROCEDURE trigger_func('before_tru_row');
-ERROR: relation "main_view" does not exist
+ERROR: "main_view" is a view
+DETAIL: Views cannot have TRUNCATE triggers.
-- INSTEAD OF triggers aren't allowed on tables
CREATE TRIGGER invalid_trig INSTEAD OF INSERT ON main_table
FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_ins');
@@ -865,100 +867,112 @@ DETAIL: Tables cannot have INSTEAD OF triggers.
-- Don't support WHEN clauses with INSTEAD OF triggers
CREATE TRIGGER invalid_trig INSTEAD OF UPDATE ON main_view
FOR EACH ROW WHEN (OLD.a <> NEW.a) EXECUTE PROCEDURE view_trigger('instead_of_upd');
-ERROR: relation "main_view" does not exist
+ERROR: INSTEAD OF triggers cannot have WHEN conditions
-- Don't support column-level INSTEAD OF triggers
CREATE TRIGGER invalid_trig INSTEAD OF UPDATE OF a ON main_view
FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_upd');
-ERROR: relation "main_view" does not exist
+ERROR: INSTEAD OF triggers cannot have column lists
-- Don't support statement-level INSTEAD OF triggers
CREATE TRIGGER invalid_trig INSTEAD OF UPDATE ON main_view
EXECUTE PROCEDURE view_trigger('instead_of_upd');
-ERROR: relation "main_view" does not exist
+ERROR: INSTEAD OF triggers must be FOR EACH ROW
-- Valid INSTEAD OF triggers
CREATE TRIGGER instead_of_insert_trig INSTEAD OF INSERT ON main_view
FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_ins');
-ERROR: relation "main_view" does not exist
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
CREATE TRIGGER instead_of_update_trig INSTEAD OF UPDATE ON main_view
FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_upd');
-ERROR: relation "main_view" does not exist
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
CREATE TRIGGER instead_of_delete_trig INSTEAD OF DELETE ON main_view
FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_del');
-ERROR: relation "main_view" does not exist
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
-- Valid BEFORE statement VIEW triggers
CREATE TRIGGER before_ins_stmt_trig BEFORE INSERT ON main_view
FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_ins_stmt');
-ERROR: relation "main_view" does not exist
CREATE TRIGGER before_upd_stmt_trig BEFORE UPDATE ON main_view
FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_upd_stmt');
-ERROR: relation "main_view" does not exist
CREATE TRIGGER before_del_stmt_trig BEFORE DELETE ON main_view
FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_del_stmt');
-ERROR: relation "main_view" does not exist
-- Valid AFTER statement VIEW triggers
CREATE TRIGGER after_ins_stmt_trig AFTER INSERT ON main_view
FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_ins_stmt');
-ERROR: relation "main_view" does not exist
CREATE TRIGGER after_upd_stmt_trig AFTER UPDATE ON main_view
FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_upd_stmt');
-ERROR: relation "main_view" does not exist
CREATE TRIGGER after_del_stmt_trig AFTER DELETE ON main_view
FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_del_stmt');
-ERROR: relation "main_view" does not exist
\set QUIET false
-- Insert into view using trigger
INSERT INTO main_view VALUES (20, 30);
-ERROR: relation "main_view" does not exist
-LINE 1: INSERT INTO main_view VALUES (20, 30);
- ^
+ERROR: cannot insert into view "main_view"
+HINT: You need an unconditional ON INSERT DO INSTEAD rule or an INSTEAD OF INSERT trigger.
INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
-ERROR: relation "main_view" does not exist
-LINE 1: INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
- ^
+ERROR: RETURNING clause not yet supported
-- Table trigger will prevent updates
UPDATE main_view SET b = 31 WHERE a = 20;
-ERROR: relation "main_view" does not exist
-LINE 1: UPDATE main_view SET b = 31 WHERE a = 20;
- ^
+ERROR: cannot update view "main_view"
+HINT: You need an unconditional ON UPDATE DO INSTEAD rule or an INSTEAD OF UPDATE trigger.
UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
-ERROR: relation "main_view" does not exist
-LINE 1: UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNIN...
- ^
+ERROR: RETURNING clause not yet supported
-- Remove table trigger to allow updates
DROP TRIGGER before_upd_a_row_trig ON main_table;
ERROR: trigger "before_upd_a_row_trig" for table "main_table" does not exist
UPDATE main_view SET b = 31 WHERE a = 20;
-ERROR: relation "main_view" does not exist
-LINE 1: UPDATE main_view SET b = 31 WHERE a = 20;
- ^
+ERROR: cannot update view "main_view"
+HINT: You need an unconditional ON UPDATE DO INSTEAD rule or an INSTEAD OF UPDATE trigger.
UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
-ERROR: relation "main_view" does not exist
-LINE 1: UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNIN...
- ^
+ERROR: RETURNING clause not yet supported
-- Before and after stmt triggers should fire even when no rows are affected
UPDATE main_view SET b = 0 WHERE false;
-ERROR: relation "main_view" does not exist
-LINE 1: UPDATE main_view SET b = 0 WHERE false;
- ^
+ERROR: cannot update view "main_view"
+HINT: You need an unconditional ON UPDATE DO INSTEAD rule or an INSTEAD OF UPDATE trigger.
-- Delete from view using trigger
DELETE FROM main_view WHERE a IN (20,21);
-ERROR: relation "main_view" does not exist
-LINE 1: DELETE FROM main_view WHERE a IN (20,21);
- ^
+ERROR: cannot delete from view "main_view"
+HINT: You need an unconditional ON DELETE DO INSTEAD rule or an INSTEAD OF DELETE trigger.
DELETE FROM main_view WHERE a = 31 RETURNING a, b;
-ERROR: relation "main_view" does not exist
-LINE 1: DELETE FROM main_view WHERE a = 31 RETURNING a, b;
- ^
+ERROR: RETURNING clause not yet supported
\set QUIET true
-- Describe view should list triggers
\d main_view
+ View "public.main_view"
+ Column | Type | Modifiers
+--------+---------+-----------
+ a | integer |
+ b | integer |
+Triggers:
+ after_del_stmt_trig AFTER DELETE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_del_stmt')
+ after_ins_stmt_trig AFTER INSERT ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_ins_stmt')
+ after_upd_stmt_trig AFTER UPDATE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_upd_stmt')
+ before_del_stmt_trig BEFORE DELETE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_del_stmt')
+ before_ins_stmt_trig BEFORE INSERT ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_ins_stmt')
+ before_upd_stmt_trig BEFORE UPDATE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_upd_stmt')
+
-- Test dropping view triggers
DROP TRIGGER instead_of_insert_trig ON main_view;
-ERROR: relation "main_view" does not exist
+ERROR: trigger "instead_of_insert_trig" for table "main_view" does not exist
DROP TRIGGER instead_of_delete_trig ON main_view;
-ERROR: relation "main_view" does not exist
+ERROR: trigger "instead_of_delete_trig" for table "main_view" does not exist
\d+ main_view
+ View "public.main_view"
+ Column | Type | Modifiers | Storage | Description
+--------+---------+-----------+---------+-------------
+ a | integer | | plain |
+ b | integer | | plain |
+View definition:
+ SELECT main_table.a, main_table.b
+ FROM main_table;
+Triggers:
+ after_del_stmt_trig AFTER DELETE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_del_stmt')
+ after_ins_stmt_trig AFTER INSERT ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_ins_stmt')
+ after_upd_stmt_trig AFTER UPDATE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_upd_stmt')
+ before_del_stmt_trig BEFORE DELETE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_del_stmt')
+ before_ins_stmt_trig BEFORE INSERT ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_ins_stmt')
+ before_upd_stmt_trig BEFORE UPDATE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_upd_stmt')
+
DROP VIEW main_view;
-ERROR: view "main_view" does not exist
--
-- Test triggers on a join view
--
@@ -1237,7 +1251,7 @@ end;
$$;
create trigger depth_a_tr before insert on depth_a
for each row execute procedure depth_a_tf();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create function depth_b_tf() returns trigger
language plpgsql as $$
@@ -1258,7 +1272,7 @@ end;
$$;
create trigger depth_b_tr before insert on depth_b
for each row execute procedure depth_b_tf();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
create function depth_c_tf() returns trigger
language plpgsql as $$
@@ -1273,7 +1287,7 @@ end;
$$;
create trigger depth_c_tr before insert on depth_c
for each row execute procedure depth_c_tf();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
select pg_trigger_depth();
pg_trigger_depth
diff --git a/src/test/regress/expected/tsearch_1.out b/src/test/regress/expected/tsearch_1.out
index b6d018d712..c1009e07af 100644
--- a/src/test/regress/expected/tsearch_1.out
+++ b/src/test/regress/expected/tsearch_1.out
@@ -1052,7 +1052,7 @@ SELECT to_tsquery('SKIES & My | booKs');
CREATE TRIGGER tsvectorupdate
BEFORE UPDATE OR INSERT ON test_tsvector
FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger(a, 'pg_catalog.english', t);
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty');
count
diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out
index d5ef568daa..eb708c5251 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -1403,7 +1403,7 @@ end;
$$ LANGUAGE plpgsql;
CREATE TRIGGER y_trig BEFORE INSERT ON y FOR EACH ROW
EXECUTE PROCEDURE y_trigger();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
WITH t AS (
INSERT INTO y
@@ -1434,7 +1434,7 @@ DROP TRIGGER y_trig ON y;
ERROR: trigger "y_trig" for table "y" does not exist
CREATE TRIGGER y_trig AFTER INSERT ON y FOR EACH ROW
EXECUTE PROCEDURE y_trigger();
-ERROR: Postgres-XC does not support TRIGGER yet
+ERROR: Postgres-XC does not support ROW TRIGGER yet
DETAIL: The feature is not currently supported
WITH t AS (
INSERT INTO y
@@ -1471,8 +1471,6 @@ end;
$$ LANGUAGE plpgsql;
CREATE TRIGGER y_trig AFTER INSERT ON y FOR EACH STATEMENT
EXECUTE PROCEDURE y_trigger();
-ERROR: Postgres-XC does not support TRIGGER yet
-DETAIL: The feature is not currently supported
WITH t AS (
INSERT INTO y
VALUES
@@ -1499,7 +1497,6 @@ SELECT * FROM y order by 1;
(10 rows)
DROP TRIGGER y_trig ON y;
-ERROR: trigger "y_trig" for table "y" does not exist
DROP FUNCTION y_trigger();
-- WITH attached to inherited UPDATE or DELETE
CREATE TEMP TABLE parent ( id int, val text );
diff --git a/src/test/regress/expected/xc_triggers.out b/src/test/regress/expected/xc_triggers.out
new file mode 100644
index 0000000000..989602b612
--- /dev/null
+++ b/src/test/regress/expected/xc_triggers.out
@@ -0,0 +1,305 @@
+--
+-- XC_TRIGGER
+--
+-- Creation of a trigger-based method to improve run of count queries
+-- by incrementation and decrementation of statement-based and row-based counters
+-- Create tables
+CREATE TABLE xc_trigger_rep_tab (a int, b int) DISTRIBUTE BY REPLICATION;
+CREATE TABLE xc_trigger_hash_tab (a int, b int) DISTRIBUTE BY HASH(a);
+CREATE TABLE xc_trigger_rr_tab (a int, b int) DISTRIBUTE BY ROUNDROBIN;
+CREATE TABLE xc_trigger_modulo_tab (a int, b int) DISTRIBUTE BY MODULO(a);
+CREATE TABLE table_stats (table_name text primary key,
+num_insert_query int DEFAULT 0,
+num_update_query int DEFAULT 0,
+num_delete_query int DEFAULT 0,
+num_truncate_query int DEFAULT 0,
+num_insert_row int DEFAULT 0,
+num_update_row int DEFAULT 0,
+num_delete_row int DEFAULT 0);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "table_stats_pkey" for table "table_stats"
+-- Insert default entries
+INSERT INTO table_stats (table_name) VALUES ('xc_trigger_rep_tab');
+INSERT INTO table_stats (table_name) VALUES ('xc_trigger_hash_tab');
+INSERT INTO table_stats (table_name) VALUES ('xc_trigger_rr_tab');
+INSERT INTO table_stats (table_name) VALUES ('xc_trigger_modulo_tab');
+-- Functions to manage stats of table
+-- Count the number of queries run
+CREATE FUNCTION count_insert_query() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_insert_query = num_insert_query + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN NEW;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION count_update_query() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_update_query = num_update_query + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION count_delete_query() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_delete_query = num_delete_query + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION count_truncate_query() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_truncate_query = num_truncate_query + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+-- Count the number of rows used
+CREATE FUNCTION count_insert_row() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_insert_row = num_insert_row + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN NEW;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION count_update_row() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_update_row = num_update_row + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION count_delete_row() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_delete_row = num_delete_row + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+-- Define the events for each table
+-- Replicated table
+CREATE TRIGGER rep_count_insert_query AFTER INSERT ON xc_trigger_rep_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_insert_query();
+CREATE TRIGGER rep_count_update_query BEFORE UPDATE ON xc_trigger_rep_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_update_query();
+CREATE TRIGGER rep_count_delete_query BEFORE DELETE ON xc_trigger_rep_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_delete_query();
+CREATE TRIGGER rep_count_truncate_query BEFORE TRUNCATE ON xc_trigger_rep_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_truncate_query();
+CREATE TRIGGER rep_count_insert_row BEFORE INSERT ON xc_trigger_rep_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_insert_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+CREATE TRIGGER rep_count_update_row BEFORE UPDATE ON xc_trigger_rep_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_update_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+CREATE TRIGGER rep_count_delete_row BEFORE DELETE ON xc_trigger_rep_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_delete_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+-- Renaming of trigger based on a table
+ALTER TRIGGER repcount_update_row ON my_table RENAME TO repcount_update_row2;
+ERROR: relation "my_table" does not exist
+-- Hash table
+CREATE TRIGGER hash_count_insert_query AFTER INSERT ON xc_trigger_hash_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_insert_query();
+CREATE TRIGGER hash_count_update_query BEFORE UPDATE ON xc_trigger_hash_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_update_query();
+CREATE TRIGGER hash_count_delete_query BEFORE DELETE ON xc_trigger_hash_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_delete_query();
+CREATE TRIGGER hash_count_truncate_query BEFORE TRUNCATE ON xc_trigger_hash_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_truncate_query();
+CREATE TRIGGER hash_count_insert_row BEFORE INSERT ON xc_trigger_hash_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_insert_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+CREATE TRIGGER hash_count_update_row BEFORE UPDATE ON xc_trigger_hash_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_update_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+CREATE TRIGGER hash_count_delete_row BEFORE DELETE ON xc_trigger_hash_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_delete_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+-- Round robin table
+CREATE TRIGGER rr_count_insert_query AFTER INSERT ON xc_trigger_rr_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_insert_query();
+CREATE TRIGGER rr_count_update_query BEFORE UPDATE ON xc_trigger_rr_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_update_query();
+CREATE TRIGGER rr_count_delete_query BEFORE DELETE ON xc_trigger_rr_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_delete_query();
+CREATE TRIGGER rr_count_truncate_query BEFORE TRUNCATE ON xc_trigger_rr_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_truncate_query();
+CREATE TRIGGER rr_count_insert_row BEFORE INSERT ON xc_trigger_rr_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_insert_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+CREATE TRIGGER rr_count_update_row BEFORE UPDATE ON xc_trigger_rr_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_update_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+CREATE TRIGGER rr_count_delete_row BEFORE DELETE ON xc_trigger_rr_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_delete_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+-- Modulo table
+CREATE TRIGGER modulo_count_insert_query AFTER INSERT ON xc_trigger_modulo_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_insert_query();
+CREATE TRIGGER modulo_count_update_query BEFORE UPDATE ON xc_trigger_modulo_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_update_query();
+CREATE TRIGGER modulo_count_delete_query BEFORE DELETE ON xc_trigger_modulo_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_delete_query();
+CREATE TRIGGER modulo_count_truncate_query BEFORE TRUNCATE ON xc_trigger_modulo_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_truncate_query();
+CREATE TRIGGER modulo_count_insert_row BEFORE INSERT ON xc_trigger_modulo_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_insert_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+CREATE TRIGGER modulo_count_update_row BEFORE UPDATE ON xc_trigger_modulo_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_update_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+CREATE TRIGGER modulo_count_delete_row BEFORE DELETE ON xc_trigger_modulo_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_delete_row();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+-- Insert some values to test the INSERT triggers
+INSERT INTO xc_trigger_rep_tab VALUES (1,2);
+INSERT INTO xc_trigger_rep_tab VALUES (3,4);
+INSERT INTO xc_trigger_rep_tab VALUES (5,6),(7,8),(9,10);
+INSERT INTO xc_trigger_hash_tab VALUES (1,2);
+INSERT INTO xc_trigger_hash_tab VALUES (3,4);
+INSERT INTO xc_trigger_hash_tab VALUES (5,6),(7,8),(9,10);
+INSERT INTO xc_trigger_rr_tab VALUES (1,2);
+INSERT INTO xc_trigger_rr_tab VALUES (3,4);
+INSERT INTO xc_trigger_rr_tab VALUES (5,6),(7,8),(9,10);
+INSERT INTO xc_trigger_modulo_tab VALUES (1,2);
+INSERT INTO xc_trigger_modulo_tab VALUES (3,4);
+INSERT INTO xc_trigger_modulo_tab VALUES (5,6),(7,8),(9,10);
+SELECT * FROM table_stats ORDER BY table_name;
+ table_name | num_insert_query | num_update_query | num_delete_query | num_truncate_query | num_insert_row | num_update_row | num_delete_row
+-----------------------+------------------+------------------+------------------+--------------------+----------------+----------------+----------------
+ xc_trigger_hash_tab | 3 | 0 | 0 | 0 | 0 | 0 | 0
+ xc_trigger_modulo_tab | 3 | 0 | 0 | 0 | 0 | 0 | 0
+ xc_trigger_rep_tab | 3 | 0 | 0 | 0 | 0 | 0 | 0
+ xc_trigger_rr_tab | 3 | 0 | 0 | 0 | 0 | 0 | 0
+(4 rows)
+
+-- Update some values to test the UPDATE triggers
+UPDATE xc_trigger_rep_tab SET b = b+1 WHERE a = 1;
+UPDATE xc_trigger_rep_tab SET b = b+1 WHERE a = 3;
+UPDATE xc_trigger_rep_tab SET b = b+1 WHERE a IN (5,7,9);
+UPDATE xc_trigger_hash_tab SET b = b+1 WHERE a = 1;
+UPDATE xc_trigger_hash_tab SET b = b+1 WHERE a = 3;
+UPDATE xc_trigger_hash_tab SET b = b+1 WHERE a IN (5,7,9);
+UPDATE xc_trigger_rr_tab SET b = b+1 WHERE a = 1;
+UPDATE xc_trigger_rr_tab SET b = b+1 WHERE a = 3;
+UPDATE xc_trigger_rr_tab SET b = b+1 WHERE a IN (5,7,9);
+UPDATE xc_trigger_modulo_tab SET b = b+1 WHERE a = 1;
+UPDATE xc_trigger_modulo_tab SET b = b+1 WHERE a = 3;
+UPDATE xc_trigger_modulo_tab SET b = b+1 WHERE a IN (5,7,9);
+SELECT * FROM table_stats ORDER BY table_name;
+ table_name | num_insert_query | num_update_query | num_delete_query | num_truncate_query | num_insert_row | num_update_row | num_delete_row
+-----------------------+------------------+------------------+------------------+--------------------+----------------+----------------+----------------
+ xc_trigger_hash_tab | 3 | 3 | 0 | 0 | 0 | 0 | 0
+ xc_trigger_modulo_tab | 3 | 3 | 0 | 0 | 0 | 0 | 0
+ xc_trigger_rep_tab | 3 | 3 | 0 | 0 | 0 | 0 | 0
+ xc_trigger_rr_tab | 3 | 3 | 0 | 0 | 0 | 0 | 0
+(4 rows)
+
+-- Delete some values to test the DELETE triggers
+DELETE FROM xc_trigger_rep_tab WHERE a = 1;
+DELETE FROM xc_trigger_rep_tab WHERE a = 3;
+DELETE FROM xc_trigger_rep_tab WHERE a IN (5,7,9);
+DELETE FROM xc_trigger_hash_tab WHERE a = 1;
+DELETE FROM xc_trigger_hash_tab WHERE a = 3;
+DELETE FROM xc_trigger_hash_tab WHERE a IN (5,7,9);
+DELETE FROM xc_trigger_rr_tab WHERE a = 1;
+DELETE FROM xc_trigger_rr_tab WHERE a = 3;
+DELETE FROM xc_trigger_rr_tab WHERE a IN (5,7,9);
+DELETE FROM xc_trigger_modulo_tab WHERE a = 1;
+DELETE FROM xc_trigger_modulo_tab WHERE a = 3;
+DELETE FROM xc_trigger_modulo_tab WHERE a IN (5,7,9);
+SELECT * FROM table_stats ORDER BY table_name;
+ table_name | num_insert_query | num_update_query | num_delete_query | num_truncate_query | num_insert_row | num_update_row | num_delete_row
+-----------------------+------------------+------------------+------------------+--------------------+----------------+----------------+----------------
+ xc_trigger_hash_tab | 3 | 3 | 3 | 0 | 0 | 0 | 0
+ xc_trigger_modulo_tab | 3 | 3 | 3 | 0 | 0 | 0 | 0
+ xc_trigger_rep_tab | 3 | 3 | 3 | 0 | 0 | 0 | 0
+ xc_trigger_rr_tab | 3 | 3 | 3 | 0 | 0 | 0 | 0
+(4 rows)
+
+-- Truncate the table to test the TRUNCATE triggers
+TRUNCATE xc_trigger_rep_tab;
+TRUNCATE xc_trigger_hash_tab;
+TRUNCATE xc_trigger_rr_tab;
+TRUNCATE xc_trigger_modulo_tab;
+SELECT * FROM table_stats ORDER BY table_name;
+ table_name | num_insert_query | num_update_query | num_delete_query | num_truncate_query | num_insert_row | num_update_row | num_delete_row
+-----------------------+------------------+------------------+------------------+--------------------+----------------+----------------+----------------
+ xc_trigger_hash_tab | 3 | 3 | 3 | 1 | 0 | 0 | 0
+ xc_trigger_modulo_tab | 3 | 3 | 3 | 1 | 0 | 0 | 0
+ xc_trigger_rep_tab | 3 | 3 | 3 | 1 | 0 | 0 | 0
+ xc_trigger_rr_tab | 3 | 3 | 3 | 1 | 0 | 0 | 0
+(4 rows)
+
+-- Clean up everything
+DROP TABLE xc_trigger_rep_tab, xc_trigger_hash_tab, xc_trigger_rr_tab, xc_trigger_modulo_tab, table_stats;
+DROP FUNCTION count_tuple_increment();
+ERROR: function count_tuple_increment() does not exist
+DROP FUNCTION count_tuple_decrement();
+ERROR: function count_tuple_decrement() does not exist
+DROP FUNCTION count_insert_query();
+DROP FUNCTION count_update_query();
+DROP FUNCTION count_delete_query();
+DROP FUNCTION count_truncate_query();
+DROP FUNCTION count_insert_row();
+DROP FUNCTION count_update_row();
+DROP FUNCTION count_delete_row();
+-- Tests for INSTEAD OF
+-- Replace operations on a view by operations on a table
+CREATE TABLE real_table (a int, b int);
+CREATE VIEW real_view AS SELECT a,b FROM real_table;
+CREATE FUNCTION insert_real() RETURNS TRIGGER AS $_$
+ BEGIN
+ INSERT INTO real_table VALUES (NEW.a, NEW.b);
+ RETURN NEW;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION update_real() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE real_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b;
+ RETURN NEW;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION delete_real() RETURNS TRIGGER AS $_$
+ BEGIN
+ DELETE FROM real_table WHERE a = OLD.a AND b = OLD.b;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE TRIGGER insert_real_trig INSTEAD OF INSERT ON real_view FOR EACH ROW EXECUTE PROCEDURE insert_real();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+CREATE TRIGGER update_real_trig INSTEAD OF UPDATE ON real_view FOR EACH ROW EXECUTE PROCEDURE update_real();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+CREATE TRIGGER delete_real_trig INSTEAD OF DELETE ON real_view FOR EACH ROW EXECUTE PROCEDURE delete_real();
+ERROR: Postgres-XC does not support ROW TRIGGER yet
+DETAIL: The feature is not currently supported
+-- Renaming of trigger based on a view
+ALTER TRIGGER delete_real_trig ON real_view RENAME TO delete_real_trig2;
+ERROR: trigger "delete_real_trig" for table "real_view" does not exist
+-- Actions
+INSERT INTO real_view VALUES(1,1);
+ERROR: cannot insert into view "real_view"
+HINT: You need an unconditional ON INSERT DO INSTEAD rule or an INSTEAD OF INSERT trigger.
+SELECT * FROM real_table;
+ a | b
+---+---
+(0 rows)
+
+UPDATE real_view SET b = 4 WHERE a = 1;
+ERROR: cannot update view "real_view"
+HINT: You need an unconditional ON UPDATE DO INSTEAD rule or an INSTEAD OF UPDATE trigger.
+SELECT * FROM real_table;
+ a | b
+---+---
+(0 rows)
+
+DELETE FROM real_view WHERE a = 1;
+ERROR: cannot delete from view "real_view"
+HINT: You need an unconditional ON DELETE DO INSTEAD rule or an INSTEAD OF DELETE trigger.
+SELECT * FROM real_table;
+ a | b
+---+---
+(0 rows)
+
+-- Clean up
+DROP VIEW real_view CASCADE;
+DROP FUNCTION insert_real() cascade;
+DROP FUNCTION update_real() cascade;
+DROP FUNCTION delete_real() cascade;
+DROP TABLE real_table;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 62e54867a5..d1d2856641 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -113,7 +113,7 @@ test: stats
# This creates functions used by tests xc_misc, xc_FQS and xc_FQS_join
test: xc_create_function
# Those ones can be run in parallel
-test: xc_groupby xc_distkey xc_having xc_temp xc_remote xc_FQS xc_FQS_join xc_copy xc_for_update xc_alter_table xc_sequence xc_misc
+test: xc_groupby xc_distkey xc_having xc_temp xc_remote xc_FQS xc_FQS_join xc_copy xc_for_update xc_alter_table xc_sequence xc_misc xc_triggers
# Cluster setting related test is independant
test: xc_node
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 10a97ad3b8..3082236dd5 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -142,6 +142,7 @@ test: xc_node
test: xc_FQS
test: xc_FQS_join
test: xc_misc
+test: xc_triggers
test: xc_copy
test: xc_for_update
test: xc_alter_table
diff --git a/src/test/regress/sql/xc_triggers.sql b/src/test/regress/sql/xc_triggers.sql
new file mode 100644
index 0000000000..268b952dc5
--- /dev/null
+++ b/src/test/regress/sql/xc_triggers.sql
@@ -0,0 +1,231 @@
+--
+-- XC_TRIGGER
+--
+
+-- Creation of a trigger-based method to improve run of count queries
+-- by incrementation and decrementation of statement-based and row-based counters
+
+-- Create tables
+CREATE TABLE xc_trigger_rep_tab (a int, b int) DISTRIBUTE BY REPLICATION;
+CREATE TABLE xc_trigger_hash_tab (a int, b int) DISTRIBUTE BY HASH(a);
+CREATE TABLE xc_trigger_rr_tab (a int, b int) DISTRIBUTE BY ROUNDROBIN;
+CREATE TABLE xc_trigger_modulo_tab (a int, b int) DISTRIBUTE BY MODULO(a);
+CREATE TABLE table_stats (table_name text primary key,
+num_insert_query int DEFAULT 0,
+num_update_query int DEFAULT 0,
+num_delete_query int DEFAULT 0,
+num_truncate_query int DEFAULT 0,
+num_insert_row int DEFAULT 0,
+num_update_row int DEFAULT 0,
+num_delete_row int DEFAULT 0);
+
+-- Insert default entries
+INSERT INTO table_stats (table_name) VALUES ('xc_trigger_rep_tab');
+INSERT INTO table_stats (table_name) VALUES ('xc_trigger_hash_tab');
+INSERT INTO table_stats (table_name) VALUES ('xc_trigger_rr_tab');
+INSERT INTO table_stats (table_name) VALUES ('xc_trigger_modulo_tab');
+
+-- Functions to manage stats of table
+-- Count the number of queries run
+CREATE FUNCTION count_insert_query() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_insert_query = num_insert_query + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN NEW;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION count_update_query() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_update_query = num_update_query + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION count_delete_query() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_delete_query = num_delete_query + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION count_truncate_query() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_truncate_query = num_truncate_query + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+-- Count the number of rows used
+CREATE FUNCTION count_insert_row() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_insert_row = num_insert_row + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN NEW;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION count_update_row() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_update_row = num_update_row + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION count_delete_row() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE table_stats SET num_delete_row = num_delete_row + 1 WHERE table_name = TG_TABLE_NAME;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+
+-- Define the events for each table
+-- Replicated table
+CREATE TRIGGER rep_count_insert_query AFTER INSERT ON xc_trigger_rep_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_insert_query();
+CREATE TRIGGER rep_count_update_query BEFORE UPDATE ON xc_trigger_rep_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_update_query();
+CREATE TRIGGER rep_count_delete_query BEFORE DELETE ON xc_trigger_rep_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_delete_query();
+CREATE TRIGGER rep_count_truncate_query BEFORE TRUNCATE ON xc_trigger_rep_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_truncate_query();
+CREATE TRIGGER rep_count_insert_row BEFORE INSERT ON xc_trigger_rep_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_insert_row();
+CREATE TRIGGER rep_count_update_row BEFORE UPDATE ON xc_trigger_rep_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_update_row();
+CREATE TRIGGER rep_count_delete_row BEFORE DELETE ON xc_trigger_rep_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_delete_row();
+-- Renaming of trigger based on a table
+ALTER TRIGGER repcount_update_row ON my_table RENAME TO repcount_update_row2;
+-- Hash table
+CREATE TRIGGER hash_count_insert_query AFTER INSERT ON xc_trigger_hash_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_insert_query();
+CREATE TRIGGER hash_count_update_query BEFORE UPDATE ON xc_trigger_hash_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_update_query();
+CREATE TRIGGER hash_count_delete_query BEFORE DELETE ON xc_trigger_hash_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_delete_query();
+CREATE TRIGGER hash_count_truncate_query BEFORE TRUNCATE ON xc_trigger_hash_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_truncate_query();
+CREATE TRIGGER hash_count_insert_row BEFORE INSERT ON xc_trigger_hash_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_insert_row();
+CREATE TRIGGER hash_count_update_row BEFORE UPDATE ON xc_trigger_hash_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_update_row();
+CREATE TRIGGER hash_count_delete_row BEFORE DELETE ON xc_trigger_hash_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_delete_row();
+-- Round robin table
+CREATE TRIGGER rr_count_insert_query AFTER INSERT ON xc_trigger_rr_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_insert_query();
+CREATE TRIGGER rr_count_update_query BEFORE UPDATE ON xc_trigger_rr_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_update_query();
+CREATE TRIGGER rr_count_delete_query BEFORE DELETE ON xc_trigger_rr_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_delete_query();
+CREATE TRIGGER rr_count_truncate_query BEFORE TRUNCATE ON xc_trigger_rr_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_truncate_query();
+CREATE TRIGGER rr_count_insert_row BEFORE INSERT ON xc_trigger_rr_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_insert_row();
+CREATE TRIGGER rr_count_update_row BEFORE UPDATE ON xc_trigger_rr_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_update_row();
+CREATE TRIGGER rr_count_delete_row BEFORE DELETE ON xc_trigger_rr_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_delete_row();
+-- Modulo table
+CREATE TRIGGER modulo_count_insert_query AFTER INSERT ON xc_trigger_modulo_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_insert_query();
+CREATE TRIGGER modulo_count_update_query BEFORE UPDATE ON xc_trigger_modulo_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_update_query();
+CREATE TRIGGER modulo_count_delete_query BEFORE DELETE ON xc_trigger_modulo_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_delete_query();
+CREATE TRIGGER modulo_count_truncate_query BEFORE TRUNCATE ON xc_trigger_modulo_tab
+ FOR EACH STATEMENT EXECUTE PROCEDURE count_truncate_query();
+CREATE TRIGGER modulo_count_insert_row BEFORE INSERT ON xc_trigger_modulo_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_insert_row();
+CREATE TRIGGER modulo_count_update_row BEFORE UPDATE ON xc_trigger_modulo_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_update_row();
+CREATE TRIGGER modulo_count_delete_row BEFORE DELETE ON xc_trigger_modulo_tab
+ FOR EACH ROW EXECUTE PROCEDURE count_delete_row();
+
+-- Insert some values to test the INSERT triggers
+INSERT INTO xc_trigger_rep_tab VALUES (1,2);
+INSERT INTO xc_trigger_rep_tab VALUES (3,4);
+INSERT INTO xc_trigger_rep_tab VALUES (5,6),(7,8),(9,10);
+INSERT INTO xc_trigger_hash_tab VALUES (1,2);
+INSERT INTO xc_trigger_hash_tab VALUES (3,4);
+INSERT INTO xc_trigger_hash_tab VALUES (5,6),(7,8),(9,10);
+INSERT INTO xc_trigger_rr_tab VALUES (1,2);
+INSERT INTO xc_trigger_rr_tab VALUES (3,4);
+INSERT INTO xc_trigger_rr_tab VALUES (5,6),(7,8),(9,10);
+INSERT INTO xc_trigger_modulo_tab VALUES (1,2);
+INSERT INTO xc_trigger_modulo_tab VALUES (3,4);
+INSERT INTO xc_trigger_modulo_tab VALUES (5,6),(7,8),(9,10);
+SELECT * FROM table_stats ORDER BY table_name;
+
+-- Update some values to test the UPDATE triggers
+UPDATE xc_trigger_rep_tab SET b = b+1 WHERE a = 1;
+UPDATE xc_trigger_rep_tab SET b = b+1 WHERE a = 3;
+UPDATE xc_trigger_rep_tab SET b = b+1 WHERE a IN (5,7,9);
+UPDATE xc_trigger_hash_tab SET b = b+1 WHERE a = 1;
+UPDATE xc_trigger_hash_tab SET b = b+1 WHERE a = 3;
+UPDATE xc_trigger_hash_tab SET b = b+1 WHERE a IN (5,7,9);
+UPDATE xc_trigger_rr_tab SET b = b+1 WHERE a = 1;
+UPDATE xc_trigger_rr_tab SET b = b+1 WHERE a = 3;
+UPDATE xc_trigger_rr_tab SET b = b+1 WHERE a IN (5,7,9);
+UPDATE xc_trigger_modulo_tab SET b = b+1 WHERE a = 1;
+UPDATE xc_trigger_modulo_tab SET b = b+1 WHERE a = 3;
+UPDATE xc_trigger_modulo_tab SET b = b+1 WHERE a IN (5,7,9);
+SELECT * FROM table_stats ORDER BY table_name;
+
+-- Delete some values to test the DELETE triggers
+DELETE FROM xc_trigger_rep_tab WHERE a = 1;
+DELETE FROM xc_trigger_rep_tab WHERE a = 3;
+DELETE FROM xc_trigger_rep_tab WHERE a IN (5,7,9);
+DELETE FROM xc_trigger_hash_tab WHERE a = 1;
+DELETE FROM xc_trigger_hash_tab WHERE a = 3;
+DELETE FROM xc_trigger_hash_tab WHERE a IN (5,7,9);
+DELETE FROM xc_trigger_rr_tab WHERE a = 1;
+DELETE FROM xc_trigger_rr_tab WHERE a = 3;
+DELETE FROM xc_trigger_rr_tab WHERE a IN (5,7,9);
+DELETE FROM xc_trigger_modulo_tab WHERE a = 1;
+DELETE FROM xc_trigger_modulo_tab WHERE a = 3;
+DELETE FROM xc_trigger_modulo_tab WHERE a IN (5,7,9);
+SELECT * FROM table_stats ORDER BY table_name;
+
+-- Truncate the table to test the TRUNCATE triggers
+TRUNCATE xc_trigger_rep_tab;
+TRUNCATE xc_trigger_hash_tab;
+TRUNCATE xc_trigger_rr_tab;
+TRUNCATE xc_trigger_modulo_tab;
+SELECT * FROM table_stats ORDER BY table_name;
+
+-- Clean up everything
+DROP TABLE xc_trigger_rep_tab, xc_trigger_hash_tab, xc_trigger_rr_tab, xc_trigger_modulo_tab, table_stats;
+DROP FUNCTION count_tuple_increment();
+DROP FUNCTION count_tuple_decrement();
+DROP FUNCTION count_insert_query();
+DROP FUNCTION count_update_query();
+DROP FUNCTION count_delete_query();
+DROP FUNCTION count_truncate_query();
+DROP FUNCTION count_insert_row();
+DROP FUNCTION count_update_row();
+DROP FUNCTION count_delete_row();
+
+-- Tests for INSTEAD OF
+-- Replace operations on a view by operations on a table
+CREATE TABLE real_table (a int, b int);
+CREATE VIEW real_view AS SELECT a,b FROM real_table;
+CREATE FUNCTION insert_real() RETURNS TRIGGER AS $_$
+ BEGIN
+ INSERT INTO real_table VALUES (NEW.a, NEW.b);
+ RETURN NEW;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION update_real() RETURNS TRIGGER AS $_$
+ BEGIN
+ UPDATE real_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b;
+ RETURN NEW;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE FUNCTION delete_real() RETURNS TRIGGER AS $_$
+ BEGIN
+ DELETE FROM real_table WHERE a = OLD.a AND b = OLD.b;
+ RETURN OLD;
+ END $_$ LANGUAGE 'plpgsql';
+CREATE TRIGGER insert_real_trig INSTEAD OF INSERT ON real_view FOR EACH ROW EXECUTE PROCEDURE insert_real();
+CREATE TRIGGER update_real_trig INSTEAD OF UPDATE ON real_view FOR EACH ROW EXECUTE PROCEDURE update_real();
+CREATE TRIGGER delete_real_trig INSTEAD OF DELETE ON real_view FOR EACH ROW EXECUTE PROCEDURE delete_real();
+-- Renaming of trigger based on a view
+ALTER TRIGGER delete_real_trig ON real_view RENAME TO delete_real_trig2;
+-- Actions
+INSERT INTO real_view VALUES(1,1);
+SELECT * FROM real_table;
+UPDATE real_view SET b = 4 WHERE a = 1;
+SELECT * FROM real_table;
+DELETE FROM real_view WHERE a = 1;
+SELECT * FROM real_table;
+-- Clean up
+DROP VIEW real_view CASCADE;
+DROP FUNCTION insert_real() cascade;
+DROP FUNCTION update_real() cascade;
+DROP FUNCTION delete_real() cascade;
+DROP TABLE real_table;