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,
* 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
* 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.
* 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;
* 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:
{
CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
- AcquireRewriteLocks((Query *) cte->ctequery);
+ AcquireRewriteLocks((Query *) cte->ctequery, forExecute);
}
/*
* the rtable and cteList.
*/
if (parsetree->hasSubLinks)
- query_tree_walker(parsetree, acquireLocksOnSubLinks, NULL,
+ query_tree_walker(parsetree, acquireLocksOnSubLinks, &context,
QTW_IGNORE_RC_SUBQUERIES);
}
* 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;
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 */
}
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
/*
* 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);
*/
rule_action = copyObject(linitial(rule->actions));
- AcquireRewriteLocks(rule_action);
+ AcquireRewriteLocks(rule_action, true);
/*
* Recursively expand any view references inside the view.
{
/* 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
* 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);