]> granicus.if.org Git - postgresql/commitdiff
Refactor index cost estimation functions in view of IndexClause changes.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 15 Feb 2019 18:05:19 +0000 (13:05 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 15 Feb 2019 18:05:19 +0000 (13:05 -0500)
Get rid of deconstruct_indexquals() in favor of just iterating over the
IndexClause list directly.  The extra services that that function used to
provide, such as hiding clause commutation and associating the right index
column with each clause, are no longer useful given the new data structure.
I'd originally thought that it'd provide a useful amount of abstraction
by freeing callers from paying attention to the exact clause type of each
indexqual, but that hope proves to have been vain, because few callers can
ignore the semantic differences between different clause types.  Indeed,
removing it results in a net code savings, and probably some cycles shaved
by not having to build an extra list-of-structs data structure.

Also, export a few formerly-static support functions, with the goal
of allowing extension AMs to write functionality equivalent to
genericcostestimate() without pointless code duplication.

Discussion: https://postgr.es/m/24586.1550106354@sss.pgh.pa.us

contrib/bloom/blcost.c
src/backend/utils/adt/selfuncs.c
src/include/utils/selfuncs.h

index 2d8a7f1d2638520d229fd48f8956eb3fcc5bb437..f9fe57fb84538df5ee9c6be9425b7b075f45e76b 100644 (file)
@@ -27,19 +27,15 @@ blcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                           double *indexPages)
 {
        IndexOptInfo *index = path->indexinfo;
-       List       *qinfos;
        GenericCosts costs;
 
-       /* Do preliminary analysis of indexquals */
-       qinfos = deconstruct_indexquals(path);
-
        MemSet(&costs, 0, sizeof(costs));
 
        /* We have to visit all index tuples anyway */
        costs.numIndexTuples = index->tuples;
 
        /* Use generic estimate */
-       genericcostestimate(root, path, loop_count, qinfos, &costs);
+       genericcostestimate(root, path, loop_count, &costs);
 
        *indexStartupCost = costs.indexStartupCost;
        *indexTotalCost = costs.indexTotalCost;
index 0ceb72eaea689102be0314d294427300cb1625bc..2e3fab6a9588045563cbf2dbebb3db874557fb9f 100644 (file)
@@ -197,7 +197,6 @@ static bool get_actual_variable_range(PlannerInfo *root,
                                                  Oid sortop,
                                                  Datum *min, Datum *max);
 static RelOptInfo *find_join_input_rel(PlannerInfo *root, Relids relids);
-static List *add_predicate_to_quals(IndexOptInfo *index, List *indexQuals);
 
 
 /*
@@ -5251,9 +5250,11 @@ find_join_input_rel(PlannerInfo *root, Relids relids)
  *-------------------------------------------------------------------------
  */
 
-/* Extract the actual indexquals (as RestrictInfos) from an IndexClause list */
-static List *
-get_index_quals(List *indexclauses)
+/*
+ * Extract the actual indexquals (as RestrictInfos) from an IndexClause list
+ */
+List *
+get_quals_from_indexclauses(List *indexclauses)
 {
        List       *result = NIL;
        ListCell   *lc;
@@ -5273,113 +5274,59 @@ get_index_quals(List *indexclauses)
        return result;
 }
 
-List *
-deconstruct_indexquals(IndexPath *path)
-{
-       List       *result = NIL;
-       ListCell   *lc;
-
-       foreach(lc, path->indexclauses)
-       {
-               IndexClause *iclause = lfirst_node(IndexClause, lc);
-               int                     indexcol = iclause->indexcol;
-               ListCell   *lc2;
-
-               foreach(lc2, iclause->indexquals)
-               {
-                       RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc2);
-                       Expr       *clause = rinfo->clause;
-                       IndexQualInfo *qinfo;
-
-                       qinfo = (IndexQualInfo *) palloc(sizeof(IndexQualInfo));
-                       qinfo->rinfo = rinfo;
-                       qinfo->indexcol = indexcol;
-
-                       if (IsA(clause, OpExpr))
-                       {
-                               qinfo->clause_op = ((OpExpr *) clause)->opno;
-                               qinfo->other_operand = get_rightop(clause);
-                       }
-                       else if (IsA(clause, RowCompareExpr))
-                       {
-                               RowCompareExpr *rc = (RowCompareExpr *) clause;
-
-                               qinfo->clause_op = linitial_oid(rc->opnos);
-                               qinfo->other_operand = (Node *) rc->rargs;
-                       }
-                       else if (IsA(clause, ScalarArrayOpExpr))
-                       {
-                               ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
-
-                               qinfo->clause_op = saop->opno;
-                               qinfo->other_operand = (Node *) lsecond(saop->args);
-                       }
-                       else if (IsA(clause, NullTest))
-                       {
-                               qinfo->clause_op = InvalidOid;
-                               qinfo->other_operand = NULL;
-                       }
-                       else
-                       {
-                               elog(ERROR, "unsupported indexqual type: %d",
-                                        (int) nodeTag(clause));
-                       }
-
-                       result = lappend(result, qinfo);
-               }
-       }
-       return result;
-}
-
 /*
- * Simple function to compute the total eval cost of the "other operands"
- * in an IndexQualInfo list.  Since we know these will be evaluated just
+ * Compute the total evaluation cost of the comparison operands in a list
+ * of index qual expressions.  Since we know these will be evaluated just
  * once per scan, there's no need to distinguish startup from per-row cost.
- */
-static Cost
-other_operands_eval_cost(PlannerInfo *root, List *qinfos)
-{
-       Cost            qual_arg_cost = 0;
-       ListCell   *lc;
-
-       foreach(lc, qinfos)
-       {
-               IndexQualInfo *qinfo = (IndexQualInfo *) lfirst(lc);
-               QualCost        index_qual_cost;
-
-               cost_qual_eval_node(&index_qual_cost, qinfo->other_operand, root);
-               qual_arg_cost += index_qual_cost.startup + index_qual_cost.per_tuple;
-       }
-       return qual_arg_cost;
-}
-
-/*
- * Get other-operand eval cost for an index orderby list.
  *
- * Index orderby expressions aren't represented as RestrictInfos (since they
- * aren't boolean, usually).  So we can't apply deconstruct_indexquals to
- * them.  However, they are much simpler to deal with since they are always
- * OpExprs and the index column is always on the left.
+ * This can be used either on the result of get_quals_from_indexclauses(),
+ * or directly on an indexorderbys list.  In both cases, we expect that the
+ * index key expression is on the left side of binary clauses.
  */
