mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Fix markQueryForLocking() to work correctly in the presence of nested views.
It has been wrong for this case since it was first written for 7.1 :-( Per report from Pavel Hanák.
This commit is contained in:
		@@ -7,7 +7,7 @@
 | 
			
		||||
 * Portions Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.158.2.2 2005/11/23 17:21:22 tgl Exp $
 | 
			
		||||
 *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.158.2.3 2007/03/01 18:50:42 tgl Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@@ -52,8 +52,8 @@ static TargetEntry *process_matched_tle(TargetEntry *src_tle,
 | 
			
		||||
					TargetEntry *prior_tle,
 | 
			
		||||
					const char *attrName);
 | 
			
		||||
static Node *get_assignment_input(Node *node);
 | 
			
		||||
static void markQueryForLocking(Query *qry, bool forUpdate, bool noWait,
 | 
			
		||||
					bool skipOldNew);
 | 
			
		||||
static void markQueryForLocking(Query *qry, Node *jtnode,
 | 
			
		||||
								bool forUpdate, bool noWait);
 | 
			
		||||
static List *matchLocks(CmdType event, RuleLock *rulelocks,
 | 
			
		||||
		   int varno, Query *parsetree);
 | 
			
		||||
static Query *fireRIRrules(Query *parsetree, List *activeRIRs);
 | 
			
		||||
@@ -966,8 +966,8 @@ ApplyRetrieveRule(Query *parsetree,
 | 
			
		||||
		/*
 | 
			
		||||
		 * Set up the view's referenced tables as if FOR UPDATE/SHARE.
 | 
			
		||||
		 */
 | 
			
		||||
		markQueryForLocking(rule_action, parsetree->forUpdate,
 | 
			
		||||
							parsetree->rowNoWait, true);
 | 
			
		||||
		markQueryForLocking(rule_action, (Node *) rule_action->jointree,
 | 
			
		||||
							parsetree->forUpdate, parsetree->rowNoWait);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return parsetree;
 | 
			
		||||
@@ -979,14 +979,15 @@ ApplyRetrieveRule(Query *parsetree,
 | 
			
		||||
 * This may generate an invalid query, eg if some sub-query uses an
 | 
			
		||||
 * aggregate.  We leave it to the planner to detect that.
 | 
			
		||||
 *
 | 
			
		||||
 * NB: this must agree with the parser's transformLocking() routine.
 | 
			
		||||
 * NB: this must agree with the parser's transformLockingClause() routine.
 | 
			
		||||
 * However, unlike the parser we have to be careful not to mark a view's
 | 
			
		||||
 * OLD and NEW rels for updating.  The best way to handle that seems to be
 | 
			
		||||
 * to scan the jointree to determine which rels are used.
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
 | 
			
		||||
markQueryForLocking(Query *qry, Node *jtnode, bool forUpdate, bool noWait)
 | 
			
		||||
{
 | 
			
		||||
	Index		rti = 0;
 | 
			
		||||
	ListCell   *l;
 | 
			
		||||
 | 
			
		||||
	/* when recursing, this check is redundant; cheap enough not to worry */
 | 
			
		||||
	if (qry->rowMarks)
 | 
			
		||||
	{
 | 
			
		||||
		if (forUpdate != qry->forUpdate)
 | 
			
		||||
@@ -1001,16 +1002,12 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
 | 
			
		||||
	qry->forUpdate = forUpdate;
 | 
			
		||||
	qry->rowNoWait = noWait;
 | 
			
		||||
 | 
			
		||||
	foreach(l, qry->rtable)
 | 
			
		||||
	if (jtnode == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
	if (IsA(jtnode, RangeTblRef))
 | 
			
		||||
	{
 | 
			
		||||
		RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
 | 
			
		||||
 | 
			
		||||
		rti++;
 | 
			
		||||
 | 
			
		||||
		/* Ignore OLD and NEW entries if we are at top level of view */
 | 
			
		||||
		if (skipOldNew &&
 | 
			
		||||
			(rti == PRS2_OLD_VARNO || rti == PRS2_NEW_VARNO))
 | 
			
		||||
			continue;
 | 
			
		||||
		int			rti = ((RangeTblRef *) jtnode)->rtindex;
 | 
			
		||||
		RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
 | 
			
		||||
 | 
			
		||||
		if (rte->rtekind == RTE_RELATION)
 | 
			
		||||
		{
 | 
			
		||||
@@ -1020,9 +1017,28 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
 | 
			
		||||
		else if (rte->rtekind == RTE_SUBQUERY)
 | 
			
		||||
		{
 | 
			
		||||
			/* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
 | 
			
		||||
			markQueryForLocking(rte->subquery, forUpdate, noWait, false);
 | 
			
		||||
			markQueryForLocking(rte->subquery, (Node *) rte->subquery->jointree,
 | 
			
		||||
								forUpdate, noWait);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (IsA(jtnode, FromExpr))
 | 
			
		||||
	{
 | 
			
		||||
		FromExpr   *f = (FromExpr *) jtnode;
 | 
			
		||||
		ListCell   *l;
 | 
			
		||||
 | 
			
		||||
		foreach(l, f->fromlist)
 | 
			
		||||
			markQueryForLocking(qry, lfirst(l), forUpdate, noWait);
 | 
			
		||||
	}
 | 
			
		||||
	else if (IsA(jtnode, JoinExpr))
 | 
			
		||||
	{
 | 
			
		||||
		JoinExpr   *j = (JoinExpr *) jtnode;
 | 
			
		||||
 | 
			
		||||
		markQueryForLocking(qry, j->larg, forUpdate, noWait);
 | 
			
		||||
		markQueryForLocking(qry, j->rarg, forUpdate, noWait);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		elog(ERROR, "unrecognized node type: %d",
 | 
			
		||||
			 (int) nodeTag(jtnode));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user