From 46f95306013011c4195fc222224dc3aa724c64d9 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 18 Jun 2009 01:27:02 +0000 Subject: [PATCH] Fix the just-reported problem that you can't specify all four trigger event 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 | 12 +++----- src/backend/commands/trigger.c | 50 ++++---------------------------- src/backend/nodes/copyfuncs.c | 2 +- src/backend/nodes/equalfuncs.c | 3 +- src/backend/parser/gram.y | 37 +++++++++-------------- src/include/nodes/parsenodes.h | 3 +- 6 files changed, 27 insertions(+), 80 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 9401c18d92..7afe6e7f02 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -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) diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index afa27d2e97..bd46102bb2 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -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. diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index a1239d5fbf..2c7d48122b 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -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); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 435d45b55f..c61de970e6 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -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); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 9a4535501a..ac17b93bf6 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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 TriggerActionTime TriggerForSpec opt_trusted opt_restart_seqs %type opt_lancompiler -%type TriggerEvents +%type TriggerEvents TriggerOneEvent %type TriggerFuncArg %type relation_name copy_file_name @@ -266,7 +267,6 @@ static TypeName *TableFuncTypeName(List *columns); %type privilege_target %type function_with_argtypes %type function_with_argtypes_list -%type TriggerOneEvent %type 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: diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 71c864adf1..a108b80ddf 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -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 */ -- 2.39.5