@ -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 ) ;