Fix breakage of bitmap scan plan creation for special index operators such
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 20 Nov 2008 19:52:54 +0000 (19:52 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 20 Nov 2008 19:52:54 +0000 (19:52 +0000)
as LIKE.  I oversimplified this code when removing support for plan-time
determination of index operator lossiness back in April --- I had thought
create_bitmap_subplan could stop returning two separate lists of qual
conditions, but it still must so that we can treat special operators
correctly in create_bitmap_scan_plan.  Per report from Rushabh Lathia.

src/backend/optimizer/plan/createplan.c
src/test/regress/expected/btree_index.out
src/test/regress/sql/btree_index.sql

index 7bddf33e5c87a84bdde2d6d155586c0a9d5f13f9..f5d4f41c032c7e0633366e51ffcd61a6f9ece74a 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.251 2008/10/21 20:42:53 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.252 2008/11/20 19:52:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,7 +53,7 @@ static BitmapHeapScan *create_bitmap_scan_plan(PlannerInfo *root,
                        BitmapHeapPath *best_path,
                        List *tlist, List *scan_clauses);
 static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
-                     List **qual);
+                     List **qual, List **indexqual);
 static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
                    List *tlist, List *scan_clauses);
 static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root, Path *best_path,
@@ -987,6 +987,7 @@ create_bitmap_scan_plan(PlannerInfo *root,
    Index       baserelid = best_path->path.parent->relid;
    Plan       *bitmapqualplan;
    List       *bitmapqualorig;
+   List       *indexquals;
    List       *qpqual;
    ListCell   *l;
    BitmapHeapScan *scan_plan;
@@ -995,9 +996,9 @@ create_bitmap_scan_plan(PlannerInfo *root,
    Assert(baserelid > 0);
    Assert(best_path->path.parent->rtekind == RTE_RELATION);
 
-   /* Process the bitmapqual tree into a Plan tree and qual list */
+   /* Process the bitmapqual tree into a Plan tree and qual lists */
    bitmapqualplan = create_bitmap_subplan(root, best_path->bitmapqual,
-                                          &bitmapqualorig);
+                                          &bitmapqualorig, &indexquals);
 
    /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
    scan_clauses = extract_actual_clauses(scan_clauses, false);
@@ -1021,7 +1022,7 @@ create_bitmap_scan_plan(PlannerInfo *root,
     * (either by the index itself, or by nodeBitmapHeapscan.c), but if there
     * are any "special" operators involved then they must be added to qpqual.
     * The upshot is that qpqual must contain scan_clauses minus whatever
-    * appears in bitmapqualorig.
+    * appears in indexquals.
     *
     * In normal cases simple equal() checks will be enough to spot duplicate
     * clauses, so we try that first.  In some situations (particularly with
@@ -1033,22 +1034,22 @@ create_bitmap_scan_plan(PlannerInfo *root,
     *
     * Unlike create_indexscan_plan(), we need take no special thought here
     * for partial index predicates; this is because the predicate conditions
-    * are already listed in bitmapqualorig.  Bitmap scans have to do it that
-    * way because predicate conditions need to be rechecked if the scan's
-    * bitmap becomes lossy.
+    * are already listed in bitmapqualorig and indexquals.  Bitmap scans have
+    * to do it that way because predicate conditions need to be rechecked if
+    * the scan becomes lossy.
     */
    qpqual = NIL;
    foreach(l, scan_clauses)
    {
        Node       *clause = (Node *) lfirst(l);
 
-       if (list_member(bitmapqualorig, clause))
+       if (list_member(indexquals, clause))
            continue;
        if (!contain_mutable_functions(clause))
        {
            List       *clausel = list_make1(clause);
 
-           if (predicate_implied_by(clausel, bitmapqualorig))
+           if (predicate_implied_by(clausel, indexquals))
                continue;
        }
        qpqual = lappend(qpqual, clause);
@@ -1082,19 +1083,21 @@ create_bitmap_scan_plan(PlannerInfo *root,
 /*
  * Given a bitmapqual tree, generate the Plan tree that implements it
  *
- * As a byproduct, we also return in *qual a qual list (in implicit-AND
- * form, without RestrictInfos) describing the generated indexqual
- * conditions, as needed for rechecking heap tuples in lossy cases.
- * This list also includes partial-index predicates, because we have to
- * recheck predicates as well as index conditions if the scan's bitmap
- * becomes lossy.
+ * As byproducts, we also return in *qual and *indexqual the qual lists
+ * (in implicit-AND form, without RestrictInfos) describing the original index
+ * conditions and the generated indexqual conditions.  (These are the same in
+ * simple cases, but when special index operators are involved, the former
+ * list includes the special conditions while the latter includes the actual
+ * indexable conditions derived from them.)  Both lists include partial-index
+ * predicates, because we have to recheck predicates as well as index
+ * conditions if the bitmap scan becomes lossy.
  *
  * Note: if you find yourself changing this, you probably need to change
  * make_restrictinfo_from_bitmapqual too.
  */
 static Plan *
 create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
-                     List **qual)
+                     List **qual, List **indexqual)
 {
    Plan       *plan;
 
@@ -1103,6 +1106,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
        BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
        List       *subplans = NIL;
        List       *subquals = NIL;
+       List       *subindexquals = NIL;
        ListCell   *l;
 
        /*
@@ -1116,11 +1120,13 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
        {
            Plan       *subplan;
            List       *subqual;
+           List       *subindexqual;
 
            subplan = create_bitmap_subplan(root, (Path *) lfirst(l),
-                                           &subqual);
+                                           &subqual, &subindexqual);
            subplans = lappend(subplans, subplan);
            subquals = list_concat_unique(subquals, subqual);
+           subindexquals = list_concat_unique(subindexquals, subindexqual);
        }
        plan = (Plan *) make_bitmap_and(subplans);
        plan->startup_cost = apath->path.startup_cost;
@@ -1129,13 +1135,16 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
            clamp_row_est(apath->bitmapselectivity * apath->path.parent->tuples);
        plan->plan_width = 0;   /* meaningless */
        *qual = subquals;
+       *indexqual = subindexquals;
    }
    else if (IsA(bitmapqual, BitmapOrPath))
    {
        BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;
        List       *subplans = NIL;
        List       *subquals = NIL;
+       List       *subindexquals = NIL;
        bool        const_true_subqual = false;
+       bool        const_true_subindexqual = false;
        ListCell   *l;
 
        /*
@@ -1151,15 +1160,21 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
        {
            Plan       *subplan;
            List       *subqual;
+           List       *subindexqual;
 
            subplan = create_bitmap_subplan(root, (Path *) lfirst(l),
-                                           &subqual);
+                                           &subqual, &subindexqual);
            subplans = lappend(subplans, subplan);
            if (subqual == NIL)
                const_true_subqual = true;
            else if (!const_true_subqual)
                subquals = lappend(subquals,
                                   make_ands_explicit(subqual));
+           if (subindexqual == NIL)
+               const_true_subindexqual = true;
+           else if (!const_true_subindexqual)
+               subindexquals = lappend(subindexquals,
+                                       make_ands_explicit(subindexqual));
        }
 
        /*
@@ -1191,6 +1206,12 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
            *qual = subquals;
        else
            *qual = list_make1(make_orclause(subquals));
+       if (const_true_subindexqual)
+           *indexqual = NIL;
+       else if (list_length(subindexquals) <= 1)
+           *indexqual = subindexquals;
+       else
+           *indexqual = list_make1(make_orclause(subindexquals));
    }
    else if (IsA(bitmapqual, IndexPath))
    {
@@ -1211,6 +1232,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
            clamp_row_est(ipath->indexselectivity * ipath->path.parent->tuples);
        plan->plan_width = 0;   /* meaningless */
        *qual = get_actual_clauses(ipath->indexclauses);
+       *indexqual = get_actual_clauses(ipath->indexquals);
        foreach(l, ipath->indexinfo->indpred)
        {
            Expr       *pred = (Expr *) lfirst(l);
@@ -1222,7 +1244,10 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
             * generating redundant conditions.
             */
            if (!predicate_implied_by(list_make1(pred), ipath->indexclauses))
+           {
                *qual = lappend(*qual, pred);
+               *indexqual = lappend(*indexqual, pred);
+           }
        }
    }
    else
index cedb7e7ec2877da9698ec06065c441233f8a0c6c..74d47beae8142a4f3eb9cca11afd8e8cf56f1dfa 100644 (file)
@@ -98,3 +98,32 @@ SELECT b.*
   4500 | 2080851358
 (1 row)
 
+--
+-- Check correct optimization of LIKE (special index operator support)
+-- for both indexscan and bitmapscan cases
+--
+set enable_seqscan to false;
+set enable_indexscan to true;
+set enable_bitmapscan to false;
+select proname from pg_proc where proname like E'RI\\_FKey%del' order by 1;
+        proname         
+------------------------
+ RI_FKey_cascade_del
+ RI_FKey_noaction_del
+ RI_FKey_restrict_del
+ RI_FKey_setdefault_del
+ RI_FKey_setnull_del
+(5 rows)
+
+set enable_indexscan to false;
+set enable_bitmapscan to true;
+select proname from pg_proc where proname like E'RI\\_FKey%del' order by 1;
+        proname         
+------------------------
+ RI_FKey_cascade_del
+ RI_FKey_noaction_del
+ RI_FKey_restrict_del
+ RI_FKey_setdefault_del
+ RI_FKey_setnull_del
+(5 rows)
+
index 62dd7f72ebb32554e4456e7746a2ddba71b83a52..3f264683e17c3088992039380e6e2d13936576ad 100644 (file)
@@ -51,3 +51,16 @@ SELECT b.*
    FROM bt_f8_heap b
    WHERE b.seqno = '4500'::float8;
 
+--
+-- Check correct optimization of LIKE (special index operator support)
+-- for both indexscan and bitmapscan cases
+--
+
+set enable_seqscan to false;
+set enable_indexscan to true;
+set enable_bitmapscan to false;
+select proname from pg_proc where proname like E'RI\\_FKey%del' order by 1;
+
+set enable_indexscan to false;
+set enable_bitmapscan to true;
+select proname from pg_proc where proname like E'RI\\_FKey%del' order by 1;