diff options
author | Dean Rasheed <dean.a.rasheed@gmail.com> | 2024-02-29 15:56:59 +0000 |
---|---|---|
committer | Dean Rasheed <dean.a.rasheed@gmail.com> | 2024-02-29 15:56:59 +0000 |
commit | 5f2e179bd31e5f5803005101eb12a8d7bf8db8f3 (patch) | |
tree | 838a9f273c1d3d825db322161c0b8cdf3fbb0ce1 /src/backend/executor/execMain.c | |
parent | 8b29a119fdaa381d6f75105f539b1e658c0f8cdb (diff) | |
download | postgresql-5f2e179bd31e5f5803005101eb12a8d7bf8db8f3.tar.gz postgresql-5f2e179bd31e5f5803005101eb12a8d7bf8db8f3.zip |
Support MERGE into updatable views.
This allows the target relation of MERGE to be an auto-updatable or
trigger-updatable view, and includes support for WITH CHECK OPTION,
security barrier views, and security invoker views.
A trigger-updatable view must have INSTEAD OF triggers for every type
of action (INSERT, UPDATE, and DELETE) mentioned in the MERGE command.
An auto-updatable view must not have any INSTEAD OF triggers. Mixing
auto-update and trigger-update actions (i.e., having a partial set of
INSTEAD OF triggers) is not supported.
Rule-updatable views are also not supported, since there is no
rewriter support for non-SELECT rules with MERGE operations.
Dean Rasheed, reviewed by Jian He and Alvaro Herrera.
Discussion: https://postgr.es/m/CAEZATCVcB1g0nmxuEc-A+gGB0HnfcGQNGYH7gS=7rq0u0zOBXA@mail.gmail.com
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r-- | src/backend/executor/execMain.c | 51 |
1 files changed, 14 insertions, 37 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 13a9b7da83b..79ef46f2614 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -56,6 +56,7 @@ #include "miscadmin.h" #include "parser/parse_relation.h" #include "parser/parsetree.h" +#include "rewrite/rewriteHandler.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "tcop/utility.h" @@ -1017,14 +1018,18 @@ InitPlan(QueryDesc *queryDesc, int eflags) * Generally the parser and/or planner should have noticed any such mistake * already, but let's make sure. * + * For MERGE, mergeActions is the list of actions that may be performed. The + * result relation is required to support every action, regardless of whether + * or not they are all executed. + * * Note: when changing this function, you probably also need to look at * CheckValidRowMarkRel. */ void -CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation) +CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, + List *mergeActions) { Relation resultRel = resultRelInfo->ri_RelationDesc; - TriggerDesc *trigDesc = resultRel->trigdesc; FdwRoutine *fdwroutine; switch (resultRel->rd_rel->relkind) @@ -1048,42 +1053,14 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation) case RELKIND_VIEW: /* - * Okay only if there's a suitable INSTEAD OF trigger. Messages - * here should match rewriteHandler.c's rewriteTargetView and - * RewriteQuery, except that we omit errdetail because we haven't - * got the information handy (and given that we really shouldn't - * get here anyway, it's not worth great exertion to get). + * Okay only if there's a suitable INSTEAD OF trigger. Otherwise, + * complain, but omit errdetail because we haven't got the + * information handy (and given that it really shouldn't happen, + * it's not worth great exertion to get). */ - 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(resultRel)), - errhint("To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule."))); - 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(resultRel)), - errhint("To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule."))); - 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(resultRel)), - errhint("To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule."))); - break; - default: - elog(ERROR, "unrecognized CmdType: %d", (int) operation); - break; - } + if (!view_has_instead_trigger(resultRel, operation, mergeActions)) + error_view_not_updatable(resultRel, operation, mergeActions, + NULL); break; case RELKIND_MATVIEW: if (!MatViewIncrementalMaintenanceIsEnabled()) |