diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 1999-07-24 23:21:14 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 1999-07-24 23:21:14 +0000 |
commit | ac4913a0dd433ac1c2207014f886338f2ccd5fef (patch) | |
tree | d959e2082fcd500541ccdc9875b093b40c7d116a /src/backend/optimizer/path/orindxpath.c | |
parent | 348bdbce7942324dd19349d4d6f3f7dabae219c3 (diff) |
Clean up messy clause-selectivity code in clausesel.c; repair bug
identified by Hiroshi (incorrect cost attributed to OR clauses
after multiple passes through set_rest_selec()). I think the code
was trying to allow selectivities of OR subclauses to be passed in
from outside, but noplace was actually passing any useful data, and
set_rest_selec() was passing wrong data.
Restructure representation of "indexqual" in IndexPath nodes so that
it is the same as for indxqual in completed IndexScan nodes: namely,
a toplevel list with an entry for each pass of the index scan, having
sublists that are implicitly-ANDed index qual conditions for that pass.
You don't want to know what the old representation was :-(
Improve documentation of OR-clause indexscan functions.
Remove useless 'notclause' field from RestrictInfo nodes. (This might
force an initdb for anyone who has stored rules containing RestrictInfos,
but I do not think that RestrictInfo ever appears in completed plans.)
Diffstat (limited to 'src/backend/optimizer/path/orindxpath.c')
-rw-r--r-- | src/backend/optimizer/path/orindxpath.c | 183 |
1 files changed, 105 insertions, 78 deletions
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c index ceb8c3eb47f..4a511372a53 100644 --- a/src/backend/optimizer/path/orindxpath.c +++ b/src/backend/optimizer/path/orindxpath.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.28 1999/07/16 04:59:15 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.29 1999/07/24 23:21:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -26,61 +26,66 @@ #include "parser/parsetree.h" -static void best_or_subclause_indices(Query *root, RelOptInfo *rel, List *subclauses, - List *indices, List **indexids, Cost *cost, Cost *selec); -static void best_or_subclause_index(Query *root, RelOptInfo *rel, Expr *subclause, - List *indices, int *indexid, Cost *cost, Cost *selec); +static void best_or_subclause_indices(Query *root, RelOptInfo *rel, + List *subclauses, List *indices, + List **indexids, + Cost *cost, Cost *selec); +static void best_or_subclause_index(Query *root, RelOptInfo *rel, + Expr *subclause, List *indices, + int *indexid, Cost *cost, Cost *selec); /* * create_or_index_paths * Creates index paths for indices that match 'or' clauses. + * create_index_paths() must already have been called. * * 'rel' is the relation entry for which the paths are to be defined on * 'clauses' is the list of available restriction clause nodes * - * Returns a list of these index path nodes. + * Returns a list of index path nodes. * */ List * create_or_index_paths(Query *root, RelOptInfo *rel, List *clauses) { - List *t_list = NIL; + List *path_list = NIL; List *clist; foreach(clist, clauses) { - RestrictInfo *clausenode = (RestrictInfo *) (lfirst(clist)); + RestrictInfo *clausenode = (RestrictInfo *) lfirst(clist); /* * Check to see if this clause is an 'or' clause, and, if so, * whether or not each of the subclauses within the 'or' clause - * has been matched by an index (the 'Index field was set in - * (match_or) if no index matches a given subclause, one of the - * lists of index nodes returned by (get_index) will be 'nil'). + * has been matched by an index. The information used was + * saved by create_index_paths(). */ - if (valid_or_clause(clausenode) && + if (restriction_is_or_clause(clausenode) && clausenode->indexids) { - List *temp = NIL; - List *index_list = NIL; - bool index_flag = true; + bool all_indexable = true; + List *temp; - index_list = clausenode->indexids; - foreach(temp, index_list) + foreach(temp, clausenode->indexids) { - if (!lfirst(temp)) + if (lfirst(temp) == NIL) { - index_flag = false; + all_indexable = false; break; } } - /* do they all have indexes? */ - if (index_flag) - { /* used to be a lisp every function */ + if (all_indexable) + { + /* + * OK, build an IndexPath for this OR clause, using the + * best available index for each subclause. + */ IndexPath *pathnode = makeNode(IndexPath); - List *indexids = NIL; + List *indexids; + List *orclause; Cost cost; Cost selec; @@ -98,16 +103,35 @@ create_or_index_paths(Query *root, pathnode->path.pathorder->ordtype = SORTOP_ORDER; /* - * This is an IndexScan, but it does index lookups based - * on the order of the fields specified in the WHERE - * clause, not in any order, so the sortop is NULL. + * This is an IndexScan, but the overall result will consist + * of tuples extracted in multiple passes (one for each + * subclause of the OR), so the result cannot be claimed + * to have any particular ordering. */ pathnode->path.pathorder->ord.sortop = NULL; pathnode->path.pathkeys = NIL; - pathnode->indexqual = lcons(clausenode, NIL); + /* + * Generate an indexqual list from the OR clause's args. + * We want two levels of sublist: the first is implicit OR + * and the second is implicit AND. (Currently, we will never + * see a sub-AND-clause because of cnfify(), but someday maybe + * the code below will do something useful...) + */ + pathnode->indexqual = NIL; + foreach(orclause, clausenode->clause->args) + { + List *sublist; + if (and_clause(lfirst(orclause))) + sublist = ((Expr *) lfirst(orclause))->args; + else + sublist = lcons(lfirst(orclause), NIL); + pathnode->indexqual = lappend(pathnode->indexqual, + sublist); + } pathnode->indexid = indexids; pathnode->path.path_cost = cost; + clausenode->selectivity = (Cost) selec; /* * copy restrictinfo list into path for expensive function @@ -121,33 +145,28 @@ create_or_index_paths(Query *root, if (XfuncMode != XFUNC_OFF) ((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path) pathnode); #endif - clausenode->selectivity = (Cost) selec; - t_list = lappend(t_list, pathnode); + path_list = lappend(path_list, pathnode); } } } - return t_list; + return path_list; } /* * best_or_subclause_indices * Determines the best index to be used in conjunction with each subclause * of an 'or' clause and the cost of scanning a relation using these - * indices. The cost is the sum of the individual index costs. + * indices. The cost is the sum of the individual index costs, since + * the executor will perform a scan for each subclause of the 'or'. * - * 'rel' is the node of the relation on which the index is defined + * 'rel' is the node of the relation on which the indexes are defined * 'subclauses' are the subclauses of the 'or' clause - * 'indices' are those index nodes that matched subclauses of the 'or' - * clause - * 'examined_indexids' is a list of those index ids to be used with - * subclauses that have already been examined - * 'subcost' is the cost of using the indices in 'examined_indexids' - * 'selec' is a list of all subclauses that have already been examined - * - * Returns a list of the indexids, cost, and selectivities of each - * subclause, e.g., ((i1 i2 i3) cost (s1 s2 s3)), where 'i' is an OID, - * 'cost' is a flonum, and 's' is a flonum. + * 'indices' is a list of sublists of the index nodes that matched each + * subclause of the 'or' clause + * '*indexids' gets a list of the best index ID to use for each subclause + * '*cost' gets the total cost of the path + * '*selec' gets the total selectivity of the path. */ static void best_or_subclause_indices(Query *root, @@ -155,11 +174,12 @@ best_or_subclause_indices(Query *root, List *subclauses, List *indices, List **indexids, /* return value */ - Cost *cost, /* return value */ - Cost *selec) /* return value */ + Cost *cost, /* return value */ + Cost *selec) /* return value */ { List *slist; + *indexids = NIL; *selec = (Cost) 0.0; *cost = (Cost) 0.0; @@ -180,8 +200,6 @@ best_or_subclause_indices(Query *root, indices = lnext(indices); } - - return; } /* @@ -193,10 +211,9 @@ best_or_subclause_indices(Query *root, * 'rel' is the node of the relation on which the index is defined * 'subclause' is the subclause * 'indices' is a list of index nodes that match the subclause - * - * Returns a list (index_id index_subcost index_selectivity) - * (a fixnum, a fixnum, and a flonum respectively). - * + * '*retIndexid' gets the ID of the best index + * '*retCost' gets the cost of a scan with that index + * '*retSelec' gets the selectivity of that scan */ static void best_or_subclause_index(Query *root, @@ -207,49 +224,60 @@ best_or_subclause_index(Query *root, Cost *retCost, /* return value */ Cost *retSelec) /* return value */ { - List *ilist; + Oid relid = getrelid(lfirsti(rel->relids), + root->rtable); + Oid opno = ((Oper *) subclause->oper)->opno; + AttrNumber attno = (get_leftop(subclause))->varattno; + bool constant_on_right = non_null((Expr *) get_rightop(subclause)); + Datum value; + int flag; + List *opnos, + *attnos, + *values, + *flags; bool first_run = true; + List *ilist; /* if we don't match anything, return zeros */ *retIndexid = 0; - *retCost = 0.0; - *retSelec = 0.0; + *retCost = (Cost) 0.0; + *retSelec = (Cost) 0.0; + + if (constant_on_right) /* XXX looks pretty bogus ... tgl */ + value = ((Const *) get_rightop(subclause))->constvalue; + else + value = NameGetDatum(""); + if (constant_on_right) + flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_); + else + flag = _SELEC_CONSTANT_RIGHT_; + + /* prebuild lists since we will pass same list to each index */ + opnos = lconsi(opno, NIL); + attnos = lconsi(attno, NIL); + values = lconsi(value, NIL); + flags = lconsi(flag, NIL); foreach(ilist, indices) { RelOptInfo *index = (RelOptInfo *) lfirst(ilist); - - Datum value; - int flag = 0; + Oid indexid = (Oid) lfirsti(index->relids); Cost subcost; - AttrNumber attno = (get_leftop(subclause))->varattno; - Oid opno = ((Oper *) subclause->oper)->opno; - bool constant_on_right = non_null((Expr *) get_rightop(subclause)); float npages, selec; - if (constant_on_right) - value = ((Const *) get_rightop(subclause))->constvalue; - else - value = NameGetDatum(""); - if (constant_on_right) - flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_); - else - flag = _SELEC_CONSTANT_RIGHT_; - - index_selectivity(lfirsti(index->relids), + index_selectivity(indexid, index->classlist, - lconsi(opno, NIL), - getrelid(lfirsti(rel->relids), - root->rtable), - lconsi(attno, NIL), - lconsi(value, NIL), - lconsi(flag, NIL), + opnos, + relid, + attnos, + values, + flags, 1, &npages, &selec); - subcost = cost_index((Oid) lfirsti(index->relids), + subcost = cost_index(indexid, (int) npages, (Cost) selec, rel->pages, @@ -260,12 +288,11 @@ best_or_subclause_index(Query *root, if (first_run || subcost < *retCost) { - *retIndexid = lfirsti(index->relids); + *retIndexid = indexid; *retCost = subcost; *retSelec = selec; first_run = false; } } - return; } |