diff options
Diffstat (limited to 'src/backend/rewrite/rewriteHandler.c')
-rw-r--r-- | src/backend/rewrite/rewriteHandler.c | 58 |
1 files changed, 40 insertions, 18 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 8d9805013bb..4e7b307ef2e 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -36,7 +36,13 @@ typedef struct rewrite_event CmdType event; /* type of rule being fired */ } rewrite_event; -static bool acquireLocksOnSubLinks(Node *node, void *context); +typedef struct acquireLocksOnSubLinks_context +{ + bool for_execute; /* AcquireRewriteLocks' forExecute param */ +} acquireLocksOnSubLinks_context; + +static bool acquireLocksOnSubLinks(Node *node, + acquireLocksOnSubLinks_context *context); static Query *rewriteRuleAction(Query *parsetree, Query *rule_action, Node *rule_qual, @@ -65,6 +71,15 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs); * These locks will ensure that the relation schemas don't change under us * while we are rewriting and planning the query. * + * forExecute indicates that the query is about to be executed. + * If so, we'll acquire RowExclusiveLock on the query's resultRelation, + * RowShareLock on any relation accessed FOR UPDATE/SHARE, and + * AccessShareLock on all other relations mentioned. + * + * If forExecute is false, AccessShareLock is acquired on all relations. + * This case is suitable for ruleutils.c, for example, where we only need + * schema stability and we don't intend to actually modify any relations. + * * A secondary purpose of this routine is to fix up JOIN RTE references to * dropped columns (see details below). Because the RTEs are modified in * place, it is generally appropriate for the caller of this routine to have @@ -91,10 +106,13 @@ static Query *fireRIRrules(Query *parsetree, List *activeRIRs); * construction of a nested join was O(N^2) in the nesting depth.) */ void -AcquireRewriteLocks(Query *parsetree) +AcquireRewriteLocks(Query *parsetree, bool forExecute) { ListCell *l; int rt_index; + acquireLocksOnSubLinks_context context; + + context.for_execute = forExecute; /* * First, process RTEs of the current query level. @@ -120,14 +138,12 @@ AcquireRewriteLocks(Query *parsetree) * release it until end of transaction. This protects the * rewriter and planner against schema changes mid-query. * - * If the relation is the query's result relation, then we - * need RowExclusiveLock. Otherwise, check to see if the - * relation is accessed FOR UPDATE/SHARE or not. We can't - * just grab AccessShareLock because then the executor would - * be trying to upgrade the lock, leading to possible - * deadlocks. + * Assuming forExecute is true, this logic must match what the + * executor will do, else we risk lock-upgrade deadlocks. */ - if (rt_index == parsetree->resultRelation) + if (!forExecute) + lockmode = AccessShareLock; + else if (rt_index == parsetree->resultRelation) lockmode = RowExclusiveLock; else if (get_rowmark(parsetree, rt_index)) lockmode = RowShareLock; @@ -206,7 +222,7 @@ AcquireRewriteLocks(Query *parsetree) * The subquery RTE itself is all right, but we have to * recurse to process the represented subquery. */ - AcquireRewriteLocks(rte->subquery); + AcquireRewriteLocks(rte->subquery, forExecute); break; default: @@ -220,7 +236,7 @@ AcquireRewriteLocks(Query *parsetree) { CommonTableExpr *cte = (CommonTableExpr *) lfirst(l); - AcquireRewriteLocks((Query *) cte->ctequery); + AcquireRewriteLocks((Query *) cte->ctequery, forExecute); } /* @@ -228,7 +244,7 @@ AcquireRewriteLocks(Query *parsetree) * the rtable and cteList. */ if (parsetree->hasSubLinks) - query_tree_walker(parsetree, acquireLocksOnSubLinks, NULL, + query_tree_walker(parsetree, acquireLocksOnSubLinks, &context, QTW_IGNORE_RC_SUBQUERIES); } @@ -236,7 +252,7 @@ AcquireRewriteLocks(Query *parsetree) * Walker to find sublink subqueries for AcquireRewriteLocks */ static bool -acquireLocksOnSubLinks(Node *node, void *context) +acquireLocksOnSubLinks(Node *node, acquireLocksOnSubLinks_context *context) { if (node == NULL) return false; @@ -245,7 +261,7 @@ acquireLocksOnSubLinks(Node *node, void *context) SubLink *sub = (SubLink *) node; /* Do what we came for */ - AcquireRewriteLocks((Query *) sub->subselect); + AcquireRewriteLocks((Query *) sub->subselect, context->for_execute); /* Fall through to process lefthand args of SubLink */ } @@ -287,6 +303,9 @@ rewriteRuleAction(Query *parsetree, int rt_length; Query *sub_action; Query **sub_action_ptr; + acquireLocksOnSubLinks_context context; + + context.for_execute = true; /* * Make modifiable copies of rule action and qual (what we're passed are @@ -298,8 +317,8 @@ rewriteRuleAction(Query *parsetree, /* * Acquire necessary locks and fix any deleted JOIN RTE entries. */ - AcquireRewriteLocks(rule_action); - (void) acquireLocksOnSubLinks(rule_qual, NULL); + AcquireRewriteLocks(rule_action, true); + (void) acquireLocksOnSubLinks(rule_qual, &context); current_varno = rt_index; rt_length = list_length(parsetree->rtable); @@ -1154,7 +1173,7 @@ ApplyRetrieveRule(Query *parsetree, */ rule_action = copyObject(linitial(rule->actions)); - AcquireRewriteLocks(rule_action); + AcquireRewriteLocks(rule_action, true); /* * Recursively expand any view references inside the view. @@ -1465,6 +1484,9 @@ CopyAndAddInvertedQual(Query *parsetree, { /* Don't scribble on the passed qual (it's in the relcache!) */ Node *new_qual = (Node *) copyObject(rule_qual); + acquireLocksOnSubLinks_context context; + + context.for_execute = true; /* * In case there are subqueries in the qual, acquire necessary locks and @@ -1472,7 +1494,7 @@ CopyAndAddInvertedQual(Query *parsetree, * rewriteRuleAction, but not entirely ... consider restructuring so that * we only need to process the qual this way once.) */ - (void) acquireLocksOnSubLinks(new_qual, NULL); + (void) acquireLocksOnSubLinks(new_qual, &context); /* Fix references to OLD */ ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0); |