mirror of
https://github.com/postgres/postgres.git
synced 2025-06-03 01:21:48 +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:
parent
e9a97570fa
commit
3b14809f92
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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,
|
TargetEntry *prior_tle,
|
||||||
const char *attrName);
|
const char *attrName);
|
||||||
static Node *get_assignment_input(Node *node);
|
static Node *get_assignment_input(Node *node);
|
||||||
static void markQueryForLocking(Query *qry, bool forUpdate, bool noWait,
|
static void markQueryForLocking(Query *qry, Node *jtnode,
|
||||||
bool skipOldNew);
|
bool forUpdate, bool noWait);
|
||||||
static List *matchLocks(CmdType event, RuleLock *rulelocks,
|
static List *matchLocks(CmdType event, RuleLock *rulelocks,
|
||||||
int varno, Query *parsetree);
|
int varno, Query *parsetree);
|
||||||
static Query *fireRIRrules(Query *parsetree, List *activeRIRs);
|
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.
|
* Set up the view's referenced tables as if FOR UPDATE/SHARE.
|
||||||
*/
|
*/
|
||||||
markQueryForLocking(rule_action, parsetree->forUpdate,
|
markQueryForLocking(rule_action, (Node *) rule_action->jointree,
|
||||||
parsetree->rowNoWait, true);
|
parsetree->forUpdate, parsetree->rowNoWait);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsetree;
|
return parsetree;
|
||||||
@ -979,14 +979,15 @@ ApplyRetrieveRule(Query *parsetree,
|
|||||||
* This may generate an invalid query, eg if some sub-query uses an
|
* This may generate an invalid query, eg if some sub-query uses an
|
||||||
* aggregate. We leave it to the planner to detect that.
|
* 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
|
static void
|
||||||
markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
|
markQueryForLocking(Query *qry, Node *jtnode, bool forUpdate, bool noWait)
|
||||||
{
|
{
|
||||||
Index rti = 0;
|
/* when recursing, this check is redundant; cheap enough not to worry */
|
||||||
ListCell *l;
|
|
||||||
|
|
||||||
if (qry->rowMarks)
|
if (qry->rowMarks)
|
||||||
{
|
{
|
||||||
if (forUpdate != qry->forUpdate)
|
if (forUpdate != qry->forUpdate)
|
||||||
@ -1001,16 +1002,12 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
|
|||||||
qry->forUpdate = forUpdate;
|
qry->forUpdate = forUpdate;
|
||||||
qry->rowNoWait = noWait;
|
qry->rowNoWait = noWait;
|
||||||
|
|
||||||
foreach(l, qry->rtable)
|
if (jtnode == NULL)
|
||||||
|
return;
|
||||||
|
if (IsA(jtnode, RangeTblRef))
|
||||||
{
|
{
|
||||||
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
int rti = ((RangeTblRef *) jtnode)->rtindex;
|
||||||
|
RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
|
||||||
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;
|
|
||||||
|
|
||||||
if (rte->rtekind == RTE_RELATION)
|
if (rte->rtekind == RTE_RELATION)
|
||||||
{
|
{
|
||||||
@ -1020,9 +1017,28 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
|
|||||||
else if (rte->rtekind == RTE_SUBQUERY)
|
else if (rte->rtekind == RTE_SUBQUERY)
|
||||||
{
|
{
|
||||||
/* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
|
/* 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user