aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/createplan.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2005-04-25 01:30:14 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2005-04-25 01:30:14 +0000
commit5b05185262fd562080ecfd675c7b3634a69851c0 (patch)
treeb9a9ff51a51e72d5076d6828584b30a504335303 /src/backend/optimizer/plan/createplan.c
parent186655e9a53b62f75e57bcfc218129a6cfe8ea68 (diff)
downloadpostgresql-5b05185262fd562080ecfd675c7b3634a69851c0.tar.gz
postgresql-5b05185262fd562080ecfd675c7b3634a69851c0.zip
Remove support for OR'd indexscans internal to a single IndexScan plan
node, as this behavior is now better done as a bitmap OR indexscan. This allows considerable simplification in nodeIndexscan.c itself as well as several planner modules concerned with indexscan plan generation. Also we can improve the sharing of code between regular and bitmap indexscans, since they are now working with nigh-identical Plan nodes.
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r--src/backend/optimizer/plan/createplan.c574
1 files changed, 199 insertions, 375 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 21af9f7e3e2..0ce65a93d19 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.184 2005/04/23 01:29:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.185 2005/04/25 01:30:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,13 +47,14 @@ static Plan *create_unique_plan(Query *root, UniquePath *best_path);
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);
+ List *tlist, List *scan_clauses,
+ List **nonlossy_clauses);
static BitmapHeapScan *create_bitmap_scan_plan(Query *root,
BitmapHeapPath *best_path,
List *tlist, List *scan_clauses);
-static Plan *create_bitmap_subplan(Query *root, Path *bitmapqual);
+static Plan *create_bitmap_subplan(Query *root, Path *bitmapqual,
+ List **qual, List **indexqual);
static List *create_bitmap_qual(Path *bitmapqual);
-static List *create_bitmap_indxqual(Path *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,
@@ -66,31 +67,26 @@ static MergeJoin *create_mergejoin_plan(Query *root, MergePath *best_path,
Plan *outer_plan, Plan *inner_plan);
static HashJoin *create_hashjoin_plan(Query *root, HashPath *best_path,
Plan *outer_plan, Plan *inner_plan);
-static void fix_indxqual_references(List *indexquals, IndexPath *index_path,
- List **fixed_indexquals,
- List **indxstrategy,
- List **indxsubtype,
- List **indxlossy);
-static void fix_indxqual_sublist(List *indexqual, IndexOptInfo *index,
- List **fixed_quals,
- List **strategy,
- List **subtype,
- List **lossy);
-static Node *fix_indxqual_operand(Node *node, IndexOptInfo *index,
+static void fix_indexqual_references(List *indexquals, IndexPath *index_path,
+ List **fixed_indexquals,
+ List **nonlossy_indexquals,
+ List **indexstrategy,
+ List **indexsubtype);
+static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index,
Oid *opclass);
static List *get_switched_clauses(List *clauses, Relids outerrelids);
static void copy_path_costsize(Plan *dest, Path *src);
static void copy_plan_costsize(Plan *dest, Plan *src);
static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
- List *indxid, List *indxqual, List *indxqualorig,
- List *indxstrategy, List *indxsubtype, List *indxlossy,
+ Oid indexid, List *indexqual, List *indexqualorig,
+ List *indexstrategy, List *indexsubtype,
ScanDirection indexscandir);
-static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indxid,
- List *indxqual,
- List *indxqualorig,
- List *indxstrategy,
- List *indxsubtype);
+static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indexid,
+ List *indexqual,
+ List *indexqualorig,
+ List *indexstrategy,
+ List *indexsubtype);
static BitmapHeapScan *make_bitmap_heapscan(List *qptlist,
List *qpqual,
Plan *lefttree,
@@ -236,7 +232,8 @@ create_scan_plan(Query *root, Path *best_path)
plan = (Scan *) create_indexscan_plan(root,
(IndexPath *) best_path,
tlist,
- scan_clauses);
+ scan_clauses,
+ NULL);
break;
case T_BitmapHeapScan:
@@ -701,121 +698,84 @@ create_seqscan_plan(Query *root, Path *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
- * qual conditions for each scan of the index(es); if there is more than one
- * scan then the retrieved tuple sets are ORed together. The indexquals
- * and indexinfo lists must have the same length, ie, the number of scans
- * that will occur. Note it is possible for a qual condition sublist
- * to be empty --- then no index restrictions will be applied during that
- * scan.
+ * The indexquals list of the path contains implicitly-ANDed qual conditions.
+ * The list can be empty --- then no index restrictions will be applied during
+ * the scan.
+ *
+ * If nonlossy_clauses isn't NULL, *nonlossy_clauses receives a list of the
+ * nonlossy indexquals.
*/
static IndexScan *
create_indexscan_plan(Query *root,
IndexPath *best_path,
List *tlist,
- List *scan_clauses)
+ List *scan_clauses,
+ List **nonlossy_clauses)
{
- List *indxquals = best_path->indexquals;
+ List *indexquals = best_path->indexquals;
Index baserelid = best_path->path.parent->relid;
+ Oid indexoid = best_path->indexinfo->indexoid;
List *qpqual;
- Expr *indxqual_or_expr = NULL;
- List *stripped_indxquals;
- List *fixed_indxquals;
- List *indxstrategy;
- List *indxsubtype;
- List *indxlossy;
- List *indexids;
- ListCell *l;
+ List *stripped_indexquals;
+ List *fixed_indexquals;
+ List *nonlossy_indexquals;
+ List *indexstrategy;
+ List *indexsubtype;
IndexScan *scan_plan;
/* it should be a base rel... */
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
+ * executor as indexqualorig
*/
- stripped_indxquals = NIL;
- foreach(l, indxquals)
- {
- List *andlist = (List *) lfirst(l);
-
- stripped_indxquals = lappend(stripped_indxquals,
- get_actual_clauses(andlist));
- }
+ stripped_indexquals = get_actual_clauses(indexquals);
/*
* 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);
+ fix_indexqual_references(indexquals, best_path,
+ &fixed_indexquals,
+ &nonlossy_indexquals,
+ &indexstrategy,
+ &indexsubtype);
+
+ /* pass back nonlossy quals if caller wants 'em */
+ if (nonlossy_clauses)
+ *nonlossy_clauses = nonlossy_indexquals;
/*
- * If this is a innerjoin scan, the indexclauses will contain join
+ * If this is an 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.
+ *
+ * Note: pointer comparison should be enough to determine RestrictInfo
+ * matches.
*/
if (best_path->isjoininner)
- {
- /*
- * We don't currently support OR indexscans in joins, so we only
- * need to worry about the plain AND case. Also, pointer
- * comparison should be enough to determine RestrictInfo matches.
- */
- Assert(list_length(best_path->indexclauses) == 1);
- scan_clauses = list_union_ptr(scan_clauses,
- (List *) linitial(best_path->indexclauses));
- }
-
- /* Reduce RestrictInfo list to bare expressions */
- scan_clauses = get_actual_clauses(scan_clauses);
+ scan_clauses = list_union_ptr(scan_clauses, best_path->indexclauses);
/*
* 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 nodeIndexscan.c), but if
- * there are any "special" operators involved then they must be added
- * to qpqual. The upshot is that qpquals must contain scan_clauses
- * minus whatever appears in indxquals.
+ * there are any "special" operators involved then they must be included
+ * in qpqual. Also, any lossy index operators must be rechecked in
+ * the qpqual. The upshot is that qpquals must contain scan_clauses
+ * minus whatever appears in nonlossy_indexquals.
*/
- if (list_length(indxquals) > 1)
- {
- /*
- * Build an expression representation of the indexqual, expanding
- * the implicit OR and AND semantics of the first- and
- * second-level lists. (The odds that this will exactly match any
- * scan_clause are not great; perhaps we need more smarts here.)
- */
- indxqual_or_expr = make_expr_from_indexclauses(indxquals);
- qpqual = list_difference(scan_clauses, list_make1(indxqual_or_expr));
- }
- else
- {
- /*
- * Here, we can simply treat the first sublist as an independent
- * set of qual expressions, since there is no top-level OR
- * behavior.
- */
- Assert(stripped_indxquals != NIL);
- qpqual = list_difference(scan_clauses, linitial(stripped_indxquals));
- }
+ qpqual = list_difference_ptr(scan_clauses, nonlossy_indexquals);
+
+ /* Reduce RestrictInfo list to bare expressions */
+ qpqual = get_actual_clauses(qpqual);
/* Sort clauses into best execution order */
qpqual = order_qual_clauses(root, qpqual);
@@ -824,12 +784,11 @@ create_indexscan_plan(Query *root,
scan_plan = make_indexscan(tlist,
qpqual,
baserelid,
- indexids,
- fixed_indxquals,
- stripped_indxquals,
- indxstrategy,
- indxsubtype,
- indxlossy,
+ indexoid,
+ fixed_indexquals,
+ stripped_indexquals,
+ indexstrategy,
+ indexsubtype,
best_path->indexscandir);
copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
@@ -861,14 +820,9 @@ create_bitmap_scan_plan(Query *root,
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);
+ /* Process the bitmapqual tree into a Plan tree and qual lists */
+ bitmapqualplan = create_bitmap_subplan(root, best_path->bitmapqual,
+ &bitmapqualorig, &indexquals);
/* Reduce RestrictInfo list to bare expressions */
scan_clauses = get_actual_clauses(scan_clauses);
@@ -922,70 +876,101 @@ create_bitmap_scan_plan(Query *root,
/*
* Given a bitmapqual tree, generate the Plan tree that implements it
+ *
+ * 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. The latter is made to
+ * exclude lossy index operators.
*/
static Plan *
-create_bitmap_subplan(Query *root, Path *bitmapqual)
+create_bitmap_subplan(Query *root, Path *bitmapqual,
+ List **qual, List **indexqual)
{
Plan *plan;
if (IsA(bitmapqual, BitmapAndPath))
{
BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
- List *newlist = NIL;
+ List *subplans = NIL;
+ List *subquals = NIL;
+ List *subindexquals = NIL;
ListCell *l;
foreach(l, apath->bitmapquals)
{
- Plan *subplan = create_bitmap_subplan(root, lfirst(l));
-
- newlist = lappend(newlist, subplan);
+ Plan *subplan;
+ List *subqual;
+ List *subindexqual;
+
+ subplan = create_bitmap_subplan(root, (Path *) lfirst(l),
+ &subqual, &subindexqual);
+ subplans = lappend(subplans, subplan);
+ subquals = list_concat(subquals, subqual);
+ subindexquals = list_concat(subindexquals, subindexqual);
}
- plan = (Plan *) make_bitmap_and(newlist);
+ plan = (Plan *) make_bitmap_and(subplans);
plan->startup_cost = apath->path.startup_cost;
plan->total_cost = apath->path.total_cost;
plan->plan_rows =
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 *newlist = NIL;
+ List *subplans = NIL;
+ List *subquals = NIL;
+ List *subindexquals = NIL;
ListCell *l;
foreach(l, opath->bitmapquals)
{
- Plan *subplan = create_bitmap_subplan(root, lfirst(l));
-
- newlist = lappend(newlist, subplan);
+ Plan *subplan;
+ List *subqual;
+ List *subindexqual;
+
+ subplan = create_bitmap_subplan(root, (Path *) lfirst(l),
+ &subqual, &subindexqual);
+ subplans = lappend(subplans, subplan);
+ subquals = lappend(subquals,
+ make_ands_explicit(subqual));
+ subindexquals = lappend(subindexquals,
+ make_ands_explicit(subindexqual));
}
- plan = (Plan *) make_bitmap_or(newlist);
+ plan = (Plan *) make_bitmap_or(subplans);
plan->startup_cost = opath->path.startup_cost;
plan->total_cost = opath->path.total_cost;
plan->plan_rows =
clamp_row_est(opath->bitmapselectivity * opath->path.parent->tuples);
plan->plan_width = 0; /* meaningless */
+ *qual = list_make1(make_orclause(subquals));
+ *indexqual = list_make1(make_orclause(subindexquals));
}
else if (IsA(bitmapqual, IndexPath))
{
IndexPath *ipath = (IndexPath *) bitmapqual;
IndexScan *iscan;
+ List *nonlossy_clauses;
/* Use the regular indexscan plan build machinery... */
- iscan = create_indexscan_plan(root, ipath, NIL, NIL);
- Assert(list_length(iscan->indxid) == 1);
+ iscan = create_indexscan_plan(root, ipath, NIL, NIL,
+ &nonlossy_clauses);
/* then convert to a bitmap indexscan */
plan = (Plan *) make_bitmap_indexscan(iscan->scan.scanrelid,
- linitial_oid(iscan->indxid),
- linitial(iscan->indxqual),
- linitial(iscan->indxqualorig),
- linitial(iscan->indxstrategy),
- linitial(iscan->indxsubtype));
+ iscan->indexid,
+ iscan->indexqual,
+ iscan->indexqualorig,
+ iscan->indexstrategy,
+ iscan->indexsubtype);
plan->startup_cost = 0.0;
plan->total_cost = ipath->indextotalcost;
plan->plan_rows =
clamp_row_est(ipath->indexselectivity * ipath->path.parent->tuples);
plan->plan_width = 0; /* meaningless */
+ *qual = get_actual_clauses(ipath->indexclauses);
+ *indexqual = get_actual_clauses(nonlossy_clauses);
}
else
{
@@ -1041,8 +1026,7 @@ create_bitmap_qual(Path *bitmapqual)
{
IndexPath *ipath = (IndexPath *) bitmapqual;
- Assert(list_length(ipath->indexclauses) == 1);
- result = get_actual_clauses(linitial(ipath->indexclauses));
+ result = get_actual_clauses(ipath->indexclauses);
}
else
{
@@ -1054,132 +1038,27 @@ create_bitmap_qual(Path *bitmapqual)
}
/*
- * 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.
+ * Given a bitmapqual tree, generate the equivalent RestrictInfo list.
*/
-static List *
-create_bitmap_indxqual(Path *bitmapqual)
+List *
+create_bitmap_restriction(Path *bitmapqual)
{
- List *result;
- List *sublist;
+ List *bitmapquals;
+ List *bitmapclauses;
ListCell *l;
- if (IsA(bitmapqual, BitmapAndPath))
- {
- BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
+ bitmapquals = create_bitmap_qual(bitmapqual);
- result = NIL;
- foreach(l, apath->bitmapquals)
- {
- sublist = create_bitmap_indxqual(lfirst(l));
- result = list_concat(result, sublist);
- }
- }
- else if (IsA(bitmapqual, BitmapOrPath))
+ /* must convert qual list to restrictinfos ... painful ... */
+ bitmapclauses = NIL;
+ foreach(l, bitmapquals)
{
- BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;
- List *newlist = NIL;
-
- foreach(l, opath->bitmapquals)
- {
- 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 */
+ bitmapclauses = lappend(bitmapclauses,
+ make_restrictinfo((Expr *) lfirst(l),
+ true, true));
}
- return result;
+ return bitmapclauses;
}
/*
@@ -1299,10 +1178,7 @@ create_nestloop_plan(Query *root,
* An index is being used to reduce the number of tuples scanned
* in the inner relation. If there are join clauses being used
* with the index, we may remove those join clauses from the list
- * of clauses that have to be checked as qpquals at the join node
- * --- but only if there's just one indexscan in the inner path
- * (otherwise, several different sets of clauses are being ORed
- * together).
+ * of clauses that have to be checked as qpquals at the join node.
*
* We can also remove any join clauses that are redundant with those
* being used in the index scan; prior redundancy checks will not
@@ -1313,15 +1189,13 @@ create_nestloop_plan(Query *root,
* not a special innerjoin path.
*/
IndexPath *innerpath = (IndexPath *) best_path->innerjoinpath;
- List *indexclauses = innerpath->indexclauses;
- if (innerpath->isjoininner &&
- list_length(indexclauses) == 1) /* single indexscan? */
+ if (innerpath->isjoininner)
{
joinrestrictclauses =
select_nonredundant_join_clauses(root,
joinrestrictclauses,
- linitial(indexclauses),
+ innerpath->indexclauses,
IS_OUTER_JOIN(best_path->jointype));
}
}
@@ -1334,21 +1208,9 @@ create_nestloop_plan(Query *root,
if (innerpath->isjoininner)
{
- List *bitmapquals;
List *bitmapclauses;
- ListCell *l;
-
- bitmapquals = create_bitmap_qual(innerpath->bitmapqual);
-
- /* must convert qual list to restrictinfos ... painful ... */
- bitmapclauses = NIL;
- foreach(l, bitmapquals)
- {
- bitmapclauses = lappend(bitmapclauses,
- make_restrictinfo((Expr *) lfirst(l),
- true, true));
- }
+ bitmapclauses = create_bitmap_restriction(innerpath->bitmapqual);
joinrestrictclauses =
select_nonredundant_join_clauses(root,
joinrestrictclauses,
@@ -1542,95 +1404,54 @@ create_hashjoin_plan(Query *root,
*****************************************************************************/
/*
- * fix_indxqual_references
+ * fix_indexqual_references
* Adjust indexqual clauses to the form the executor's indexqual
* machinery needs, and check for recheckable (lossy) index conditions.
*
- * We have four tasks here:
+ * We have five tasks here:
* * Remove RestrictInfo nodes from the input clauses.
* * Index keys must be represented by Var nodes with varattno set to the
* index's attribute number, not the attribute number in the original rel.
* * If the index key is on the right, commute the clause to put it on the
- * left. (Someday the executor might not need this, but for now it does.)
- * * We must construct lists of operator strategy numbers, subtypes, and
- * recheck (lossy-operator) flags for the top-level operators of each
- * index clause.
- *
- * Both the input list and the "fixed" output list have the form of lists of
- * sublists of qual clauses --- the top-level list has one entry for each
- * indexscan to be performed. The semantics are OR-of-ANDs. Note however
- * that the input list contains RestrictInfos, while the output list doesn't.
+ * left.
+ * * We must construct lists of operator strategy numbers and subtypes
+ * for the top-level operators of each index clause.
+ * * We must detect any lossy index operators. The API is that we return
+ * a list of the input clauses whose operators are NOT lossy.
*
- * fixed_indexquals receives a modified copy of the indexqual list --- the
+ * fixed_indexquals receives a modified copy of the indexquals list --- the
* original is not changed. Note also that the copy shares no substructure
* with the original; this is needed in case there is a subplan in it (we need
* two separate copies of the subplan tree, or things will go awry).
*
- * indxstrategy receives a list of integer sublists of strategy numbers.
- * indxsubtype receives a list of OID sublists of strategy subtypes.
- * indxlossy receives a list of integer sublists of lossy-operator booleans.
- */
-static void
-fix_indxqual_references(List *indexquals, IndexPath *index_path,
- List **fixed_indexquals,
- List **indxstrategy,
- List **indxsubtype,
- List **indxlossy)
-{
- List *index_info = index_path->indexinfo;
- ListCell *iq,
- *ii;
-
- *fixed_indexquals = NIL;
- *indxstrategy = NIL;
- *indxsubtype = NIL;
- *indxlossy = NIL;
- forboth(iq, indexquals, ii, index_info)
- {
- List *indexqual = (List *) lfirst(iq);
- IndexOptInfo *index = (IndexOptInfo *) lfirst(ii);
- List *fixed_qual;
- List *strategy;
- List *subtype;
- List *lossy;
-
- fix_indxqual_sublist(indexqual, index,
- &fixed_qual, &strategy, &subtype, &lossy);
- *fixed_indexquals = lappend(*fixed_indexquals, fixed_qual);
- *indxstrategy = lappend(*indxstrategy, strategy);
- *indxsubtype = lappend(*indxsubtype, subtype);
- *indxlossy = lappend(*indxlossy, lossy);
- }
-}
-
-/*
- * Fix the sublist of indexquals to be used in a particular scan.
- *
- * For each qual clause, commute if needed to put the indexkey operand on the
- * left, and then fix its varattno. (We do not need to change the other side
- * of the clause.) Then determine the operator's strategy number and subtype
- * number, and check for lossy index behavior.
+ * nonlossy_indexquals receives a list of the original input clauses (with
+ * RestrictInfos) that contain non-lossy operators.
*
- * Returns four lists:
- * the list of fixed indexquals
- * the integer list of strategy numbers
- * the OID list of strategy subtypes
- * the integer list of lossiness flags (1/0)
+ * indexstrategy receives an integer list of strategy numbers.
+ * indexsubtype receives an OID list of strategy subtypes.
*/
static void
-fix_indxqual_sublist(List *indexqual, IndexOptInfo *index,
- List **fixed_quals,
- List **strategy,
- List **subtype,
- List **lossy)
+fix_indexqual_references(List *indexquals, IndexPath *index_path,
+ List **fixed_indexquals,
+ List **nonlossy_indexquals,
+ List **indexstrategy,
+ List **indexsubtype)
{
+ IndexOptInfo *index = index_path->indexinfo;
ListCell *l;
- *fixed_quals = NIL;
- *strategy = NIL;
- *subtype = NIL;
- *lossy = NIL;
- foreach(l, indexqual)
+ *fixed_indexquals = NIL;
+ *nonlossy_indexquals = NIL;
+ *indexstrategy = NIL;
+ *indexsubtype = NIL;
+
+ /*
+ * For each qual clause, commute if needed to put the indexkey operand on
+ * the left, and then fix its varattno. (We do not need to change the
+ * other side of the clause.) Then determine the operator's strategy
+ * number and subtype number, and check for lossy index behavior.
+ */
+ foreach(l, indexquals)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
OpExpr *clause;
@@ -1642,7 +1463,8 @@ fix_indxqual_sublist(List *indexqual, IndexOptInfo *index,
Assert(IsA(rinfo, RestrictInfo));
clause = (OpExpr *) rinfo->clause;
- if (!IsA(clause, OpExpr) ||list_length(clause->args) != 2)
+ if (!IsA(clause, OpExpr) ||
+ list_length(clause->args) != 2)
elog(ERROR, "indexqual clause is not binary opclause");
/*
@@ -1666,11 +1488,12 @@ fix_indxqual_sublist(List *indexqual, IndexOptInfo *index,
* Now, determine which index attribute this is, change the
* indexkey operand as needed, and get the index opclass.
*/
- linitial(newclause->args) = fix_indxqual_operand(linitial(newclause->args),
- index,
- &opclass);
+ linitial(newclause->args) =
+ fix_indexqual_operand(linitial(newclause->args),
+ index,
+ &opclass);
- *fixed_quals = lappend(*fixed_quals, newclause);
+ *fixed_indexquals = lappend(*fixed_indexquals, newclause);
/*
* Look up the (possibly commuted) operator in the operator class
@@ -1681,14 +1504,17 @@ fix_indxqual_sublist(List *indexqual, IndexOptInfo *index,
get_op_opclass_properties(newclause->opno, opclass,
&stratno, &stratsubtype, &recheck);
- *strategy = lappend_int(*strategy, stratno);
- *subtype = lappend_oid(*subtype, stratsubtype);
- *lossy = lappend_int(*lossy, (int) recheck);
+ *indexstrategy = lappend_int(*indexstrategy, stratno);
+ *indexsubtype = lappend_oid(*indexsubtype, stratsubtype);
+
+ /* If it's not lossy, add to nonlossy_indexquals */
+ if (!recheck)
+ *nonlossy_indexquals = lappend(*nonlossy_indexquals, rinfo);
}
}
static Node *
-fix_indxqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
+fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
{
/*
* We represent index keys by Var nodes having the varno of the base
@@ -1923,12 +1749,11 @@ static IndexScan *
make_indexscan(List *qptlist,
List *qpqual,
Index scanrelid,
- List *indxid,
- List *indxqual,
- List *indxqualorig,
- List *indxstrategy,
- List *indxsubtype,
- List *indxlossy,
+ Oid indexid,
+ List *indexqual,
+ List *indexqualorig,
+ List *indexstrategy,
+ List *indexsubtype,
ScanDirection indexscandir)
{
IndexScan *node = makeNode(IndexScan);
@@ -1940,24 +1765,23 @@ make_indexscan(List *qptlist,
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;
- node->indxlossy = indxlossy;
- node->indxorderdir = indexscandir;
+ node->indexid = indexid;
+ node->indexqual = indexqual;
+ node->indexqualorig = indexqualorig;
+ node->indexstrategy = indexstrategy;
+ node->indexsubtype = indexsubtype;
+ node->indexorderdir = indexscandir;
return node;
}
static BitmapIndexScan *
make_bitmap_indexscan(Index scanrelid,
- Oid indxid,
- List *indxqual,
- List *indxqualorig,
- List *indxstrategy,
- List *indxsubtype)
+ Oid indexid,
+ List *indexqual,
+ List *indexqualorig,
+ List *indexstrategy,
+ List *indexsubtype)
{
BitmapIndexScan *node = makeNode(BitmapIndexScan);
Plan *plan = &node->scan.plan;
@@ -1968,11 +1792,11 @@ make_bitmap_indexscan(Index scanrelid,
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;
+ node->indexid = indexid;
+ node->indexqual = indexqual;
+ node->indexqualorig = indexqualorig;
+ node->indexstrategy = indexstrategy;
+ node->indexsubtype = indexsubtype;
return node;
}