From 5f2e179bd31e5f5803005101eb12a8d7bf8db8f3 Mon Sep 17 00:00:00 2001 From: Dean Rasheed Date: Thu, 29 Feb 2024 15:56:59 +0000 Subject: 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 --- src/backend/parser/parse_merge.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'src/backend/parser/parse_merge.c') diff --git a/src/backend/parser/parse_merge.c b/src/backend/parser/parse_merge.c index 73f7a48b3c6..4356d61f8ed 100644 --- a/src/backend/parser/parse_merge.c +++ b/src/backend/parser/parse_merge.c @@ -172,28 +172,27 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) * Set up the MERGE target table. The target table is added to the * namespace below and to joinlist in transform_MERGE_to_join, so don't do * it here. + * + * Initially mergeTargetRelation is the same as resultRelation, so data is + * read from the table being updated. However, that might be changed by + * the rewriter, if the target is a trigger-updatable view, to allow + * target data to be read from the expanded view query while updating the + * original view relation. */ qry->resultRelation = setTargetTable(pstate, stmt->relation, stmt->relation->inh, false, targetPerms); + qry->mergeTargetRelation = qry->resultRelation; - /* - * MERGE is unsupported in various cases - */ + /* The target relation must be a table or a view */ if (pstate->p_target_relation->rd_rel->relkind != RELKIND_RELATION && - pstate->p_target_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) + pstate->p_target_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE && + pstate->p_target_relation->rd_rel->relkind != RELKIND_VIEW) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot execute MERGE on relation \"%s\"", RelationGetRelationName(pstate->p_target_relation)), errdetail_relkind_not_supported(pstate->p_target_relation->rd_rel->relkind))); - if (pstate->p_target_relation->rd_rules != NULL && - pstate->p_target_relation->rd_rules->numLocks > 0) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot execute MERGE on relation \"%s\"", - RelationGetRelationName(pstate->p_target_relation)), - errdetail("MERGE is not supported for relations with rules."))); /* Now transform the source relation to produce the source RTE. */ transformFromClause(pstate, -- cgit v1.2.3