Commit 348bdbce authored by Tom Lane's avatar Tom Lane

Minor code beautification, extensive improvement of

comments.  This file was full of obsolete and just plain wrong
commentary...
parent baac6f98
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
* *
* indxpath.c * indxpath.c
* Routines to determine which indices are usable for scanning a * Routines to determine which indices are usable for scanning a
* given relation * given relation, and create IndexPaths accordingly.
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.61 1999/07/16 04:59:15 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.62 1999/07/23 03:34:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -40,16 +40,15 @@ ...@@ -40,16 +40,15 @@
static void match_index_orclauses(RelOptInfo *rel, RelOptInfo *index, int indexkey, static void match_index_orclauses(RelOptInfo *rel, RelOptInfo *index, int indexkey,
int xclass, List *restrictinfo_list); int xclass, List *restrictinfo_list);
static bool match_index_to_operand(int indexkey, Expr *operand,
RelOptInfo *rel, RelOptInfo *index);
static List *match_index_orclause(RelOptInfo *rel, RelOptInfo *index, int indexkey, static List *match_index_orclause(RelOptInfo *rel, RelOptInfo *index, int indexkey,
int xclass, List *or_clauses, List *other_matching_indices); int xclass, List *or_clauses, List *other_matching_indices);
static List *group_clauses_by_indexkey(RelOptInfo *rel, RelOptInfo *index, static List *group_clauses_by_indexkey(RelOptInfo *rel, RelOptInfo *index,
int *indexkeys, Oid *classes, List *restrictinfo_list); int *indexkeys, Oid *classes, List *restrictinfo_list);
static List *group_clauses_by_ikey_for_joins(RelOptInfo *rel, RelOptInfo *index, static List *group_clauses_by_ikey_for_joins(RelOptInfo *rel, RelOptInfo *index,
int *indexkeys, Oid *classes, List *join_cinfo_list, List *restr_cinfo_list); int *indexkeys, Oid *classes, List *join_cinfo_list, List *restr_cinfo_list);
static RestrictInfo *match_clause_to_indexkey(RelOptInfo *rel, RelOptInfo *index, int indexkey, static bool match_clause_to_indexkey(RelOptInfo *rel, RelOptInfo *index,
int xclass, RestrictInfo *restrictInfo, bool join); int indexkey, int xclass,
Expr *clause, bool join);
static bool pred_test(List *predicate_list, List *restrictinfo_list, static bool pred_test(List *predicate_list, List *restrictinfo_list,
List *joininfo_list); List *joininfo_list);
static bool one_pred_test(Expr *predicate, List *restrictinfo_list); static bool one_pred_test(Expr *predicate, List *restrictinfo_list);
...@@ -62,34 +61,28 @@ static List *index_innerjoin(Query *root, RelOptInfo *rel, ...@@ -62,34 +61,28 @@ static List *index_innerjoin(Query *root, RelOptInfo *rel,
List *clausegroup_list, RelOptInfo *index); List *clausegroup_list, RelOptInfo *index);
static List *create_index_path_group(Query *root, RelOptInfo *rel, RelOptInfo *index, static List *create_index_path_group(Query *root, RelOptInfo *rel, RelOptInfo *index,
List *clausegroup_list, bool join); List *clausegroup_list, bool join);
static List *add_index_paths(List *indexpaths, List *new_indexpaths); static bool match_index_to_operand(int indexkey, Expr *operand,
RelOptInfo *rel, RelOptInfo *index);
static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index); static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index);
/* find_index_paths() /*
* Finds all possible index paths by determining which indices in the * create_index_paths()
* list 'indices' are usable. * Generate all interesting index paths for the given relation.
*
* To be usable, an index must match against either a set of
* restriction clauses or join clauses.
* *
* Note that the current implementation requires that there exist * To be considered for an index scan, an index must match one or more
* matching clauses for every key in the index (i.e., no partial * restriction clauses or join clauses from the query's qual condition.
* matches are allowed).
* *
* If an index can't be used with restriction clauses, but its keys * Note: an index scan might also be used simply to order the result,
* match those of the result sort order (according to information stored * either for use in a mergejoin or to satisfy an ORDER BY request.
* within 'sortkeys'), then the index is also considered. * That possibility is handled elsewhere.
* *
* 'rel' is the relation entry to which these index paths correspond * 'rel' is the relation for which we want to generate index paths
* 'indices' is a list of possible index paths * 'indices' is a list of available indexes for 'rel'
* 'restrictinfo_list' is a list of restriction restrictinfo nodes for 'rel' * 'restrictinfo_list' is a list of restrictinfo nodes for 'rel'
* 'joininfo_list' is a list of joininfo nodes for 'rel' * 'joininfo_list' is a list of joininfo nodes for 'rel'
* 'sortkeys' is a node describing the result sort order (from
* (find_sortkeys))
*
* Returns a list of index nodes.
* *
* Returns a list of IndexPath access path descriptors.
*/ */
List * List *
create_index_paths(Query *root, create_index_paths(Query *root,
...@@ -98,21 +91,18 @@ create_index_paths(Query *root, ...@@ -98,21 +91,18 @@ create_index_paths(Query *root,
List *restrictinfo_list, List *restrictinfo_list,
List *joininfo_list) List *joininfo_list)
{ {
List *scanclausegroups = NIL;
List *scanpaths = NIL;
RelOptInfo *index = (RelOptInfo *) NULL;
List *joinclausegroups = NIL;
List *joinpaths = NIL;
List *retval = NIL; List *retval = NIL;
List *ilist; List *ilist;
foreach(ilist, indices) foreach(ilist, indices)
{ {
index = (RelOptInfo *) lfirst(ilist); RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
List *scanclausegroups;
List *joinclausegroups;
/* /*
* If this is a partial index, return if it fails the predicate * If this is a partial index, we can only use it if it passes
* test * the predicate test.
*/ */
if (index->indpred != NIL) if (index->indpred != NIL)
if (!pred_test(index->indpred, restrictinfo_list, joininfo_list)) if (!pred_test(index->indpred, restrictinfo_list, joininfo_list))
...@@ -121,7 +111,7 @@ create_index_paths(Query *root, ...@@ -121,7 +111,7 @@ create_index_paths(Query *root,
/* /*
* 1. Try matching the index against subclauses of an 'or' clause. * 1. Try matching the index against subclauses of an 'or' clause.
* The fields of the restrictinfo nodes are marked with lists of * The fields of the restrictinfo nodes are marked with lists of
* the matching indices. No path are actually created. We * the matching indices. No paths are actually created. We
* currently only look to match the first key. We don't find * currently only look to match the first key. We don't find
* multi-key index cases where an AND matches the first key, and * multi-key index cases where an AND matches the first key, and
* the OR matches the second key. * the OR matches the second key.
...@@ -134,8 +124,8 @@ create_index_paths(Query *root, ...@@ -134,8 +124,8 @@ create_index_paths(Query *root,
/* /*
* 2. If the keys of this index match any of the available * 2. If the keys of this index match any of the available
* restriction clauses, then create pathnodes corresponding to * restriction clauses, then create a path using those clauses
* each group of usable clauses. * as indexquals.
*/ */
scanclausegroups = group_clauses_by_indexkey(rel, scanclausegroups = group_clauses_by_indexkey(rel,
index, index,
...@@ -143,13 +133,13 @@ create_index_paths(Query *root, ...@@ -143,13 +133,13 @@ create_index_paths(Query *root,
index->classlist, index->classlist,
restrictinfo_list); restrictinfo_list);
scanpaths = NIL;
if (scanclausegroups != NIL) if (scanclausegroups != NIL)
scanpaths = create_index_path_group(root, retval = nconc(retval,
create_index_path_group(root,
rel, rel,
index, index,
scanclausegroups, scanclausegroups,
false); false));
/* /*
* 3. If this index can be used with any join clause, then create * 3. If this index can be used with any join clause, then create
...@@ -158,36 +148,31 @@ create_index_paths(Query *root, ...@@ -158,36 +148,31 @@ create_index_paths(Query *root,
* mergejoin, or if the index can possibly be used for scanning * mergejoin, or if the index can possibly be used for scanning
* the inner relation of a nestloop join. * the inner relation of a nestloop join.
*/ */
joinclausegroups = indexable_joinclauses(rel, index, joininfo_list, restrictinfo_list); joinclausegroups = indexable_joinclauses(rel, index,
joinpaths = NIL; joininfo_list,
restrictinfo_list);
if (joinclausegroups != NIL) if (joinclausegroups != NIL)
{ {
joinpaths = create_index_path_group(root, rel, retval = nconc(retval,
create_index_path_group(root,
rel,
index, index,
joinclausegroups, joinclausegroups,
true); true));
rel->innerjoin = nconc(rel->innerjoin, rel->innerjoin = nconc(rel->innerjoin,
index_innerjoin(root, rel, index_innerjoin(root, rel,
joinclausegroups, index)); joinclausegroups,
index));
} }
/*
* Some sanity checks to make sure that the indexpath is valid.
*/
if (joinpaths != NULL)
retval = add_index_paths(joinpaths, retval);
if (scanpaths != NULL)
retval = add_index_paths(scanpaths, retval);
} }
return retval; return retval;
} }
/**************************************************************************** /****************************************************************************
* ---- ROUTINES TO MATCH 'OR' CLAUSES ---- * ---- ROUTINES TO PROCESS 'OR' CLAUSES ----
****************************************************************************/ ****************************************************************************/
...@@ -202,12 +187,9 @@ create_index_paths(Query *root, ...@@ -202,12 +187,9 @@ create_index_paths(Query *root,
* *
* 'rel' is the node of the relation on which the index is defined. * 'rel' is the node of the relation on which the index is defined.
* 'index' is the index node. * 'index' is the index node.
* 'indexkey' is the (single) key of the index * 'indexkey' is the (single) key of the index that we will consider.
* 'class' is the class of the operator corresponding to 'indexkey'. * 'class' is the class of the operator corresponding to 'indexkey'.
* 'restrictinfo_list' is the list of available restriction clauses. * 'restrictinfo_list' is the list of available restriction clauses.
*
* Returns nothing.
*
*/ */
static void static void
match_index_orclauses(RelOptInfo *rel, match_index_orclauses(RelOptInfo *rel,
...@@ -216,72 +198,43 @@ match_index_orclauses(RelOptInfo *rel, ...@@ -216,72 +198,43 @@ match_index_orclauses(RelOptInfo *rel,
int xclass, int xclass,
List *restrictinfo_list) List *restrictinfo_list)
{ {
RestrictInfo *restrictinfo = (RestrictInfo *) NULL; List *i;
List *i = NIL;
foreach(i, restrictinfo_list) foreach(i, restrictinfo_list)
{ {
restrictinfo = (RestrictInfo *) lfirst(i); RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i);
if (valid_or_clause(restrictinfo)) if (valid_or_clause(restrictinfo))
{ {
/* /*
* Mark the 'or' clause with a list of indices which match * Mark the 'or' clause with a list of indices which match
* each of its subclauses. The list is generated by adding * each of its subclauses. We add entries to the existing
* 'index' to the existing list where appropriate. * list, if any.
*/ */
restrictinfo->indexids = match_index_orclause(rel, index, indexkey, restrictinfo->indexids =
xclass, match_index_orclause(rel, index,
indexkey, xclass,
restrictinfo->clause->args, restrictinfo->clause->args,
restrictinfo->indexids); restrictinfo->indexids);
} }
} }
} }
/* match_index_to_operand()
* Generalize test for a match between an existing index's key
* and the operand on the rhs of a restriction clause. Now check
* for functional indices as well.
*/
static bool
match_index_to_operand(int indexkey,
Expr *operand,
RelOptInfo *rel,
RelOptInfo *index)
{
bool result;
/*
* Normal index.
*/
if (index->indproc == InvalidOid)
{
result = match_indexkey_operand(indexkey, (Var *) operand, rel);
return result;
}
/*
* functional index check
*/
result = function_index_operand(operand, rel, index);
return result;
}
/* /*
* match_index_orclause * match_index_orclause
* Attempts to match an index against the subclauses of an 'or' clause. * Attempts to match an index against the subclauses of an 'or' clause.
* *
* A match means that: * A match means that:
* (1) the operator within the subclause can be used with one * (1) the operator within the subclause can be used with the
* of the index's operator classes, and * index's specified operator class, and
* (2) there is a usable key that matches the variable within a * (2) the variable on one side of the subclause matches the index key.
* searchable clause.
* *
* 'or_clauses' are the remaining subclauses within the 'or' clause * 'or_clauses' is the list of subclauses within the 'or' clause
* 'other_matching_indices' is the list of information on other indices * 'other_matching_indices' is the list of information on other indices
* that have already been matched to subclauses within this * that have already been matched to subclauses within this
* particular 'or' clause (i.e., a list previously generated by * particular 'or' clause (i.e., a list previously generated by
* this routine) * this routine), or NIL if this routine has not previously been
* run for this 'or' clause.
* *
* Returns a list of the form ((a b c) (d e f) nil (g h) ...) where * Returns a list of the form ((a b c) (d e f) nil (g h) ...) where
* a,b,c are nodes of indices that match the first subclause in * a,b,c are nodes of indices that match the first subclause in
...@@ -296,14 +249,14 @@ match_index_orclause(RelOptInfo *rel, ...@@ -296,14 +249,14 @@ match_index_orclause(RelOptInfo *rel,
List *or_clauses, List *or_clauses,
List *other_matching_indices) List *other_matching_indices)
{ {
Node *clause = NULL; List *matching_indices;
List *matching_indices = other_matching_indices; List *index_list;
List *index_list = NIL;
List *clist; List *clist;
/* first time through, we create index list */ /* first time through, we create empty list of same length as OR clause */
if (!other_matching_indices) if (!other_matching_indices)
{ {
matching_indices = NIL;
foreach(clist, or_clauses) foreach(clist, or_clauses)
matching_indices = lcons(NIL, matching_indices); matching_indices = lcons(NIL, matching_indices);
} }
...@@ -314,20 +267,12 @@ match_index_orclause(RelOptInfo *rel, ...@@ -314,20 +267,12 @@ match_index_orclause(RelOptInfo *rel,
foreach(clist, or_clauses) foreach(clist, or_clauses)
{ {
clause = lfirst(clist); Expr *clause = lfirst(clist);
if (is_opclause(clause)) if (match_clause_to_indexkey(rel, index, indexkey, xclass,
clause, false))
{ {
Expr *left = (Expr *) get_leftop((Expr *) clause); /* OK to add this index to sublist for this subclause */
Expr *right = (Expr *) get_rightop((Expr *) clause);
if (left && right &&
op_class(((Oper *) ((Expr *) clause)->oper)->opno,
xclass, index->relam) &&
((IsA(right, Const) &&
match_index_to_operand(indexkey, left, rel, index)) ||
(IsA(left, Const) &&
match_index_to_operand(indexkey, right, rel, index))))
lfirst(matching_indices) = lcons(index, lfirst(matching_indices) = lcons(index,
lfirst(matching_indices)); lfirst(matching_indices));
} }
...@@ -358,26 +303,26 @@ match_index_orclause(RelOptInfo *rel, ...@@ -358,26 +303,26 @@ match_index_orclause(RelOptInfo *rel,
/* /*
* group_clauses_by_indexkey * group_clauses_by_indexkey
* Determines whether there are clauses which will match each and every * Generates a list of restriction clauses that can be used with an index.
* one of the remaining keys of an index.
* *
* 'rel' is the node of the relation corresponding to the index. * 'rel' is the node of the relation itself.
* 'indexkeys' are the remaining index keys to be matched. * 'index' is a index on 'rel'.
* 'indexkeys' are the index keys to be matched.
* 'classes' are the classes of the index operators on those keys. * 'classes' are the classes of the index operators on those keys.
* 'clauses' is either: * 'clauses' is the list of available restriction clauses for 'rel'.
* (1) the list of available restriction clauses on a single
* relation, or
* (2) a list of join clauses between 'rel' and a fixed set of
* relations,
* depending on the value of 'join'.
* *
* NOTE: it works now for restriction clauses only. - vadim 03/18/97 * Returns NIL if no clauses can be used with this index.
* * Otherwise, a list containing a single sublist is returned (indicating
* Returns all possible groups of clauses that will match (given that * to create_index_path_group() that a single IndexPath should be created).
* one or more clauses can match any of the remaining keys). * The sublist is ordered by index key, and contains sublists of clauses
* E.g., if you have clauses A, B, and C, ((A B) (A C)) might be * that can be used with that index key.
* returned for an index with 2 keys.
* *
* Note that in a multi-key index, we stop if we find a key that cannot be
* used with any clause. For example, given an index on (A,B,C), we might
* return (((C1 C2) (C3 C4))) if we find that clauses C1 and C2 use column A,
* clauses C3 and C4 use column B, and no clauses use column C. But if no
* clauses match B we will return (((C1 C2))), whether or not there are
* clauses matching column C, because the executor couldn't use them anyway.
*/ */
static List * static List *
group_clauses_by_indexkey(RelOptInfo *rel, group_clauses_by_indexkey(RelOptInfo *rel,
...@@ -386,60 +331,61 @@ group_clauses_by_indexkey(RelOptInfo *rel, ...@@ -386,60 +331,61 @@ group_clauses_by_indexkey(RelOptInfo *rel,
Oid *classes, Oid *classes,
List *restrictinfo_list) List *restrictinfo_list)
{ {
List *curCinfo = NIL; List *clausegroup_list = NIL;
RestrictInfo *matched_clause = (RestrictInfo *) NULL;
List *clausegroup = NIL;
int curIndxKey;
Oid curClass;
if (restrictinfo_list == NIL || indexkeys[0] == 0) if (restrictinfo_list == NIL || indexkeys[0] == 0)
return NIL; return NIL;
do do
{ {
List *tempgroup = NIL; int curIndxKey = indexkeys[0];
Oid curClass = classes[0];
curIndxKey = indexkeys[0]; List *clausegroup = NIL;
curClass = classes[0]; List *curCinfo;
foreach(curCinfo, restrictinfo_list) foreach(curCinfo, restrictinfo_list)
{ {
RestrictInfo *temp = (RestrictInfo *) lfirst(curCinfo); RestrictInfo *rinfo = (RestrictInfo *) lfirst(curCinfo);
matched_clause = match_clause_to_indexkey(rel, if (match_clause_to_indexkey(rel,
index, index,
curIndxKey, curIndxKey,
curClass, curClass,
temp, rinfo->clause,
false); false))
if (!matched_clause) clausegroup = lappend(clausegroup, rinfo);
continue;
tempgroup = lappend(tempgroup, matched_clause);
} }
if (tempgroup == NIL)
/* If no clauses match this key, we're done; we don't want to
* look at keys to its right.
*/
if (clausegroup == NIL)
break; break;
clausegroup = nconc(clausegroup, tempgroup); clausegroup_list = nconc(clausegroup_list, clausegroup);
indexkeys++; indexkeys++;
classes++; classes++;
} while (!DoneMatchingIndexKeys(indexkeys, index)); } while (!DoneMatchingIndexKeys(indexkeys, index));
/* clausegroup holds all matched clauses ordered by indexkeys */ /* clausegroup_list holds all matched clauses ordered by indexkeys */
if (clausegroup_list != NIL)
if (clausegroup != NIL) return lcons(clausegroup_list, NIL);
return lcons(clausegroup, NIL);
return NIL; return NIL;
} }
/* /*
* group_clauses_by_ikey_for_joins * group_clauses_by_ikey_for_joins
* special edition of group_clauses_by_indexkey - will * Generates a list of join clauses that can be used with an index.
* match join & restriction clauses. See comment in indexable_joinclauses.
* - vadim 03/18/97
* *
* This is much like group_clauses_by_indexkey(), but we consider both
* join and restriction clauses. For each indexkey in the index, we
* accept both join and restriction clauses that match it (since both
* will make useful indexquals if the index is being used to scan the
* inner side of a join). But there must be at least one matching
* join clause, or we return NIL indicating that this index isn't useful
* for joining.
*/ */
static List * static List *
group_clauses_by_ikey_for_joins(RelOptInfo *rel, group_clauses_by_ikey_for_joins(RelOptInfo *rel,
...@@ -449,11 +395,7 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel, ...@@ -449,11 +395,7 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
List *join_cinfo_list, List *join_cinfo_list,
List *restr_cinfo_list) List *restr_cinfo_list)
{ {
List *curCinfo = NIL; List *clausegroup_list = NIL;
RestrictInfo *matched_clause = (RestrictInfo *) NULL;
List *clausegroup = NIL;
int curIndxKey;
Oid curClass;
bool jfound = false; bool jfound = false;
if (join_cinfo_list == NIL || indexkeys[0] == 0) if (join_cinfo_list == NIL || indexkeys[0] == 0)
...@@ -461,148 +403,144 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel, ...@@ -461,148 +403,144 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
do do
{ {
List *tempgroup = NIL; int curIndxKey = indexkeys[0];
Oid curClass = classes[0];
curIndxKey = indexkeys[0]; List *clausegroup = NIL;
curClass = classes[0]; List *curCinfo;
foreach(curCinfo, join_cinfo_list) foreach(curCinfo, join_cinfo_list)
{ {
RestrictInfo *temp = (RestrictInfo *) lfirst(curCinfo); RestrictInfo *rinfo = (RestrictInfo *) lfirst(curCinfo);
matched_clause = match_clause_to_indexkey(rel, if (match_clause_to_indexkey(rel,
index, index,
curIndxKey, curIndxKey,
curClass, curClass,
temp, rinfo->clause,
true); true))
if (!matched_clause) {
continue; clausegroup = lappend(clausegroup, rinfo);
tempgroup = lappend(tempgroup, matched_clause);
jfound = true; jfound = true;
} }
}
foreach(curCinfo, restr_cinfo_list) foreach(curCinfo, restr_cinfo_list)
{ {
RestrictInfo *temp = (RestrictInfo *) lfirst(curCinfo); RestrictInfo *rinfo = (RestrictInfo *) lfirst(curCinfo);
matched_clause = match_clause_to_indexkey(rel, if (match_clause_to_indexkey(rel,
index, index,
curIndxKey, curIndxKey,
curClass, curClass,
temp, rinfo->clause,
false); false))
if (!matched_clause) clausegroup = lappend(clausegroup, rinfo);
continue;
tempgroup = lappend(tempgroup, matched_clause);
} }
if (tempgroup == NIL)
/* If no clauses match this key, we're done; we don't want to
* look at keys to its right.
*/
if (clausegroup == NIL)
break; break;
clausegroup = nconc(clausegroup, tempgroup); clausegroup_list = nconc(clausegroup_list, clausegroup);
indexkeys++; indexkeys++;
classes++; classes++;
} while (!DoneMatchingIndexKeys(indexkeys, index)); } while (!DoneMatchingIndexKeys(indexkeys, index));
/* clausegroup holds all matched clauses ordered by indexkeys */ /* clausegroup_list holds all matched clauses ordered by indexkeys */
if (clausegroup != NIL) if (clausegroup_list != NIL)
{ {
/* /*
* if no one join clause was matched then there ain't clauses for * if no join clause was matched then there ain't clauses for
* joins at all. * joins at all.
*/ */
if (!jfound) if (!jfound)
{ {
freeList(clausegroup); freeList(clausegroup_list);
return NIL; return NIL;
} }
return lcons(clausegroup, NIL); return lcons(clausegroup_list, NIL);
} }
return NIL; return NIL;
} }
/*
* IndexScanableClause () MACRO
*
* Generalize condition on which we match a clause with an index.
* Now we can match with functional indices.
*/
#define IndexScanableOperand(opnd, indkeys, rel, index) \
((index->indproc == InvalidOid) ? \
match_indexkey_operand(indkeys, opnd, rel) : \
function_index_operand((Expr*)opnd,rel,index))
/* /*
* There was * match_clause_to_indexkey()
* equal_indexkey_var(indkeys,opnd) : \ * Determines whether a restriction or join clause matches
* above, and now * a key of an index.
* match_indexkey_operand(indkeys, opnd, rel) : \
* - vadim 01/22/97
*/
/* match_clause_to_indexkey()
* Finds the first of a relation's available restriction clauses that
* matches a key of an index.
* *
* To match, the clause must: * To match, the clause must:
* (1) be in the form (op var const) if the clause is a single- * (1) be in the form (var op const) for a restriction clause,
* relation clause, and * or (var op var) for a join clause, where the var or one
* of the vars matches the index key; and
* (2) contain an operator which is in the same class as the index * (2) contain an operator which is in the same class as the index
* operator for this key. * operator for this key.
* *
* If the clause being matched is a join clause, then 'join' is t. * In the restriction case, we can cope with (const op var) by commuting
* the clause to (var op const), if there is a commutator operator.
* XXX why do we bother to commute? The executor doesn't care!!
*
* In the join case, later code will try to commute the clause if needed
* to put the inner relation's var on the right. We have no idea here
* which relation might wind up on the inside, so we just accept
* a match for either var.
* XXX is this right? We are making a list for this relation to
* be an inner join relation, so if there is any commuting then
* this rel must be on the right. But again, it's not really clear
* that we have to commute at all!
* *
* Returns a single restrictinfo node corresponding to the matching * 'rel' is the relation of interest.
* clause. * 'index' is an index on 'rel'.
* 'indexkey' is a key of 'index'.
* 'xclass' is the corresponding operator class.
* 'clause' is the clause to be tested.
* 'join' is true if we are considering this clause for joins.
* *
* NOTE: returns nil if clause is an or_clause. * Returns true if the clause can be used with this index key.
* *
* NOTE: returns false if clause is an or_clause; that's handled elsewhere.
*/ */
static RestrictInfo * static bool
match_clause_to_indexkey(RelOptInfo *rel, match_clause_to_indexkey(RelOptInfo *rel,
RelOptInfo *index, RelOptInfo *index,
int indexkey, int indexkey,
int xclass, int xclass,
RestrictInfo *restrictInfo, Expr *clause,
bool join) bool join)
{ {
Expr *clause = restrictInfo->clause; bool isIndexable = false;
Var *leftop, Var *leftop,
*rightop; *rightop;
Oid join_op = InvalidOid;
Oid restrict_op = InvalidOid;
bool isIndexable = false;
if (or_clause((Node *) clause) ||
not_clause((Node *) clause) || single_node((Node *) clause))
return (RestrictInfo *) NULL;
if (! is_opclause((Node *) clause))
return false;
leftop = get_leftop(clause); leftop = get_leftop(clause);
rightop = get_rightop(clause); rightop = get_rightop(clause);
if (! leftop || ! rightop)
return false;
/*
* If this is not a join clause, check for clauses of the form:
* (operator var/func constant) and (operator constant var/func)
*/
if (!join) if (!join)
{ {
/*
* Not considering joins, so check for clauses of the form:
* (var/func operator constant) and (constant operator var/func)
*/
Oid restrict_op = InvalidOid;
/* /*
* Check for standard s-argable clause * Check for standard s-argable clause
*/ */
if ((rightop && IsA(rightop, Const)) || if (IsA(rightop, Const) || IsA(rightop, Param))
(rightop && IsA(rightop, Param)))
{ {
restrict_op = ((Oper *) ((Expr *) clause)->oper)->opno; restrict_op = ((Oper *) ((Expr *) clause)->oper)->opno;
isIndexable = (op_class(restrict_op, xclass, index->relam) && isIndexable = (op_class(restrict_op, xclass, index->relam) &&
IndexScanableOperand(leftop, match_index_to_operand(indexkey,
indexkey, (Expr *) leftop,
rel, rel,
index)); index));
...@@ -614,11 +552,8 @@ match_clause_to_indexkey(RelOptInfo *rel, ...@@ -614,11 +552,8 @@ match_clause_to_indexkey(RelOptInfo *rel,
*/ */
if (!isIndexable) if (!isIndexable)
{ {
Oid ltype; Oid ltype = exprType((Node *) leftop);
Oid rtype; Oid rtype = exprType((Node *) rightop);
ltype = exprType((Node *) leftop);
rtype = exprType((Node *) rightop);
/* /*
* make sure we have two different binary-compatible * make sure we have two different binary-compatible
...@@ -637,13 +572,14 @@ match_clause_to_indexkey(RelOptInfo *rel, ...@@ -637,13 +572,14 @@ match_clause_to_indexkey(RelOptInfo *rel,
newop = NULL; newop = NULL;
/* actually have a different operator to try? */ /* actually have a different operator to try? */
if (HeapTupleIsValid(newop) && (oprid(newop) != restrict_op)) if (HeapTupleIsValid(newop) &&
(oprid(newop) != restrict_op))
{ {
restrict_op = oprid(newop); restrict_op = oprid(newop);
isIndexable = (op_class(restrict_op, xclass, index->relam) && isIndexable = (op_class(restrict_op, xclass, index->relam) &&
IndexScanableOperand(leftop, match_index_to_operand(indexkey,
indexkey, (Expr *) leftop,
rel, rel,
index)); index));
...@@ -658,15 +594,16 @@ match_clause_to_indexkey(RelOptInfo *rel, ...@@ -658,15 +594,16 @@ match_clause_to_indexkey(RelOptInfo *rel,
/* /*
* Must try to commute the clause to standard s-arg format. * Must try to commute the clause to standard s-arg format.
*/ */
else if ((leftop && IsA(leftop, Const)) || else if (IsA(leftop, Const) || IsA(leftop, Param))
(leftop && IsA(leftop, Param)))
{ {
restrict_op = get_commutator(((Oper *) ((Expr *) clause)->oper)->opno); restrict_op = get_commutator(((Oper *) ((Expr *) clause)->oper)->opno);
isIndexable = ((restrict_op != InvalidOid) && isIndexable = ((restrict_op != InvalidOid) &&
op_class(restrict_op, xclass, index->relam) && op_class(restrict_op, xclass, index->relam) &&
IndexScanableOperand(rightop, match_index_to_operand(indexkey,
indexkey, rel, index)); (Expr *) rightop,
rel,
index));
#ifndef IGNORE_BINARY_COMPATIBLE_INDICES #ifndef IGNORE_BINARY_COMPATIBLE_INDICES
if (!isIndexable) if (!isIndexable)
...@@ -697,8 +634,8 @@ match_clause_to_indexkey(RelOptInfo *rel, ...@@ -697,8 +634,8 @@ match_clause_to_indexkey(RelOptInfo *rel,
isIndexable = ((restrict_op != InvalidOid) && isIndexable = ((restrict_op != InvalidOid) &&
op_class(restrict_op, xclass, index->relam) && op_class(restrict_op, xclass, index->relam) &&
IndexScanableOperand(rightop, match_index_to_operand(indexkey,
indexkey, (Expr *) rightop,
rel, rel,
index)); index));
...@@ -720,42 +657,30 @@ match_clause_to_indexkey(RelOptInfo *rel, ...@@ -720,42 +657,30 @@ match_clause_to_indexkey(RelOptInfo *rel,
} }
} }
} }
/*
* Check for an indexable scan on one of the join relations. clause is
* of the form (operator var/func var/func)
*/
else else
{ {
if (rightop /*
&& match_index_to_operand(indexkey, (Expr *) rightop, rel, index)) * Check for an indexable scan on one of the join relations.
{ * clause is of the form (operator var/func var/func)
join_op = get_commutator(((Oper *) ((Expr *) clause)->oper)->opno); * XXX this does not seem right. Should check other side
* looks like var/func? do we really want to only consider
* this rel on lefthand side??
*/
Oid join_op = InvalidOid;
} if (match_index_to_operand(indexkey, (Expr *) leftop,
else if (leftop rel, index))
&& match_index_to_operand(indexkey,
(Expr *) leftop, rel, index))
join_op = ((Oper *) ((Expr *) clause)->oper)->opno; join_op = ((Oper *) ((Expr *) clause)->oper)->opno;
else if (match_index_to_operand(indexkey, (Expr *) rightop,
rel, index))
join_op = get_commutator(((Oper *) ((Expr *) clause)->oper)->opno);
if (join_op && op_class(join_op, xclass, index->relam) && if (join_op && op_class(join_op, xclass, index->relam) &&
is_joinable((Node *) clause)) is_joinable((Node *) clause))
{
isIndexable = true; isIndexable = true;
/*
* If we're using the operand's commutator we must commute the
* clause.
*/
if (join_op != ((Oper *) ((Expr *) clause)->oper)->opno)
CommuteClause((Node *) clause);
}
} }
if (isIndexable) return isIndexable;
return restrictInfo;
return NULL;
} }
/**************************************************************************** /****************************************************************************
...@@ -960,7 +885,8 @@ one_pred_clause_test(Expr *predicate, Node *clause) ...@@ -960,7 +885,8 @@ one_pred_clause_test(Expr *predicate, Node *clause)
* this test should always be considered false. * this test should always be considered false.
*/ */
StrategyNumber BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = { static StrategyNumber
BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = {
{2, 2, 0, 0, 0}, {2, 2, 0, 0, 0},
{1, 2, 0, 0, 0}, {1, 2, 0, 0, 0},
{1, 2, 3, 4, 5}, {1, 2, 3, 4, 5},
...@@ -1179,14 +1105,13 @@ static List * ...@@ -1179,14 +1105,13 @@ static List *
indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index, indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
List *joininfo_list, List *restrictinfo_list) List *joininfo_list, List *restrictinfo_list)
{ {
JoinInfo *joininfo = (JoinInfo *) NULL;
List *cg_list = NIL; List *cg_list = NIL;
List *i = NIL; List *i;
List *clausegroups = NIL;
foreach(i, joininfo_list) foreach(i, joininfo_list)
{ {
joininfo = (JoinInfo *) lfirst(i); JoinInfo *joininfo = (JoinInfo *) lfirst(i);
List *clausegroups;
if (joininfo->jinfo_restrictinfo == NIL) if (joininfo->jinfo_restrictinfo == NIL)
continue; continue;
...@@ -1202,9 +1127,9 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index, ...@@ -1202,9 +1127,9 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
List *clauses = lfirst(clausegroups); List *clauses = lfirst(clausegroups);
((RestrictInfo *) lfirst(clauses))->restrictinfojoinid = joininfo->unjoined_relids; ((RestrictInfo *) lfirst(clauses))->restrictinfojoinid = joininfo->unjoined_relids;
}
cg_list = nconc(cg_list, clausegroups); cg_list = nconc(cg_list, clausegroups);
} }
}
return cg_list; return cg_list;
} }
...@@ -1212,30 +1137,6 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index, ...@@ -1212,30 +1137,6 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
* ---- PATH CREATION UTILITIES ---- * ---- PATH CREATION UTILITIES ----
****************************************************************************/ ****************************************************************************/
/*
* extract_restrict_clauses -
* the list of clause info contains join clauses and restriction clauses.
* This routine returns the restriction clauses only.
*/
#ifdef NOT_USED
static List *
extract_restrict_clauses(List *clausegroup)
{
List *restrict_cls = NIL;
List *l;
foreach(l, clausegroup)
{
RestrictInfo *cinfo = lfirst(l);
if (!is_joinable((Node *) cinfo->clause))
restrict_cls = lappend(restrict_cls, cinfo);
}
return restrict_cls;
}
#endif
/* /*
* index_innerjoin * index_innerjoin
* Creates index path nodes corresponding to paths to be used as inner * Creates index path nodes corresponding to paths to be used as inner
...@@ -1251,22 +1152,19 @@ static List * ...@@ -1251,22 +1152,19 @@ static List *
index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list, index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
RelOptInfo *index) RelOptInfo *index)
{ {
List *clausegroup = NIL; List *path_list = NIL;
List *cg_list = NIL; List *i;
List *i = NIL;
IndexPath *pathnode = (IndexPath *) NULL;
Cost temp_selec;
float temp_pages;
foreach(i, clausegroup_list) foreach(i, clausegroup_list)
{ {
List *clausegroup = lfirst(i);
IndexPath *pathnode = makeNode(IndexPath);
Cost temp_selec;
float temp_pages;
List *attnos, List *attnos,
*values, *values,
*flags; *flags;
clausegroup = lfirst(i);
pathnode = makeNode(IndexPath);
get_joinvars(lfirsti(rel->relids), clausegroup, get_joinvars(lfirsti(rel->relids), clausegroup,
&attnos, &values, &flags); &attnos, &values, &flags);
index_selectivity(lfirsti(index->relids), index_selectivity(lfirsti(index->relids),
...@@ -1315,9 +1213,9 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list, ...@@ -1315,9 +1213,9 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
if (XfuncMode != XFUNC_OFF) if (XfuncMode != XFUNC_OFF)
((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path *) pathnode); ((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path *) pathnode);
#endif #endif
cg_list = lappend(cg_list, pathnode); path_list = lappend(path_list, pathnode);
} }
return cg_list; return path_list;
} }
/* /*
...@@ -1341,41 +1239,69 @@ create_index_path_group(Query *root, ...@@ -1341,41 +1239,69 @@ create_index_path_group(Query *root,
List *clausegroup_list, List *clausegroup_list,
bool join) bool join)
{ {
List *clausegroup = NIL; List *path_list = NIL;
List *ip_list = NIL; List *i;
List *i = NIL;
List *j = NIL;
IndexPath *temp_path;
foreach(i, clausegroup_list) foreach(i, clausegroup_list)
{ {
RestrictInfo *restrictinfo; List *clausegroup = lfirst(i);
bool temp = true; bool usable = true;
clausegroup = lfirst(i); if (join)
{
List *j;
foreach(j, clausegroup) foreach(j, clausegroup)
{ {
restrictinfo = (RestrictInfo *) lfirst(j); RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(j);
if (!(is_joinable((Node *) restrictinfo->clause) && if (!(is_joinable((Node *) restrictinfo->clause) &&
equal_path_merge_ordering(index->ordering, equal_path_merge_ordering(index->ordering,
restrictinfo->mergejoinorder))) restrictinfo->mergejoinorder)))
temp = false; {
usable = false;
break;
}
}
} }
if (!join || temp) if (usable)
{ /* restriction, ordering scan */ {
temp_path = create_index_path(root, rel, index, clausegroup, join); path_list = lappend(path_list,
ip_list = lappend(ip_list, temp_path); create_index_path(root, rel, index,
clausegroup, join));
} }
} }
return ip_list; return path_list;
} }
static List * /****************************************************************************
add_index_paths(List *indexpaths, List *new_indexpaths) * ---- ROUTINES TO CHECK OPERANDS ----
****************************************************************************/
/*
* match_index_to_operand()
* Generalized test for a match between an index's key
* and the operand on one side of a restriction or join clause.
* Now check for functional indices as well.
*/
static bool
match_index_to_operand(int indexkey,
Expr *operand,
RelOptInfo *rel,
RelOptInfo *index)
{ {
return nconc(indexpaths, new_indexpaths); if (index->indproc == InvalidOid)
{
/*
* Normal index.
*/
return match_indexkey_operand(indexkey, (Var *) operand, rel);
}
/*
* functional index check
*/
return function_index_operand(operand, rel, index);
} }
static bool static bool
...@@ -1408,7 +1334,6 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index) ...@@ -1408,7 +1334,6 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index)
* refer to the right relatiion. 2. the args have the right attr. * refer to the right relatiion. 2. the args have the right attr.
* numbers in the right order. * numbers in the right order.
* *
*
* Check all args refer to the correct relation (i.e. the one with the * Check all args refer to the correct relation (i.e. the one with the
* functional index defined on it (rel). To do this we can simply * functional index defined on it (rel). To do this we can simply
* compare range table entry numbers, they must be the same. * compare range table entry numbers, they must be the same.
...@@ -1425,7 +1350,6 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index) ...@@ -1425,7 +1350,6 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index)
i = 0; i = 0;
foreach(arg, funcargs) foreach(arg, funcargs)
{ {
if (indexKeys[i] == 0) if (indexKeys[i] == 0)
return false; return false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment