diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/nbtree/nbtutils.c | 2 | ||||
-rw-r--r-- | src/backend/nodes/outfuncs.c | 2 | ||||
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 50 | ||||
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 399 | ||||
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 303 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 2 | ||||
-rw-r--r-- | src/backend/optimizer/util/pathnode.c | 35 | ||||
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 309 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/catalog/pg_proc.h | 10 | ||||
-rw-r--r-- | src/include/nodes/relation.h | 46 | ||||
-rw-r--r-- | src/include/optimizer/cost.h | 5 | ||||
-rw-r--r-- | src/include/optimizer/pathnode.h | 4 | ||||
-rw-r--r-- | src/include/optimizer/paths.h | 7 | ||||
-rw-r--r-- | src/include/pg_config_manual.h | 2 |
15 files changed, 529 insertions, 649 deletions
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index bb4d07368ff..90e441c3a98 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -616,7 +616,7 @@ _bt_advance_array_keys(IndexScanDesc scan, ScanDirection dir) * * The output keys must be sorted by index attribute. Presently we expect * (but verify) that the input keys are already so sorted --- this is done - * by group_clauses_by_indexkey() in indxpath.c. Some reordering of the keys + * by match_clauses_to_index() in indxpath.c. Some reordering of the keys * within each attribute may be done as a byproduct of the processing here, * but no other code depends on that. * diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index cdc2cab55c6..60931dcb735 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -1512,7 +1512,9 @@ _outIndexPath(StringInfo str, const IndexPath *node) WRITE_NODE_FIELD(indexinfo); WRITE_NODE_FIELD(indexclauses); WRITE_NODE_FIELD(indexquals); + WRITE_NODE_FIELD(indexqualcols); WRITE_NODE_FIELD(indexorderbys); + WRITE_NODE_FIELD(indexorderbycols); WRITE_BOOL_FIELD(isjoininner); WRITE_ENUM_FIELD(indexscandir, ScanDirection); WRITE_FLOAT_FIELD(indextotalcost, "%.2f"); diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 7bc1e6e2ba1..efc49dad1ec 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -52,7 +52,9 @@ * results into. All the input data they need is passed as separate * parameters, even though much of it could be extracted from the Path. * An exception is made for the cost_XXXjoin() routines, which expect all - * the non-cost fields of the passed XXXPath to be filled in. + * the non-cost fields of the passed XXXPath to be filled in, and similarly + * cost_index() assumes the passed IndexPath is valid except for its output + * values. * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group @@ -208,38 +210,28 @@ cost_seqscan(Path *path, PlannerInfo *root, * cost_index * Determines and returns the cost of scanning a relation using an index. * - * 'index' is the index to be used - * 'indexQuals' is a list of lists of applicable qual clauses (implicit AND - * semantics, one sub-list per index column) - * 'indexOrderBys' is a list of lists of lists of ORDER BY expressions for - * amcanorderbyop indexes (lists per pathkey and index column) - * 'indexonly' is true if it's an index-only scan + * 'path' describes the indexscan under consideration, and is complete + * except for the fields to be set by this routine * 'outer_rel' is the outer relation when we are considering using the index - * scan as the inside of a nestloop join (hence, some of the indexQuals + * scan as the inside of a nestloop join (hence, some of the indexquals * are join clauses, and we should expect repeated scans of the index); * NULL for a plain index scan * - * cost_index() takes an IndexPath not just a Path, because it sets a few - * additional fields of the IndexPath besides startup_cost and total_cost. - * These fields are needed if the IndexPath is used in a BitmapIndexScan. + * In addition to startup_cost and total_cost, cost_index() sets the path's + * indextotalcost and indexselectivity fields. These values are needed if + * the IndexPath is used in a BitmapIndexScan. * - * indexQuals is a list of lists of RestrictInfo nodes, but indexOrderBys - * is a list of lists of lists of bare expressions. - * - * NOTE: 'indexQuals' must contain only clauses usable as index restrictions. - * 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: path->indexquals must contain only clauses usable as index + * restrictions. 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. */ void -cost_index(IndexPath *path, PlannerInfo *root, - IndexOptInfo *index, - List *indexQuals, - List *indexOrderBys, - bool indexonly, - RelOptInfo *outer_rel) +cost_index(IndexPath *path, PlannerInfo *root, RelOptInfo *outer_rel) { + IndexOptInfo *index = path->indexinfo; RelOptInfo *baserel = index->rel; + bool indexonly = (path->path.pathtype == T_IndexOnlyScan); Cost startup_cost = 0; Cost run_cost = 0; Cost indexStartupCost; @@ -271,11 +263,9 @@ cost_index(IndexPath *path, PlannerInfo *root, * the fraction of main-table tuples we will have to retrieve) and its * correlation to the main-table tuple order. */ - OidFunctionCall9(index->amcostestimate, + OidFunctionCall7(index->amcostestimate, PointerGetDatum(root), - PointerGetDatum(index), - PointerGetDatum(indexQuals), - PointerGetDatum(indexOrderBys), + PointerGetDatum(path), PointerGetDatum(outer_rel), PointerGetDatum(&indexStartupCost), PointerGetDatum(&indexTotalCost), @@ -431,7 +421,7 @@ cost_index(IndexPath *path, PlannerInfo *root, { QualCost index_qual_cost; - cost_qual_eval(&index_qual_cost, indexQuals, root); + cost_qual_eval(&index_qual_cost, path->indexquals, root); /* any startup cost still has to be paid ... */ cpu_per_tuple -= index_qual_cost.per_tuple; } @@ -589,7 +579,7 @@ get_indexpath_pages(Path *bitmapqual) * 'baserel' is the relation to be scanned * 'bitmapqual' is a tree of IndexPaths, BitmapAndPaths, and BitmapOrPaths * 'outer_rel' is the outer relation when we are considering using the bitmap - * scan as the inside of a nestloop join (hence, some of the indexQuals + * scan as the inside of a nestloop join (hence, some of the indexquals * are join clauses, and we should expect repeated scans of the table); * NULL for a plain bitmap scan * diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 26d7c1c2331..b851af06a17 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -90,11 +90,13 @@ static PathClauseUsage *classify_index_clause_usage(Path *path, static void find_indexpath_quals(Path *bitmapqual, List **quals, List **preds); static int find_list_position(Node *node, List **nodelist); static bool check_index_only(RelOptInfo *rel, IndexOptInfo *index); -static List *group_clauses_by_indexkey(IndexOptInfo *index, - List *clauses, List *outer_clauses, - Relids outer_relids, - SaOpControl saop_control, - bool *found_clause); +static void match_clauses_to_index(IndexOptInfo *index, + List *clauses, List *outer_clauses, + Relids outer_relids, + SaOpControl saop_control, + List **index_clauses_p, + List **clause_columns_p, + bool *found_clause); static bool match_clause_to_indexcol(IndexOptInfo *index, int indexcol, RestrictInfo *rinfo, @@ -108,7 +110,9 @@ static bool match_rowcompare_to_indexcol(IndexOptInfo *index, Oid idxcollation, RowCompareExpr *clause, Relids outer_relids); -static List *match_index_to_pathkeys(IndexOptInfo *index, List *pathkeys); +static void match_pathkeys_to_index(IndexOptInfo *index, List *pathkeys, + List **orderby_clauses_p, + List **clause_columns_p); static Expr *match_clause_to_ordering_op(IndexOptInfo *index, int indexcol, Expr *clause, Oid pk_opfamily); static Relids indexable_outerrelids(PlannerInfo *root, RelOptInfo *rel); @@ -312,7 +316,9 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist); IndexPath *ipath; List *restrictclauses; + List *restrictclausecols; List *orderbyclauses; + List *orderbyclausecols; List *index_pathkeys; List *useful_pathkeys; bool useful_predicate; @@ -396,12 +402,14 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel, * clauses was used (and, if saop_control is SAOP_REQUIRE, it has to * have been a ScalarArrayOpExpr clause). */ - restrictclauses = group_clauses_by_indexkey(index, - clauses, - outer_clauses, - outer_relids, - saop_control, - &found_clause); + match_clauses_to_index(index, + clauses, + outer_clauses, + outer_relids, + saop_control, + &restrictclauses, + &restrictclausecols, + &found_clause); /* * Not all index AMs support scans with no restriction clauses. We @@ -425,13 +433,15 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel, useful_pathkeys = truncate_useless_pathkeys(root, rel, index_pathkeys); orderbyclauses = NIL; + orderbyclausecols = NIL; } else if (index->amcanorderbyop && possibly_useful_pathkeys && istoplevel && outer_rel == NULL && scantype != ST_BITMAPSCAN) { /* see if we can generate ordering operators for query_pathkeys */ - orderbyclauses = match_index_to_pathkeys(index, - root->query_pathkeys); + match_pathkeys_to_index(index, root->query_pathkeys, + &orderbyclauses, + &orderbyclausecols); if (orderbyclauses) useful_pathkeys = root->query_pathkeys; else @@ -441,6 +451,7 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel, { useful_pathkeys = NIL; orderbyclauses = NIL; + orderbyclausecols = NIL; } /* @@ -460,7 +471,9 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel, { ipath = create_index_path(root, index, restrictclauses, + restrictclausecols, orderbyclauses, + orderbyclausecols, useful_pathkeys, index_is_ordered ? ForwardScanDirection : @@ -485,6 +498,8 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel, { ipath = create_index_path(root, index, restrictclauses, + restrictclausecols, + NIL, NIL, useful_pathkeys, BackwardScanDirection, @@ -1142,14 +1157,15 @@ check_index_only(RelOptInfo *rel, IndexOptInfo *index) /* - * group_clauses_by_indexkey + * match_clauses_to_index * Find restriction clauses that can be used with an index. * - * Returns a list of sublists of RestrictInfo nodes for clauses that can be - * used with this index. Each sublist contains clauses that can be used - * with one index key (in no particular order); the top list is ordered by - * index key. (This is depended on by expand_indexqual_conditions() and - * fix_indexqual_references().) + * Returns a list of RestrictInfo nodes for clauses that can be used with + * this index, along with an integer list of the index column numbers + * (zero based) that each clause would be used with. The clauses are + * ordered by index key, so that the column numbers form a nondecreasing + * sequence. (This order is depended on by btree and possibly other places.) + * NIL lists are returned if there are no matching clauses. * * We can use clauses from either the current clauses or outer_clauses lists, * but *found_clause is set TRUE only if we used at least one clause from @@ -1164,40 +1180,38 @@ check_index_only(RelOptInfo *rel, IndexOptInfo *index) * * If the index has amoptionalkey = false, we give up and return NIL when * there are no restriction clauses matching the first index key. Otherwise, - * we return NIL if there are no restriction clauses matching any index key. - * A non-NIL result will have one (possibly empty) sublist for each index key. - * - * Example: given an index on (A,B,C), we would return ((C1 C2) () (C3 C4)) - * if we find that clauses C1 and C2 use column A, clauses C3 and C4 use - * column C, and no clauses use column B. + * we return NIL only if there are no restriction clauses matching any index + * key. There could be unused index keys after the first one in any case. * * Note: in some circumstances we may find the same RestrictInfos coming - * from multiple places. Defend against redundant outputs by keeping a side - * list of already-used clauses (pointer equality should be a good enough - * check for this). That also keeps us from matching the same clause to + * from multiple places. Defend against redundant outputs by refusing to + * match an already-used clause (pointer equality should be a good enough + * check for this). This also keeps us from matching the same clause to * multiple columns of a badly-defined index, which is unlikely to be helpful * and is likely to give us an inflated idea of the index's selectivity. */ -static List * -group_clauses_by_indexkey(IndexOptInfo *index, - List *clauses, List *outer_clauses, - Relids outer_relids, - SaOpControl saop_control, - bool *found_clause) +static void +match_clauses_to_index(IndexOptInfo *index, + List *clauses, List *outer_clauses, + Relids outer_relids, + SaOpControl saop_control, + List **index_clauses_p, + List **clause_columns_p, + bool *found_clause) { - List *clausegroup_list = NIL; - List *used_clauses = NIL; - bool found_outer_clause = false; + List *index_clauses = NIL; + List *clause_columns = NIL; int indexcol; - *found_clause = false; /* default result */ + *index_clauses_p = NIL; /* set default results */ + *clause_columns_p = NIL; + *found_clause = false; if (clauses == NIL && outer_clauses == NIL) - return NIL; /* cannot succeed */ + return; /* cannot succeed */ for (indexcol = 0; indexcol < index->ncolumns; indexcol++) { - List *clausegroup = NIL; ListCell *l; /* check the current clauses */ @@ -1206,7 +1220,7 @@ group_clauses_by_indexkey(IndexOptInfo *index, RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); Assert(IsA(rinfo, RestrictInfo)); - if (list_member_ptr(used_clauses, rinfo)) + if (list_member_ptr(index_clauses, rinfo)) continue; if (match_clause_to_indexcol(index, indexcol, @@ -1214,8 +1228,8 @@ group_clauses_by_indexkey(IndexOptInfo *index, outer_relids, saop_control)) { - clausegroup = lappend(clausegroup, rinfo); - used_clauses = lappend(used_clauses, rinfo); + index_clauses = lappend(index_clauses, rinfo); + clause_columns = lappend_int(clause_columns, indexcol); if (saop_control != SAOP_REQUIRE || IsA(rinfo->clause, ScalarArrayOpExpr)) *found_clause = true; @@ -1228,7 +1242,7 @@ group_clauses_by_indexkey(IndexOptInfo *index, RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); Assert(IsA(rinfo, RestrictInfo)); - if (list_member_ptr(used_clauses, rinfo)) + if (list_member_ptr(index_clauses, rinfo)) continue; if (match_clause_to_indexcol(index, indexcol, @@ -1236,27 +1250,20 @@ group_clauses_by_indexkey(IndexOptInfo *index, outer_relids, saop_control)) { - clausegroup = lappend(clausegroup, rinfo); - used_clauses = lappend(used_clauses, rinfo); - found_outer_clause = true; + index_clauses = lappend(index_clauses, rinfo); + clause_columns = lappend_int(clause_columns, indexcol); } } /* * If no clauses match this key, check for amoptionalkey restriction. */ - if (clausegroup == NIL && !index->amoptionalkey && indexcol == 0) - return NIL; - - clausegroup_list = lappend(clausegroup_list, clausegroup); + if (index_clauses == NIL && !index->amoptionalkey) + return; } - list_free(used_clauses); - - if (!*found_clause && !found_outer_clause) - return NIL; /* no indexable clauses anywhere */ - - return clausegroup_list; + *index_clauses_p = index_clauses; + *clause_columns_p = clause_columns; } @@ -1562,24 +1569,33 @@ match_rowcompare_to_indexcol(IndexOptInfo *index, ****************************************************************************/ /* - * match_index_to_pathkeys + * match_pathkeys_to_index * Test whether an index can produce output ordered according to the * given pathkeys using "ordering operators". * - * If it can, return a list of lists of lists of ORDER BY expressions, - * each of the form "indexedcol operator pseudoconstant". If not, return NIL. - * (The top list corresponds to pathkeys and the sub-lists to index columns; - * see comments for indexorderbys in nodes/relation.h.) + * If it can, return a list of suitable ORDER BY expressions, each of the form + * "indexedcol operator pseudoconstant", along with an integer list of the + * index column numbers (zero based) that each clause would be used with. + * NIL lists are returned if the ordering is not achievable this way. + * + * On success, the result list is ordered by pathkeys, and in fact is + * one-to-one with the requested pathkeys. */ -static List * -match_index_to_pathkeys(IndexOptInfo *index, List *pathkeys) +static void +match_pathkeys_to_index(IndexOptInfo *index, List *pathkeys, + List **orderby_clauses_p, + List **clause_columns_p) { - List *orderbylists = NIL; + List *orderby_clauses = NIL; + List *clause_columns = NIL; ListCell *lc1; + *orderby_clauses_p = NIL; /* set default results */ + *clause_columns_p = NIL; + /* Only indexes with the amcanorderbyop property are interesting here */ if (!index->amcanorderbyop) - return NIL; + return; foreach(lc1, pathkeys) { @@ -1595,11 +1611,11 @@ match_index_to_pathkeys(IndexOptInfo *index, List *pathkeys) /* Pathkey must request default sort order for the target opfamily */ if (pathkey->pk_strategy != BTLessStrategyNumber || pathkey->pk_nulls_first) - return NIL; + return; /* If eclass is volatile, no hope of using an indexscan */ if (pathkey->pk_eclass->ec_has_volatile) - return NIL; + return; /* Try to match eclass member expression(s) to index */ foreach(lc2, pathkey->pk_eclass->ec_members) @@ -1621,17 +1637,8 @@ match_index_to_pathkeys(IndexOptInfo *index, List *pathkeys) pathkey->pk_opfamily); if (expr) { - /* - * Generate list-of-sublists representation to show which - * index column this expression matches. - */ - List *sublist = NIL; - int i; - - for (i = 0; i < indexcol; i++) - sublist = lappend(sublist, NIL); - sublist = lappend(sublist, list_make1(expr)); - orderbylists = lappend(orderbylists, sublist); + orderby_clauses = lappend(orderby_clauses, expr); + clause_columns = lappend_int(clause_columns, indexcol); found = true; break; } @@ -1642,10 +1649,11 @@ match_index_to_pathkeys(IndexOptInfo *index, List *pathkeys) } if (!found) /* fail if no match for this pathkey */ - return NIL; + return; } - return orderbylists; /* success! */ + *orderby_clauses_p = orderby_clauses; /* success! */ + *clause_columns_p = clause_columns; } /* @@ -2451,65 +2459,6 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, /**************************************************************************** - * ---- PATH CREATION UTILITIES ---- - ****************************************************************************/ - -/* - * flatten_clausegroups_list - * Given a list of lists of RestrictInfos, flatten it to a list - * of RestrictInfos. - * - * This is used to flatten out a list of sublists of index clauses (such as - * the result of group_clauses_by_indexkey()) into a single list, for use - * where we don't care which clause goes with which index column. The input - * list structure mustn't be altered, but it's OK to share copies of the - * underlying RestrictInfos. - */ -List * -flatten_clausegroups_list(List *clausegroups) -{ - List *allclauses = NIL; - ListCell *l; - - foreach(l, clausegroups) - allclauses = list_concat(allclauses, list_copy((List *) lfirst(l))); - return allclauses; -} - -/* - * flatten_indexorderbys_list - * Given a list of lists of lists of ORDER BY expressions, flatten it. - * - * This is similar to flatten_clausegroups_list, but is used to flatten the - * three-list-level result of match_index_to_pathkeys(). We assume the - * bottom lists each have zero or one member. - */ -List * -flatten_indexorderbys_list(List *indexorderbys) -{ - List *allclauses = NIL; - ListCell *lc1; - - foreach(lc1, indexorderbys) - { - List *sublist = (List *) lfirst(lc1); - ListCell *lc2; - - foreach(lc2, sublist) - { - List *subsublist = (List *) lfirst(lc2); - - if (subsublist == NIL) - continue; - Assert(list_length(subsublist) == 1); - allclauses = lappend(allclauses, (Expr *) linitial(subsublist)); - } - } - return allclauses; -} - - -/**************************************************************************** * ---- ROUTINES TO CHECK OPERANDS ---- ****************************************************************************/ @@ -2635,13 +2584,12 @@ match_index_to_operand(Node *operand, * match_boolean_index_clause() similarly detects clauses that can be * converted into boolean equality operators. * - * expand_indexqual_conditions() converts a list of lists of RestrictInfo - * nodes (with implicit AND semantics across list elements) into a list of - * lists of clauses that the executor can actually handle. For operators - * that are members of the index's opfamily this transformation is a no-op, - * but clauses recognized by match_special_index_operator() or - * match_boolean_index_clause() must be converted into one or more "regular" - * indexqual conditions. + * expand_indexqual_conditions() converts a list of RestrictInfo nodes + * (with implicit AND semantics across list elements) into a list of clauses + * that the executor can actually handle. For operators that are members of + * the index's opfamily this transformation is a no-op, but clauses recognized + * by match_special_index_operator() or match_boolean_index_clause() must be + * converted into one or more "regular" indexqual conditions. *---------- */ @@ -2855,99 +2803,100 @@ match_special_index_operator(Expr *clause, Oid opfamily, Oid idxcollation, /* * expand_indexqual_conditions - * Given a list of sublists of RestrictInfo nodes, produce a list of lists - * of index qual clauses. Standard qual clauses (those in the index's - * opfamily) are passed through unchanged. Boolean clauses and "special" - * index operators are expanded into clauses that the indexscan machinery - * will know what to do with. RowCompare clauses are simplified if - * necessary to create a clause that is fully checkable by the index. - * - * The input clauses are grouped by index key, and so the output is too. + * Given a list of RestrictInfo nodes, produce a list of directly usable + * index qual clauses. + * + * Standard qual clauses (those in the index's opfamily) are passed through + * unchanged. Boolean clauses and "special" index operators are expanded + * into clauses that the indexscan machinery will know what to do with. + * RowCompare clauses are simplified if necessary to create a clause that is + * fully checkable by the index. + * + * In addition to the expressions themselves, there are auxiliary lists + * of the index column numbers that the clauses are meant to be used with; + * we generate an updated column number list for the result. (This is not + * the identical list because one input clause sometimes produces more than + * one output clause.) + * + * The input clauses are sorted by column number, and so the output is too. * (This is depended on in various places in both planner and executor.) */ -List * -expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) +void +expand_indexqual_conditions(IndexOptInfo *index, + List *indexclauses, List *indexclausecols, + List **indexquals_p, List **indexqualcols_p) { - List *resultgroups = NIL; - ListCell *lc; - int indexcol; - - if (clausegroups == NIL) - return NIL; - - /* clausegroups must correspond to index columns */ - Assert(list_length(clausegroups) <= index->ncolumns); + List *indexquals = NIL; + List *indexqualcols = NIL; + ListCell *lcc, + *lci; - indexcol = 0; - foreach(lc, clausegroups) + forboth(lcc, indexclauses, lci, indexclausecols) { - List *clausegroup = (List *) lfirst(lc); + RestrictInfo *rinfo = (RestrictInfo *) lfirst(lcc); + int indexcol = lfirst_int(lci); + Expr *clause = rinfo->clause; Oid curFamily = index->opfamily[indexcol]; Oid curCollation = index->indexcollations[indexcol]; - List *newgroup = NIL; - ListCell *lc2; - foreach(lc2, clausegroup) + /* First check for boolean cases */ + if (IsBooleanOpfamily(curFamily)) { - RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2); - Expr *clause = rinfo->clause; + Expr *boolqual; - /* First check for boolean cases */ - if (IsBooleanOpfamily(curFamily)) - { - Expr *boolqual; - - boolqual = expand_boolean_index_clause((Node *) clause, - indexcol, - index); - if (boolqual) - { - newgroup = lappend(newgroup, - make_simple_restrictinfo(boolqual)); - continue; - } - } - - /* - * Else it must be an opclause (usual case), ScalarArrayOp, - * RowCompare, or NullTest - */ - if (is_opclause(clause)) - { - newgroup = list_concat(newgroup, - expand_indexqual_opclause(rinfo, - curFamily, - curCollation)); - } - else if (IsA(clause, ScalarArrayOpExpr)) - { - /* no extra work at this time */ - newgroup = lappend(newgroup, rinfo); - } - else if (IsA(clause, RowCompareExpr)) - { - newgroup = lappend(newgroup, - expand_indexqual_rowcompare(rinfo, - index, - indexcol)); - } - else if (IsA(clause, NullTest)) + boolqual = expand_boolean_index_clause((Node *) clause, + indexcol, + index); + if (boolqual) { - Assert(index->amsearchnulls); - newgroup = lappend(newgroup, - make_simple_restrictinfo(clause)); + indexquals = lappend(indexquals, + make_simple_restrictinfo(boolqual)); + indexqualcols = lappend_int(indexqualcols, indexcol); + continue; } - else - elog(ERROR, "unsupported indexqual type: %d", - (int) nodeTag(clause)); } - resultgroups = lappend(resultgroups, newgroup); - - indexcol++; + /* + * Else it must be an opclause (usual case), ScalarArrayOp, + * RowCompare, or NullTest + */ + if (is_opclause(clause)) + { + indexquals = list_concat(indexquals, + expand_indexqual_opclause(rinfo, + curFamily, + curCollation)); + /* expand_indexqual_opclause can produce multiple clauses */ + while (list_length(indexqualcols) < list_length(indexquals)) + indexqualcols = lappend_int(indexqualcols, indexcol); + } + else if (IsA(clause, ScalarArrayOpExpr)) + { + /* no extra work at this time */ + indexquals = lappend(indexquals, rinfo); + indexqualcols = lappend_int(indexqualcols, indexcol); + } + else if (IsA(clause, RowCompareExpr)) + { + indexquals = lappend(indexquals, + expand_indexqual_rowcompare(rinfo, + index, + indexcol)); + indexqualcols = lappend_int(indexqualcols, indexcol); + } + else if (IsA(clause, NullTest)) + { + Assert(index->amsearchnulls); + indexquals = lappend(indexquals, rinfo); + indexqualcols = lappend_int(indexqualcols, indexcol); + } + else + elog(ERROR, "unsupported indexqual type: %d", + (int) nodeTag(clause)); } - return resultgroups; + *indexquals_p = indexquals; + *indexqualcols_p = indexqualcols; } /* diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 04024cc4939..cec76e38443 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -83,10 +83,8 @@ static HashJoin *create_hashjoin_plan(PlannerInfo *root, HashPath *best_path, Plan *outer_plan, Plan *inner_plan); static Node *replace_nestloop_params(PlannerInfo *root, Node *expr); static Node *replace_nestloop_params_mutator(Node *node, PlannerInfo *root); -static List *fix_indexqual_references(PlannerInfo *root, IndexPath *index_path, - List *indexquals); -static List *fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path, - List *indexorderbys); +static List *fix_indexqual_references(PlannerInfo *root, IndexPath *index_path); +static List *fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path); static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index, int indexcol); static List *get_switched_clauses(List *clauses, Relids outerrelids); static List *order_qual_clauses(PlannerInfo *root, List *clauses); @@ -1082,11 +1080,11 @@ create_indexscan_plan(PlannerInfo *root, bool indexonly) { Scan *scan_plan; + List *indexquals = best_path->indexquals; List *indexorderbys = best_path->indexorderbys; Index baserelid = best_path->path.parent->relid; Oid indexoid = best_path->indexinfo->indexoid; List *qpqual; - List *indexquals; List *stripped_indexquals; List *fixed_indexquals; List *fixed_indexorderbys; @@ -1097,13 +1095,6 @@ create_indexscan_plan(PlannerInfo *root, Assert(best_path->path.parent->rtekind == RTE_RELATION); /* - * We need to flatten the indexquals list-of-sublists, since most of the - * processing below doesn't care which index column each qual is - * associated with. - */ - indexquals = flatten_clausegroups_list(best_path->indexquals); - - /* * Build "stripped" indexquals structure (no RestrictInfos) to pass to * executor as indexqualorig */ @@ -1111,23 +1102,14 @@ create_indexscan_plan(PlannerInfo *root, /* * The executor needs a copy with the indexkey on the left of each clause - * and with index Vars substituted for table ones. Here we use the - * unflattened list so we can conveniently tell which index column each - * clause is for. + * and with index Vars substituted for table ones. */ - fixed_indexquals = fix_indexqual_references(root, best_path, - best_path->indexquals); + fixed_indexquals = fix_indexqual_references(root, best_path); /* * Likewise fix up index attr references in the ORDER BY expressions. */ - fixed_indexorderbys = fix_indexorderby_references(root, best_path, - indexorderbys); - - /* - * Also produce a flat list to become the indexorderbyorig. - */ - indexorderbys = flatten_indexorderbys_list(indexorderbys); + fixed_indexorderbys = fix_indexorderby_references(root, best_path); /* * If this is an innerjoin scan, the indexclauses will contain join @@ -1506,7 +1488,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, clamp_row_est(ipath->indexselectivity * ipath->path.parent->tuples); plan->plan_width = 0; /* meaningless */ *qual = get_actual_clauses(ipath->indexclauses); - *indexqual = get_actual_clauses(flatten_clausegroups_list(ipath->indexquals)); + *indexqual = get_actual_clauses(ipath->indexquals); foreach(l, ipath->indexinfo->indpred) { Expr *pred = (Expr *) lfirst(l); @@ -2484,8 +2466,7 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root) * Adjust indexqual clauses to the form the executor's indexqual * machinery needs. * - * We have five tasks here: - * * Flatten the list-of-sublists structure of indexquals into a simple list. + * We have four tasks here: * * Remove RestrictInfo nodes from the input clauses. * * Replace any outer-relation Var or PHV nodes with nestloop Params. * (XXX eventually, that responsibility should go elsewhere?) @@ -2494,140 +2475,128 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root) * * If the index key is on the right, commute the clause to put it on the * left. * - * The result is a modified copy of the indexquals list --- the + * The result is a modified copy of the path's 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). */ static List * -fix_indexqual_references(PlannerInfo *root, IndexPath *index_path, - List *indexquals) +fix_indexqual_references(PlannerInfo *root, IndexPath *index_path) { IndexOptInfo *index = index_path->indexinfo; List *fixed_indexquals; - ListCell *lc1; - int indexcol; + ListCell *lcc, + *lci; fixed_indexquals = NIL; - /* clausegroups must correspond to index columns */ - Assert(list_length(indexquals) <= index->ncolumns); - - indexcol = 0; - foreach(lc1, indexquals) + forboth(lcc, index_path->indexquals, lci, index_path->indexqualcols) { - List *clausegroup = (List *) lfirst(lc1); - ListCell *lc2; + RestrictInfo *rinfo = (RestrictInfo *) lfirst(lcc); + int indexcol = lfirst_int(lci); + Node *clause; + + Assert(IsA(rinfo, RestrictInfo)); + + /* + * Replace any outer-relation variables with nestloop params. + * + * This also makes a copy of the clause, so it's safe to modify it + * in-place below. + */ + clause = replace_nestloop_params(root, (Node *) rinfo->clause); - foreach(lc2, clausegroup) + if (IsA(clause, OpExpr)) { - RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc2); - Node *clause; + OpExpr *op = (OpExpr *) clause; - Assert(IsA(rinfo, RestrictInfo)); + if (list_length(op->args) != 2) + elog(ERROR, "indexqual clause is not binary opclause"); /* - * Replace any outer-relation variables with nestloop params. - * - * This also makes a copy of the clause, so it's safe to modify it - * in-place below. + * Check to see if the indexkey is on the right; if so, commute + * the clause. The indexkey should be the side that refers to + * (only) the base relation. */ - clause = replace_nestloop_params(root, (Node *) rinfo->clause); + if (!bms_equal(rinfo->left_relids, index->rel->relids)) + CommuteOpExpr(op); - if (IsA(clause, OpExpr)) - { - OpExpr *op = (OpExpr *) clause; + /* + * Now replace the indexkey expression with an index Var. + */ + linitial(op->args) = fix_indexqual_operand(linitial(op->args), + index, + indexcol); + } + else if (IsA(clause, RowCompareExpr)) + { + RowCompareExpr *rc = (RowCompareExpr *) clause; + Expr *newrc; + List *indexcolnos; + bool var_on_left; + ListCell *lca, + *lcai; - if (list_length(op->args) != 2) - elog(ERROR, "indexqual clause is not binary opclause"); + /* + * Re-discover which index columns are used in the rowcompare. + */ + newrc = adjust_rowcompare_for_index(rc, + index, + indexcol, + &indexcolnos, + &var_on_left); - /* - * Check to see if the indexkey is on the right; if so, - * commute the clause. The indexkey should be the side that - * refers to (only) the base relation. - */ - if (!bms_equal(rinfo->left_relids, index->rel->relids)) - CommuteOpExpr(op); + /* + * Trouble if adjust_rowcompare_for_index thought the + * RowCompareExpr didn't match the index as-is; the clause should + * have gone through that routine already. + */ + if (newrc != (Expr *) rc) + elog(ERROR, "inconsistent results from adjust_rowcompare_for_index"); - /* - * Now replace the indexkey expression with an index Var. - */ - linitial(op->args) = fix_indexqual_operand(linitial(op->args), - index, - indexcol); - } - else if (IsA(clause, RowCompareExpr)) - { - RowCompareExpr *rc = (RowCompareExpr *) clause; - Expr *newrc; - List *indexcolnos; - bool var_on_left; - ListCell *lca, - *lci; + /* + * Check to see if the indexkey is on the right; if so, commute + * the clause. + */ + if (!var_on_left) + CommuteRowCompareExpr(rc); - /* - * Re-discover which index columns are used in the rowcompare. - */ - newrc = adjust_rowcompare_for_index(rc, + /* + * Now replace the indexkey expressions with index Vars. + */ + Assert(list_length(rc->largs) == list_length(indexcolnos)); + forboth(lca, rc->largs, lcai, indexcolnos) + { + lfirst(lca) = fix_indexqual_operand(lfirst(lca), index, - indexcol, - &indexcolnos, - &var_on_left); - - /* - * Trouble if adjust_rowcompare_for_index thought the - * RowCompareExpr didn't match the index as-is; the clause - * should have gone through that routine already. - */ - if (newrc != (Expr *) rc) - elog(ERROR, "inconsistent results from adjust_rowcompare_for_index"); - - /* - * Check to see if the indexkey is on the right; if so, - * commute the clause. - */ - if (!var_on_left) - CommuteRowCompareExpr(rc); - - /* - * Now replace the indexkey expressions with index Vars. - */ - Assert(list_length(rc->largs) == list_length(indexcolnos)); - forboth(lca, rc->largs, lci, indexcolnos) - { - lfirst(lca) = fix_indexqual_operand(lfirst(lca), - index, - lfirst_int(lci)); - } + lfirst_int(lcai)); } - else if (IsA(clause, ScalarArrayOpExpr)) - { - ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; - - /* Never need to commute... */ + } + else if (IsA(clause, ScalarArrayOpExpr)) + { + ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; - /* Replace the indexkey expression with an index Var. */ - linitial(saop->args) = fix_indexqual_operand(linitial(saop->args), - index, - indexcol); - } - else if (IsA(clause, NullTest)) - { - NullTest *nt = (NullTest *) clause; + /* Never need to commute... */ - /* Replace the indexkey expression with an index Var. */ - nt->arg = (Expr *) fix_indexqual_operand((Node *) nt->arg, + /* Replace the indexkey expression with an index Var. */ + linitial(saop->args) = fix_indexqual_operand(linitial(saop->args), index, indexcol); - } - else - elog(ERROR, "unsupported indexqual type: %d", - (int) nodeTag(clause)); + } + else if (IsA(clause, NullTest)) + { + NullTest *nt = (NullTest *) clause; - fixed_indexquals = lappend(fixed_indexquals, clause); + /* Replace the indexkey expression with an index Var. */ + nt->arg = (Expr *) fix_indexqual_operand((Node *) nt->arg, + index, + indexcol); } + else + elog(ERROR, "unsupported indexqual type: %d", + (int) nodeTag(clause)); - indexcol++; + fixed_indexquals = lappend(fixed_indexquals, clause); } return fixed_indexquals; @@ -2645,67 +2614,47 @@ fix_indexqual_references(PlannerInfo *root, IndexPath *index_path, * is allowed for ordering operators. */ static List * -fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path, - List *indexorderbys) +fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path) { IndexOptInfo *index = index_path->indexinfo; List *fixed_indexorderbys; - ListCell *lc1; + ListCell *lcc, + *lci; fixed_indexorderbys = NIL; - foreach(lc1, indexorderbys) + forboth(lcc, index_path->indexorderbys, lci, index_path->indexorderbycols) { - List *percollists = (List *) lfirst(lc1); - ListCell *lc2; - int indexcol; + Node *clause = (Node *) lfirst(lcc); + int indexcol = lfirst_int(lci); - /* percollists must correspond to index columns */ - Assert(list_length(percollists) <= index->ncolumns); + /* + * Replace any outer-relation variables with nestloop params. + * + * This also makes a copy of the clause, so it's safe to modify it + * in-place below. + */ + clause = replace_nestloop_params(root, clause); - indexcol = 0; - foreach(lc2, percollists) + if (IsA(clause, OpExpr)) { - List *percollist = (List *) lfirst(lc2); - - if (percollist != NIL) - { - Node *clause = (Node *) linitial(percollist); - - /* Should have only one clause per index column */ - Assert(list_length(percollist) == 1); - - /* - * Replace any outer-relation variables with nestloop params. - * - * This also makes a copy of the clause, so it's safe to - * modify it in-place below. - */ - clause = replace_nestloop_params(root, clause); - - if (IsA(clause, OpExpr)) - { - OpExpr *op = (OpExpr *) clause; - - if (list_length(op->args) != 2) - elog(ERROR, "indexorderby clause is not binary opclause"); - - /* - * Now replace the indexkey expression with an index Var. - */ - linitial(op->args) = fix_indexqual_operand(linitial(op->args), - index, - indexcol); - } - else - elog(ERROR, "unsupported indexorderby type: %d", - (int) nodeTag(clause)); + OpExpr *op = (OpExpr *) clause; - fixed_indexorderbys = lappend(fixed_indexorderbys, clause); - } + if (list_length(op->args) != 2) + elog(ERROR, "indexorderby clause is not binary opclause"); - indexcol++; + /* + * Now replace the indexkey expression with an index Var. + */ + linitial(op->args) = fix_indexqual_operand(linitial(op->args), + index, + indexcol); } + else + elog(ERROR, "unsupported indexorderby type: %d", + (int) nodeTag(clause)); + + fixed_indexorderbys = lappend(fixed_indexorderbys, clause); } return fixed_indexorderbys; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 5c18b72344d..c5378eb60af 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -3296,7 +3296,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid) /* Estimate the cost of index scan */ indexScanPath = create_index_path(root, indexInfo, - NIL, NIL, NIL, + NIL, NIL, NIL, NIL, NIL, ForwardScanDirection, false, NULL); return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost); diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 9e99c9d9d7b..5b7be94de5e 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -410,10 +410,14 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel) * Creates a path node for an index scan. * * 'index' is a usable index. - * 'clause_groups' is a list of lists of RestrictInfo nodes + * 'indexclauses' is a list of RestrictInfo nodes representing clauses * to be used as index qual conditions in the scan. - * 'indexorderbys' is a list of lists of lists of bare expressions (not - * RestrictInfos) to be used as index ordering operators. + * 'indexclausecols' is an integer list of index column numbers (zero based) + * the indexclauses can be used with. + * 'indexorderbys' is a list of bare expressions (no RestrictInfos) + * to be used as index ordering operators in the scan. + * 'indexorderbycols' is an integer list of index column numbers (zero based) + * the ordering operators can be used with. * 'pathkeys' describes the ordering of the path. * 'indexscandir' is ForwardScanDirection or BackwardScanDirection * for an ordered index, or NoMovementScanDirection for @@ -427,8 +431,10 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel) IndexPath * create_index_path(PlannerInfo *root, IndexOptInfo *index, - List *clause_groups, + List *indexclauses, + List *indexclausecols, List *indexorderbys, + List *indexorderbycols, List *pathkeys, ScanDirection indexscandir, bool indexonly, @@ -437,7 +443,7 @@ create_index_path(PlannerInfo *root, IndexPath *pathnode = makeNode(IndexPath); RelOptInfo *rel = index->rel; List *indexquals, - *allclauses; + *indexqualcols; /* * For a join inner scan, there's no point in marking the path with any @@ -457,16 +463,16 @@ create_index_path(PlannerInfo *root, pathnode->path.pathkeys = pathkeys; /* Convert clauses to indexquals the executor can handle */ - indexquals = expand_indexqual_conditions(index, clause_groups); - - /* Flatten the clause-groups list to produce indexclauses list */ - allclauses = flatten_clausegroups_list(clause_groups); + expand_indexqual_conditions(index, indexclauses, indexclausecols, + &indexquals, &indexqualcols); /* Fill in the pathnode */ pathnode->indexinfo = index; - pathnode->indexclauses = allclauses; + pathnode->indexclauses = indexclauses; pathnode->indexquals = indexquals; + pathnode->indexqualcols = indexqualcols; pathnode->indexorderbys = indexorderbys; + pathnode->indexorderbycols = indexorderbycols; pathnode->isjoininner = (outer_rel != NULL); pathnode->indexscandir = indexscandir; @@ -476,7 +482,7 @@ create_index_path(PlannerInfo *root, /* * We must compute the estimated number of output rows for the * indexscan. This is less than rel->rows because of the additional - * selectivity of the join clauses. Since clause_groups may contain + * selectivity of the join clauses. Since indexclauses may contain * both restriction and join clauses, we have to do a set union to get * the full set of clauses that must be considered to compute the * correct selectivity. (Without the union operation, we might have @@ -489,7 +495,9 @@ create_index_path(PlannerInfo *root, * Note that we force the clauses to be treated as non-join clauses * during selectivity estimation. */ - allclauses = list_union_ptr(rel->baserestrictinfo, allclauses); + List *allclauses; + + allclauses = list_union_ptr(rel->baserestrictinfo, indexclauses); pathnode->rows = rel->tuples * clauselist_selectivity(root, allclauses, @@ -508,8 +516,7 @@ create_index_path(PlannerInfo *root, pathnode->rows = rel->rows; } - cost_index(pathnode, root, index, indexquals, indexorderbys, - indexonly, outer_rel); + cost_index(pathnode, root, outer_rel); return pathnode; } diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 3e6cabf7e74..cfc7dae55b6 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 diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 94b7d897907..b2bf8f0d8c0 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201112231 +#define CATALOG_VERSION_NO 201112241 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 32be6b13747..c893c3a1708 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -548,7 +548,7 @@ DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 DESCR("btree(internal)"); DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 16 "2281" _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ )); DESCR("btree(internal)"); -DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ )); +DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ )); DESCR("btree(internal)"); DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ )); DESCR("btree(internal)"); @@ -662,7 +662,7 @@ DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4 DESCR("hash(internal)"); DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ )); DESCR("hash(internal)"); -DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ )); +DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ )); DESCR("hash(internal)"); DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ )); DESCR("hash(internal)"); @@ -917,7 +917,7 @@ DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4 DESCR("gist(internal)"); DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ )); DESCR("gist(internal)"); -DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ )); +DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ )); DESCR("gist(internal)"); DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ )); DESCR("gist(internal)"); @@ -3870,7 +3870,7 @@ DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4 DESCR("gin(internal)"); DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ )); DESCR("gin(internal)"); -DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ )); +DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ )); DESCR("gin(internal)"); DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ )); DESCR("gin(internal)"); @@ -4530,7 +4530,7 @@ DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v DESCR("spgist(internal)"); DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 16 "2281" _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ )); DESCR("spgist(internal)"); -DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ )); +DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ )); DESCR("spgist(internal)"); DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ )); DESCR("spgist(internal)"); diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index b137142f3ea..13018027b61 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -657,27 +657,33 @@ typedef struct Path * * 'indexclauses' is a list of index qualification clauses, with implicit * AND semantics across the list. Each clause is a RestrictInfo node from - * the query's WHERE or JOIN conditions. - * - * 'indexquals' is a list of sub-lists of the actual index qual conditions - * that can be used with the index. There is one possibly-empty sub-list - * for each index column (but empty sub-lists for trailing columns can be - * omitted). The qual conditions are RestrictInfos, and in simple cases - * are the same RestrictInfos that appear in the flat indexclauses list. - * But when special indexable operators appear in 'indexclauses', they are - * replaced by their derived indexscannable conditions in 'indexquals'. - * Note that an entirely empty indexquals list denotes a full-index scan. - * - * 'indexorderbys', if not NIL, is a list of lists of lists of ORDER BY - * expressions that have been found to be usable as ordering operators for an - * amcanorderbyop index. These are not RestrictInfos, just bare expressions, + * the query's WHERE or JOIN conditions. An empty list implies a full + * index scan. + * + * 'indexquals' has the same structure as 'indexclauses', but it contains + * the actual index qual conditions that can be used with the index. + * In simple cases this is identical to 'indexclauses', but when special + * indexable operators appear in 'indexclauses', they are replaced by the + * derived indexscannable conditions in 'indexquals'. + * + * 'indexqualcols' is an integer list of index column numbers (zero-based) + * of the same length as 'indexquals', showing which index column each qual + * is meant to be used with. 'indexquals' is required to be ordered by + * index column, so 'indexqualcols' must form a nondecreasing sequence. + * (The order of multiple quals for the same index column is unspecified.) + * + * 'indexorderbys', if not NIL, is a list of ORDER BY expressions that have + * been found to be usable as ordering operators for an amcanorderbyop index. + * The list must match the path's pathkeys, ie, one expression per pathkey + * in the same order. These are not RestrictInfos, just bare expressions, * since they generally won't yield booleans. Also, unlike the case for * quals, it's guaranteed that each expression has the index key on the left - * side of the operator. The top list has one entry per pathkey in the - * path's pathkeys, and the sub-lists have one sub-sublist per index column. - * This representation is a bit of overkill, since there will be only one - * actual expression per pathkey, but it's convenient because each sub-list - * has the same structure as the indexquals list. + * side of the operator. + * + * 'indexorderbycols' is an integer list of index column numbers (zero-based) + * of the same length as 'indexorderbys', showing which index column each + * ORDER BY expression is meant to be used with. (There is no restriction + * on which index column each ORDER BY can be used with.) * * 'isjoininner' is TRUE if the path is a nestloop inner scan (that is, * some of the index conditions are join rather than restriction clauses). @@ -711,7 +717,9 @@ typedef struct IndexPath IndexOptInfo *indexinfo; List *indexclauses; List *indexquals; + List *indexqualcols; List *indexorderbys; + List *indexorderbycols; bool isjoininner; ScanDirection indexscandir; Cost indextotalcost; diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index 125808ae980..6c56439f109 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -67,9 +67,8 @@ extern double clamp_row_est(double nrows); extern double index_pages_fetched(double tuples_fetched, BlockNumber pages, double index_pages, PlannerInfo *root); extern void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel); -extern void cost_index(IndexPath *path, PlannerInfo *root, IndexOptInfo *index, - List *indexQuals, List *indexOrderBys, - bool indexonly, RelOptInfo *outer_rel); +extern void cost_index(IndexPath *path, PlannerInfo *root, + RelOptInfo *outer_rel); extern void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, Path *bitmapqual, RelOptInfo *outer_rel); extern void cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root); diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 38c8c1c9a35..8eec2ac596d 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -30,8 +30,10 @@ extern void add_path(RelOptInfo *parent_rel, Path *new_path); extern Path *create_seqscan_path(PlannerInfo *root, RelOptInfo *rel); extern IndexPath *create_index_path(PlannerInfo *root, IndexOptInfo *index, - List *clause_groups, + List *indexclauses, + List *indexclausecols, List *indexorderbys, + List *indexorderbycols, List *pathkeys, ScanDirection indexscandir, bool indexonly, diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index b0075d78654..2fa862fb6f3 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -57,11 +57,10 @@ extern bool eclass_matches_any_index(EquivalenceClass *ec, RelOptInfo *rel); extern bool match_index_to_operand(Node *operand, int indexcol, IndexOptInfo *index); -extern List *expand_indexqual_conditions(IndexOptInfo *index, - List *clausegroups); +extern void expand_indexqual_conditions(IndexOptInfo *index, + List *indexclauses, List *indexclausecols, + List **indexquals_p, List **indexqualcols_p); extern void check_partial_indexes(PlannerInfo *root, RelOptInfo *rel); -extern List *flatten_clausegroups_list(List *clausegroups); -extern List *flatten_indexorderbys_list(List *indexorderbys); extern Expr *adjust_rowcompare_for_index(RowCompareExpr *clause, IndexOptInfo *index, int indexcol, diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index 6c8e31269c5..ac434fabbc4 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -22,7 +22,7 @@ /* * Maximum number of arguments to a function. * - * The minimum value is 9 (index cost estimation uses 9-argument functions). + * The minimum value is 8 (GIN indexes use 8-argument support functions). * The maximum possible value is around 600 (limited by index tuple size in * pg_proc's index; BLCKSZ larger than 8K would allow more). Values larger * than needed will waste memory and processing time, but do not directly |