Fix breakage of bitmap scan plan creation for special index operators such

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.
This commit is contained in:
Tom Lane 2008-11-20 19:52:54 +00:00
parent 6c3690d835
commit 176961c1f1
3 changed files with 86 additions and 19 deletions

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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, BitmapHeapPath *best_path,
List *tlist, List *scan_clauses); List *tlist, List *scan_clauses);
static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, 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, static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
List *tlist, List *scan_clauses); List *tlist, List *scan_clauses);
static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root, Path *best_path, 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; Index baserelid = best_path->path.parent->relid;
Plan *bitmapqualplan; Plan *bitmapqualplan;
List *bitmapqualorig; List *bitmapqualorig;
List *indexquals;
List *qpqual; List *qpqual;
ListCell *l; ListCell *l;
BitmapHeapScan *scan_plan; BitmapHeapScan *scan_plan;
@ -995,9 +996,9 @@ create_bitmap_scan_plan(PlannerInfo *root,
Assert(baserelid > 0); Assert(baserelid > 0);
Assert(best_path->path.parent->rtekind == RTE_RELATION); 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, bitmapqualplan = create_bitmap_subplan(root, best_path->bitmapqual,
&bitmapqualorig); &bitmapqualorig, &indexquals);
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */ /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
scan_clauses = extract_actual_clauses(scan_clauses, false); 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 * (either by the index itself, or by nodeBitmapHeapscan.c), but if there
* are any "special" operators involved then they must be added to qpqual. * are any "special" operators involved then they must be added to qpqual.
* The upshot is that qpqual must contain scan_clauses minus whatever * 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 * In normal cases simple equal() checks will be enough to spot duplicate
* clauses, so we try that first. In some situations (particularly with * 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 * Unlike create_indexscan_plan(), we need take no special thought here
* for partial index predicates; this is because the predicate conditions * for partial index predicates; this is because the predicate conditions
* are already listed in bitmapqualorig. Bitmap scans have to do it that * are already listed in bitmapqualorig and indexquals. Bitmap scans have
* way because predicate conditions need to be rechecked if the scan's * to do it that way because predicate conditions need to be rechecked if
* bitmap becomes lossy. * the scan becomes lossy.
*/ */
qpqual = NIL; qpqual = NIL;
foreach(l, scan_clauses) foreach(l, scan_clauses)
{ {
Node *clause = (Node *) lfirst(l); Node *clause = (Node *) lfirst(l);
if (list_member(bitmapqualorig, clause)) if (list_member(indexquals, clause))
continue; continue;
if (!contain_mutable_functions(clause)) if (!contain_mutable_functions(clause))
{ {
List *clausel = list_make1(clause); List *clausel = list_make1(clause);
if (predicate_implied_by(clausel, bitmapqualorig)) if (predicate_implied_by(clausel, indexquals))
continue; continue;
} }
qpqual = lappend(qpqual, clause); 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 * 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 * As byproducts, we also return in *qual and *indexqual the qual lists
* form, without RestrictInfos) describing the generated indexqual * (in implicit-AND form, without RestrictInfos) describing the original index
* conditions, as needed for rechecking heap tuples in lossy cases. * conditions and the generated indexqual conditions. (These are the same in
* This list also includes partial-index predicates, because we have to * simple cases, but when special index operators are involved, the former
* recheck predicates as well as index conditions if the scan's bitmap * list includes the special conditions while the latter includes the actual
* becomes lossy. * 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 * Note: if you find yourself changing this, you probably need to change
* make_restrictinfo_from_bitmapqual too. * make_restrictinfo_from_bitmapqual too.
*/ */
static Plan * static Plan *
create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
List **qual) List **qual, List **indexqual)
{ {
Plan *plan; Plan *plan;
@ -1103,6 +1106,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
BitmapAndPath *apath = (BitmapAndPath *) bitmapqual; BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
List *subplans = NIL; List *subplans = NIL;
List *subquals = NIL; List *subquals = NIL;
List *subindexquals = NIL;
ListCell *l; ListCell *l;
/* /*
@ -1116,11 +1120,13 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
{ {
Plan *subplan; Plan *subplan;
List *subqual; List *subqual;
List *subindexqual;
subplan = create_bitmap_subplan(root, (Path *) lfirst(l), subplan = create_bitmap_subplan(root, (Path *) lfirst(l),
&subqual); &subqual, &subindexqual);
subplans = lappend(subplans, subplan); subplans = lappend(subplans, subplan);
subquals = list_concat_unique(subquals, subqual); subquals = list_concat_unique(subquals, subqual);
subindexquals = list_concat_unique(subindexquals, subindexqual);
} }
plan = (Plan *) make_bitmap_and(subplans); plan = (Plan *) make_bitmap_and(subplans);
plan->startup_cost = apath->path.startup_cost; 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); clamp_row_est(apath->bitmapselectivity * apath->path.parent->tuples);
plan->plan_width = 0; /* meaningless */ plan->plan_width = 0; /* meaningless */
*qual = subquals; *qual = subquals;
*indexqual = subindexquals;
} }
else if (IsA(bitmapqual, BitmapOrPath)) else if (IsA(bitmapqual, BitmapOrPath))
{ {
BitmapOrPath *opath = (BitmapOrPath *) bitmapqual; BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;
List *subplans = NIL; List *subplans = NIL;
List *subquals = NIL; List *subquals = NIL;
List *subindexquals = NIL;
bool const_true_subqual = false; bool const_true_subqual = false;
bool const_true_subindexqual = false;
ListCell *l; ListCell *l;
/* /*
@ -1151,15 +1160,21 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
{ {
Plan *subplan; Plan *subplan;
List *subqual; List *subqual;
List *subindexqual;
subplan = create_bitmap_subplan(root, (Path *) lfirst(l), subplan = create_bitmap_subplan(root, (Path *) lfirst(l),
&subqual); &subqual, &subindexqual);
subplans = lappend(subplans, subplan); subplans = lappend(subplans, subplan);
if (subqual == NIL) if (subqual == NIL)
const_true_subqual = true; const_true_subqual = true;
else if (!const_true_subqual) else if (!const_true_subqual)
subquals = lappend(subquals, subquals = lappend(subquals,
make_ands_explicit(subqual)); 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; *qual = subquals;
else else
*qual = list_make1(make_orclause(subquals)); *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)) 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); clamp_row_est(ipath->indexselectivity * ipath->path.parent->tuples);
plan->plan_width = 0; /* meaningless */ plan->plan_width = 0; /* meaningless */
*qual = get_actual_clauses(ipath->indexclauses); *qual = get_actual_clauses(ipath->indexclauses);
*indexqual = get_actual_clauses(ipath->indexquals);
foreach(l, ipath->indexinfo->indpred) foreach(l, ipath->indexinfo->indpred)
{ {
Expr *pred = (Expr *) lfirst(l); Expr *pred = (Expr *) lfirst(l);
@ -1222,7 +1244,10 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
* generating redundant conditions. * generating redundant conditions.
*/ */
if (!predicate_implied_by(list_make1(pred), ipath->indexclauses)) if (!predicate_implied_by(list_make1(pred), ipath->indexclauses))
{
*qual = lappend(*qual, pred); *qual = lappend(*qual, pred);
*indexqual = lappend(*indexqual, pred);
}
} }
} }
else else

View File

@ -98,3 +98,32 @@ SELECT b.*
4500 | 2080851358 4500 | 2080851358
(1 row) (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)

View File

@ -51,3 +51,16 @@ SELECT b.*
FROM bt_f8_heap b FROM bt_f8_heap b
WHERE b.seqno = '4500'::float8; 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;