Allow binary-compatible indices to be considered when checking for valid
authorThomas G. Lockhart
Fri, 14 Aug 1998 16:13:07 +0000 (16:13 +0000)
committerThomas G. Lockhart
Fri, 14 Aug 1998 16:13:07 +0000 (16:13 +0000)
 indices for restriction clauses containing a constant.
Note that if an index does not match directly (usually because the types
 on both side of the clause don't match), and if a binary-compatible index
 is identified, then the operator function will be replaced by a new
 one. Should not be a problem, but be sure that if types are listed as
 being binary compatible (in parse_coerce.h) then the comparison functions
 are also binary-compatible, giving equivalent results.

src/backend/optimizer/path/indxpath.c

index 2932f82b7ecd1310bc164c36b2d730924d09570e..41583a1c1c6b54a8c017770f30e33c6697554612 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.28 1998/08/11 19:32:37 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.29 1998/08/14 16:13:07 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,6 +39,9 @@
 #include "optimizer/pathnode.h"
 #include "optimizer/xfunc.h"
 #include "parser/parsetree.h"  /* for getrelid() */
+#include "parser/parse_expr.h" /* for exprType() */
+#include "parser/parse_oper.h" /* for oprid() and oper() */
+#include "parser/parse_coerce.h"   /* for IS_BINARY_COMPATIBLE() */
 #include "utils/lsyscache.h"
 
 
@@ -80,8 +83,7 @@ static List *add_index_paths(List *indexpaths, List *new_indexpaths);
 static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index);
 
 
-/*
- * find-index-paths--
+/* find_index_paths()
  *   Finds all possible index paths by determining which indices in the
  *   list 'indices' are usable.
  *
@@ -120,16 +122,16 @@ find_index_paths(Query *root,
    List       *joinpaths = NIL;
    List       *retval = NIL;
    List       *ilist;
-   
+
    foreach(ilist, indices)
    {
        index = (RelOptInfo *) lfirst(ilist);
-   
+
        /* If this is a partial index, return if it fails the predicate test */
        if (index->indpred != NIL)
            if (!pred_test(index->indpred, clauseinfo_list, joininfo_list))
                continue;
-   
+
        /*
         * 1. Try matching the index against subclauses of an 'or' clause.
         * The fields of the clauseinfo nodes are marked with lists of the
@@ -143,7 +145,7 @@ find_index_paths(Query *root,
                                  index->indexkeys[0],
                                  index->classlist[0],
                                  clauseinfo_list);
-   
+
        /*
         * 2. If the keys of this index match any of the available restriction
         * clauses, then create pathnodes corresponding to each group of
@@ -154,7 +156,7 @@ find_index_paths(Query *root,
                                                     index->indexkeys,
                                                     index->classlist,
                                                     clauseinfo_list);
-   
+
        scanpaths = NIL;
        if (scanclausegroups != NIL)
            scanpaths = create_index_paths(root,
@@ -162,7 +164,7 @@ find_index_paths(Query *root,
                                           index,
                                           scanclausegroups,
                                           false);
-   
+
        /*
         * 3. If this index can be used with any join clause, then create
         * pathnodes for each group of usable clauses.  An index can be used
@@ -172,7 +174,7 @@ find_index_paths(Query *root,
         */
        joinclausegroups = indexable_joinclauses(rel, index, joininfo_list, clauseinfo_list);
        joinpaths = NIL;
-   
+
        if (joinclausegroups != NIL)
        {
            List       *new_join_paths = create_index_paths(root, rel,
@@ -180,11 +182,11 @@ find_index_paths(Query *root,
                                                            joinclausegroups,
                                                            true);
            List       *innerjoin_paths = index_innerjoin(root, rel, joinclausegroups, index);
-   
+
            rel->innerjoin = nconc(rel->innerjoin, innerjoin_paths);
            joinpaths = new_join_paths;
        }
-   
+
        /*
         * Some sanity checks to make sure that the indexpath is valid.
         */
@@ -193,7 +195,7 @@ find_index_paths(Query *root,
        if (scanpaths != NULL)
            retval = add_index_paths(scanpaths, retval);
    }
-   
+
    return retval;
 
 }
@@ -252,8 +254,7 @@ match_index_orclauses(RelOptInfo *rel,
    }
 }
 
-/*
- * match_index_operand--
+/* 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.
@@ -264,17 +265,22 @@ match_index_to_operand(int indexkey,
                       RelOptInfo *rel,
                       RelOptInfo *index)
 {
+   bool    result;
 
    /*
     * Normal index.
     */
    if (index->indproc == InvalidOid)
