diff options
author | Michael Paquier | 2012-09-06 04:55:05 +0000 |
---|---|---|
committer | Michael Paquier | 2012-09-06 04:55:05 +0000 |
commit | c1b86b2c885e0f18e15169cb2d8088c3f5276249 (patch) | |
tree | 26f3777f8c4c38b3c4e693b2beef6c3f8c5ef517 | |
parent | 63013850114cd690fda43c278f9558801e199993 (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.
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; |