Allow binary-compatible indices to be considered when checking for valid

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.
This commit is contained in:
Thomas G. Lockhart 1998-08-14 16:13:07 +00:00
parent 94f42ed389
commit 6912beea70

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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/pathnode.h"
#include "optimizer/xfunc.h" #include "optimizer/xfunc.h"
#include "parser/parsetree.h" /* for getrelid() */ #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" #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); 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 * Finds all possible index paths by determining which indices in the
* list 'indices' are usable. * list 'indices' are usable.
* *
@ -120,16 +122,16 @@ find_index_paths(Query *root,
List *joinpaths = NIL; List *joinpaths = NIL;
List *retval = NIL; List *retval = NIL;
List *ilist; List *ilist;
foreach(ilist, indices) foreach(ilist, indices)
{ {
index = (RelOptInfo *) lfirst(ilist); index = (RelOptInfo *) lfirst(ilist);
/* If this is a partial index, return if it fails the predicate test */ /* If this is a partial index, return if it fails the predicate test */
if (index->indpred != NIL) if (index->indpred != NIL)
if (!pred_test(index->indpred, clauseinfo_list, joininfo_list)) if (!pred_test(index->indpred, clauseinfo_list, joininfo_list))
continue; continue;
/* /*
* 1. Try matching the index against subclauses of an 'or' clause. * 1. Try matching the index against subclauses of an 'or' clause.
* The fields of the clauseinfo nodes are marked with lists of the * 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->indexkeys[0],
index->classlist[0], index->classlist[0],
clauseinfo_list); clauseinfo_list);
/* /*
* 2. If the keys of this index match any of the available restriction * 2. If the keys of this index match any of the available restriction
* clauses, then create pathnodes corresponding to each group of * clauses, then create pathnodes corresponding to each group of
@ -154,7 +156,7 @@ find_index_paths(Query *root,
index->indexkeys, index->indexkeys,
index->classlist, index->classlist,
clauseinfo_list); clauseinfo_list);
scanpaths = NIL; scanpaths = NIL;
if (scanclausegroups != NIL) if (scanclausegroups != NIL)
scanpaths = create_index_paths(root, scanpaths = create_index_paths(root,
@ -162,7 +164,7 @@ find_index_paths(Query *root,
index, index,
scanclausegroups, scanclausegroups,
false); false);
/* /*
* 3. If this index can be used with any join clause, then create * 3. If this index can be used with any join clause, then create
* pathnodes for each group of usable clauses. An index can be used * 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); joinclausegroups = indexable_joinclauses(rel, index, joininfo_list, clauseinfo_list);
joinpaths = NIL; joinpaths = NIL;
if (joinclausegroups != NIL) if (joinclausegroups != NIL)
{ {
List *new_join_paths = create_index_paths(root, rel, List *new_join_paths = create_index_paths(root, rel,
@ -180,11 +182,11 @@ find_index_paths(Query *root,
joinclausegroups, joinclausegroups,
true); true);
List *innerjoin_paths = index_innerjoin(root, rel, joinclausegroups, index); List *innerjoin_paths = index_innerjoin(root, rel, joinclausegroups, index);
rel->innerjoin = nconc(rel->innerjoin, innerjoin_paths); rel->innerjoin = nconc(rel->innerjoin, innerjoin_paths);
joinpaths = new_join_paths; joinpaths = new_join_paths;
} }
/* /*
* Some sanity checks to make sure that the indexpath is valid. * Some sanity checks to make sure that the indexpath is valid.
*/ */
@ -193,7 +195,7 @@ find_index_paths(Query *root,
if (scanpaths != NULL) if (scanpaths != NULL)
retval = add_index_paths(scanpaths, retval); retval = add_index_paths(scanpaths, retval);
} }
return retval; return retval;
} }
@ -252,8 +254,7 @@ match_index_orclauses(RelOptInfo *rel,
} }
} }
/* /* match_index_to_operand()
* match_index_operand--
* Generalize test for a match between an existing index's key * Generalize test for a match between an existing index's key
* and the operand on the rhs of a restriction clause. Now check * and the operand on the rhs of a restriction clause. Now check
* for functional indices as well. * for functional indices as well.
@ -264,17 +265,22 @@ match_index_to_operand(int indexkey,
RelOptInfo *rel, RelOptInfo *rel,
RelOptInfo *index) RelOptInfo *index)
{ {
bool result;
/* /*
* Normal index. * Normal index.
*/ */
if (index->indproc == InvalidOid) 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 * 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; else matching_indices = other_matching_indices;
index_list = matching_indices; index_list = matching_indices;
foreach(clist, or_clauses) foreach(clist, or_clauses)
{ {
clause = lfirst(clist); clause = lfirst(clist);
@ -555,8 +561,7 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
* - vadim 01/22/97 * - vadim 01/22/97
*/ */
/* /* match_clause_to_indexkey()
* match_clause_to-indexkey--
* Finds the first of a relation's available restriction clauses that * Finds the first of a relation's available restriction clauses that
* matches a key of an index. * matches a key of an index.
* *
@ -609,11 +614,56 @@ match_clause_to_indexkey(RelOptInfo *rel,
(rightop && IsA(rightop, Param))) (rightop && IsA(rightop, Param)))
{ {
restrict_op = ((Oper *) ((Expr *) clause)->oper)->opno; restrict_op = ((Oper *) ((Expr *) clause)->oper)->opno;
isIndexable = (op_class(restrict_op, xclass, index->relam) && isIndexable = (op_class(restrict_op, xclass, index->relam) &&
IndexScanableOperand(leftop, 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, indexkey,
rel, rel,
index)); index));
if (isIndexable)
{
((Oper *) ((Expr *) clause)->oper)->opno = restrict_op;
}
}
}
}
#endif
} }
/* /*
@ -625,13 +675,54 @@ match_clause_to_indexkey(RelOptInfo *rel,
restrict_op = restrict_op =
get_commutator(((Oper *) ((Expr *) clause)->oper)->opno); get_commutator(((Oper *) ((Expr *) clause)->oper)->opno);
if ((restrict_op != InvalidOid) && isIndexable = ((restrict_op != InvalidOid) &&
op_class(restrict_op, xclass, index->relam) && op_class(restrict_op, xclass, index->relam) &&
IndexScanableOperand(rightop, IndexScanableOperand(rightop,
indexkey, rel, index)) indexkey, rel, index));
{
isIndexable = true;
#ifndef IGNORE_BINARY_COMPATIBLE_INDICES
if (! isIndexable)
{
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 * In place list modification. (op const var/func) -> (op
* var/func const) * var/func const)