Commit 1e3593ce authored by Tom Lane's avatar Tom Lane

The 8.1 planner removes WHERE quals from the plan when the quals are

implied by the predicate of a partial index being used to scan a table.
However, this optimization is unsafe in an UPDATE, DELETE, or SELECT FOR
UPDATE query, because the quals need to be rechecked by EvalPlanQual if
there's an update conflict.  Per example from Jean-Samuel Reynaud.
parent ff49a020
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.208 2006/03/05 15:58:29 momjian Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.209 2006/04/25 16:54:09 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -816,8 +816,12 @@ create_indexscan_plan(PlannerInfo *root, ...@@ -816,8 +816,12 @@ create_indexscan_plan(PlannerInfo *root,
* are not equal to, but are logically implied by, the index quals; so we * are not equal to, but are logically implied by, the index quals; so we
* also try a predicate_implied_by() check to see if we can discard quals * also try a predicate_implied_by() check to see if we can discard quals
* that way. (predicate_implied_by assumes its first input contains only * that way. (predicate_implied_by assumes its first input contains only
* immutable functions, so we have to check that.) We can also discard * immutable functions, so we have to check that.)
* quals that are implied by a partial index's predicate. *
* We can also discard quals that are implied by a partial index's
* predicate, but only in a plain SELECT; when scanning a target relation
* of UPDATE/DELETE/SELECT FOR UPDATE, we must leave such quals in the
* plan so that they'll be properly rechecked by EvalPlanQual testing.
* *
* While at it, we strip off the RestrictInfos to produce a list of plain * While at it, we strip off the RestrictInfos to produce a list of plain
* expressions. * expressions.
...@@ -836,9 +840,15 @@ create_indexscan_plan(PlannerInfo *root, ...@@ -836,9 +840,15 @@ create_indexscan_plan(PlannerInfo *root,
if (predicate_implied_by(clausel, nonlossy_indexquals)) if (predicate_implied_by(clausel, nonlossy_indexquals))
continue; continue;
if (predicate_implied_by(clausel, best_path->indexinfo->indpred)) if (best_path->indexinfo->indpred)
{
if (baserelid != root->parse->resultRelation &&
!list_member_int(root->parse->rowMarks, baserelid))
if (predicate_implied_by(clausel,
best_path->indexinfo->indpred))
continue; continue;
} }
}
qpqual = lappend(qpqual, rinfo->clause); qpqual = lappend(qpqual, rinfo->clause);
} }
...@@ -920,8 +930,12 @@ create_bitmap_scan_plan(PlannerInfo *root, ...@@ -920,8 +930,12 @@ create_bitmap_scan_plan(PlannerInfo *root,
* but are logically implied by, the index quals; so we also try a * but are logically implied by, the index quals; so we also try a
* predicate_implied_by() check to see if we can discard quals that way. * predicate_implied_by() check to see if we can discard quals that way.
* (predicate_implied_by assumes its first input contains only immutable * (predicate_implied_by assumes its first input contains only immutable
* functions, so we have to check that.) We can also discard quals that * functions, so we have to check that.)
* are implied by a partial index's predicate. *
* We can also discard quals that are implied by a partial index's
* predicate, but only in a plain SELECT; when scanning a target relation
* of UPDATE/DELETE/SELECT FOR UPDATE, we must leave such quals in the
* plan so that they'll be properly rechecked by EvalPlanQual testing.
* *
* XXX For the moment, we only consider partial index predicates in the * XXX For the moment, we only consider partial index predicates in the
* simple single-index-scan case. Is it worth trying to be smart about * simple single-index-scan case. Is it worth trying to be smart about
...@@ -945,10 +959,16 @@ create_bitmap_scan_plan(PlannerInfo *root, ...@@ -945,10 +959,16 @@ create_bitmap_scan_plan(PlannerInfo *root,
{ {
IndexPath *ipath = (IndexPath *) best_path->bitmapqual; IndexPath *ipath = (IndexPath *) best_path->bitmapqual;
if (predicate_implied_by(clausel, ipath->indexinfo->indpred)) if (ipath->indexinfo->indpred)
{
if (baserelid != root->parse->resultRelation &&
!list_member_int(root->parse->rowMarks, baserelid))
if (predicate_implied_by(clausel,
ipath->indexinfo->indpred))
continue; continue;
} }
} }
}
qpqual = lappend(qpqual, clause); qpqual = lappend(qpqual, clause);
} }
...@@ -1303,7 +1323,9 @@ create_nestloop_plan(PlannerInfo *root, ...@@ -1303,7 +1323,9 @@ create_nestloop_plan(PlannerInfo *root,
* join quals; failing to prove that doesn't result in an incorrect * join quals; failing to prove that doesn't result in an incorrect
* plan. It is the right way to proceed because adding more quals to * plan. It is the right way to proceed because adding more quals to
* the stuff we got from the original query would just make it harder * the stuff we got from the original query would just make it harder
* to detect duplication. * to detect duplication. (Also, to change this we'd have to be
* wary of UPDATE/DELETE/SELECT FOR UPDATE target relations; see
* notes above about EvalPlanQual.)
*/ */
BitmapHeapPath *innerpath = (BitmapHeapPath *) best_path->innerjoinpath; BitmapHeapPath *innerpath = (BitmapHeapPath *) best_path->innerjoinpath;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment