Minor code beautification, extensive improvement of
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 23 Jul 1999 03:34:49 +0000 (03:34 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 23 Jul 1999 03:34:49 +0000 (03:34 +0000)
comments.  This file was full of obsolete and just plain wrong
commentary...

src/backend/optimizer/path/indxpath.c

index 2fc7d07060c9f62b9cff70e991b2f0d973f5b9b1..c539b1f90517475e7eca05f127cabcf2df520ec1 100644 (file)
@@ -2,13 +2,13 @@
  *
  * indxpath.c
  *       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
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 
 static void match_index_orclauses(RelOptInfo *rel, RelOptInfo *index, int indexkey,
                                          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,
                         int xclass, List *or_clauses, List *other_matching_indices);
 static List *group_clauses_by_indexkey(RelOptInfo *rel, RelOptInfo *index,
                                  int *indexkeys, Oid *classes, List *restrictinfo_list);
 static List *group_clauses_by_ikey_for_joins(RelOptInfo *rel, RelOptInfo *index,
                                                                int *indexkeys, Oid *classes, List *join_cinfo_list, List *restr_cinfo_list);
-static RestrictInfo *match_clause_to_indexkey(RelOptInfo *rel, RelOptInfo *index, int indexkey,
-                                         int xclass, RestrictInfo *restrictInfo, bool join);
+static bool match_clause_to_indexkey(RelOptInfo *rel, RelOptInfo *index,
+                                                                        int indexkey, int xclass,
+                                                                        Expr *clause, bool join);
 static bool pred_test(List *predicate_list, List *restrictinfo_list,
                  List *joininfo_list);
 static bool one_pred_test(Expr *predicate, List *restrictinfo_list);
@@ -62,34 +61,28 @@ static List *index_innerjoin(Query *root, RelOptInfo *rel,
                                List *clausegroup_list, RelOptInfo *index);
 static List *create_index_path_group(Query *root, RelOptInfo *rel, RelOptInfo *index,
                                                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);
 
 
-/* find_index_paths()
- *       Finds all possible index paths by determining which indices in the
- *       list 'indices' are usable.
- *
- *       To be usable, an index must match against either a set of
- *       restriction clauses or join clauses.
+/*
+ * create_index_paths()
+ *       Generate all interesting index paths for the given relation.
  *
- *       Note that the current implementation requires that there exist
- *       matching clauses for every key in the index (i.e., no partial
- *       matches are allowed).
+ *       To be considered for an index scan, an index must match one or more
+ *       restriction clauses or join clauses from the query's qual condition.
  *
- *       If an index can't be used with restriction clauses, but its keys
- *       match those of the result sort order (according to information stored
- *       within 'sortkeys'), then the index is also considered.
+ *       Note: an index scan might also be used simply to order the result,
+ *       either for use in a mergejoin or to satisfy an ORDER BY request.
+ *       That possibility is handled elsewhere.
  *
- * 'rel' is the relation entry to which these index paths correspond
- * 'indices' is a list of possible index paths
- * 'restrictinfo_list' is a list of restriction restrictinfo nodes for 'rel'
+ * 'rel' is the relation for which we want to generate index paths
+ * 'indices' is a list of available indexes for 'rel'
+ * 'restrictinfo_list' is a list of restrictinfo 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 *
 create_index_paths(Query *root,
@@ -98,21 +91,18 @@ create_index_paths(Query *root,
                                   List *restrictinfo_list,
                                   List *joininfo_list)
 {
-       List       *scanclausegroups = NIL;
-       List       *scanpaths = NIL;
-       RelOptInfo *index = (RelOptInfo *) NULL;
-       List       *joinclausegroups = NIL;
-       List       *joinpaths = NIL;
        List       *retval = NIL;
        List       *ilist;
 
        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
-                * test
+                * If this is a partial index, we can only use it if it passes
+                * the predicate test.
                 */
                if (index->indpred != NIL)
                        if (!pred_test(index->indpred, restrictinfo_list, joininfo_list))
@@ -121,7 +111,7 @@ create_index_paths(Query *root,
                /*
                 * 1. Try matching the index against subclauses of an 'or' clause.
                 * 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
                 * multi-key index cases where an AND matches the first key, and
                 * the OR matches the second key.
@@ -134,8 +124,8 @@ create_index_paths(Query *root,
 
                /*
                 * 2. If the keys of this index match any of the available
-                * restriction clauses, then create pathnodes corresponding to
-                * each group of usable clauses.
+                * restriction clauses, then create a path using those clauses
+                * as indexquals.
                 */
                scanclausegroups = group_clauses_by_indexkey(rel,
                                                                                                         index,
@@ -143,13 +133,13 @@ create_index_paths(Query *root,
                                                                                                         index->classlist,
                                                                                                         restrictinfo_list);
 
-               scanpaths = NIL;
                if (scanclausegroups != NIL)
-                       scanpaths = create_index_path_group(root,
-                                                                                               rel,
-                                                                                               index,
-                                                                                               scanclausegroups,
-                                                                                               false);
+                       retval = nconc(retval,
+                                                  create_index_path_group(root,
+                                                                                                  rel,
+                                                                                                  index,
+                                                                                                  scanclausegroups,
+                                                                                                  false));
 
                /*
                 * 3. If this index can be used with any join clause, then create
@@ -158,36 +148,31 @@ create_index_paths(Query *root,
                 * mergejoin, or if the index can possibly be used for scanning
                 * the inner relation of a nestloop join.
                 */
-               joinclausegroups = indexable_joinclauses(rel, index, joininfo_list, restrictinfo_list);
-               joinpaths = NIL;
+               joinclausegroups = indexable_joinclauses(rel, index,
+                                                                                                joininfo_list,
+                                                                                                restrictinfo_list);
 
                if (joinclausegroups != NIL)
                {
-                       joinpaths = create_index_path_group(root, rel,
-                                                                                               index,
-                                                                                               joinclausegroups,
-                                                                                               true);
+                       retval = nconc(retval,
+                                                  create_index_path_group(root,
+                                                                                                  rel,
+                                                                                                  index,
+                                                                                                  joinclausegroups,
+                                                                                                  true));
                        rel->innerjoin = nconc(rel->innerjoin,
                                                                   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;
-
 }
 
 
 /****************************************************************************
- *             ----  ROUTINES TO MATCH 'OR' CLAUSES  ----
+ *             ----  ROUTINES TO PROCESS 'OR' CLAUSES  ----
  ****************************************************************************/
 
 
@@ -202,12 +187,9 @@ create_index_paths(Query *root,
  *
  * 'rel' is the node of the relation on which the index is defined.
  * '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'.
  * 'restrictinfo_list' is the list of available restriction clauses.
- *
- * Returns nothing.
- *
  */
 static void
 match_index_orclauses(RelOptInfo *rel,
@@ -216,72 +198,43 @@ match_index_orclauses(RelOptInfo *rel,
                                          int xclass,
                                          List *restrictinfo_list)
 {
-       RestrictInfo *restrictinfo = (RestrictInfo *) NULL;
-       List       *i = NIL;
+       List       *i;
 
        foreach(i, restrictinfo_list)
        {
-               restrictinfo = (RestrictInfo *) lfirst(i);
+               RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i);
+
                if (valid_or_clause(restrictinfo))
                {
-
                        /*
                         * Mark the 'or' clause with a list of indices which match
-                        * each of its subclauses.      The list is generated by adding
-                        * 'index' to the existing list where appropriate.
+                        * each of its subclauses.      We add entries to the existing
+                        * list, if any.
                         */
-                       restrictinfo->indexids = match_index_orclause(rel, index, indexkey,
-                                                                                                                 xclass,
-                                                                                         restrictinfo->clause->args,
-                                                                                                restrictinfo->indexids);
+                       restrictinfo->indexids =
+                               match_index_orclause(rel, index,
+                                                                        indexkey, xclass,
+                                                                        restrictinfo->clause->args,
+                                                                        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
  *       Attempts to match an index against the subclauses of an 'or' clause.
  *
  *       A match means that:
- *       (1) the operator within the subclause can be used with one
- *                             of the index's operator classes, and
- *       (2) there is a usable key that matches the variable within a
- *                             searchable clause.
+ *       (1) the operator within the subclause can be used with the
+ *                             index's specified operator class, and
+ *       (2) the variable on one side of the subclause matches the index key.
  *
- * '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
  *             that have already been matched to subclauses within this
  *             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
  * a,b,c are nodes of indices that match the first subclause in
@@ -296,14 +249,14 @@ match_index_orclause(RelOptInfo *rel,
                                         List *or_clauses,
                                         List *other_matching_indices)
 {
-       Node       *clause = NULL;
-       List       *matching_indices = other_matching_indices;
-       List       *index_list = NIL;
+       List       *matching_indices;
+       List       *index_list;
        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)
        {
+               matching_indices = NIL;
                foreach(clist, or_clauses)
                        matching_indices = lcons(NIL, matching_indices);
        }
@@ -314,22 +267,14 @@ match_index_orclause(RelOptInfo *rel,
 
        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);
-                       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));
+                       /* OK to add this index to sublist for this subclause */
+                       lfirst(matching_indices) = lcons(index,
+                                                                                        lfirst(matching_indices));
                }
 
                matching_indices = lnext(matching_indices);
@@ -358,26 +303,26 @@ match_index_orclause(RelOptInfo *rel,
 
 /*
  * group_clauses_by_indexkey
- *       Determines whether there are clauses which will match each and every
- *       one of the remaining keys of an index.
+ *       Generates a list of restriction clauses that can be used with an index.
  *
- * 'rel' is the node of the relation corresponding to the index.
- * 'indexkeys' are the remaining index keys to be matched.
+ * 'rel' is the node of the relation itself.
+ * '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.
- * 'clauses' is either:
- *             (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
+ * 'clauses' is the list of available restriction clauses for 'rel'.
  *
- * Returns all possible groups of clauses that will match (given that
- * one or more clauses can match any of the remaining keys).
- * E.g., if you have clauses A, B, and C, ((A B) (A C)) might be
- * returned for an index with 2 keys.
+ * Returns NIL if no clauses can be used with this index.
+ * Otherwise, a list containing a single sublist is returned (indicating
+ * to create_index_path_group() that a single IndexPath should be created).
+ * The sublist is ordered by index key, and contains sublists of clauses
+ * that can be used with that index key.
  *
+ * 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 *
 group_clauses_by_indexkey(RelOptInfo *rel,
@@ -386,60 +331,61 @@ group_clauses_by_indexkey(RelOptInfo *rel,
                                                  Oid *classes,
                                                  List *restrictinfo_list)
 {
-       List       *curCinfo = NIL;
-       RestrictInfo *matched_clause = (RestrictInfo *) NULL;
-       List       *clausegroup = NIL;
-       int                     curIndxKey;
-       Oid                     curClass;
+       List       *clausegroup_list = NIL;
 
        if (restrictinfo_list == NIL || indexkeys[0] == 0)
                return NIL;
 
        do
        {
-               List       *tempgroup = NIL;
-
-               curIndxKey = indexkeys[0];
-               curClass = classes[0];
+               int                     curIndxKey = indexkeys[0];
+               Oid                     curClass = classes[0];
+               List       *clausegroup = NIL;
+               List       *curCinfo;
 
                foreach(curCinfo, restrictinfo_list)
                {
-                       RestrictInfo *temp = (RestrictInfo *) lfirst(curCinfo);
-
-                       matched_clause = match_clause_to_indexkey(rel,
-                                                                                                         index,
-                                                                                                         curIndxKey,
-                                                                                                         curClass,
-                                                                                                         temp,
-                                                                                                         false);
-                       if (!matched_clause)
-                               continue;
-
-                       tempgroup = lappend(tempgroup, matched_clause);
+                       RestrictInfo *rinfo = (RestrictInfo *) lfirst(curCinfo);
+
+                       if (match_clause_to_indexkey(rel,
+                                                                                index,
+                                                                                curIndxKey,
+                                                                                curClass,
+                                                                                rinfo->clause,
+                                                                                false))
+                               clausegroup = lappend(clausegroup, rinfo);
                }
-               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;
 
-               clausegroup = nconc(clausegroup, tempgroup);
+               clausegroup_list = nconc(clausegroup_list, clausegroup);
 
                indexkeys++;
                classes++;
 
        } while (!DoneMatchingIndexKeys(indexkeys, index));
 
-       /* clausegroup holds all matched clauses ordered by indexkeys */
-
-       if (clausegroup != NIL)
-               return lcons(clausegroup, NIL);
+       /* clausegroup_list holds all matched clauses ordered by indexkeys */
+       if (clausegroup_list != NIL)
+               return lcons(clausegroup_list, NIL);
        return NIL;
 }
 
 /*
  * group_clauses_by_ikey_for_joins
- *       special edition of group_clauses_by_indexkey - will
- *       match join & restriction clauses. See comment in indexable_joinclauses.
- *             - vadim 03/18/97
+ *    Generates a list of join clauses that can be used with an index.
  *
+ * 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 *
 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 *restr_cinfo_list)
 {
-       List       *curCinfo = NIL;
-       RestrictInfo *matched_clause = (RestrictInfo *) NULL;
-       List       *clausegroup = NIL;
-       int                     curIndxKey;
-       Oid                     curClass;
+       List       *clausegroup_list = NIL;
        bool            jfound = false;
 
        if (join_cinfo_list == NIL || indexkeys[0] == 0)
@@ -461,150 +403,146 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
 
        do
        {
-               List       *tempgroup = NIL;
-
-               curIndxKey = indexkeys[0];
-               curClass = classes[0];
+               int                     curIndxKey = indexkeys[0];
+               Oid                     curClass = classes[0];
+               List       *clausegroup = NIL;
+               List       *curCinfo;
 
                foreach(curCinfo, join_cinfo_list)
                {
-                       RestrictInfo *temp = (RestrictInfo *) lfirst(curCinfo);
-
-                       matched_clause = match_clause_to_indexkey(rel,
-                                                                                                         index,
-                                                                                                         curIndxKey,
-                                                                                                         curClass,
-                                                                                                         temp,
-                                                                                                         true);
-                       if (!matched_clause)
-                               continue;
-
-                       tempgroup = lappend(tempgroup, matched_clause);
-                       jfound = true;
+                       RestrictInfo *rinfo = (RestrictInfo *) lfirst(curCinfo);
+
+                       if (match_clause_to_indexkey(rel,
+                                                                                index,
+                                                                                curIndxKey,
+                                                                                curClass,
+                                                                                rinfo->clause,
+                                                                                true))
+                       {
+                               clausegroup = lappend(clausegroup, rinfo);
+                               jfound = true;
+                       }
                }
                foreach(curCinfo, restr_cinfo_list)
                {
-                       RestrictInfo *temp = (RestrictInfo *) lfirst(curCinfo);
-
-                       matched_clause = match_clause_to_indexkey(rel,
-                                                                                                         index,
-                                                                                                         curIndxKey,
-                                                                                                         curClass,
-                                                                                                         temp,
-                                                                                                         false);
-                       if (!matched_clause)
-                               continue;
-
-                       tempgroup = lappend(tempgroup, matched_clause);
+                       RestrictInfo *rinfo = (RestrictInfo *) lfirst(curCinfo);
+
+                       if (match_clause_to_indexkey(rel,
+                                                                                index,
+                                                                                curIndxKey,
+                                                                                curClass,
+                                                                                rinfo->clause,
+                                                                                false))
+                               clausegroup = lappend(clausegroup, rinfo);
                }
-               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;
 
-               clausegroup = nconc(clausegroup, tempgroup);
+               clausegroup_list = nconc(clausegroup_list, clausegroup);
 
                indexkeys++;
                classes++;
 
        } 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.
                 */
                if (!jfound)
                {
-                       freeList(clausegroup);
+                       freeList(clausegroup_list);
                        return NIL;
                }
-               return lcons(clausegroup, NIL);
+               return lcons(clausegroup_list, 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
- *             equal_indexkey_var(indkeys,opnd) : \
- * above, and now
- *             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.
+ * match_clause_to_indexkey()
+ *    Determines whether a restriction or join clause matches
+ *    a key of an index.
  *
  *       To match, the clause must:
- *       (1) be in the form (op var const) if the clause is a single-
- *                             relation clause, and
+ *       (1) be in the form (var op const) for a restriction clause,
+ *               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
- *                             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!!
  *
- * Returns a single restrictinfo node corresponding to the matching
- * clause.
+ *       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!
  *
- * NOTE:  returns nil if clause is an or_clause.
+ * 'rel' is the relation of interest.
+ * '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.
  *
+ * 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,
                                                 RelOptInfo *index,
                                                 int indexkey,
                                                 int xclass,
-                                                RestrictInfo *restrictInfo,
+                                                Expr *clause,
                                                 bool join)
 {
-       Expr       *clause = restrictInfo->clause;
+       bool            isIndexable = false;
        Var                *leftop,
                           *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);
        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)
        {
+               /*
+                * 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
                 */
-               if ((rightop && IsA(rightop, Const)) ||
-                       (rightop && IsA(rightop, Param)))
+               if (IsA(rightop, Const) || IsA(rightop, Param))
                {
                        restrict_op = ((Oper *) ((Expr *) clause)->oper)->opno;
 
                        isIndexable = (op_class(restrict_op, xclass, index->relam) &&
-                                                  IndexScanableOperand(leftop,
-                                                                                               indexkey,
-                                                                                               rel,
-                                                                                               index));
+                                                  match_index_to_operand(indexkey,
+                                                                                                 (Expr *) leftop,
+                                                                                                 rel,
+                                                                                                 index));
 
 #ifndef IGNORE_BINARY_COMPATIBLE_INDICES
 
@@ -614,11 +552,8 @@ match_clause_to_indexkey(RelOptInfo *rel,
                         */
                        if (!isIndexable)
                        {
-                               Oid                     ltype;
-                               Oid                     rtype;
-
-                               ltype = exprType((Node *) leftop);
-                               rtype = exprType((Node *) rightop);
+                               Oid                     ltype = exprType((Node *) leftop);
+                               Oid                     rtype = exprType((Node *) rightop);
 
                                /*
                                 * make sure we have two different binary-compatible
@@ -637,15 +572,16 @@ match_clause_to_indexkey(RelOptInfo *rel,
                                                newop = NULL;
 
                                        /* 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);
 
                                                isIndexable = (op_class(restrict_op, xclass, index->relam) &&
-                                                                          IndexScanableOperand(leftop,
-                                                                                                                       indexkey,
-                                                                                                                       rel,
-                                                                                                                       index));
+                                                                          match_index_to_operand(indexkey,
+                                                                                                                         (Expr *) leftop,
+                                                                                                                         rel,
+                                                                                                                         index));
 
                                                if (isIndexable)
                                                        ((Oper *) ((Expr *) clause)->oper)->opno = restrict_op;
@@ -658,15 +594,16 @@ match_clause_to_indexkey(RelOptInfo *rel,
                /*
                 * Must try to commute the clause to standard s-arg format.
                 */
-               else if ((leftop && IsA(leftop, Const)) ||
-                                (leftop && IsA(leftop, Param)))
+               else if (IsA(leftop, Const) || IsA(leftop, Param))
                {
                        restrict_op = get_commutator(((Oper *) ((Expr *) clause)->oper)->opno);
 
                        isIndexable = ((restrict_op != InvalidOid) &&
                                                   op_class(restrict_op, xclass, index->relam) &&
-                                                  IndexScanableOperand(rightop,
-                                                                                               indexkey, rel, index));
+                                                  match_index_to_operand(indexkey,
+                                                                                                 (Expr *) rightop,
+                                                                                                 rel,
+                                                                                                 index));
 
 #ifndef IGNORE_BINARY_COMPATIBLE_INDICES
                        if (!isIndexable)
@@ -697,10 +634,10 @@ match_clause_to_indexkey(RelOptInfo *rel,
 
                                                isIndexable = ((restrict_op != InvalidOid) &&
                                                   op_class(restrict_op, xclass, index->relam) &&
-                                                                          IndexScanableOperand(rightop,
-                                                                                                                       indexkey,
-                                                                                                                       rel,
-                                                                                                                       index));
+                                                                          match_index_to_operand(indexkey,
+                                                                                                                         (Expr *) rightop,
+                                                                                                                         rel,
+                                                                                                                         index));
 
                                                if (isIndexable)
                                                        ((Oper *) ((Expr *) clause)->oper)->opno = oprid(newop);
@@ -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
        {
-               if (rightop
-               && match_index_to_operand(indexkey, (Expr *) rightop, rel, index))
-               {
-                       join_op = get_commutator(((Oper *) ((Expr *) clause)->oper)->opno);
+               /*
+                * Check for an indexable scan on one of the join relations.
+                * clause is of the form (operator var/func var/func)
+                *  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;
 
-               }
-               else if (leftop
-                                && match_index_to_operand(indexkey,
-                                                                                  (Expr *) leftop, rel, index))
+               if (match_index_to_operand(indexkey, (Expr *) leftop,
+                                                                  rel, index))
                        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) &&
                        is_joinable((Node *) clause))
-               {
                        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 restrictInfo;
-
-       return NULL;
+       return isIndexable;
 }
 
 /****************************************************************************
@@ -960,7 +885,8 @@ one_pred_clause_test(Expr *predicate, Node *clause)
  * 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},
        {1, 2, 0, 0, 0},
        {1, 2, 3, 4, 5},
@@ -1179,14 +1105,13 @@ static List *
 indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
                                          List *joininfo_list, List *restrictinfo_list)
 {
-       JoinInfo   *joininfo = (JoinInfo *) NULL;
        List       *cg_list = NIL;
-       List       *i = NIL;
-       List       *clausegroups = NIL;
+       List       *i;
 
        foreach(i, joininfo_list)
        {
-               joininfo = (JoinInfo *) lfirst(i);
+               JoinInfo   *joininfo = (JoinInfo *) lfirst(i);
+               List       *clausegroups;
 
                if (joininfo->jinfo_restrictinfo == NIL)
                        continue;
@@ -1202,8 +1127,8 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
                        List       *clauses = lfirst(clausegroups);
 
                        ((RestrictInfo *) lfirst(clauses))->restrictinfojoinid = joininfo->unjoined_relids;
+                       cg_list = nconc(cg_list, clausegroups);
                }
-               cg_list = nconc(cg_list, clausegroups);
        }
        return cg_list;
 }
@@ -1212,30 +1137,6 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
  *                             ----  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
  *       Creates index path nodes corresponding to paths to be used as inner
@@ -1251,22 +1152,19 @@ static List *
 index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
                                RelOptInfo *index)
 {
-       List       *clausegroup = NIL;
-       List       *cg_list = NIL;
-       List       *i = NIL;
-       IndexPath  *pathnode = (IndexPath *) NULL;
-       Cost            temp_selec;
-       float           temp_pages;
+       List       *path_list = NIL;
+       List       *i;
 
        foreach(i, clausegroup_list)
        {
+               List       *clausegroup = lfirst(i);
+               IndexPath  *pathnode = makeNode(IndexPath);
+               Cost            temp_selec;
+               float           temp_pages;
                List       *attnos,
                                   *values,
                                   *flags;
 
-               clausegroup = lfirst(i);
-               pathnode = makeNode(IndexPath);
-
                get_joinvars(lfirsti(rel->relids), clausegroup,
                                         &attnos, &values, &flags);
                index_selectivity(lfirsti(index->relids),
@@ -1315,9 +1213,9 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
                if (XfuncMode != XFUNC_OFF)
                        ((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path *) pathnode);
 #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,
                                                List *clausegroup_list,
                                                bool join)
 {
-       List       *clausegroup = NIL;
-       List       *ip_list = NIL;
-       List       *i = NIL;
-       List       *j = NIL;
-       IndexPath  *temp_path;
+       List       *path_list = NIL;
+       List       *i;
 
        foreach(i, clausegroup_list)
        {
-               RestrictInfo *restrictinfo;
-               bool            temp = true;
-
-               clausegroup = lfirst(i);
+               List       *clausegroup = lfirst(i);
+               bool            usable = true;
 
-               foreach(j, clausegroup)
+               if (join)
                {
-                       restrictinfo = (RestrictInfo *) lfirst(j);
-                       if (!(is_joinable((Node *) restrictinfo->clause) &&
-                                 equal_path_merge_ordering(index->ordering,
-                                                                                 restrictinfo->mergejoinorder)))
-                               temp = false;
+                       List       *j;
+
+                       foreach(j, clausegroup)
+                       {
+                               RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(j);
+                               if (!(is_joinable((Node *) restrictinfo->clause) &&
+                                         equal_path_merge_ordering(index->ordering,
+                                                                                               restrictinfo->mergejoinorder)))
+                               {
+                                       usable = false;
+                                       break;
+                               }
+                       }
                }
 
-               if (!join || temp)
-               {                                               /* restriction, ordering scan */
-                       temp_path = create_index_path(root, rel, index, clausegroup, join);
-                       ip_list = lappend(ip_list, temp_path);
+               if (usable)
+               {
+                       path_list = lappend(path_list,
+                                                               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
@@ -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.
         * numbers in the right order.
         *
-        *
         * 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
         * compare range table entry numbers, they must be the same.
@@ -1425,7 +1350,6 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index)
        i = 0;
        foreach(arg, funcargs)
        {
-
                if (indexKeys[i] == 0)
                        return false;