diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-10-10 13:43:33 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-10-10 13:45:07 -0400 |
commit | 2ec993a7cbdd8e251817ac6bbc9a704ce8346f73 (patch) | |
tree | 1568fb4b00b6fa7997755113a3d0bbfead45c1fb /src/backend/executor/execMain.c | |
parent | f7b15b5098ee89a2628129fbbef9901bded9d27b (diff) | |
download | postgresql-2ec993a7cbdd8e251817ac6bbc9a704ce8346f73.tar.gz postgresql-2ec993a7cbdd8e251817ac6bbc9a704ce8346f73.zip |
Support triggers on views.
This patch adds the SQL-standard concept of an INSTEAD OF trigger, which
is fired instead of performing a physical insert/update/delete. The
trigger function is passed the entire old and/or new rows of the view,
and must figure out what to do to the underlying tables to implement
the update. So this feature can be used to implement updatable views
using trigger programming style rather than rule hacking.
In passing, this patch corrects the names of some columns in the
information_schema.triggers view. It seems the SQL committee renamed
them somewhere between SQL:99 and SQL:2003.
Dean Rasheed, reviewed by Bernd Helmle; some additional hacking by me.
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r-- | src/backend/executor/execMain.c | 44 |
1 files changed, 37 insertions, 7 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 20af966ddb0..69f3a28d415 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -877,9 +877,13 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo, CmdType operation, int instrument_options) { + TriggerDesc *trigDesc = resultRelationDesc->trigdesc; + /* - * Check valid relkind ... parser and/or planner should have noticed this - * already, but let's make sure. + * Check valid relkind ... in most cases parser and/or planner should have + * noticed this already, but let's make sure. In the view case we do need + * a test here, because if the view wasn't rewritten by a rule, it had + * better have an INSTEAD trigger. */ switch (resultRelationDesc->rd_rel->relkind) { @@ -899,10 +903,36 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo, RelationGetRelationName(resultRelationDesc)))); break; case RELKIND_VIEW: - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot change view \"%s\"", - RelationGetRelationName(resultRelationDesc)))); + switch (operation) + { + case CMD_INSERT: + if (!trigDesc || !trigDesc->trig_insert_instead_row) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("cannot insert into view \"%s\"", + RelationGetRelationName(resultRelationDesc)), + errhint("You need an unconditional ON INSERT DO INSTEAD rule or an INSTEAD OF INSERT trigger."))); + break; + case CMD_UPDATE: + if (!trigDesc || !trigDesc->trig_update_instead_row) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("cannot update view \"%s\"", + RelationGetRelationName(resultRelationDesc)), + errhint("You need an unconditional ON UPDATE DO INSTEAD rule or an INSTEAD OF UPDATE trigger."))); + break; + case CMD_DELETE: + if (!trigDesc || !trigDesc->trig_delete_instead_row) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("cannot delete from view \"%s\"", + RelationGetRelationName(resultRelationDesc)), + errhint("You need an unconditional ON DELETE DO INSTEAD rule or an INSTEAD OF DELETE trigger."))); + break; + default: + elog(ERROR, "unrecognized CmdType: %d", (int) operation); + break; + } break; default: ereport(ERROR, @@ -921,7 +951,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo, resultRelInfo->ri_IndexRelationDescs = NULL; resultRelInfo->ri_IndexRelationInfo = NULL; /* make a copy so as not to depend on relcache info not changing... */ - resultRelInfo->ri_TrigDesc = CopyTriggerDesc(resultRelationDesc->trigdesc); + resultRelInfo->ri_TrigDesc = CopyTriggerDesc(trigDesc); if (resultRelInfo->ri_TrigDesc) { int n = resultRelInfo->ri_TrigDesc->numtriggers; |