-       return match_indexkey_operand(indexkey, (Var *) operand, rel);
+   {
+       result = match_indexkey_operand(indexkey, (Var *) operand, rel);
+       return result;
+   }
 
    /*
     * functional index check
     */
-   return (function_index_operand(operand, rel, index));
+   result = function_index_operand(operand, rel, index);
+   return result;
 }
 
 /*
@@ -320,7 +326,7 @@ match_index_orclause(RelOptInfo *rel,
    else    matching_indices = other_matching_indices;
 
    index_list = matching_indices;
-   
+
    foreach(clist, or_clauses)
    {
        clause = lfirst(clist);
@@ -555,8 +561,7 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
  * - vadim 01/22/97
  */
 
-/*
- * match_clause_to-indexkey--
+/* match_clause_to_indexkey()
  *   Finds the first of a relation's available restriction clauses that
  *   matches a key of an index.
  *
@@ -609,11 +614,56 @@ match_clause_to_indexkey(RelOptInfo *rel,
            (rightop && IsA(rightop, Param)))
        {
            restrict_op = ((Oper *) ((Expr *) clause)->oper)->opno;
+
            isIndexable = (op_class(restrict_op, xclass, index->relam) &&
-                           IndexScanableOperand(leftop,
+                          IndexScanableOperand(leftop,
+                                               indexkey,
+                                               rel,
+                                               index));
+
+#ifndef IGNORE_BINARY_COMPATIBLE_INDICES
+           /* Didn't find an index?
+            * Then maybe we can find another binary-compatible index instead...
+            * thomas 1998-08-14
+            */
+           if (! isIndexable)
+           {
+               Oid   ltype;
+               Oid   rtype;
+
+               ltype = exprType((Node *)leftop);
+               rtype = exprType((Node *)rightop);
+
+               /* make sure we have two different binary-compatible types... */
+               if ((ltype != rtype)
+                && IS_BINARY_COMPATIBLE(ltype, rtype))
+               {
+                   char     *opname;
+                   Operator  newop;
+
+                   opname = get_opname(restrict_op);
+                   newop = oper(opname, ltype, ltype, TRUE);
+
+                   /* actually have a different operator to try? */
+                   if (HeapTupleIsValid(newop) && (oprid(newop) != restrict_op))
+                   {
+                       restrict_op = oprid(newop);
+
+                       isIndexable =
+                           (op_class(restrict_op, xclass, index->relam) &&
+                            IndexScanableOperand(leftop,
                                                  indexkey,
                                                  rel,
                                                  index));
+
+                       if (isIndexable)
+                       {
+                           ((Oper *) ((Expr *) clause)->oper)->opno = restrict_op;
+                       }
+                   }
+               }
+           }
+#endif
        }
 
        /*
@@ -625,13 +675,54 @@ match_clause_to_indexkey(RelOptInfo *rel,
            restrict_op =
                get_commutator(((Oper *) ((Expr *) clause)->oper)->opno);
 
-           if ((restrict_op != InvalidOid) &&
+           isIndexable = ((restrict_op != InvalidOid) &&
                op_class(restrict_op, xclass, index->relam) &&
                IndexScanableOperand(rightop,
-                                    indexkey, rel, index))
+                                    indexkey, rel, index));
+
+#ifndef IGNORE_BINARY_COMPATIBLE_INDICES
+           if (! isIndexable)
            {
-               isIndexable = true;
+               Oid   ltype;
+               Oid   rtype;
+
+               ltype = exprType((Node *)leftop);
+               rtype = exprType((Node *)rightop);
+
+               if ((ltype != rtype)
+                && IS_BINARY_COMPATIBLE(ltype, rtype))
+               {
+                   char     *opname;
+                   Operator  newop;
+
+                   restrict_op = ((Oper *) ((Expr *) clause)->oper)->opno;
+
+                   opname = get_opname(restrict_op);
+                   newop = oper(opname, rtype, rtype, TRUE);
+
+                   if (HeapTupleIsValid(newop) && (oprid(newop) != restrict_op))
+                   {
+                       restrict_op =
+                           get_commutator(oprid(newop));
+
+                       isIndexable = ((restrict_op != InvalidOid) &&
+                                       op_class(restrict_op, xclass, index->relam) &&
+                                       IndexScanableOperand(rightop,
+                                                            indexkey,
+                                                            rel,
+                                                            index));
+
+                       if (isIndexable)
+                       {
+                           ((Oper *) ((Expr *) clause)->oper)->opno = oprid(newop);
+                       }
+                   }
+               }
+           }
+#endif
 
+           if (isIndexable)
+           {
                /*
                 * In place list modification. (op const var/func) -> (op
                 * var/func const)