aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/path/allpaths.c5
-rw-r--r--src/backend/optimizer/path/costsize.c34
-rw-r--r--src/backend/optimizer/path/joinpath.c3
-rw-r--r--src/backend/optimizer/plan/createplan.c557
-rw-r--r--src/backend/optimizer/plan/setrefs.c27
-rw-r--r--src/backend/optimizer/plan/subselect.c48
-rw-r--r--src/backend/optimizer/util/pathnode.c35
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.