aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path')
-rw-r--r--src/backend/optimizer/path/costsize.c5
-rw-r--r--src/backend/optimizer/path/indxpath.c105
-rw-r--r--src/backend/optimizer/path/orindxpath.c64
3 files changed, 114 insertions, 60 deletions
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index fa7dcdc9740..7353e73462b 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.120 2004/01/05 05:07:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.121 2004/01/05 23:39:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -238,6 +238,9 @@ cost_nonsequential_access(double relpages)
* Any additional quals evaluated as qpquals may reduce the number of returned
* tuples, but they won't reduce the number of tuples we have to fetch from
* the table, so they don't reduce the scan cost.
+ *
+ * NOTE: as of 7.5, indexQuals is a list of RestrictInfo nodes, where formerly
+ * it was a list of bare clause expressions.
*/
void
cost_index(Path *path, Query *root,
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 83d129d0c9c..da11d7f86d0 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.154 2004/01/05 05:07:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.155 2004/01/05 23:39:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -76,7 +76,7 @@ static bool match_index_to_operand(Node *operand, int indexcol,
RelOptInfo *rel, IndexOptInfo *index);
static bool match_special_index_operator(Expr *clause, Oid opclass,
bool indexkey_on_left);
-static List *expand_indexqual_condition(Expr *clause, Oid opclass);
+static List *expand_indexqual_condition(RestrictInfo *rinfo, Oid opclass);
static List *prefix_quals(Node *leftop, Oid opclass,
Const *prefix, Pattern_Prefix_Status pstatus);
static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass,
@@ -1418,8 +1418,7 @@ make_innerjoin_index_path(Query *root,
{
IndexPath *pathnode = makeNode(IndexPath);
List *indexquals,
- *allclauses,
- *l;
+ *allclauses;
/* XXX perhaps this code should be merged with create_index_path? */
@@ -1433,28 +1432,21 @@ make_innerjoin_index_path(Query *root,
*/
pathnode->path.pathkeys = NIL;
- /* Convert RestrictInfo nodes to indexquals the executor can handle */
+ /* Convert clauses to indexquals the executor can handle */
indexquals = expand_indexqual_conditions(index, clausegroups);
- /*
- * Also make a flattened list of the RestrictInfo nodes; createplan.c
- * will need this later. We assume here that we can destructively
- * modify the passed-in clausegroups list structure.
- */
- allclauses = NIL;
- foreach(l, clausegroups)
- {
- /* nconc okay here since same clause couldn't be in two sublists */
- allclauses = nconc(allclauses, (List *) lfirst(l));
- }
+ /* Flatten the clausegroups list to produce indexclauses list */
+ allclauses = flatten_clausegroups_list(clausegroups);
/*
* Note that we are making a pathnode for a single-scan indexscan;
- * therefore, indexinfo and indexqual should be single-element lists.
+ * therefore, indexinfo etc should be single-element lists.
*/
pathnode->indexinfo = makeList1(index);
- pathnode->indexqual = makeList1(indexquals);
- pathnode->indexjoinclauses = makeList1(allclauses);
+ pathnode->indexclauses = makeList1(allclauses);
+ pathnode->indexquals = makeList1(indexquals);
+
+ pathnode->isjoininner = true;
/* We don't actually care what order the index scans in ... */
pathnode->indexscandir = NoMovementScanDirection;
@@ -1489,6 +1481,61 @@ make_innerjoin_index_path(Query *root,
return (Path *) pathnode;
}
+/*
+ * flatten_clausegroups_list
+ * Given a list of lists of RestrictInfos, flatten it to a list
+ * of RestrictInfos.
+ *
+ * This is used to flatten out the result of group_clauses_by_indexkey()
+ * or one of its sibling routines, to produce an indexclauses list.
+ */
+List *
+flatten_clausegroups_list(List *clausegroups)
+{
+ List *allclauses = NIL;
+ List *l;
+
+ foreach(l, clausegroups)
+ {
+ allclauses = nconc(allclauses, listCopy((List *) lfirst(l)));
+ }
+ return allclauses;
+}
+
+/*
+ * make_expr_from_indexclauses()
+ * Given an indexclauses structure, produce an ordinary boolean expression.
+ *
+ * This consists of stripping out the RestrictInfo nodes and inserting
+ * explicit AND and OR nodes as needed. There's not much to it, but
+ * the functionality is needed in a few places, so centralize the logic.
+ */
+Expr *
+make_expr_from_indexclauses(List *indexclauses)
+{
+ List *orclauses = NIL;
+ List *orlist;
+
+ /* There's no such thing as an indexpath with zero scans */
+ Assert(indexclauses != NIL);
+
+ foreach(orlist, indexclauses)
+ {
+ List *andlist = (List *) lfirst(orlist);
+
+ /* Strip RestrictInfos */
+ andlist = get_actual_clauses(andlist);
+ /* Insert AND node if needed, and add to orclauses list */
+ orclauses = lappend(orclauses, make_ands_explicit(andlist));
+ }
+
+ if (length(orclauses) > 1)
+ return make_orclause(orclauses);
+ else
+ return (Expr *) lfirst(orclauses);
+}
+
+
/****************************************************************************
* ---- ROUTINES TO CHECK OPERANDS ----
****************************************************************************/
@@ -1799,8 +1846,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
RestrictInfo *rinfo = (RestrictInfo *) lfirst(i);
FastConc(&resultquals,
- expand_indexqual_condition(rinfo->clause,
- curClass));
+ expand_indexqual_condition(rinfo, curClass));
}
clausegroups = lnext(clausegroups);
@@ -1816,10 +1862,13 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
/*
* expand_indexqual_condition --- expand a single indexqual condition
+ *
+ * The input is a single RestrictInfo, the output a list of RestrictInfos
*/
static List *
-expand_indexqual_condition(Expr *clause, Oid opclass)
+expand_indexqual_condition(RestrictInfo *rinfo, Oid opclass)
{
+ Expr *clause = rinfo->clause;
/* we know these will succeed */
Node *leftop = get_leftop(clause);
Node *rightop = get_rightop(clause);
@@ -1883,7 +1932,7 @@ expand_indexqual_condition(Expr *clause, Oid opclass)
break;
default:
- result = makeList1(clause);
+ result = makeList1(rinfo);
break;
}
@@ -1978,7 +2027,7 @@ prefix_quals(Node *leftop, Oid opclass,
elog(ERROR, "no = operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) prefix_const);
- result = makeList1(expr);
+ result = makeList1(make_restrictinfo(expr, true, true));
return result;
}
@@ -1993,7 +2042,7 @@ prefix_quals(Node *leftop, Oid opclass,
elog(ERROR, "no >= operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) prefix_const);
- result = makeList1(expr);
+ result = makeList1(make_restrictinfo(expr, true, true));
/*-------
* If we can create a string larger than the prefix, we can say
@@ -2009,7 +2058,7 @@ prefix_quals(Node *leftop, Oid opclass,
elog(ERROR, "no < operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) greaterstr);
- result = lappend(result, expr);
+ result = lappend(result, make_restrictinfo(expr, true, true));
}
return result;
@@ -2080,7 +2129,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
(Expr *) leftop,
(Expr *) makeConst(datatype, -1, opr1right,
false, false));
- result = makeList1(expr);
+ result = makeList1(make_restrictinfo(expr, true, true));
/* create clause "key <= network_scan_last( rightop )" */
@@ -2095,7 +2144,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
(Expr *) leftop,
(Expr *) makeConst(datatype, -1, opr2right,
false, false));
- result = lappend(result, expr);
+ result = lappend(result, make_restrictinfo(expr, true, true));
return result;
}
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c
index 02e486ec35c..9722b69965d 100644
--- a/src/backend/optimizer/path/orindxpath.c
+++ b/src/backend/optimizer/path/orindxpath.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.56 2004/01/05 05:07:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.57 2004/01/05 23:39:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,7 +28,8 @@ static bool best_or_subclause_index(Query *root,
RelOptInfo *rel,
Expr *subclause,
IndexOptInfo **retIndexInfo,
- List **retIndexQual,
+ List **retIndexClauses,
+ List **retIndexQuals,
Cost *retStartupCost,
Cost *retTotalCost);
@@ -95,9 +96,7 @@ create_or_index_quals(Query *root, RelOptInfo *rel)
{
IndexPath *bestpath = NULL;
RestrictInfo *bestrinfo = NULL;
- FastList orclauses;
- List *orclause;
- Expr *indxqual_or_expr;
+ List *newrinfos;
RestrictInfo *or_rinfo;
Selectivity or_selec,
orig_selec;
@@ -145,20 +144,14 @@ create_or_index_quals(Query *root, RelOptInfo *rel)
return false;
/*
- * Build an expression representation of the indexqual, expanding
- * the implicit OR and AND semantics of the first- and
- * second-level lists.
+ * Convert the indexclauses structure to a RestrictInfo tree,
+ * and add it to the rel's restriction list.
*/
- FastListInit(&orclauses);
- foreach(orclause, bestpath->indexqual)
- FastAppend(&orclauses, make_ands_explicit(lfirst(orclause)));
- indxqual_or_expr = make_orclause(FastListValue(&orclauses));
-
- /*
- * And add it to the rel's restriction list.
- */
- or_rinfo = make_restrictinfo(indxqual_or_expr, true, true);
- rel->baserestrictinfo = lappend(rel->baserestrictinfo, or_rinfo);
+ newrinfos = make_restrictinfo_from_indexclauses(bestpath->indexclauses,
+ true, true);
+ Assert(length(newrinfos) == 1);
+ or_rinfo = (RestrictInfo *) lfirst(newrinfos);
+ rel->baserestrictinfo = nconc(rel->baserestrictinfo, newrinfos);
/*
* Adjust the original OR clause's cached selectivity to compensate
@@ -251,6 +244,7 @@ best_or_subclause_indexes(Query *root,
List *subclauses)
{
FastList infos;
+ FastList clauses;
FastList quals;
Cost path_startup_cost;
Cost path_total_cost;
@@ -258,6 +252,7 @@ best_or_subclause_indexes(Query *root,
IndexPath *pathnode;
FastListInit(&infos);
+ FastListInit(&clauses);
FastListInit(&quals);
path_startup_cost = 0;
path_total_cost = 0;
@@ -267,17 +262,20 @@ best_or_subclause_indexes(Query *root,
{
Expr *subclause = lfirst(slist);
IndexOptInfo *best_indexinfo;
- List *best_indexqual;
+ List *best_indexclauses;
+ List *best_indexquals;
Cost best_startup_cost;
Cost best_total_cost;
if (!best_or_subclause_index(root, rel, subclause,
- &best_indexinfo, &best_indexqual,
+ &best_indexinfo,
+ &best_indexclauses, &best_indexquals,
&best_startup_cost, &best_total_cost))
return NULL; /* failed to match this subclause */
FastAppend(&infos, best_indexinfo);
- FastAppend(&quals, best_indexqual);
+ FastAppend(&clauses, best_indexclauses);
+ FastAppend(&quals, best_indexquals);
/*
* Path startup_cost is the startup cost for the first index scan only;
* startup costs for later scans will be paid later on, so they just
@@ -306,10 +304,11 @@ best_or_subclause_indexes(Query *root,
pathnode->path.pathkeys = NIL;
pathnode->indexinfo = FastListValue(&infos);
- pathnode->indexqual = FastListValue(&quals);
+ pathnode->indexclauses = FastListValue(&clauses);
+ pathnode->indexquals = FastListValue(&quals);
/* It's not an innerjoin path. */
- pathnode->indexjoinclauses = NIL;
+ pathnode->isjoininner = false;
/* We don't actually care what order the index scans in. */
pathnode->indexscandir = NoMovementScanDirection;
@@ -336,7 +335,8 @@ best_or_subclause_indexes(Query *root,
* 'subclause' is the OR subclause being considered
*
* '*retIndexInfo' gets the IndexOptInfo of the best index
- * '*retIndexQual' gets a list of the indexqual conditions for the best index
+ * '*retIndexClauses' gets a list of the index clauses for the best index
+ * '*retIndexQuals' gets a list of the expanded indexquals for the best index
* '*retStartupCost' gets the startup cost of a scan with that index
* '*retTotalCost' gets the total cost of a scan with that index
*/
@@ -345,7 +345,8 @@ best_or_subclause_index(Query *root,
RelOptInfo *rel,
Expr *subclause,
IndexOptInfo **retIndexInfo, /* return value */
- List **retIndexQual, /* return value */
+ List **retIndexClauses, /* return value */
+ List **retIndexQuals, /* return value */
Cost *retStartupCost, /* return value */
Cost *retTotalCost) /* return value */
{
@@ -355,7 +356,7 @@ best_or_subclause_index(Query *root,
foreach(ilist, rel->indexlist)
{
IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
- List *qualrinfos;
+ List *indexclauses;
List *indexquals;
Path subclause_path;
@@ -364,21 +365,22 @@ best_or_subclause_index(Query *root,
continue;
/* Collect index clauses usable with this index */
- qualrinfos = group_clauses_by_indexkey_for_or(rel, index, subclause);
+ indexclauses = group_clauses_by_indexkey_for_or(rel, index, subclause);
/* Ignore index if it doesn't match the subclause at all */
- if (qualrinfos == NIL)
+ if (indexclauses == NIL)
continue;
- /* Convert RestrictInfo nodes to indexquals the executor can handle */
- indexquals = expand_indexqual_conditions(index, qualrinfos);
+ /* Convert clauses to indexquals the executor can handle */
+ indexquals = expand_indexqual_conditions(index, indexclauses);
cost_index(&subclause_path, root, rel, index, indexquals, false);
if (!found || subclause_path.total_cost < *retTotalCost)
{
*retIndexInfo = index;
- *retIndexQual = indexquals;
+ *retIndexClauses = flatten_clausegroups_list(indexclauses);
+ *retIndexQuals = indexquals;
*retStartupCost = subclause_path.startup_cost;
*retTotalCost = subclause_path.total_cost;
found = true;