summaryrefslogtreecommitdiff
path: root/src/backend/utils/adt
diff options
context:
space:
mode:
authorTom Lane2011-12-25 00:03:21 +0000
committerTom Lane2011-12-25 00:03:21 +0000
commit472d3935a2793343e450ba7cda4adbc323a984c3 (patch)
tree30fc6e85cc76a7b48ff84243237ccdc1dd41a00b /src/backend/utils/adt
parente2c2c2e8b1df7dfdb01e7e6f6191a569ce3c3195 (diff)
Rethink representation of index clauses' mapping to index columns.HEADmaster
In commit e2c2c2e8b1df7dfdb01e7e6f6191a569ce3c3195 I made use of nested list structures to show which clauses went with which index columns, but on reflection that's a data structure that only an old-line Lisp hacker could love. Worse, it adds unnecessary complication to the many places that don't much care which clauses go with which index columns. Revert to the previous arrangement of flat lists of clauses, and instead add a parallel integer list of column numbers. The places that care about the pairing can chase both lists with forboth(), while the places that don't care just examine one list the same as before. The only real downside to this is that there are now two more lists that need to be passed to amcostestimate functions in case they care about column matching (which btcostestimate does, so not passing the info is not an option). Rather than deal with 11-argument amcostestimate functions, pass just the IndexPath and expect the functions to extract fields from it. That gets us down to 7 arguments which is better than 11, and it seems more future-proof against likely additions to the information we keep about an index path.
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r--src/backend/utils/adt/selfuncs.c309
1 files changed, 142 insertions, 167 deletions
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 3e6cabf7e7..cfc7dae55b 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -5970,9 +5970,7 @@ string_to_bytea_const(const char *str, size_t str_len)
static void
genericcostestimate(PlannerInfo *root,
- IndexOptInfo *index,
- List *indexQuals,
- List *indexOrderBys,
+ IndexPath *path,
RelOptInfo *outer_rel,
double numIndexTuples,
Cost *indexStartupCost,
@@ -5980,6 +5978,9 @@ genericcostestimate(PlannerInfo *root,
Selectivity *indexSelectivity,
double *indexCorrelation)
{
+ IndexOptInfo *index = path->indexinfo;
+ List *indexQuals = path->indexquals;
+ List *indexOrderBys = path->indexorderbys;
double numIndexPages;
double num_sa_scans;
double num_outer_scans;
@@ -5991,14 +5992,6 @@ genericcostestimate(PlannerInfo *root,
List *selectivityQuals;
ListCell *l;
- /*
- * For our purposes here, it doesn't matter which index columns the
- * individual quals and order-by expressions go with, so flatten the
- * lists for convenience.
- */
- indexQuals = flatten_clausegroups_list(indexQuals);
- indexOrderBys = flatten_indexorderbys_list(indexOrderBys);
-
/*----------
* If the index is partial, AND the index predicate with the explicitly
* given indexquals to produce a more accurate idea of the index
@@ -6030,7 +6023,7 @@ genericcostestimate(PlannerInfo *root,
if (!predicate_implied_by(oneQual, indexQuals))
predExtraQuals = list_concat(predExtraQuals, oneQual);
}
- /* list_concat avoids modifying the indexQuals list */
+ /* list_concat avoids modifying the passed-in indexQuals list */
selectivityQuals = list_concat(predExtraQuals, indexQuals);
}
else
@@ -6240,14 +6233,13 @@ Datum
btcostestimate(PG_FUNCTION_ARGS)
{
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(1);
- List *indexQuals = (List *) PG_GETARG_POINTER(2);
- List *indexOrderBys = (List *) PG_GETARG_POINTER(3);
- RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(4);
- Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(5);
- Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(6);
- Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(7);
- double *indexCorrelation = (double *) PG_GETARG_POINTER(8);
+ IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
+ RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(2);
+ Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
+ Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
+ Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
+ double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
+ IndexOptInfo *index = path->indexinfo;
Oid relid;
AttrNumber colnum;
VariableStatData vardata;
@@ -6258,7 +6250,8 @@ btcostestimate(PG_FUNCTION_ARGS)
bool found_saop;
bool found_is_null_op;
double num_sa_scans;
- ListCell *lc1;
+ ListCell *lcc,
+ *lci;
/*
* For a btree scan, only leading '=' quals plus inequality quals for the
@@ -6266,8 +6259,9 @@ btcostestimate(PG_FUNCTION_ARGS)
* the "boundary quals" that determine the starting and stopping points of
* the index scan). Additional quals can suppress visits to the heap, so
* it's OK to count them in indexSelectivity, but they should not count
- * for estimating numIndexTuples. So we must examine the given indexQuals
- * to find out which ones count as boundary quals.
+ * for estimating numIndexTuples. So we must examine the given indexquals
+ * to find out which ones count as boundary quals. We rely on the
+ * knowledge that they are given in index column order.
*
* For a RowCompareExpr, we consider only the first column, just as
* rowcomparesel() does.
@@ -6277,119 +6271,113 @@ btcostestimate(PG_FUNCTION_ARGS)
* considered to act the same as it normally does.
*/
indexBoundQuals = NIL;
+ indexcol = 0;
eqQualHere = false;
found_saop = false;
found_is_null_op = false;
num_sa_scans = 1;
-
- /* clausegroups must correspond to index columns */
- Assert(list_length(indexQuals) <= index->ncolumns);
-
- indexcol = 0;
- foreach(lc1, indexQuals)
+ forboth(lcc, path->indexquals, lci, path->indexqualcols)
{
- List *clausegroup = (List *) lfirst(lc1);
- ListCell *lc2;
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(lcc);
+ Expr *clause;
+ Node *leftop,
+ *rightop;
+ Oid clause_op;
+ int op_strategy;
+ bool is_null_op = false;
- eqQualHere = false;
+ if (indexcol != lfirst_int(lci))
+ {
+ /* Beginning of a new column's quals */
+ if (!eqQualHere)
+ break; /* done if no '=' qual for indexcol */
+ eqQualHere = false;
+ indexcol++;
+ if (indexcol != lfirst_int(lci))
+ break; /* no quals at all for indexcol */
+ }
+
+ Assert(IsA(rinfo, RestrictInfo));
+ clause = rinfo->clause;
- foreach(lc2, clausegroup)
+ if (IsA(clause, OpExpr))
{
- RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2);
- Expr *clause;
- Node *leftop,
- *rightop;
- Oid clause_op;
- int op_strategy;
- bool is_null_op = false;
-
- Assert(IsA(rinfo, RestrictInfo));
- clause = rinfo->clause;
- if (IsA(clause, OpExpr))
- {
- leftop = get_leftop(clause);
- rightop = get_rightop(clause);
- clause_op = ((OpExpr *) clause)->opno;
- }
- else if (IsA(clause, RowCompareExpr))
- {
- RowCompareExpr *rc = (RowCompareExpr *) clause;
+ leftop = get_leftop(clause);
+ rightop = get_rightop(clause);
+ clause_op = ((OpExpr *) clause)->opno;
+ }
+ else if (IsA(clause, RowCompareExpr))
+ {
+ RowCompareExpr *rc = (RowCompareExpr *) clause;
- leftop = (Node *) linitial(rc->largs);
- rightop = (Node *) linitial(rc->rargs);
- clause_op = linitial_oid(rc->opnos);
- }
- else if (IsA(clause, ScalarArrayOpExpr))
- {
- ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
+ leftop = (Node *) linitial(rc->largs);
+ rightop = (Node *) linitial(rc->rargs);
+ clause_op = linitial_oid(rc->opnos);
+ }
+ else if (IsA(clause, ScalarArrayOpExpr))
+ {
+ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
- leftop = (Node *) linitial(saop->args);
- rightop = (Node *) lsecond(saop->args);
- clause_op = saop->opno;
- found_saop = true;
- }
- else if (IsA(clause, NullTest))
- {
- NullTest *nt = (NullTest *) clause;
+ leftop = (Node *) linitial(saop->args);
+ rightop = (Node *) lsecond(saop->args);
+ clause_op = saop->opno;
+ found_saop = true;
+ }
+ else if (IsA(clause, NullTest))
+ {
+ NullTest *nt = (NullTest *) clause;
- leftop = (Node *) nt->arg;
- rightop = NULL;
- clause_op = InvalidOid;
- if (nt->nulltesttype == IS_NULL)
- {
- found_is_null_op = true;
- is_null_op = true;
- }
- }
- else
+ leftop = (Node *) nt->arg;
+ rightop = NULL;
+ clause_op = InvalidOid;
+ if (nt->nulltesttype == IS_NULL)
{
- elog(ERROR, "unsupported indexqual type: %d",
- (int) nodeTag(clause));
- continue; /* keep compiler quiet */
+ found_is_null_op = true;
+ is_null_op = true;
}
+ }
+ else
+ {
+ elog(ERROR, "unsupported indexqual type: %d",
+ (int) nodeTag(clause));
+ continue; /* keep compiler quiet */
+ }
- if (match_index_to_operand(leftop, indexcol, index))
- {
- /* clause_op is correct */
- }
- else
- {
- Assert(match_index_to_operand(rightop, indexcol, index));
- /* Must flip operator to get the opfamily member */
- clause_op = get_commutator(clause_op);
- }
+ if (match_index_to_operand(leftop, indexcol, index))
+ {
+ /* clause_op is correct */
+ }
+ else
+ {
+ Assert(match_index_to_operand(rightop, indexcol, index));
+ /* Must flip operator to get the opfamily member */
+ clause_op = get_commutator(clause_op);
+ }
- /* check for equality operator */
- if (OidIsValid(clause_op))
- {
- op_strategy = get_op_opfamily_strategy(clause_op,
+ /* check for equality operator */
+ if (OidIsValid(clause_op))
+ {
+ op_strategy = get_op_opfamily_strategy(clause_op,
index->opfamily[indexcol]);
- Assert(op_strategy != 0); /* not a member of opfamily?? */
- if (op_strategy == BTEqualStrategyNumber)
- eqQualHere = true;
- }
- else if (is_null_op)
- {
- /* IS NULL is like = for selectivity determination */
+ Assert(op_strategy != 0); /* not a member of opfamily?? */
+ if (op_strategy == BTEqualStrategyNumber)
eqQualHere = true;
- }
- /* count up number of SA scans induced by indexBoundQuals only */
- if (IsA(clause, ScalarArrayOpExpr))
- {
- ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
- int alength = estimate_array_length(lsecond(saop->args));
-
- if (alength > 1)
- num_sa_scans *= alength;
- }
- indexBoundQuals = lappend(indexBoundQuals, rinfo);
}
+ else if (is_null_op)
+ {
+ /* IS NULL is like = for purposes of selectivity determination */
+ eqQualHere = true;
+ }
+ /* count up number of SA scans induced by indexBoundQuals only */
+ if (IsA(clause, ScalarArrayOpExpr))
+ {
+ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
+ int alength = estimate_array_length(lsecond(saop->args));
- /* Done with this indexcol, continue to next only if it had = qual */
- if (!eqQualHere)
- break;
-
- indexcol++;
+ if (alength > 1)
+ num_sa_scans *= alength;
+ }
+ indexBoundQuals = lappend(indexBoundQuals, rinfo);
}
/*
@@ -6399,7 +6387,7 @@ btcostestimate(PG_FUNCTION_ARGS)
* NullTest invalidates that theory, even though it sets eqQualHere.
*/
if (index->unique &&
- indexcol == index->ncolumns &&
+ indexcol == index->ncolumns - 1 &&
eqQualHere &&
!found_saop &&
!found_is_null_op)
@@ -6422,8 +6410,8 @@ btcostestimate(PG_FUNCTION_ARGS)
numIndexTuples = rint(numIndexTuples / num_sa_scans);
}
- genericcostestimate(root, index, indexQuals, indexOrderBys,
- outer_rel, numIndexTuples,
+ genericcostestimate(root, path, outer_rel,
+ numIndexTuples,
indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation);
@@ -6538,16 +6526,14 @@ Datum
hashcostestimate(PG_FUNCTION_ARGS)
{
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(1);
- List *indexQuals = (List *) PG_GETARG_POINTER(2);
- List *indexOrderBys = (List *) PG_GETARG_POINTER(3);
- RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(4);
- Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(5);
- Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(6);
- Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(7);
- double *indexCorrelation = (double *) PG_GETARG_POINTER(8);
-
- genericcostestimate(root, index, indexQuals, indexOrderBys, outer_rel, 0.0,
+ IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
+ RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(2);
+ Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
+ Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
+ Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
+ double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
+
+ genericcostestimate(root, path, outer_rel, 0.0,
indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation);
@@ -6558,16 +6544,14 @@ Datum
gistcostestimate(PG_FUNCTION_ARGS)
{
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(1);
- List *indexQuals = (List *) PG_GETARG_POINTER(2);
- List *indexOrderBys = (List *) PG_GETARG_POINTER(3);
- RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(4);
- Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(5);
- Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(6);
- Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(7);
- double *indexCorrelation = (double *) PG_GETARG_POINTER(8);
-
- genericcostestimate(root, index, indexQuals, indexOrderBys, outer_rel, 0.0,
+ IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
+ RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(2);
+ Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
+ Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
+ Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
+ double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
+
+ genericcostestimate(root, path, outer_rel, 0.0,
indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation);
@@ -6578,16 +6562,14 @@ Datum
spgcostestimate(PG_FUNCTION_ARGS)
{
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(1);
- List *indexQuals = (List *) PG_GETARG_POINTER(2);
- List *indexOrderBys = (List *) PG_GETARG_POINTER(3);
- RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(4);
- Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(5);
- Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(6);
- Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(7);
- double *indexCorrelation = (double *) PG_GETARG_POINTER(8);
-
- genericcostestimate(root, index, indexQuals, indexOrderBys, outer_rel, 0.0,
+ IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
+ RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(2);
+ Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
+ Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
+ Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
+ double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
+
+ genericcostestimate(root, path, outer_rel, 0.0,
indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation);
@@ -6901,14 +6883,15 @@ Datum
gincostestimate(PG_FUNCTION_ARGS)
{
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
- IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(1);
- List *indexQuals = (List *) PG_GETARG_POINTER(2);
- List *indexOrderBys = (List *) PG_GETARG_POINTER(3);
- RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(4);
- Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(5);
- Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(6);
- Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(7);
- double *indexCorrelation = (double *) PG_GETARG_POINTER(8);
+ IndexPath *path = (IndexPath *) PG_GETARG_POINTER(1);
+ RelOptInfo *outer_rel = (RelOptInfo *) PG_GETARG_POINTER(2);
+ Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
+ Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
+ Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
+ double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
+ IndexOptInfo *index = path->indexinfo;
+ List *indexQuals = path->indexquals;
+ List *indexOrderBys = path->indexorderbys;
ListCell *l;
List *selectivityQuals;
double numPages = index->pages,
@@ -6931,14 +6914,6 @@ gincostestimate(PG_FUNCTION_ARGS)
GinStatsData ginStats;
/*
- * For our purposes here, it doesn't matter which index columns the
- * individual quals and order-by expressions go with, so flatten the
- * lists for convenience.
- */
- indexQuals = flatten_clausegroups_list(indexQuals);
- indexOrderBys = flatten_indexorderbys_list(indexOrderBys);
-
- /*
* Obtain statistic information from the meta page
*/
indexRel = index_open(index->indexoid, AccessShareLock);
@@ -6994,7 +6969,7 @@ gincostestimate(PG_FUNCTION_ARGS)
if (!predicate_implied_by(oneQual, indexQuals))
predExtraQuals = list_concat(predExtraQuals, oneQual);
}
- /* list_concat avoids modifying the indexQuals list */
+ /* list_concat avoids modifying the passed-in indexQuals list */
selectivityQuals = list_concat(predExtraQuals, indexQuals);
}
else