summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-03-01 18:50:42 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-03-01 18:50:42 +0000
commit3b14809f9281bf258c281f6ebcc8b6b7b408a467 (patch)
tree31066cb4b6797a331231437b5cd25b23e6a94d5c
parente9a97570fadeb79d5a21086399bdf5b48d924b17 (diff)
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.
-rw-r--r--src/backend/rewrite/rewriteHandler.c56
1 files changed, 36 insertions, 20 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 969188acdb7..bf244b7e63a 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -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));
}