-static Cost
-orderby_operands_eval_cost(PlannerInfo *root, IndexPath *path)
+Cost
+index_other_operands_eval_cost(PlannerInfo *root, List *indexquals)
 {
        Cost            qual_arg_cost = 0;
        ListCell   *lc;
 
-       foreach(lc, path->indexorderbys)
+       foreach(lc, indexquals)
        {
                Expr       *clause = (Expr *) lfirst(lc);
                Node       *other_operand;
                QualCost        index_qual_cost;
 
+               /*
+                * Index quals will have RestrictInfos, indexorderbys won't.  Look
+                * through RestrictInfo if present.
+                */
+               if (IsA(clause, RestrictInfo))
+                       clause = ((RestrictInfo *) clause)->clause;
+
                if (IsA(clause, OpExpr))
                {
-                       other_operand = get_rightop(clause);
+                       OpExpr     *op = (OpExpr *) clause;
+
+                       other_operand = (Node *) lsecond(op->args);
+               }
+               else if (IsA(clause, RowCompareExpr))
+               {
+                       RowCompareExpr *rc = (RowCompareExpr *) clause;
+
+                       other_operand = (Node *) rc->rargs;
+               }
+               else if (IsA(clause, ScalarArrayOpExpr))
+               {
+                       ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
+
+                       other_operand = (Node *) lsecond(saop->args);
+               }
+               else if (IsA(clause, NullTest))
+               {
+                       other_operand = NULL;
                }
                else
                {
-                       elog(ERROR, "unsupported indexorderby type: %d",
+                       elog(ERROR, "unsupported indexqual type: %d",
                                 (int) nodeTag(clause));
                        other_operand = NULL;   /* keep compiler quiet */
                }
@@ -5394,11 +5341,10 @@ void
 genericcostestimate(PlannerInfo *root,
                                        IndexPath *path,
                                        double loop_count,
-                                       List *qinfos,
                                        GenericCosts *costs)
 {
        IndexOptInfo *index = path->indexinfo;
-       List       *indexQuals = get_index_quals(path->indexclauses);
+       List       *indexQuals = get_quals_from_indexclauses(path->indexclauses);
        List       *indexOrderBys = path->indexorderbys;
        Cost            indexStartupCost;
        Cost            indexTotalCost;
@@ -5420,7 +5366,7 @@ genericcostestimate(PlannerInfo *root,
         * given indexquals to produce a more accurate idea of the index
         * selectivity.
         */
-       selectivityQuals = add_predicate_to_quals(index, indexQuals);
+       selectivityQuals = add_predicate_to_index_quals(index, indexQuals);
 
        /*
         * Check for ScalarArrayOpExpr index quals, and estimate the number of
@@ -5563,8 +5509,8 @@ genericcostestimate(PlannerInfo *root,
         * Detecting that that might be needed seems more expensive than it's
         * worth, though, considering all the other inaccuracies here ...
         */
-       qual_arg_cost = other_operands_eval_cost(root, qinfos) +
-               orderby_operands_eval_cost(root, path);
+       qual_arg_cost = index_other_operands_eval_cost(root, indexQuals) +
+               index_other_operands_eval_cost(root, indexOrderBys);
        qual_op_cost = cpu_operator_cost *
                (list_length(indexQuals) + list_length(indexOrderBys));
 
@@ -5609,8 +5555,8 @@ genericcostestimate(PlannerInfo *root,
  * predicate_implied_by() and clauselist_selectivity(), but might be
  * problematic if the result were passed to other things.
  */
-static List *
-add_predicate_to_quals(IndexOptInfo *index, List *indexQuals)
+List *
+add_predicate_to_index_quals(IndexOptInfo *index, List *indexQuals)
 {
        List       *predExtraQuals = NIL;
        ListCell   *lc;
@@ -5638,7 +5584,6 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                           double *indexPages)
 {
        IndexOptInfo *index = path->indexinfo;
-       List       *qinfos;
        GenericCosts costs;
        Oid                     relid;
        AttrNumber      colnum;
@@ -5653,9 +5598,6 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
        double          num_sa_scans;
        ListCell   *lc;
 
-       /* Do preliminary analysis of indexquals */
-       qinfos = deconstruct_indexquals(path);
-
        /*
         * For a btree scan, only leading '=' quals plus inequality quals for the
         * immediately next attribute contribute to index selectivity (these are
@@ -5679,58 +5621,81 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
        found_saop = false;
        found_is_null_op = false;
        num_sa_scans = 1;
-       foreach(lc, qinfos)
+       foreach(lc, path->indexclauses)
        {
-               IndexQualInfo *qinfo = (IndexQualInfo *) lfirst(lc);
-               RestrictInfo *rinfo = qinfo->rinfo;
-               Expr       *clause = rinfo->clause;
-               Oid                     clause_op;
-               int                     op_strategy;
+               IndexClause *iclause = lfirst_node(IndexClause, lc);
+               ListCell   *lc2;
 
-               if (indexcol != qinfo->indexcol)
+               if (indexcol != iclause->indexcol)
                {
                        /* Beginning of a new column's quals */
                        if (!eqQualHere)
                                break;                  /* done if no '=' qual for indexcol */
                        eqQualHere = false;
                        indexcol++;
-                       if (indexcol != qinfo->indexcol)
+                       if (indexcol != iclause->indexcol)
                                break;                  /* no quals at all for indexcol */
                }
 
-               if (IsA(clause, ScalarArrayOpExpr))
+               /* Examine each indexqual associated with this index clause */
+               foreach(lc2, iclause->indexquals)
                {
-                       int                     alength = estimate_array_length(qinfo->other_operand);
+                       RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc2);
+                       Expr       *clause = rinfo->clause;
+                       Oid                     clause_op = InvalidOid;
+                       int                     op_strategy;
 
-                       found_saop = true;
-                       /* count up number of SA scans induced by indexBoundQuals only */
-                       if (alength > 1)
-                               num_sa_scans *= alength;
-               }
-               else if (IsA(clause, NullTest))
-               {
-                       NullTest   *nt = (NullTest *) clause;
+                       if (IsA(clause, OpExpr))
+                       {
+                               OpExpr     *op = (OpExpr *) clause;
+
+                               clause_op = op->opno;
+                       }
+                       else if (IsA(clause, RowCompareExpr))
+                       {
+                               RowCompareExpr *rc = (RowCompareExpr *) clause;
 
-                       if (nt->nulltesttype == IS_NULL)
+                               clause_op = linitial_oid(rc->opnos);
+                       }
+                       else if (IsA(clause, ScalarArrayOpExpr))
                        {
-                               found_is_null_op = true;
-                               /* IS NULL is like = for selectivity determination purposes */
-                               eqQualHere = true;
+                               ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
+                               Node       *other_operand = (Node *) lsecond(saop->args);
+                               int                     alength = estimate_array_length(other_operand);
+
+                               clause_op = saop->opno;
+                               found_saop = true;
+                               /* count number of SA scans induced by indexBoundQuals only */
+                               if (alength > 1)
+                                       num_sa_scans *= alength;
                        }
-               }
+                       else if (IsA(clause, NullTest))
+                       {
+                               NullTest   *nt = (NullTest *) clause;
 
-               /* check for equality operator */
-               clause_op = qinfo->clause_op;
-               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;
-               }
+                               if (nt->nulltesttype == IS_NULL)
+                               {
+                                       found_is_null_op = true;
+                                       /* IS NULL is like = for selectivity purposes */
+                                       eqQualHere = true;
+                               }
+                       }
+                       else
+                               elog(ERROR, "unsupported indexqual type: %d",
+                                        (int) nodeTag(clause));
 
-               indexBoundQuals = lappend(indexBoundQuals, rinfo);
+                       /* 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;
+                       }
+
+                       indexBoundQuals = lappend(indexBoundQuals, rinfo);
+               }
        }
 
        /*
@@ -5755,7 +5720,7 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                 * index-bound quals to produce a more accurate idea of the number of
                 * rows covered by the bound conditions.
                 */
-               selectivityQuals = add_predicate_to_quals(index, indexBoundQuals);
+               selectivityQuals = add_predicate_to_index_quals(index, indexBoundQuals);
 
                btreeSelectivity = clauselist_selectivity(root, selectivityQuals,
                                                                                                  index->rel->relid,
@@ -5777,7 +5742,7 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
        MemSet(&costs, 0, sizeof(costs));
        costs.numIndexTuples = numIndexTuples;
 
-       genericcostestimate(root, path, loop_count, qinfos, &costs);
+       genericcostestimate(root, path, loop_count, &costs);
 
        /*
         * Add a CPU-cost component to represent the costs of initial btree
@@ -5924,15 +5889,11 @@ hashcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                                 Selectivity *indexSelectivity, double *indexCorrelation,
                                 double *indexPages)
 {
-       List       *qinfos;
        GenericCosts costs;
 
-       /* Do preliminary analysis of indexquals */
-       qinfos = deconstruct_indexquals(path);
-
        MemSet(&costs, 0, sizeof(costs));
 
-       genericcostestimate(root, path, loop_count, qinfos, &costs);
+       genericcostestimate(root, path, loop_count, &costs);
 
        /*
         * A hash index has no descent costs as such, since the index AM can go
@@ -5973,16 +5934,12 @@ gistcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                                 double *indexPages)
 {
        IndexOptInfo *index = path->indexinfo;
-       List       *qinfos;
        GenericCosts costs;
        Cost            descentCost;
 
-       /* Do preliminary analysis of indexquals */
-       qinfos = deconstruct_indexquals(path);
-
        MemSet(&costs, 0, sizeof(costs));
 
-       genericcostestimate(root, path, loop_count, qinfos, &costs);
+       genericcostestimate(root, path, loop_count, &costs);
 
        /*
         * We model index descent costs similarly to those for btree, but to do
@@ -6034,16 +5991,12 @@ spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                                double *indexPages)
 {
        IndexOptInfo *index = path->indexinfo;
-       List       *qinfos;
        GenericCosts costs;
        Cost            descentCost;
 
-       /* Do preliminary analysis of indexquals */
-       qinfos = deconstruct_indexquals(path);
-
        MemSet(&costs, 0, sizeof(costs));
 
-       genericcostestimate(root, path, loop_count, qinfos, &costs);
+       genericcostestimate(root, path, loop_count, &costs);
 
        /*
         * We model index descent costs similarly to those for btree, but to do
@@ -6214,12 +6167,12 @@ gincost_pattern(IndexOptInfo *index, int indexcol,
 static bool
 gincost_opexpr(PlannerInfo *root,
                           IndexOptInfo *index,
-                          IndexQualInfo *qinfo,
+                          int indexcol,
+                          OpExpr *clause,
                           GinQualCounts *counts)
 {
-       int                     indexcol = qinfo->indexcol;
-       Oid                     clause_op = qinfo->clause_op;
-       Node       *operand = qinfo->other_operand;
+       Oid                     clause_op = clause->opno;
+       Node       *operand = (Node *) lsecond(clause->args);
 
        /* aggressively reduce to a constant, and look through relabeling */
        operand = estimate_expression_value(root, operand);
@@ -6264,13 +6217,13 @@ gincost_opexpr(PlannerInfo *root,
 static bool
 gincost_scalararrayopexpr(PlannerInfo *root,
                                                  IndexOptInfo *index,
-                                                 IndexQualInfo *qinfo,
+                                                 int indexcol,
+                                                 ScalarArrayOpExpr *clause,
                                                  double numIndexEntries,
                                                  GinQualCounts *counts)
 {
-       int                     indexcol = qinfo->indexcol;
-       Oid                     clause_op = qinfo->clause_op;
-       Node       *rightop = qinfo->other_operand;
+       Oid                     clause_op = clause->opno;
+       Node       *rightop = (Node *) lsecond(clause->args);
        ArrayType  *arrayval;
        int16           elmlen;
        bool            elmbyval;
@@ -6282,7 +6235,7 @@ gincost_scalararrayopexpr(PlannerInfo *root,
        int                     numPossible = 0;
        int                     i;
 
-       Assert(((ScalarArrayOpExpr *) qinfo->rinfo->clause)->useOr);
+       Assert(clause->useOr);
 
        /* aggressively reduce to a constant, and look through relabeling */
        rightop = estimate_expression_value(root, rightop);
@@ -6383,10 +6336,7 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                                double *indexPages)
 {
        IndexOptInfo *index = path->indexinfo;
-       List       *indexQuals = get_index_quals(path->indexclauses);
-       List       *indexOrderBys = path->indexorderbys;
-       List       *qinfos;
-       ListCell   *l;
+       List       *indexQuals = get_quals_from_indexclauses(path->indexclauses);
        List       *selectivityQuals;
        double          numPages = index->pages,
                                numTuples = index->tuples;
@@ -6406,9 +6356,7 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                                outer_scans;
        Relation        indexRel;
        GinStatsData ginStats;
-
-       /* Do preliminary analysis of indexquals */
-       qinfos = deconstruct_indexquals(path);
+       ListCell   *lc;
 
        /*
         * Obtain statistical information from the meta page, if possible.  Else
@@ -6490,7 +6438,7 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
         * quals to produce a more accurate idea of the number of rows covered by
         * the bound conditions.
         */
-       selectivityQuals = add_predicate_to_quals(index, indexQuals);
+       selectivityQuals = add_predicate_to_index_quals(index, indexQuals);
 
        /* Estimate the fraction of main-table tuples that will be visited */
        *indexSelectivity = clauselist_selectivity(root, selectivityQuals,
@@ -6515,35 +6463,43 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
        counts.arrayScans = 1;
        matchPossible = true;
 
-       foreach(l, qinfos)
+       foreach(lc, path->indexclauses)
        {
-               IndexQualInfo *qinfo = (IndexQualInfo *) lfirst(l);
-               Expr       *clause = qinfo->rinfo->clause;
+               IndexClause *iclause = lfirst_node(IndexClause, lc);
+               ListCell   *lc2;
 
-               if (IsA(clause, OpExpr))
-               {
-                       matchPossible = gincost_opexpr(root,
-                                                                                  index,
-                                                                                  qinfo,
-                                                                                  &counts);
-                       if (!matchPossible)
-                               break;
-               }
-               else if (IsA(clause, ScalarArrayOpExpr))
-               {
-                       matchPossible = gincost_scalararrayopexpr(root,
-                                                                                                         index,
-                                                                                                         qinfo,
-                                                                                                         numEntries,
-                                                                                                         &counts);
-                       if (!matchPossible)
-                               break;
-               }
-               else
+               foreach(lc2, iclause->indexquals)
                {
-                       /* shouldn't be anything else for a GIN index */
-                       elog(ERROR, "unsupported GIN indexqual type: %d",
-                                (int) nodeTag(clause));
+                       RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc2);
+                       Expr       *clause = rinfo->clause;
+
+                       if (IsA(clause, OpExpr))
+                       {
+                               matchPossible = gincost_opexpr(root,
+                                                                                          index,
+                                                                                          iclause->indexcol,
+                                                                                          (OpExpr *) clause,
+                                                                                          &counts);
+                               if (!matchPossible)
+                                       break;
+                       }
+                       else if (IsA(clause, ScalarArrayOpExpr))
+                       {
+                               matchPossible = gincost_scalararrayopexpr(root,
+                                                                                                                 index,
+                                                                                                                 iclause->indexcol,
+                                                                                                                 (ScalarArrayOpExpr *) clause,
+                                                                                                                 numEntries,
+                                                                                                                 &counts);
+                               if (!matchPossible)
+                                       break;
+                       }
+                       else
+                       {
+                               /* shouldn't be anything else for a GIN index */
+                               elog(ERROR, "unsupported GIN indexqual type: %d",
+                                        (int) nodeTag(clause));
+                       }
                }
        }
 
@@ -6670,12 +6626,11 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                dataPagesFetched * spc_random_page_cost;
 
        /*
-        * Add on index qual eval costs, much as in genericcostestimate
+        * Add on index qual eval costs, much as in genericcostestimate.  But we
+        * can disregard indexorderbys, since GIN doesn't support those.
         */
-       qual_arg_cost = other_operands_eval_cost(root, qinfos) +
-               orderby_operands_eval_cost(root, path);
-       qual_op_cost = cpu_operator_cost *
-               (list_length(indexQuals) + list_length(indexOrderBys));
+       qual_arg_cost = index_other_operands_eval_cost(root, indexQuals);
+       qual_op_cost = cpu_operator_cost * list_length(indexQuals);
 
        *indexStartupCost += qual_arg_cost;
        *indexTotalCost += qual_arg_cost;
@@ -6693,11 +6648,10 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                                 double *indexPages)
 {
        IndexOptInfo *index = path->indexinfo;
-       List       *indexQuals = get_index_quals(path->indexclauses);
+       List       *indexQuals = get_quals_from_indexclauses(path->indexclauses);
        double          numPages = index->pages;
        RelOptInfo *baserel = index->rel;
        RangeTblEntry *rte = planner_rt_fetch(baserel->relid, root);
-       List       *qinfos;
        Cost            spc_seq_page_cost;
        Cost            spc_random_page_cost;
        double          qual_arg_cost;
@@ -6735,11 +6689,10 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
         */
        *indexCorrelation = 0;
 
-       qinfos = deconstruct_indexquals(path);
-       foreach(l, qinfos)
+       foreach(l, path->indexclauses)
        {
-               IndexQualInfo *qinfo = (IndexQualInfo *) lfirst(l);
-               AttrNumber      attnum = index->indexkeys[qinfo->indexcol];
+               IndexClause *iclause = lfirst_node(IndexClause, l);
+               AttrNumber      attnum = index->indexkeys[iclause->indexcol];
 
                /* attempt to lookup stats in relation for this index column */
                if (attnum != 0)
@@ -6774,7 +6727,7 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                         */
 
                        /* get the attnum from the 0-based index. */
-                       attnum = qinfo->indexcol + 1;
+                       attnum = iclause->indexcol + 1;
 
                        if (get_index_stats_hook &&
                                (*get_index_stats_hook) (root, index->indexoid, attnum, &vardata))
@@ -6853,10 +6806,10 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
 
        /*
         * Compute the index qual costs, much as in genericcostestimate, to add to
-        * the index costs.
+        * the index costs.  We can disregard indexorderbys, since BRIN doesn't
+        * support those.
         */
-       qual_arg_cost = other_operands_eval_cost(root, qinfos) +
-               orderby_operands_eval_cost(root, path);
+       qual_arg_cost = index_other_operands_eval_cost(root, indexQuals);
 
        /*
         * Compute the startup cost as the cost to read the whole revmap
index 8829889f9f52d1578ea2b47ea7498c0be9f4306d..0ce2175f3e8f2d8a0c3aceb6c270b91fd81fcab6 100644 (file)
@@ -84,19 +84,6 @@ typedef struct VariableStatData
        } while(0)
 
 
-/*
- * deconstruct_indexquals is a simple function to examine the indexquals
- * attached to a proposed IndexPath.  It returns a list of IndexQualInfo
- * structs, one per qual expression.
- */
-typedef struct
-{
-       RestrictInfo *rinfo;            /* the indexqual itself */
-       int                     indexcol;               /* zero-based index column number */
-       Oid                     clause_op;              /* qual's operator OID, if relevant */
-       Node       *other_operand;      /* non-index operand of qual's operator */
-} IndexQualInfo;
-
 /*
  * genericcostestimate is a general-purpose estimator that can be used for
  * most index types.  In some cases we use genericcostestimate as the base
@@ -200,10 +187,13 @@ extern void estimate_hash_bucket_stats(PlannerInfo *root,
                                                   Selectivity *mcv_freq,
                                                   Selectivity *bucketsize_frac);
 
-extern List *deconstruct_indexquals(IndexPath *path);
+extern List *get_quals_from_indexclauses(List *indexclauses);
+extern Cost index_other_operands_eval_cost(PlannerInfo *root,
+                                                          List *indexquals);
+extern List *add_predicate_to_index_quals(IndexOptInfo *index,
+                                                        List *indexQuals);
 extern void genericcostestimate(PlannerInfo *root, IndexPath *path,
                                        double loop_count,
-                                       List *qinfos,
                                        GenericCosts *costs);
 
 /* Functions in array_selfuncs.c */