diff options
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 5 | ||||
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 34 | ||||
-rw-r--r-- | src/backend/optimizer/path/joinpath.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 557 | ||||
-rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 27 | ||||
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 48 | ||||
-rw-r--r-- | src/backend/optimizer/util/pathnode.c | 35 |
7 files changed, 666 insertions, 43 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 16513108450..dc5091c69af 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.125 2005/04/06 16:34:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.126 2005/04/19 22:35:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -898,6 +898,9 @@ print_path(Query *root, Path *path, int indent) case T_IndexPath: ptype = "IdxScan"; break; + case T_BitmapHeapPath: + ptype = "BitmapHeapScan"; + break; case T_TidPath: ptype = "TidScan"; break; diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 967536393ee..06ebe18fe78 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -49,7 +49,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.141 2005/04/04 01:43:12 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.142 2005/04/19 22:35:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -401,6 +401,36 @@ cost_index(Path *path, Query *root, } /* + * cost_bitmap_scan + * Determines and returns the cost of scanning a relation using a bitmap + * index-then-heap plan. + * + * 'root' is the query root + * 'baserel' is the relation to be scanned + * 'bitmapqual' is an AND/OR tree of IndexPaths for the component scans + * 'is_injoin' is T if we are considering using the scan as the inside + * of a nestloop join (hence, some of the quals are join clauses) + */ +void +cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel, + Node *bitmapqual, bool is_injoin) +{ + Cost startup_cost = 0; + Cost run_cost = 0; + + /* Should only be applied to base relations */ + Assert(IsA(baserel, RelOptInfo)); + Assert(baserel->relid > 0); + Assert(baserel->rtekind == RTE_RELATION); + + /* XXX lots to do here */ + run_cost += 10; + + path->startup_cost = startup_cost; + path->total_cost = startup_cost + run_cost; +} + +/* * cost_tidscan * Determines and returns the cost of scanning a relation using TIDs. */ @@ -760,6 +790,8 @@ cost_nestloop(NestPath *path, Query *root) */ if (IsA(inner_path, IndexPath)) inner_path_rows = ((IndexPath *) inner_path)->rows; + else if (IsA(inner_path, BitmapHeapPath)) + inner_path_rows = ((BitmapHeapPath *) inner_path)->rows; if (!enable_nestloop) startup_cost += disable_cost; diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 97e4d7dda87..b75cb6128d7 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.92 2005/01/23 02:21:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.93 2005/04/19 22:35:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -391,6 +391,7 @@ match_unsorted_outer(Query *root, * waste of time.) */ if (!(IsA(inner_cheapest_total, IndexPath) || + IsA(inner_cheapest_total, BitmapHeapPath) || IsA(inner_cheapest_total, TidPath))) matpath = (Path *) create_material_path(innerrel, inner_cheapest_total); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 6f378c76dd8..d15f0c6dcae 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.179 2005/04/12 05:11:28 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.180 2005/04/19 22:35:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -48,6 +48,12 @@ static SeqScan *create_seqscan_plan(Query *root, Path *best_path, List *tlist, List *scan_clauses); static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path, List *tlist, List *scan_clauses); +static BitmapHeapScan *create_bitmap_scan_plan(Query *root, + BitmapHeapPath *best_path, + List *tlist, List *scan_clauses); +static Plan *create_bitmap_subplan(Query *root, Node *bitmapqual); +static List *create_bitmap_qual(Node *bitmapqual); +static List *create_bitmap_indxqual(Node *bitmapqual); static TidScan *create_tidscan_plan(Query *root, TidPath *best_path, List *tlist, List *scan_clauses); static SubqueryScan *create_subqueryscan_plan(Query *root, Path *best_path, @@ -80,10 +86,22 @@ static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid, List *indxid, List *indxqual, List *indxqualorig, List *indxstrategy, List *indxsubtype, List *indxlossy, ScanDirection indexscandir); +static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indxid, + List *indxqual, + List *indxqualorig, + List *indxstrategy, + List *indxsubtype); +static BitmapHeapScan *make_bitmap_heapscan(List *qptlist, + List *qpqual, + Plan *lefttree, + List *bitmapqualorig, + Index scanrelid); static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid, List *tideval); static FunctionScan *make_functionscan(List *qptlist, List *qpqual, Index scanrelid); +static BitmapAnd *make_bitmap_and(List *bitmapplans); +static BitmapOr *make_bitmap_or(List *bitmapplans); static NestLoop *make_nestloop(List *tlist, List *joinclauses, List *otherclauses, Plan *lefttree, Plan *righttree, @@ -127,8 +145,9 @@ create_plan(Query *root, Path *best_path) switch (best_path->pathtype) { - case T_IndexScan: case T_SeqScan: + case T_IndexScan: + case T_BitmapHeapScan: case T_TidScan: case T_SubqueryScan: case T_FunctionScan: @@ -220,6 +239,13 @@ create_scan_plan(Query *root, Path *best_path) scan_clauses); break; + case T_BitmapHeapScan: + plan = (Scan *) create_bitmap_scan_plan(root, + (BitmapHeapPath *) best_path, + tlist, + scan_clauses); + break; + case T_TidScan: plan = (Scan *) create_tidscan_plan(root, (TidPath *) best_path, @@ -328,8 +354,9 @@ disuse_physical_tlist(Plan *plan, Path *path) /* Only need to undo it for path types handled by create_scan_plan() */ switch (path->pathtype) { - case T_IndexScan: case T_SeqScan: + case T_IndexScan: + case T_BitmapHeapScan: case T_TidScan: case T_SubqueryScan: case T_FunctionScan: @@ -671,7 +698,7 @@ create_seqscan_plan(Query *root, Path *best_path, /* * create_indexscan_plan - * Returns a indexscan plan for the base relation scanned by 'best_path' + * Returns an indexscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. * * The indexquals list of the path contains a sublist of implicitly-ANDed @@ -705,6 +732,37 @@ create_indexscan_plan(Query *root, Assert(baserelid > 0); Assert(best_path->path.parent->rtekind == RTE_RELATION); + /* Build list of index OIDs */ + indexids = NIL; + foreach(l, best_path->indexinfo) + { + IndexOptInfo *index = (IndexOptInfo *) lfirst(l); + + indexids = lappend_oid(indexids, index->indexoid); + } + + /* + * Build "stripped" indexquals structure (no RestrictInfos) to pass to + * executor as indxqualorig + */ + stripped_indxquals = NIL; + foreach(l, indxquals) + { + List *andlist = (List *) lfirst(l); + + stripped_indxquals = lappend(stripped_indxquals, + get_actual_clauses(andlist)); + } + + /* + * The executor needs a copy with the indexkey on the left of each + * clause and with index attr numbers substituted for table ones. This + * pass also gets strategy info and looks for "lossy" operators. + */ + fix_indxqual_references(indxquals, best_path, + &fixed_indxquals, + &indxstrategy, &indxsubtype, &indxlossy); + /* * If this is a innerjoin scan, the indexclauses will contain join * clauses that are not present in scan_clauses (since the passed-in @@ -729,31 +787,6 @@ create_indexscan_plan(Query *root, /* Reduce RestrictInfo list to bare expressions */ scan_clauses = get_actual_clauses(scan_clauses); - /* Sort clauses into best execution order */ - scan_clauses = order_qual_clauses(root, scan_clauses); - - /* Build list of index OIDs */ - indexids = NIL; - foreach(l, best_path->indexinfo) - { - IndexOptInfo *index = (IndexOptInfo *) lfirst(l); - - indexids = lappend_oid(indexids, index->indexoid); - } - - /* - * Build "stripped" indexquals structure (no RestrictInfos) to pass to - * executor as indxqualorig - */ - stripped_indxquals = NIL; - foreach(l, indxquals) - { - List *andlist = (List *) lfirst(l); - - stripped_indxquals = lappend(stripped_indxquals, - get_actual_clauses(andlist)); - } - /* * The qpqual list must contain all restrictions not automatically * handled by the index. All the predicates in the indexquals will be @@ -784,14 +817,8 @@ create_indexscan_plan(Query *root, qpqual = list_difference(scan_clauses, linitial(stripped_indxquals)); } - /* - * The executor needs a copy with the indexkey on the left of each - * clause and with index attr numbers substituted for table ones. This - * pass also gets strategy info and looks for "lossy" operators. - */ - fix_indxqual_references(indxquals, best_path, - &fixed_indxquals, - &indxstrategy, &indxsubtype, &indxlossy); + /* Sort clauses into best execution order */ + qpqual = order_qual_clauses(root, qpqual); /* Finally ready to build the plan node */ scan_plan = make_indexscan(tlist, @@ -813,6 +840,339 @@ create_indexscan_plan(Query *root, } /* + * create_bitmap_scan_plan + * Returns a bitmap scan plan for the base relation scanned by 'best_path' + * with restriction clauses 'scan_clauses' and targetlist 'tlist'. + */ +static BitmapHeapScan * +create_bitmap_scan_plan(Query *root, + BitmapHeapPath *best_path, + List *tlist, + List *scan_clauses) +{ + Index baserelid = best_path->path.parent->relid; + Plan *bitmapqualplan; + List *bitmapqualorig; + List *indexquals; + List *qpqual; + BitmapHeapScan *scan_plan; + + /* it should be a base rel... */ + Assert(baserelid > 0); + Assert(best_path->path.parent->rtekind == RTE_RELATION); + + /* Process the bitmapqual tree into a Plan tree */ + bitmapqualplan = create_bitmap_subplan(root, best_path->bitmapqual); + + /* Process the bitmapqual tree into an expression tree, too */ + bitmapqualorig = create_bitmap_qual(best_path->bitmapqual); + + /* Also extract the true index conditions */ + indexquals = create_bitmap_indxqual(best_path->bitmapqual); + + /* + * If this is a innerjoin scan, the indexclauses will contain join + * clauses that are not present in scan_clauses (since the passed-in + * value is just the rel's baserestrictinfo list). We must add these + * clauses to scan_clauses to ensure they get checked. In most cases + * we will remove the join clauses again below, but if a join clause + * contains a special operator, we need to make sure it gets into the + * scan_clauses. + */ + if (best_path->isjoininner) + { + /* + * Pointer comparison should be enough to determine RestrictInfo + * matches. + */ + scan_clauses = list_union_ptr(scan_clauses, bitmapqualorig); + } + + /* Reduce RestrictInfo list to bare expressions */ + scan_clauses = get_actual_clauses(scan_clauses); + + /* + * The qpqual list must contain all restrictions not automatically + * handled by the index. All the predicates in the indexquals will be + * checked (either by the index itself, or by nodeBitmapHeapscan.c), + * but if there are any "special" or lossy operators involved then they + * must be added to qpqual. The upshot is that qpquals must contain + * scan_clauses minus whatever appears in indexquals. + * + * NOTE: when there are OR clauses in indexquals, the simple equality + * check used by list_difference will only detect matches in case of + * chance equality of the OR subclause ordering. This is probably all + * right for now because that order will match what's in scan_clauses + * ... but perhaps we need more smarts here. + */ + qpqual = list_difference(scan_clauses, indexquals); + + /* Sort clauses into best execution order */ + qpqual = order_qual_clauses(root, qpqual); + + /* Finally ready to build the plan node */ + scan_plan = make_bitmap_heapscan(tlist, + qpqual, + bitmapqualplan, + bitmapqualorig, + baserelid); + + copy_path_costsize(&scan_plan->scan.plan, &best_path->path); + /* use the indexscan-specific rows estimate, not the parent rel's */ + scan_plan->scan.plan.plan_rows = best_path->rows; + + return scan_plan; +} + +/* + * Given a bitmapqual tree, generate the Plan tree that implements it + */ +static Plan * +create_bitmap_subplan(Query *root, Node *bitmapqual) +{ + Plan *plan; + Plan *subplan; + + if (bitmapqual == NULL) + return NULL; /* probably can't happen */ + if (IsA(bitmapqual, List)) + { + /* this case is to handle the List arguments of AND/OR */ + List *newlist = NIL; + ListCell *l; + + foreach(l, (List *) bitmapqual) + { + subplan = create_bitmap_subplan(root, lfirst(l)); + newlist = lappend(newlist, subplan); + } + plan = (Plan *) newlist; + } + else if (and_clause(bitmapqual)) + { + subplan = create_bitmap_subplan(root, + (Node *) ((BoolExpr *) bitmapqual)->args); + plan = (Plan *) make_bitmap_and((List *) subplan); + } + else if (or_clause(bitmapqual)) + { + subplan = create_bitmap_subplan(root, + (Node *) ((BoolExpr *) bitmapqual)->args); + plan = (Plan *) make_bitmap_or((List *) subplan); + } + else if (IsA(bitmapqual, IndexPath)) + { + IndexPath *ipath = (IndexPath *) bitmapqual; + IndexScan *iscan; + BitmapIndexScan *bscan; + + /* Use the regular indexscan plan build machinery... */ + iscan = create_indexscan_plan(root, ipath, NIL, NIL); + Assert(list_length(iscan->indxid) == 1); + /* then convert to a bitmap indexscan */ + bscan = make_bitmap_indexscan(iscan->scan.scanrelid, + linitial_oid(iscan->indxid), + linitial(iscan->indxqual), + linitial(iscan->indxqualorig), + linitial(iscan->indxstrategy), + linitial(iscan->indxsubtype)); + /* XXX this cost is wrong: */ + copy_path_costsize(&bscan->scan.plan, &ipath->path); + /* use the indexscan-specific rows estimate, not the parent rel's */ + bscan->scan.plan.plan_rows = ipath->rows; + plan = (Plan *) bscan; + } + else + { + elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual)); + plan = NULL; /* keep compiler quiet */ + } + + return plan; +} + +/* + * Given a bitmapqual tree, generate the equivalent ordinary expression tree + * (which we need for the bitmapqualorig field of the BitmapHeapScan plan). + * The result is expressed as an implicit-AND list. + */ +static List * +create_bitmap_qual(Node *bitmapqual) +{ + List *result; + List *sublist; + + if (and_clause(bitmapqual)) + { + ListCell *l; + + result = NIL; + foreach(l, ((BoolExpr *) bitmapqual)->args) + { + sublist = create_bitmap_qual(lfirst(l)); + result = list_concat(result, sublist); + } + } + else if (or_clause(bitmapqual)) + { + List *newlist = NIL; + ListCell *l; + + foreach(l, ((BoolExpr *) bitmapqual)->args) + { + sublist = create_bitmap_qual(lfirst(l)); + if (sublist == NIL) + { + /* constant TRUE input yields constant TRUE OR result */ + return NIL; + } + newlist = lappend(newlist, make_ands_explicit(sublist)); + } + result = list_make1(make_orclause(newlist)); + } + else if (IsA(bitmapqual, IndexPath)) + { + IndexPath *ipath = (IndexPath *) bitmapqual; + + Assert(list_length(ipath->indexclauses) == 1); + result = get_actual_clauses(linitial(ipath->indexclauses)); + } + else + { + elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual)); + result = NIL; /* keep compiler quiet */ + } + + return result; +} + +/* + * Same as above, except extract the indxqual conditions (which are different + * if there are special index operators or lossy operators involved). + * + * The result essentially represents the conditions the indexscan guarantees + * to enforce, which may be weaker than the original qual expressions. + */ +static List * +create_bitmap_indxqual(Node *bitmapqual) +{ + List *result; + List *sublist; + ListCell *l; + + if (and_clause(bitmapqual)) + { + result = NIL; + foreach(l, ((BoolExpr *) bitmapqual)->args) + { + sublist = create_bitmap_indxqual(lfirst(l)); + result = list_concat(result, sublist); + } + } + else if (or_clause(bitmapqual)) + { + List *newlist = NIL; + + foreach(l, ((BoolExpr *) bitmapqual)->args) + { + sublist = create_bitmap_indxqual(lfirst(l)); + if (sublist == NIL) + { + /* constant TRUE input yields constant TRUE OR result */ + return NIL; + } + newlist = lappend(newlist, make_ands_explicit(sublist)); + } + result = list_make1(make_orclause(newlist)); + } + else if (IsA(bitmapqual, IndexPath)) + { + IndexPath *ipath = (IndexPath *) bitmapqual; + IndexOptInfo *index; + + Assert(list_length(ipath->indexinfo) == 1); + index = linitial(ipath->indexinfo); + + /* + * We have to remove "lossy" index operators from the result, since + * the index isn't guaranteeing they are enforced. (This will lead + * to the operators being rechecked as qpquals of the BitmapHeapScan + * node.) + * + * XXX look at restructuring to share code better with + * fix_indxqual_references() + */ + result = NIL; + Assert(list_length(ipath->indexquals) == 1); + foreach(l, (List *) linitial(ipath->indexquals)) + { + RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); + OpExpr *clause; + Oid opno; + Node *indexkey; + Oid opclass; + int stratno; + Oid stratsubtype; + bool recheck; + + Assert(IsA(rinfo, RestrictInfo)); + clause = (OpExpr *) rinfo->clause; + if (!IsA(clause, OpExpr) || list_length(clause->args) != 2) + elog(ERROR, "indexqual clause is not binary opclause"); + opno = clause->opno; + + /* + * Check to see if the indexkey is on the right; if so, commute + * the operator. The indexkey should be the side that refers to + * (only) the base relation. + */ + if (!bms_equal(rinfo->left_relids, index->rel->relids)) + { + opno = get_commutator(opno); + if (!OidIsValid(opno)) + elog(ERROR, "could not find commutator for operator %u", + clause->opno); + indexkey = lsecond(clause->args); + } + else + indexkey = linitial(clause->args); + + /* + * Identify the index attribute and get the index opclass. + * We use fix_indxqual_operand() which does a little more + * than we really need, but it will do. + */ + (void) fix_indxqual_operand(indexkey, + index, + &opclass); + + /* + * Look up the (possibly commuted) operator in the operator class + * to get its strategy numbers and the recheck indicator. This + * also double-checks that we found an operator matching the + * index. + */ + get_op_opclass_properties(opno, opclass, + &stratno, &stratsubtype, &recheck); + + /* + * Finally, we can include the clause in the result if it's + * not a lossy operator. + */ + if (!recheck) + result = lappend(result, clause); + } + } + else + { + elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual)); + result = NIL; /* keep compiler quiet */ + } + + return result; +} + +/* * create_tidscan_plan * Returns a tidscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. @@ -1550,6 +1910,53 @@ make_indexscan(List *qptlist, return node; } +static BitmapIndexScan * +make_bitmap_indexscan(Index scanrelid, + Oid indxid, + List *indxqual, + List *indxqualorig, + List *indxstrategy, + List *indxsubtype) +{ + BitmapIndexScan *node = makeNode(BitmapIndexScan); + Plan *plan = &node->scan.plan; + + /* cost should be inserted by caller */ + plan->targetlist = NIL; /* not used */ + plan->qual = NIL; /* not used */ + plan->lefttree = NULL; + plan->righttree = NULL; + node->scan.scanrelid = scanrelid; + node->indxid = indxid; + node->indxqual = indxqual; + node->indxqualorig = indxqualorig; + node->indxstrategy = indxstrategy; + node->indxsubtype = indxsubtype; + + return node; +} + +static BitmapHeapScan * +make_bitmap_heapscan(List *qptlist, + List *qpqual, + Plan *lefttree, + List *bitmapqualorig, + Index scanrelid) +{ + BitmapHeapScan *node = makeNode(BitmapHeapScan); + Plan *plan = &node->scan.plan; + + /* cost should be inserted by caller */ + plan->targetlist = qptlist; + plan->qual = qpqual; + plan->lefttree = lefttree; + plan->righttree = NULL; + node->scan.scanrelid = scanrelid; + node->bitmapqualorig = bitmapqualorig; + + return node; +} + static TidScan * make_tidscan(List *qptlist, List *qpqual, @@ -1653,6 +2060,82 @@ make_append(List *appendplans, bool isTarget, List *tlist) return node; } +static BitmapAnd * +make_bitmap_and(List *bitmapplans) +{ + BitmapAnd *node = makeNode(BitmapAnd); + Plan *plan = &node->plan; + ListCell *subnode; + + /* + * Compute cost as sum of subplan costs, plus 10x cpu_operator_cost + * (a pretty arbitrary amount, agreed) for each tbm_intersect needed. + */ + plan->startup_cost = 0; + plan->total_cost = 0; + plan->plan_rows = 0; + plan->plan_width = 0; /* meaningless */ + foreach(subnode, bitmapplans) + { + Plan *subplan = (Plan *) lfirst(subnode); + + if (subnode == list_head(bitmapplans)) /* first node? */ + { + plan->startup_cost = subplan->startup_cost; + plan->plan_rows = subplan->plan_rows; + } + else + plan->plan_rows = Min(plan->plan_rows, subplan->plan_rows); + plan->total_cost += subplan->total_cost; + } + + plan->targetlist = NIL; + plan->qual = NIL; + plan->lefttree = NULL; + plan->righttree = NULL; + node->bitmapplans = bitmapplans; + + return node; +} + +static BitmapOr * +make_bitmap_or(List *bitmapplans) +{ + BitmapOr *node = makeNode(BitmapOr); + Plan *plan = &node->plan; + ListCell *subnode; + + /* + * Compute cost as sum of subplan costs, plus 10x cpu_operator_cost + * (a pretty arbitrary amount, agreed) for each tbm_union needed. + * We assume that tbm_union can be optimized away for BitmapIndexScan + * subplans. + */ + plan->startup_cost = 0; + plan->total_cost = 0; + plan->plan_rows = 0; + plan->plan_width = 0; /* meaningless */ + foreach(subnode, bitmapplans) + { + Plan *subplan = (Plan *) lfirst(subnode); + + if (subnode == list_head(bitmapplans)) /* first node? */ + plan->startup_cost = subplan->startup_cost; + else if (!IsA(subplan, BitmapIndexScan)) + plan->total_cost += cpu_operator_cost * 10; + plan->total_cost += subplan->total_cost; + plan->plan_rows += subplan->plan_rows; /* ignore overlap */ + } + + plan->targetlist = NIL; + plan->qual = NIL; + plan->lefttree = NULL; + plan->righttree = NULL; + node->bitmapplans = bitmapplans; + + return node; +} + static NestLoop * make_nestloop(List *tlist, List *joinclauses, diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 075c6a339df..0688d86b1b1 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.106 2005/04/06 16:34:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.107 2005/04/19 22:35:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -107,6 +107,21 @@ set_plan_references(Plan *plan, List *rtable) fix_expr_references(plan, (Node *) ((IndexScan *) plan)->indxqualorig); break; + case T_BitmapIndexScan: + /* no need to fix targetlist and qual */ + Assert(plan->targetlist == NIL); + Assert(plan->qual == NIL); + fix_expr_references(plan, + (Node *) ((BitmapIndexScan *) plan)->indxqual); + fix_expr_references(plan, + (Node *) ((BitmapIndexScan *) plan)->indxqualorig); + break; + case T_BitmapHeapScan: + fix_expr_references(plan, (Node *) plan->targetlist); + fix_expr_references(plan, (Node *) plan->qual); + fix_expr_references(plan, + (Node *) ((BitmapHeapScan *) plan)->bitmapqualorig); + break; case T_TidScan: fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); @@ -225,6 +240,16 @@ set_plan_references(Plan *plan, List *rtable) foreach(l, ((Append *) plan)->appendplans) set_plan_references((Plan *) lfirst(l), rtable); break; + case T_BitmapAnd: + /* BitmapAnd works like Append */ + foreach(l, ((BitmapAnd *) plan)->bitmapplans) + set_plan_references((Plan *) lfirst(l), rtable); + break; + case T_BitmapOr: + /* BitmapOr works like Append */ + foreach(l, ((BitmapOr *) plan)->bitmapplans) + set_plan_references((Plan *) lfirst(l), rtable); + break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(plan)); diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index f1519569a85..7f5a4fde63b 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.96 2005/04/11 23:06:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.97 2005/04/19 22:35:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1037,6 +1037,20 @@ finalize_plan(Plan *plan, List *rtable, */ break; + case T_BitmapIndexScan: + finalize_primnode((Node *) ((BitmapIndexScan *) plan)->indxqual, + &context); + /* + * we need not look at indxqualorig, since it will have the + * same param references as indxqual. + */ + break; + + case T_BitmapHeapScan: + finalize_primnode((Node *) ((BitmapHeapScan *) plan)->bitmapqualorig, + &context); + break; + case T_TidScan: finalize_primnode((Node *) ((TidScan *) plan)->tideval, &context); @@ -1082,6 +1096,38 @@ finalize_plan(Plan *plan, List *rtable, } break; + case T_BitmapAnd: + { + ListCell *l; + + foreach(l, ((BitmapAnd *) plan)->bitmapplans) + { + context.paramids = + bms_add_members(context.paramids, + finalize_plan((Plan *) lfirst(l), + rtable, + outer_params, + valid_params)); + } + } + break; + + case T_BitmapOr: + { + ListCell *l; + + foreach(l, ((BitmapOr *) plan)->bitmapplans) + { + context.paramids = + bms_add_members(context.paramids, + finalize_plan((Plan *) lfirst(l), + rtable, + outer_params, + valid_params)); + } + } + break; + case T_NestLoop: finalize_primnode((Node *) ((Join *) plan)->joinqual, &context); diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 14b62b80fc8..ec0fc8a29ab 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.115 2005/04/06 16:34:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.116 2005/04/19 22:35:17 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -472,6 +472,39 @@ create_index_path(Query *root, } /* + * create_bitmap_heap_path + * Creates a path node for a bitmap scan. + * + * 'bitmapqual' is an AND/OR tree of IndexPath nodes. + */ +BitmapHeapPath * +create_bitmap_heap_path(Query *root, + RelOptInfo *rel, + Node *bitmapqual) +{ + BitmapHeapPath *pathnode = makeNode(BitmapHeapPath); + + pathnode->path.pathtype = T_BitmapHeapScan; + pathnode->path.parent = rel; + pathnode->path.pathkeys = NIL; /* always unordered */ + + pathnode->bitmapqual = bitmapqual; + + /* It's not an innerjoin path. */ + pathnode->isjoininner = false; + + /* + * The number of rows is the same as the parent rel's estimate, since + * this isn't a join inner indexscan. + */ + pathnode->rows = rel->rows; + + cost_bitmap_scan(&pathnode->path, root, rel, bitmapqual, false); + + return pathnode; +} + +/* * create_tidscan_path * Creates a path corresponding to a tid_direct scan, returning the * pathnode. |