diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 332f04a254..a4e02fa197 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -1281,6 +1281,9 @@ ExplainNode(PlanState *planstate, List *ancestors, if (plan->qual) show_instrumentation_count("Rows Removed by Filter", 1, planstate, es); + if (((IndexScan *) plan)->bitmapfilterplan) + ExplainNode(((IndexScanState *) planstate)->BitmapFilterPlanState, + ancestors, "Bitmap filter", NULL, es); break; case T_IndexOnlyScan: show_scan_qual(((IndexOnlyScan *) plan)->indexqual, @@ -1297,6 +1300,9 @@ ExplainNode(PlanState *planstate, List *ancestors, if (es->analyze) ExplainPropertyLong("Heap Fetches", ((IndexOnlyScanState *) planstate)->ioss_HeapFetches, es); + if (((IndexOnlyScan *) plan)->bitmapfilterplan) + ExplainNode(((IndexOnlyScanState *) planstate)->BitmapFilterPlanState, + ancestors, "Bitmap filter", NULL, es); break; case T_BitmapIndexScan: show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig, diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index afcd1ff353..6490ba4de3 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -55,6 +55,7 @@ IndexOnlyNext(IndexOnlyScanState *node) IndexScanDesc scandesc; TupleTableSlot *slot; ItemPointer tid; + TIDBitmap *flttbm; /* * extract necessary information from index scan node @@ -73,12 +74,28 @@ IndexOnlyNext(IndexOnlyScanState *node) econtext = node->ss.ps.ps_ExprContext; slot = node->ss.ss_ScanTupleSlot; + if (node->BitmapFilterPlanState && node->BitmapFilter == NULL) + node->BitmapFilter = (TIDBitmap *) MultiExecProcNode(node->BitmapFilterPlanState); + + flttbm = node->BitmapFilter; + + Assert(flttbm == NULL || IsA(flttbm, TIDBitmap)); + /* * OK, now that we have what we need, fetch the next tuple. */ while ((tid = index_getnext_tid(scandesc, direction)) != NULL) { HeapTuple tuple = NULL; + TBMCheckResult fltres = TBMExists; + + if (flttbm) + { + fltres = tbm_check_tuple(flttbm, &scandesc->xs_ctup.t_self); + + if (fltres == TBMNotFound) + continue; + } /* * We can skip the heap fetch if the TID references a heap page on @@ -153,7 +170,7 @@ IndexOnlyNext(IndexOnlyScanState *node) * (Currently, this can never happen, but we should support the case * for possible future use, eg with GiST indexes.) */ - if (scandesc->xs_recheck) + if (scandesc->xs_recheck || fltres == TBMRecheck) { econtext->ecxt_scantuple = slot; ResetExprContext(econtext); @@ -282,6 +299,15 @@ ExecReScanIndexOnlyScan(IndexOnlyScanState *node) } node->ioss_RuntimeKeysReady = true; + if (node->BitmapFilterPlanState) + { + if (node->BitmapFilter) + tbm_free(node->BitmapFilter); + node->BitmapFilter = NULL; + + ExecReScan(node->BitmapFilterPlanState); + } + /* reset index scan */ index_rescan(node->ioss_ScanDesc, node->ioss_ScanKeys, node->ioss_NumScanKeys, @@ -339,6 +365,14 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node) if (indexRelationDesc) index_close(indexRelationDesc, NoLock); + if (node->BitmapFilterPlanState) + { + ExecEndNode(node->BitmapFilterPlanState); + + if (node->BitmapFilter) + tbm_free(node->BitmapFilter); + } + /* * close the heap relation. */ @@ -447,6 +481,18 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) ExecAssignResultTypeFromTL(&indexstate->ss.ps); ExecAssignScanProjectionInfo(&indexstate->ss); + if (node->bitmapfilterplan) + { + indexstate->BitmapFilterPlanState = + ExecInitNode(node->bitmapfilterplan, estate, + eflags & ~(EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)); + + elog(NOTICE, "TEODOR ExecInitIndexOnlyScan"); + } + else + indexstate->BitmapFilterPlanState = NULL; + indexstate->BitmapFilter = NULL; + /* * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop * here. This allows an index-advisor plugin to EXPLAIN a plan containing diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 2b89dc60f6..9258ca1b44 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -54,6 +54,7 @@ IndexNext(IndexScanState *node) IndexScanDesc scandesc; HeapTuple tuple; TupleTableSlot *slot; + TIDBitmap *flttbm; /* * extract necessary information from index scan node @@ -72,11 +73,28 @@ IndexNext(IndexScanState *node) econtext = node->ss.ps.ps_ExprContext; slot = node->ss.ss_ScanTupleSlot; + if (node->BitmapFilterPlanState && node->BitmapFilter == NULL) + node->BitmapFilter = (TIDBitmap *) MultiExecProcNode(node->BitmapFilterPlanState); + + flttbm = node->BitmapFilter; + + Assert(flttbm == NULL || IsA(flttbm, TIDBitmap)); + /* * ok, now that we have what we need, fetch the next tuple. */ while ((tuple = index_getnext(scandesc, direction)) != NULL) { + TBMCheckResult fltres = TBMExists; + + if (flttbm) + { + fltres = tbm_check_tuple(flttbm, &scandesc->xs_ctup.t_self); + + if (fltres == TBMNotFound) + continue; + } + /* * Store the scanned tuple in the scan tuple slot of the scan state. * Note: we pass 'false' because tuples returned by amgetnext are @@ -91,7 +109,7 @@ IndexNext(IndexScanState *node) * If the index was lossy, we have to recheck the index quals using * the fetched tuple. */ - if (scandesc->xs_recheck) + if (scandesc->xs_recheck || fltres == TBMRecheck) { econtext->ecxt_scantuple = slot; ResetExprContext(econtext); @@ -184,6 +202,15 @@ ExecReScanIndexScan(IndexScanState *node) } node->iss_RuntimeKeysReady = true; + if (node->BitmapFilterPlanState) + { + if (node->BitmapFilter) + tbm_free(node->BitmapFilter); + node->BitmapFilter = NULL; + + ExecReScan(node->BitmapFilterPlanState); + } + /* reset index scan */ index_rescan(node->iss_ScanDesc, node->iss_ScanKeys, node->iss_NumScanKeys, @@ -421,6 +448,13 @@ ExecEndIndexScan(IndexScanState *node) index_endscan(indexScanDesc); if (indexRelationDesc) index_close(indexRelationDesc, NoLock); + if (node->BitmapFilterPlanState) + { + ExecEndNode(node->BitmapFilterPlanState); + + if (node->BitmapFilter) + tbm_free(node->BitmapFilter); + } /* * close the heap relation. @@ -527,6 +561,18 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) ExecAssignResultTypeFromTL(&indexstate->ss.ps); ExecAssignScanProjectionInfo(&indexstate->ss); + if (node->bitmapfilterplan) + { + indexstate->BitmapFilterPlanState = + ExecInitNode(node->bitmapfilterplan, estate, + eflags & ~(EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)); + + elog(NOTICE, "TEODOR ExecInitIndexScan"); + } + else + indexstate->BitmapFilterPlanState = NULL; + indexstate->BitmapFilter = NULL; + /* * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop * here. This allows an index-advisor plugin to EXPLAIN a plan containing diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 491e4db9d6..142ae7c440 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -373,6 +373,7 @@ _copyIndexScan(const IndexScan *from) COPY_NODE_FIELD(indexorderby); COPY_NODE_FIELD(indexorderbyorig); COPY_SCALAR_FIELD(indexorderdir); + COPY_NODE_FIELD(bitmapfilterplan); return newnode; } @@ -398,6 +399,7 @@ _copyIndexOnlyScan(const IndexOnlyScan *from) COPY_NODE_FIELD(indexorderby); COPY_NODE_FIELD(indextlist); COPY_SCALAR_FIELD(indexorderdir); + COPY_NODE_FIELD(bitmapfilterplan); return newnode; } diff --git a/src/backend/nodes/tidbitmap.c b/src/backend/nodes/tidbitmap.c index a880c81cf1..02674e459e 100644 --- a/src/backend/nodes/tidbitmap.c +++ b/src/backend/nodes/tidbitmap.c @@ -1020,3 +1020,42 @@ tbm_comparator(const void *left, const void *right) return 1; return 0; } + +/* + * tbm_check_tuple - check existance of tuple in tidbitmap. + * return zero (TBMNotFound) if not, TBMRecheck if tuple exists + * and requires recheck (recheck flag set or lossy page) and + * TBMExists if tuple exists and doesn't require recheck + */ +TBMCheckResult +tbm_check_tuple(TIDBitmap *tbm, const ItemPointer tid) +{ + BlockNumber blk = ItemPointerGetBlockNumber(tid); + OffsetNumber off = ItemPointerGetOffsetNumber(tid); + PagetableEntry *page; + int wordnum, + bitnum; + + /* safety check to ensure we don't overrun bit array bounds */ + if (off < 1 || off > MAX_TUPLES_PER_PAGE) + elog(ERROR, "tuple offset out of range: %u", off); + + if (tbm_page_is_lossy(tbm, blk)) + return TBMRecheck; /* whole page is already marked */ + + page = tbm_get_pageentry(tbm, blk); + if (page->ischunk) + { + wordnum = bitnum = 0; + } + else + { + wordnum = WORDNUM(off - 1); + bitnum = BITNUM(off - 1); + } + + return ( page->words[wordnum] & ((bitmapword) 1 << bitnum) ) ? + ( (page->ischunk || page->recheck) ? TBMRecheck : TBMExists ) + : + TBMNotFound; +} diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 659daa2026..018f92913e 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -110,6 +110,7 @@ bool enable_seqscan = true; bool enable_indexscan = true; bool enable_indexonlyscan = true; bool enable_bitmapscan = true; +bool enable_bitmapfilter = true; bool enable_tidscan = true; bool enable_sort = true; bool enable_hashagg = true; @@ -456,6 +457,47 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count) path->path.total_cost = startup_cost + run_cost; } +/* + * Tweaks cost estimation of index scan with bitmap filter + */ +void +cost_filtered_index(IndexPath *path) +{ + Path *bitmapqual = path->bitmapfilter; + double rows; + Cost reducedFilterCost; + Selectivity selec = 0; + + if (IsA(path, IndexPath)) + selec = ((IndexPath *) bitmapqual)->indexselectivity; + else if (IsA(path, BitmapAndPath)) + selec = ((BitmapAndPath *) bitmapqual)->bitmapselectivity; + else if (IsA(path, BitmapOrPath)) + selec = ((BitmapOrPath *) bitmapqual)->bitmapselectivity; + else + elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual)); + + rows = path->path.rows * selec; + reducedFilterCost = rows * cpu_operator_cost; + + + //XXX + path->path.startup_cost /= 2.0; + path->path.total_cost /= 2.0; + path->indextotalcost /= 2.0; + + //path->path.startup_cost += bitmapqual->total_cost; + //path->path.total_cost += bitmapqual->total_cost - reducedFilterCost; + //path->indextotalcost += bitmapqual->total_cost - reducedFilterCost; + + if (enable_bitmapfilter == false) + { + path->path.startup_cost += disable_cost; + path->path.total_cost += disable_cost; + path->indextotalcost += disable_cost; + } +} + /* * index_pages_fetched * Estimate the number of pages actually fetched after accounting for diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 7aab644e45..59c5f771e3 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -328,11 +328,41 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel) { Path *bitmapqual; BitmapHeapPath *bpath; + List *bfpaths = NIL; bitmapqual = choose_bitmap_and(root, rel, bitindexpaths); bpath = create_bitmap_heap_path(root, rel, bitmapqual, rel->lateral_relids, 1.0); add_path(rel, (Path *) bpath); + + foreach(lc, rel->pathlist) + { + IndexPath *ipath = (IndexPath*)lfirst(lc), + *newpath; + + if (!IsA(ipath, IndexPath)) + continue; + + if (ipath->indexorderbys == NIL && ipath->indexorderbycols == NIL) + continue; + + newpath = palloc(sizeof(*newpath)); + memcpy(newpath, ipath, sizeof(*newpath)); + newpath->bitmapfilter = bitmapqual; + + cost_filtered_index(newpath); + + bfpaths = lappend(bfpaths, newpath); + + elog(NOTICE,"TEODOR create_index_paths"); + } + + foreach(lc, bfpaths) + { + Path *bfpath = (Path*)lfirst(lc); + + add_path(rel, bfpath); + } } /* diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 8f9ae4f643..404ebae8d2 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -103,12 +103,14 @@ static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid); static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid, Oid indexid, List *indexqual, List *indexqualorig, List *indexorderby, List *indexorderbyorig, - ScanDirection indexscandir); + ScanDirection indexscandir, + Plan *bitmapfilterplan); static IndexOnlyScan *make_indexonlyscan(List *qptlist, List *qpqual, Index scanrelid, Oid indexid, List *indexqual, List *indexorderby, List *indextlist, - ScanDirection indexscandir); + ScanDirection indexscandir, + Plan *bitmapfilterplan); static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indexid, List *indexqual, List *indexqualorig); @@ -1159,6 +1161,8 @@ create_indexscan_plan(PlannerInfo *root, List *fixed_indexquals; List *fixed_indexorderbys; ListCell *l; + Plan *filter_plan = NULL; + /* it should be a base rel... */ Assert(baserelid > 0); @@ -1266,6 +1270,18 @@ create_indexscan_plan(PlannerInfo *root, replace_nestloop_params(root, (Node *) indexorderbys); } + if (best_path->bitmapfilter) + { + List *bitmapqualorig; + List *indexquals; + List *indexECs; + + filter_plan = create_bitmap_subplan(root, best_path->bitmapfilter, + &bitmapqualorig, &indexquals, + &indexECs); + elog(NOTICE,"TEODOR create_indexscan_plan %p %p", best_path->bitmapfilter, filter_plan); + } + /* Finally ready to build the plan node */ if (indexonly) scan_plan = (Scan *) make_indexonlyscan(tlist, @@ -1275,7 +1291,8 @@ create_indexscan_plan(PlannerInfo *root, fixed_indexquals, fixed_indexorderbys, best_path->indexinfo->indextlist, - best_path->indexscandir); + best_path->indexscandir, + filter_plan); else scan_plan = (Scan *) make_indexscan(tlist, qpqual, @@ -1285,7 +1302,8 @@ create_indexscan_plan(PlannerInfo *root, stripped_indexquals, fixed_indexorderbys, indexorderbys, - best_path->indexscandir); + best_path->indexscandir, + filter_plan); copy_path_costsize(&scan_plan->plan, &best_path->path); @@ -3327,7 +3345,8 @@ make_indexscan(List *qptlist, List *indexqualorig, List *indexorderby, List *indexorderbyorig, - ScanDirection indexscandir) + ScanDirection indexscandir, + Plan *bitmapfilterplan) { IndexScan *node = makeNode(IndexScan); Plan *plan = &node->scan.plan; @@ -3344,6 +3363,7 @@ make_indexscan(List *qptlist, node->indexorderby = indexorderby; node->indexorderbyorig = indexorderbyorig; node->indexorderdir = indexscandir; + node->bitmapfilterplan = bitmapfilterplan; return node; } @@ -3356,7 +3376,8 @@ make_indexonlyscan(List *qptlist, List *indexqual, List *indexorderby, List *indextlist, - ScanDirection indexscandir) + ScanDirection indexscandir, + Plan *bitmapfilterplan) { IndexOnlyScan *node = makeNode(IndexOnlyScan); Plan *plan = &node->scan.plan; @@ -3372,6 +3393,7 @@ make_indexonlyscan(List *qptlist, node->indexorderby = indexorderby; node->indextlist = indextlist; node->indexorderdir = indexscandir; + node->bitmapfilterplan = bitmapfilterplan; return node; } diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 4d3fbca596..38f6e3ae76 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -463,12 +463,20 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) fix_scan_list(root, splan->indexorderby, rtoffset); splan->indexorderbyorig = fix_scan_list(root, splan->indexorderbyorig, rtoffset); + if (splan->bitmapfilterplan) + splan->bitmapfilterplan = set_plan_refs(root, + splan->bitmapfilterplan, + rtoffset); } break; case T_IndexOnlyScan: { IndexOnlyScan *splan = (IndexOnlyScan *) plan; + if (splan->bitmapfilterplan) + splan->bitmapfilterplan = set_plan_refs(root, + splan->bitmapfilterplan, + rtoffset); return set_indexonlyscan_references(root, splan, rtoffset); } break; diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 579d021893..74480399e7 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -2178,6 +2178,13 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, * indexorderbyorig. */ context.paramids = bms_add_members(context.paramids, scan_params); + if (((IndexScan *) plan)->bitmapfilterplan) + context.paramids = + bms_add_members(context.paramids, + finalize_plan(root, + (Plan *) ((IndexScan *) plan)->bitmapfilterplan, + valid_params, + scan_params)); break; case T_IndexOnlyScan: @@ -2190,6 +2197,13 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, * we need not look at indextlist, since it cannot contain Params. */ context.paramids = bms_add_members(context.paramids, scan_params); + if (((IndexOnlyScan *) plan)->bitmapfilterplan) + context.paramids = + bms_add_members(context.paramids, + finalize_plan(root, + (Plan *) ((IndexOnlyScan *) plan)->bitmapfilterplan, + valid_params, + scan_params)); break; case T_BitmapIndexScan: diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 319e8b2c37..2034e5e55e 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -765,6 +765,7 @@ create_index_path(PlannerInfo *root, pathnode->indexorderbys = indexorderbys; pathnode->indexorderbycols = indexorderbycols; pathnode->indexscandir = indexscandir; + pathnode->bitmapfilter = NULL; cost_index(pathnode, root, loop_count); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index cc62b2cfe8..163408c7f8 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3204,6 +3204,9 @@ set_plan_disabling_options(const char *arg, GucContext context, GucSource source case 'b': /* bitmapscan */ tmp = "enable_bitmapscan"; break; + case 'f': /* bitmapfilter */ + tmp = "enable_bitmapfilter"; + break; case 't': /* tidscan */ tmp = "enable_tidscan"; break; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index b1bff7f350..69827fd71c 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -743,6 +743,15 @@ static struct config_bool ConfigureNamesBool[] = true, NULL, NULL, NULL }, + { + {"enable_bitmapfilter", PGC_USERSET, QUERY_TUNING_METHOD, + gettext_noop("Enables the planner's use of bitmap-filtering in index scan."), + NULL + }, + &enable_bitmapfilter, + true, + NULL, NULL, NULL + }, { {"enable_tidscan", PGC_USERSET, QUERY_TUNING_METHOD, gettext_noop("Enables the planner's use of TID scan plans."), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index b053659f88..1edf2ffa2e 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -269,6 +269,7 @@ # - Planner Method Configuration - #enable_bitmapscan = on +#enable_bitmapfilter = on #enable_hashagg = on #enable_hashjoin = on #enable_indexscan = on diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 41b13b2b67..aabbbdc517 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1263,6 +1263,8 @@ typedef struct IndexScanState ExprContext *iss_RuntimeContext; Relation iss_RelationDesc; IndexScanDesc iss_ScanDesc; + PlanState *BitmapFilterPlanState; + TIDBitmap *BitmapFilter; } IndexScanState; /* ---------------- @@ -1299,6 +1301,8 @@ typedef struct IndexOnlyScanState IndexScanDesc ioss_ScanDesc; Buffer ioss_VMBuffer; long ioss_HeapFetches; + PlanState *BitmapFilterPlanState; + TIDBitmap *BitmapFilter; } IndexOnlyScanState; /* ---------------- diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 48203a0d21..28a0c1e065 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -318,6 +318,7 @@ typedef struct IndexScan List *indexorderby; /* list of index ORDER BY exprs */ List *indexorderbyorig; /* the same in original form */ ScanDirection indexorderdir; /* forward or backward or don't care */ + Plan *bitmapfilterplan; } IndexScan; /* ---------------- @@ -345,6 +346,7 @@ typedef struct IndexOnlyScan List *indexorderby; /* list of index ORDER BY exprs */ List *indextlist; /* TargetEntry list describing index's cols */ ScanDirection indexorderdir; /* forward or backward or don't care */ + Plan *bitmapfilterplan; } IndexOnlyScan; /* ---------------- diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 711649687a..eac7275eb2 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -805,6 +805,7 @@ typedef struct IndexPath ScanDirection indexscandir; Cost indextotalcost; Selectivity indexselectivity; + Path *bitmapfilter; /* IndexPath, BitmapAndPath or BitmapOrPath */ } IndexPath; /* diff --git a/src/include/nodes/tidbitmap.h b/src/include/nodes/tidbitmap.h index 444d4d8ae3..7ab3363390 100644 --- a/src/include/nodes/tidbitmap.h +++ b/src/include/nodes/tidbitmap.h @@ -63,4 +63,12 @@ extern TBMIterator *tbm_begin_iterate(TIDBitmap *tbm); extern TBMIterateResult *tbm_iterate(TBMIterator *iterator); extern void tbm_end_iterate(TBMIterator *iterator); +typedef enum { + TBMNotFound = 0, + TBMExists, + TBMRecheck +} TBMCheckResult; + +extern TBMCheckResult tbm_check_tuple(TIDBitmap *tbm, const ItemPointer tid); + #endif /* TIDBITMAP_H */ diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index 75e2afb1e2..07963df874 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -54,6 +54,7 @@ extern bool enable_seqscan; extern bool enable_indexscan; extern bool enable_indexonlyscan; extern bool enable_bitmapscan; +extern bool enable_bitmapfilter; extern bool enable_tidscan; extern bool enable_sort; extern bool enable_hashagg; @@ -70,6 +71,7 @@ extern void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info); extern void cost_index(IndexPath *path, PlannerInfo *root, double loop_count); +extern void cost_filtered_index(IndexPath *path); extern void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info, Path *bitmapqual, double loop_count); diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out index 7991e993f1..31d13259ba 100644 --- a/src/test/regress/expected/rangefuncs.out +++ b/src/test/regress/expected/rangefuncs.out @@ -1,6 +1,7 @@ SELECT name, setting FROM pg_settings WHERE name LIKE 'enable%'; name | setting ----------------------+--------- + enable_bitmapfilter | on enable_bitmapscan | on enable_hashagg | on enable_hashjoin | on @@ -12,7 +13,7 @@ SELECT name, setting FROM pg_settings WHERE name LIKE 'enable%'; enable_seqscan | on enable_sort | on enable_tidscan | on -(11 rows) +(12 rows) CREATE TABLE foo2(fooid int, f2 int); INSERT INTO foo2 VALUES(1, 11);