]> granicus.if.org Git - postgresql/commitdiff
The 8.1 planner removes WHERE quals from the plan when the quals are
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 25 Apr 2006 16:54:09 +0000 (16:54 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 25 Apr 2006 16:54:09 +0000 (16:54 +0000)
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.

src/backend/optimizer/plan/createplan.c

index 722f36d5c3e070c8e7a5f9458513c874f40b98c0..9750789f0c2cac9a39f8fd05b047e0617b806c1e 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * 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,
         * 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
         * that way.  (predicate_implied_by assumes its first input contains only
-        * immutable functions, so we have to check that.)      We can also discard
-        * quals that are implied by a partial index's predicate.
+        * immutable functions, so we have to check that.)
+        *
+        * 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
         * expressions.
@@ -836,8 +840,14 @@ create_indexscan_plan(PlannerInfo *root,
 
                        if (predicate_implied_by(clausel, nonlossy_indexquals))
                                continue;
-                       if (predicate_implied_by(clausel, best_path->indexinfo->indpred))
-                               continue;
+                       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;
+                       }
                }
                qpqual = lappend(qpqual, rinfo->clause);
        }
@@ -920,8 +930,12 @@ create_bitmap_scan_plan(PlannerInfo *root,
         * 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 assumes its first input contains only immutable
-        * functions, so we have to check that.)  We can also discard quals that
-        * are implied by a partial index's predicate.
+        * functions, so we have to check that.)
+        *
+        * 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
         * simple single-index-scan case.  Is it worth trying to be smart about
@@ -945,8 +959,14 @@ create_bitmap_scan_plan(PlannerInfo *root,
                        {
                                IndexPath  *ipath = (IndexPath *) best_path->bitmapqual;
 
-                               if (predicate_implied_by(clausel, ipath->indexinfo->indpred))
-                                       continue;
+                               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;
+                               }
                        }
                }
                qpqual = lappend(qpqual, clause);
@@ -1303,7 +1323,9 @@ create_nestloop_plan(PlannerInfo *root,
                 * 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
                 * 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;