Fix the just-reported problem that you can't specify all four trigger event
authorTom Lane <[email protected]>
Thu, 18 Jun 2009 01:27:02 +0000 (01:27 +0000)
committerTom Lane <[email protected]>
Thu, 18 Jun 2009 01:27:02 +0000 (01:27 +0000)
types in CREATE TRIGGER.  While at it, clean up the amazingly tedious and
inextensible way that the trigger event type list was handled.  Per report
from Greg Sabino Mullane.

src/backend/commands/tablecmds.c
src/backend/commands/trigger.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/include/nodes/parsenodes.h

index 9401c18d92dc6bc6a6571cebab7f82f2f68bf6b2..7afe6e7f026352ffc2727c0fee0d9af886616e84 100644 (file)
@@ -5206,14 +5206,13 @@ CreateFKCheckTrigger(RangeVar *myRel, FkConstraint *fkconstraint,
        if (on_insert)
        {
                fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins");
-               fk_trigger->actions[0] = 'i';
+               fk_trigger->events = TRIGGER_TYPE_INSERT;
        }
        else
        {
                fk_trigger->funcname = SystemFuncName("RI_FKey_check_upd");
-               fk_trigger->actions[0] = 'u';
+               fk_trigger->events = TRIGGER_TYPE_UPDATE;
        }
-       fk_trigger->actions[1] = '\0';
 
        fk_trigger->isconstraint = true;
        fk_trigger->deferrable = fkconstraint->deferrable;
@@ -5263,9 +5262,7 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
        fk_trigger->relation = fkconstraint->pktable;
        fk_trigger->before = false;
        fk_trigger->row = true;
-       fk_trigger->actions[0] = 'd';
-       fk_trigger->actions[1] = '\0';
-
+       fk_trigger->events = TRIGGER_TYPE_DELETE;
        fk_trigger->isconstraint = true;
        fk_trigger->constrrel = myRel;
        switch (fkconstraint->fk_del_action)
@@ -5316,8 +5313,7 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
        fk_trigger->relation = fkconstraint->pktable;
        fk_trigger->before = false;
        fk_trigger->row = true;
-       fk_trigger->actions[0] = 'u';
-       fk_trigger->actions[1] = '\0';
+       fk_trigger->events = TRIGGER_TYPE_UPDATE;
        fk_trigger->isconstraint = true;
        fk_trigger->constrrel = myRel;
        switch (fkconstraint->fk_upd_action)
index afa27d2e978afe6d85a6c12258813623115a6875..bd46102bb287fd7681058dff04afd6cd34aec6bc 100644 (file)
@@ -100,7 +100,6 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid, bool checkPermissions)
        Oid                     funcoid;
        Oid                     funcrettype;
        Oid                     trigoid;
-       int                     i;
        char            constrtrigname[NAMEDATALEN];
        char       *trigname;
        char       *constrname;
@@ -150,50 +149,13 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid, bool checkPermissions)
                TRIGGER_SETT_BEFORE(tgtype);
        if (stmt->row)
                TRIGGER_SETT_ROW(tgtype);
+       tgtype |= stmt->events;
 
-       for (i = 0; stmt->actions[i]; i++)
-       {
-               switch (stmt->actions[i])
-               {
-                       case 'i':
-                               if (TRIGGER_FOR_INSERT(tgtype))
-                                       ereport(ERROR,
-                                                       (errcode(ERRCODE_SYNTAX_ERROR),
-                                                        errmsg("multiple INSERT events specified")));
-                               TRIGGER_SETT_INSERT(tgtype);
-                               break;
-                       case 'd':
-                               if (TRIGGER_FOR_DELETE(tgtype))
-                                       ereport(ERROR,
-                                                       (errcode(ERRCODE_SYNTAX_ERROR),
-                                                        errmsg("multiple DELETE events specified")));
-                               TRIGGER_SETT_DELETE(tgtype);
-                               break;
-                       case 'u':
-                               if (TRIGGER_FOR_UPDATE(tgtype))
-                                       ereport(ERROR,
-                                                       (errcode(ERRCODE_SYNTAX_ERROR),
-                                                        errmsg("multiple UPDATE events specified")));
-                               TRIGGER_SETT_UPDATE(tgtype);
-                               break;
-                       case 't':
-                               if (TRIGGER_FOR_TRUNCATE(tgtype))
-                                       ereport(ERROR,
-                                                       (errcode(ERRCODE_SYNTAX_ERROR),
-                                                        errmsg("multiple TRUNCATE events specified")));
-                               TRIGGER_SETT_TRUNCATE(tgtype);
-                               /* Disallow ROW-level TRUNCATE triggers */
-                               if (stmt->row)
-                                       ereport(ERROR,
-                                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                        errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
-                               break;
-                       default:
-                               elog(ERROR, "unrecognized trigger event: %d",
-                                        (int) stmt->actions[i]);
-                               break;
-               }
-       }
+       /* Disallow ROW-level TRUNCATE triggers */
+       if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
 
        /*
         * Find and validate the trigger function.
index a1239d5fbf648b45b3c49b36695b4e76caff1b83..2c7d48122bd9ceb6f486249eb385a9d79f014fc1 100644 (file)
@@ -3081,7 +3081,7 @@ _copyCreateTrigStmt(CreateTrigStmt *from)
        COPY_NODE_FIELD(args);
        COPY_SCALAR_FIELD(before);
        COPY_SCALAR_FIELD(row);
-       strcpy(newnode->actions, from->actions);        /* in-line string field */
+       COPY_SCALAR_FIELD(events);
        COPY_SCALAR_FIELD(isconstraint);
        COPY_SCALAR_FIELD(deferrable);
        COPY_SCALAR_FIELD(initdeferred);
index 435d45b55fc06f3785b27816af97187fbf1c3735..c61de970e6f4b51f24c1c74ef7ff0dd44dc9845b 100644 (file)
@@ -1639,8 +1639,7 @@ _equalCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b)
        COMPARE_NODE_FIELD(args);
        COMPARE_SCALAR_FIELD(before);
        COMPARE_SCALAR_FIELD(row);
-       if (strcmp(a->actions, b->actions) != 0)        /* in-line string field */
-               return false;
+       COMPARE_SCALAR_FIELD(events);
        COMPARE_SCALAR_FIELD(isconstraint);
        COMPARE_SCALAR_FIELD(deferrable);
        COMPARE_SCALAR_FIELD(initdeferred);
index 9a4535501ab4c44fd56a5c85013ac40ebd9f4b27..ac17b93bf6863115a54496fcdf9bb2a6e7c15a20 100644 (file)
@@ -53,6 +53,7 @@
 
 #include "catalog/index.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_trigger.h"
 #include "commands/defrem.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
@@ -244,7 +245,7 @@ static TypeName *TableFuncTypeName(List *columns);
 %type <boolean> TriggerActionTime TriggerForSpec opt_trusted opt_restart_seqs
 %type <str>            opt_lancompiler
 
-%type <str>            TriggerEvents
+%type <ival>   TriggerEvents TriggerOneEvent
 %type <value>  TriggerFuncArg
 
 %type <str>            relation_name copy_file_name
@@ -266,7 +267,6 @@ static TypeName *TableFuncTypeName(List *columns);
 %type <privtarget> privilege_target
 %type <funwithargs> function_with_argtypes
 %type <list>   function_with_argtypes_list
-%type <chr>    TriggerOneEvent
 
 %type <list>   stmtblock stmtmulti
                                OptTableElementList TableElementList OptInherit definition
@@ -3133,7 +3133,7 @@ CreateTrigStmt:
                                        n->args = $13;
                                        n->before = $4;
                                        n->row = $8;
-                                       memcpy(n->actions, $5, 4);
+                                       n->events = $5;
                                        n->isconstraint  = FALSE;
                                        n->deferrable    = FALSE;
                                        n->initdeferred  = FALSE;
@@ -3153,11 +3153,10 @@ CreateTrigStmt:
                                        n->args = $18;
                                        n->before = FALSE;
                                        n->row = TRUE;
-                                       memcpy(n->actions, $6, 4);
+                                       n->events = $6;
                                        n->isconstraint  = TRUE;
                                        n->deferrable = ($10 & 1) != 0;
                                        n->initdeferred = ($10 & 2) != 0;
-
                                        n->constrrel = $9;
                                        $$ = (Node *)n;
                                }
@@ -3170,30 +3169,20 @@ TriggerActionTime:
 
 TriggerEvents:
                        TriggerOneEvent
+                               { $$ = $1; }
+                       | TriggerEvents OR TriggerOneEvent
                                {
-                                       char *e = palloc(4);
-                                       e[0] = $1; e[1] = '\0';
-                                       $$ = e;
-                               }
-                       | TriggerOneEvent OR TriggerOneEvent
-                               {
-                                       char *e = palloc(4);
-                                       e[0] = $1; e[1] = $3; e[2] = '\0';
-                                       $$ = e;
-                               }
-                       | TriggerOneEvent OR TriggerOneEvent OR TriggerOneEvent
-                               {
-                                       char *e = palloc(4);
-                                       e[0] = $1; e[1] = $3; e[2] = $5; e[3] = '\0';
-                                       $$ = e;
+                                       if ($1 & $3)
+                                               yyerror("duplicate trigger events specified");
+                                       $$ = $1 | $3;
                                }
                ;
 
 TriggerOneEvent:
-                       INSERT                                                                  { $$ = 'i'; }
-                       | DELETE_P                                                              { $$ = 'd'; }
-                       | UPDATE                                                                { $$ = 'u'; }
-                       | TRUNCATE                                                              { $$ = 't'; }
+                       INSERT                                                          { $$ = TRIGGER_TYPE_INSERT; }
+                       | DELETE_P                                                      { $$ = TRIGGER_TYPE_DELETE; }
+                       | UPDATE                                                        { $$ = TRIGGER_TYPE_UPDATE; }
+                       | TRUNCATE                                                      { $$ = TRIGGER_TYPE_TRUNCATE; }
                ;
 
 TriggerForSpec:
index 71c864adf1746e211fd1b8036a9c1f91c68e7015..a108b80ddf28c972f287ff82a13b7945a07d8226 100644 (file)
@@ -1551,7 +1551,8 @@ typedef struct CreateTrigStmt
        List       *args;                       /* list of (T_String) Values or NIL */
        bool            before;                 /* BEFORE/AFTER */
        bool            row;                    /* ROW/STATEMENT */
-       char            actions[4];             /* 1 to 3 of 'i', 'u', 'd', + trailing \0 */
+       /* events uses the TRIGGER_TYPE bits defined in catalog/pg_trigger.h */
+       int16           events;                 /* INSERT/UPDATE/DELETE/TRUNCATE */
 
        /* The following are used for referential */
        /* integrity constraint triggers */