aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/matview.c2
-rw-r--r--src/backend/rewrite/rewriteHandler.c68
-rw-r--r--src/backend/utils/adt/ruleutils.c7
-rw-r--r--src/include/rewrite/rewriteHandler.h4
4 files changed, 57 insertions, 24 deletions
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index a331f3e7176..d64f1657066 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -303,7 +303,7 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
/* Lock and rewrite, using a copy to preserve the original query. */
copied_query = copyObject(query);
- AcquireRewriteLocks(copied_query, false);
+ AcquireRewriteLocks(copied_query, true, false);
rewritten = QueryRewrite(copied_query);
/* SELECT should never rewrite to more or less than one SELECT query */
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 0b136451d80..f4f49d21f1f 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -37,7 +37,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,
@@ -71,9 +77,19 @@ static Bitmapset *adjust_view_column_set(Bitmapset *cols, List *targetlist);
* These locks will ensure that the relation schemas don't change under us
* while we are rewriting and planning the query.
*
- * forUpdatePushedDown indicates that a pushed-down FOR [KEY] UPDATE/SHARE applies
- * to the current subquery, requiring all rels to be opened with RowShareLock.
- * This should always be false at the start of the recursion.
+ * 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 [KEY] 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.
+ *
+ * forUpdatePushedDown indicates that a pushed-down FOR [KEY] UPDATE/SHARE
+ * applies to the current subquery, requiring all rels to be opened with at
+ * least RowShareLock. This should always be false at the top of the
+ * recursion. This flag is ignored if forExecute is false.
*
* 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
@@ -101,10 +117,15 @@ static Bitmapset *adjust_view_column_set(Bitmapset *cols, List *targetlist);
* construction of a nested join was O(N^2) in the nesting depth.)
*/
void
-AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
+AcquireRewriteLocks(Query *parsetree,
+ bool forExecute,
+ bool forUpdatePushedDown)
{
ListCell *l;
int rt_index;
+ acquireLocksOnSubLinks_context context;
+
+ context.for_execute = forExecute;
/*
* First, process RTEs of the current query level.
@@ -130,14 +151,12 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
* 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 [KEY] 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 (forUpdatePushedDown ||
get_parse_rowmark(parsetree, rt_index) != NULL)
@@ -225,6 +244,7 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
* recurse to process the represented subquery.
*/
AcquireRewriteLocks(rte->subquery,
+ forExecute,
(forUpdatePushedDown ||
get_parse_rowmark(parsetree, rt_index) != NULL));
break;
@@ -240,7 +260,7 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
{
CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
- AcquireRewriteLocks((Query *) cte->ctequery, false);
+ AcquireRewriteLocks((Query *) cte->ctequery, forExecute, false);
}
/*
@@ -248,7 +268,7 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
* the rtable and cteList.
*/
if (parsetree->hasSubLinks)
- query_tree_walker(parsetree, acquireLocksOnSubLinks, NULL,
+ query_tree_walker(parsetree, acquireLocksOnSubLinks, &context,
QTW_IGNORE_RC_SUBQUERIES);
}
@@ -256,7 +276,7 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
* 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;
@@ -265,7 +285,9 @@ acquireLocksOnSubLinks(Node *node, void *context)
SubLink *sub = (SubLink *) node;
/* Do what we came for */
- AcquireRewriteLocks((Query *) sub->subselect, false);
+ AcquireRewriteLocks((Query *) sub->subselect,
+ context->for_execute,
+ false);
/* Fall through to process lefthand args of SubLink */
}
@@ -307,6 +329,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
@@ -318,8 +343,8 @@ rewriteRuleAction(Query *parsetree,
/*
* Acquire necessary locks and fix any deleted JOIN RTE entries.
*/
- AcquireRewriteLocks(rule_action, false);
- (void) acquireLocksOnSubLinks(rule_qual, NULL);
+ AcquireRewriteLocks(rule_action, true, false);
+ (void) acquireLocksOnSubLinks(rule_qual, &context);
current_varno = rt_index;
rt_length = list_length(parsetree->rtable);
@@ -1389,7 +1414,7 @@ ApplyRetrieveRule(Query *parsetree,
*/
rule_action = copyObject(linitial(rule->actions));
- AcquireRewriteLocks(rule_action, forUpdatePushedDown);
+ AcquireRewriteLocks(rule_action, true, forUpdatePushedDown);
/*
* Recursively expand any view references inside the view.
@@ -1712,6 +1737,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
@@ -1719,7 +1747,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);
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index add5cd1695b..566b4c910b3 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3966,7 +3966,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
query = getInsertSelectQuery(query, NULL);
/* Must acquire locks right away; see notes in get_query_def() */
- AcquireRewriteLocks(query, false);
+ AcquireRewriteLocks(query, false, false);
context.buf = buf;
context.namespaces = list_make1(&dpns);
@@ -4108,8 +4108,11 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace,
* relations, and fix up deleted columns in JOIN RTEs. This ensures
* consistent results. Note we assume it's OK to scribble on the passed
* querytree!
+ *
+ * We are only deparsing the query (we are not about to execute it), so we
+ * only need AccessShareLock on the relations it mentions.
*/
- AcquireRewriteLocks(query, false);
+ AcquireRewriteLocks(query, false, false);
context.buf = buf;
context.namespaces = lcons(&dpns, list_copy(parentnamespace));
diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h
index e4027bd9c56..22551ece3ec 100644
--- a/src/include/rewrite/rewriteHandler.h
+++ b/src/include/rewrite/rewriteHandler.h
@@ -18,7 +18,9 @@
#include "nodes/parsenodes.h"
extern List *QueryRewrite(Query *parsetree);
-extern void AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown);
+extern void AcquireRewriteLocks(Query *parsetree,
+ bool forExecute,
+ bool forUpdatePushedDown);
extern Node *build_column_default(Relation rel, int attrno);
extern Query *get_view_query(Relation view);