From 348bdbce7942324dd19349d4d6f3f7dabae219c3 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 23 Jul 1999 03:34:49 +0000
Subject: [PATCH] Minor code beautification, extensive improvement of comments.
  This file was full of obsolete and just plain wrong commentary...

---
 src/backend/optimizer/path/indxpath.c | 668 ++++++++++++--------------
 1 file changed, 296 insertions(+), 372 deletions(-)

diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 2fc7d07060c..c539b1f9051 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,16 +40,15 @@
 
 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;
 
-- 
GitLab