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