From 79eed418f2c23da23f7380b823008ad2ccb4aab6 Mon Sep 17 00:00:00 2001 From: Pengzhou Tang Date: Tue, 3 Dec 2019 05:04:03 -0500 Subject: [PATCH] Rewrite the target view if it has conditional-INSTEAD rule When UPDATE on a view with conditional INSTEAD rules, we always get the ERROR "no relation entry for relid 2", for conditional INSTEAD OF rules, the original UPDATE operation also need to perform on the view, however, we didn't rewrite the target view for any view with INSTEAD rules. There should be only two cases that you can skip the rewrite of target view: 1) the view has INSTEAD OF triggers on the operations, the operations will be replaced by trigger-defined 2) the view has INSTEAD OF rules and it is non conditional rules, the operations will be replaced by actions. It should be a typo in commit a99c42f291421572aef2, there is a description in documents: "There is a catch if you try to use conditional rules for complex view updates: there must be an unconditional INSTEAD rule for each action you wish to allow on the view." commit a99c42f291421572aef2 explicitly change the description that the restriction only applies to complex view, conditional INSTEAD rule should work for a simple view. --- src/backend/rewrite/rewriteHandler.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 3e38007..05fc6d7 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -3647,18 +3647,32 @@ RewriteQuery(Query *parsetree, List *rewrite_events) } /* - * If there were no INSTEAD rules, and the target relation is a view - * without any INSTEAD OF triggers, see if the view can be + * If the target relation is a view, the target view must be + * rewritten except the cases shown bellow: + * 1) the view has INSTEAD OF triggers on the operations, the + * operations will be replaced by trigger-defined actions. + * 2) the view has INSTEAD OF rules and it is non conditional + * rules, the operations will be replaced by rule-defined + * actions. + * + * If target view need to be rewritten, see if the view can be * automatically updated. If so, we perform the necessary query * transformation here and add the resulting query to the * product_queries list, so that it gets recursively rewritten if * necessary. */ - if (!instead && qual_product == NULL && - rt_entry_relation->rd_rel->relkind == RELKIND_VIEW && - !view_has_instead_trigger(rt_entry_relation, event)) + if (rt_entry_relation->rd_rel->relkind == RELKIND_VIEW && + !view_has_instead_trigger(rt_entry_relation, event) && + !(instead && qual_product == NULL)) { /* + * For target view has conditional INSTEAD OF rules, we must + * rewrite the modified original query. + */ + if (qual_product) + parsetree = qual_product; + + /* * This throws an error if the view can't be automatically * updated, but that's OK since the query would fail at runtime * anyway. -- 1.8.3.1