mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
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
This commit is contained in:
@ -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())
|
||||
|
Reference in New Issue
Block a user