Commit 5f68d5c3 authored by Tom Lane's avatar Tom Lane

Clean up loose end in LIKE optimization fix: parser's code would generate

<= and >= indexquals from a LIKE even if the index in question didn't
support those operators.  (As, for example, a hash index does not.)
parent 2784a5ae
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.73 1999/11/22 17:56:07 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.74 1999/12/31 03:41:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -44,21 +44,27 @@ typedef enum { ...@@ -44,21 +44,27 @@ typedef enum {
Prefix_None, Prefix_Partial, Prefix_Exact Prefix_None, Prefix_Partial, Prefix_Exact
} Prefix_Status; } Prefix_Status;
static void match_index_orclauses(RelOptInfo *rel, RelOptInfo *index, int indexkey, static void match_index_orclauses(RelOptInfo *rel, RelOptInfo *index,
int xclass, List *restrictinfo_list); int indexkey, Oid opclass,
static List *match_index_orclause(RelOptInfo *rel, RelOptInfo *index, int indexkey, List *restrictinfo_list);
int xclass, List *or_clauses, List *other_matching_indices); static List *match_index_orclause(RelOptInfo *rel, RelOptInfo *index,
int indexkey, Oid opclass,
List *or_clauses,
List *other_matching_indices);
static bool match_or_subclause_to_indexkey(RelOptInfo *rel, RelOptInfo *index, static bool match_or_subclause_to_indexkey(RelOptInfo *rel, RelOptInfo *index,
int indexkey, int xclass, int indexkey, Oid opclass,
Expr *clause); Expr *clause);
static List *group_clauses_by_indexkey(RelOptInfo *rel, RelOptInfo *index, static List *group_clauses_by_indexkey(RelOptInfo *rel, RelOptInfo *index,
int *indexkeys, Oid *classes, List *restrictinfo_list); int *indexkeys, Oid *classes,
List *restrictinfo_list);
static List *group_clauses_by_ikey_for_joins(RelOptInfo *rel, RelOptInfo *index, static List *group_clauses_by_ikey_for_joins(RelOptInfo *rel, RelOptInfo *index,
int *indexkeys, Oid *classes, List *join_cinfo_list, List *restr_cinfo_list); int *indexkeys, Oid *classes,
List *join_cinfo_list,
List *restr_cinfo_list);
static bool match_clause_to_indexkey(RelOptInfo *rel, RelOptInfo *index, static bool match_clause_to_indexkey(RelOptInfo *rel, RelOptInfo *index,
int indexkey, int xclass, int indexkey, Oid opclass,
Expr *clause, bool join); Expr *clause, bool join);
static bool indexable_operator(Expr *clause, int xclass, Oid relam, static bool indexable_operator(Expr *clause, Oid opclass, Oid relam,
bool indexkey_on_left); bool indexkey_on_left);
static bool pred_test(List *predicate_list, List *restrictinfo_list, static bool pred_test(List *predicate_list, List *restrictinfo_list,
List *joininfo_list); List *joininfo_list);
...@@ -77,13 +83,16 @@ static bool useful_for_ordering(Query *root, RelOptInfo *rel, ...@@ -77,13 +83,16 @@ static bool useful_for_ordering(Query *root, RelOptInfo *rel,
RelOptInfo *index); RelOptInfo *index);
static bool match_index_to_operand(int indexkey, Var *operand, static bool match_index_to_operand(int indexkey, Var *operand,
RelOptInfo *rel, RelOptInfo *index); RelOptInfo *rel, RelOptInfo *index);
static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index); static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel,
static bool match_special_index_operator(Expr *clause, bool indexkey_on_left); RelOptInfo *index);
static bool match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
bool indexkey_on_left);
static Prefix_Status like_fixed_prefix(char *patt, char **prefix); static Prefix_Status like_fixed_prefix(char *patt, char **prefix);
static Prefix_Status regex_fixed_prefix(char *patt, bool case_insensitive, static Prefix_Status regex_fixed_prefix(char *patt, bool case_insensitive,
char **prefix); char **prefix);
static List *prefix_quals(Var *leftop, Oid expr_op, static List *prefix_quals(Var *leftop, Oid expr_op,
char *prefix, Prefix_Status pstatus); char *prefix, Prefix_Status pstatus);
static Oid find_operator(const char * opname, Oid datatype);
/* /*
...@@ -255,7 +264,7 @@ static void ...@@ -255,7 +264,7 @@ static void
match_index_orclauses(RelOptInfo *rel, match_index_orclauses(RelOptInfo *rel,
RelOptInfo *index, RelOptInfo *index,
int indexkey, int indexkey,
int xclass, Oid opclass,
List *restrictinfo_list) List *restrictinfo_list)
{ {
List *i; List *i;
...@@ -272,7 +281,7 @@ match_index_orclauses(RelOptInfo *rel, ...@@ -272,7 +281,7 @@ match_index_orclauses(RelOptInfo *rel,
*/ */
restrictinfo->subclauseindices = restrictinfo->subclauseindices =
match_index_orclause(rel, index, match_index_orclause(rel, index,
indexkey, xclass, indexkey, opclass,
restrictinfo->clause->args, restrictinfo->clause->args,
restrictinfo->subclauseindices); restrictinfo->subclauseindices);
} }
...@@ -304,7 +313,7 @@ static List * ...@@ -304,7 +313,7 @@ static List *
match_index_orclause(RelOptInfo *rel, match_index_orclause(RelOptInfo *rel,
RelOptInfo *index, RelOptInfo *index,
int indexkey, int indexkey,
int xclass, Oid opclass,
List *or_clauses, List *or_clauses,
List *other_matching_indices) List *other_matching_indices)
{ {
...@@ -330,7 +339,7 @@ match_index_orclause(RelOptInfo *rel, ...@@ -330,7 +339,7 @@ match_index_orclause(RelOptInfo *rel,
{ {
Expr *clause = lfirst(clist); Expr *clause = lfirst(clist);
if (match_or_subclause_to_indexkey(rel, index, indexkey, xclass, if (match_or_subclause_to_indexkey(rel, index, indexkey, opclass,
clause)) clause))
{ {
/* OK to add this index to sublist for this subclause */ /* OK to add this index to sublist for this subclause */
...@@ -355,7 +364,7 @@ static bool ...@@ -355,7 +364,7 @@ static bool
match_or_subclause_to_indexkey(RelOptInfo *rel, match_or_subclause_to_indexkey(RelOptInfo *rel,
RelOptInfo *index, RelOptInfo *index,
int indexkey, int indexkey,
int xclass, Oid opclass,
Expr *clause) Expr *clause)
{ {
if (and_clause((Node *) clause)) if (and_clause((Node *) clause))
...@@ -364,14 +373,14 @@ match_or_subclause_to_indexkey(RelOptInfo *rel, ...@@ -364,14 +373,14 @@ match_or_subclause_to_indexkey(RelOptInfo *rel,
foreach(item, clause->args) foreach(item, clause->args)
{ {
if (! match_clause_to_indexkey(rel, index, indexkey, xclass, if (! match_clause_to_indexkey(rel, index, indexkey, opclass,
lfirst(item), false)) lfirst(item), false))
return false; return false;
} }
return true; return true;
} }
else else
return match_clause_to_indexkey(rel, index, indexkey, xclass, return match_clause_to_indexkey(rel, index, indexkey, opclass,
clause, false); clause, false);
} }
...@@ -588,7 +597,7 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel, ...@@ -588,7 +597,7 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
* 'rel' is the relation of interest. * 'rel' is the relation of interest.
* 'index' is an index on 'rel'. * 'index' is an index on 'rel'.
* 'indexkey' is a key of 'index'. * 'indexkey' is a key of 'index'.
* 'xclass' is the corresponding operator class. * 'opclass' is the corresponding operator class.
* 'clause' is the clause to be tested. * 'clause' is the clause to be tested.
* 'join' is true if we are considering this clause for joins. * 'join' is true if we are considering this clause for joins.
* *
...@@ -601,7 +610,7 @@ static bool ...@@ -601,7 +610,7 @@ static bool
match_clause_to_indexkey(RelOptInfo *rel, match_clause_to_indexkey(RelOptInfo *rel,
RelOptInfo *index, RelOptInfo *index,
int indexkey, int indexkey,
int xclass, Oid opclass,
Expr *clause, Expr *clause,
bool join) bool join)
{ {
...@@ -627,26 +636,28 @@ match_clause_to_indexkey(RelOptInfo *rel, ...@@ -627,26 +636,28 @@ match_clause_to_indexkey(RelOptInfo *rel,
if ((IsA(rightop, Const) || IsA(rightop, Param)) && if ((IsA(rightop, Const) || IsA(rightop, Param)) &&
match_index_to_operand(indexkey, leftop, rel, index)) match_index_to_operand(indexkey, leftop, rel, index))
{ {
if (indexable_operator(clause, xclass, index->relam, true)) if (indexable_operator(clause, opclass, index->relam, true))
return true; return true;
/* /*
* If we didn't find a member of the index's opclass, * If we didn't find a member of the index's opclass,
* see whether it is a "special" indexable operator. * see whether it is a "special" indexable operator.
*/ */
if (match_special_index_operator(clause, true)) if (match_special_index_operator(clause, opclass, index->relam,
true))
return true; return true;
return false; return false;
} }
if ((IsA(leftop, Const) || IsA(leftop, Param)) && if ((IsA(leftop, Const) || IsA(leftop, Param)) &&
match_index_to_operand(indexkey, rightop, rel, index)) match_index_to_operand(indexkey, rightop, rel, index))
{ {
if (indexable_operator(clause, xclass, index->relam, false)) if (indexable_operator(clause, opclass, index->relam, false))
return true; return true;
/* /*
* If we didn't find a member of the index's opclass, * If we didn't find a member of the index's opclass,
* see whether it is a "special" indexable operator. * see whether it is a "special" indexable operator.
*/ */
if (match_special_index_operator(clause, false)) if (match_special_index_operator(clause, opclass, index->relam,
false))
return true; return true;
return false; return false;
} }
...@@ -666,7 +677,7 @@ match_clause_to_indexkey(RelOptInfo *rel, ...@@ -666,7 +677,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
isIndexable = ! intMember(lfirsti(rel->relids), othervarnos); isIndexable = ! intMember(lfirsti(rel->relids), othervarnos);
freeList(othervarnos); freeList(othervarnos);
if (isIndexable && if (isIndexable &&
indexable_operator(clause, xclass, index->relam, true)) indexable_operator(clause, opclass, index->relam, true))
return true; return true;
} }
else if (match_index_to_operand(indexkey, rightop, rel, index)) else if (match_index_to_operand(indexkey, rightop, rel, index))
...@@ -677,7 +688,7 @@ match_clause_to_indexkey(RelOptInfo *rel, ...@@ -677,7 +688,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
isIndexable = ! intMember(lfirsti(rel->relids), othervarnos); isIndexable = ! intMember(lfirsti(rel->relids), othervarnos);
freeList(othervarnos); freeList(othervarnos);
if (isIndexable && if (isIndexable &&
indexable_operator(clause, xclass, index->relam, false)) indexable_operator(clause, opclass, index->relam, false))
return true; return true;
} }
} }
...@@ -706,7 +717,7 @@ match_clause_to_indexkey(RelOptInfo *rel, ...@@ -706,7 +717,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
* a tad ugly... * a tad ugly...
*/ */
static bool static bool
indexable_operator(Expr *clause, int xclass, Oid relam, indexable_operator(Expr *clause, Oid opclass, Oid relam,
bool indexkey_on_left) bool indexkey_on_left)
{ {
Oid expr_op = ((Oper *) clause->oper)->opno; Oid expr_op = ((Oper *) clause->oper)->opno;
...@@ -723,7 +734,7 @@ indexable_operator(Expr *clause, int xclass, Oid relam, ...@@ -723,7 +734,7 @@ indexable_operator(Expr *clause, int xclass, Oid relam,
return false; return false;
/* Done if the (commuted) operator is a member of the index's AM */ /* Done if the (commuted) operator is a member of the index's AM */
if (op_class(commuted_op, xclass, relam)) if (op_class(commuted_op, opclass, relam))
return true; return true;
/* /*
...@@ -766,7 +777,7 @@ indexable_operator(Expr *clause, int xclass, Oid relam, ...@@ -766,7 +777,7 @@ indexable_operator(Expr *clause, int xclass, Oid relam,
if (commuted_op == InvalidOid) if (commuted_op == InvalidOid)
return false; return false;
if (op_class(commuted_op, xclass, relam)) if (op_class(commuted_op, opclass, relam))
{ {
/* /*
* Success! Change the opclause to use the * Success! Change the opclause to use the
...@@ -1561,7 +1572,8 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index) ...@@ -1561,7 +1572,8 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index)
* Return 'true' if we can do something with it anyway. * Return 'true' if we can do something with it anyway.
*/ */
static bool static bool
match_special_index_operator(Expr *clause, bool indexkey_on_left) match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
bool indexkey_on_left)
{ {
bool isIndexable = false; bool isIndexable = false;
Var *leftop, Var *leftop,
...@@ -1625,6 +1637,51 @@ match_special_index_operator(Expr *clause, bool indexkey_on_left) ...@@ -1625,6 +1637,51 @@ match_special_index_operator(Expr *clause, bool indexkey_on_left)
break; break;
} }
/* done if the expression doesn't look indexable */
if (! isIndexable)
return false;
/*
* Must also check that index's opclass supports the operators we will
* want to apply. (A hash index, for example, will not support ">=".)
* We cheat a little by not checking for availability of "=" ... any
* index type should support "=", methinks.
*/
switch (expr_op)
{
case OID_TEXT_LIKE_OP:
case OID_TEXT_REGEXEQ_OP:
case OID_TEXT_ICREGEXEQ_OP:
if (! op_class(find_operator(">=", TEXTOID), opclass, relam) ||
! op_class(find_operator("<=", TEXTOID), opclass, relam))
isIndexable = false;
break;
case OID_BPCHAR_LIKE_OP:
case OID_BPCHAR_REGEXEQ_OP:
case OID_BPCHAR_ICREGEXEQ_OP:
if (! op_class(find_operator(">=", BPCHAROID), opclass, relam) ||
! op_class(find_operator("<=", BPCHAROID), opclass, relam))
isIndexable = false;
break;
case OID_VARCHAR_LIKE_OP:
case OID_VARCHAR_REGEXEQ_OP:
case OID_VARCHAR_ICREGEXEQ_OP:
if (! op_class(find_operator(">=", VARCHAROID), opclass, relam) ||
! op_class(find_operator("<=", VARCHAROID), opclass, relam))
isIndexable = false;
break;
case OID_NAME_LIKE_OP:
case OID_NAME_REGEXEQ_OP:
case OID_NAME_ICREGEXEQ_OP:
if (! op_class(find_operator(">=", NAMEOID), opclass, relam) ||
! op_class(find_operator("<=", NAMEOID), opclass, relam))
isIndexable = false;
break;
}
return isIndexable; return isIndexable;
} }
...@@ -1848,7 +1905,7 @@ prefix_quals(Var *leftop, Oid expr_op, ...@@ -1848,7 +1905,7 @@ prefix_quals(Var *leftop, Oid expr_op,
{ {
List *result; List *result;
Oid datatype; Oid datatype;
HeapTuple optup; Oid oproid;
void *conval; void *conval;
Const *con; Const *con;
Oper *op; Oper *op;
...@@ -1893,12 +1950,8 @@ prefix_quals(Var *leftop, Oid expr_op, ...@@ -1893,12 +1950,8 @@ prefix_quals(Var *leftop, Oid expr_op,
*/ */
if (pstatus == Prefix_Exact) if (pstatus == Prefix_Exact)
{ {
optup = SearchSysCacheTuple(OPERNAME, oproid = find_operator("=", datatype);
PointerGetDatum("="), if (oproid == InvalidOid)
ObjectIdGetDatum(datatype),
ObjectIdGetDatum(datatype),
CharGetDatum('b'));
if (!HeapTupleIsValid(optup))
elog(ERROR, "prefix_quals: no = operator for type %u", datatype); elog(ERROR, "prefix_quals: no = operator for type %u", datatype);
/* Note: we cheat a little by assuming that textin() will do for /* Note: we cheat a little by assuming that textin() will do for
* bpchar and varchar constants too... * bpchar and varchar constants too...
...@@ -1908,7 +1961,7 @@ prefix_quals(Var *leftop, Oid expr_op, ...@@ -1908,7 +1961,7 @@ prefix_quals(Var *leftop, Oid expr_op,
con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1), con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
PointerGetDatum(conval), PointerGetDatum(conval),
false, false, false, false); false, false, false, false);
op = makeOper(optup->t_data->t_oid, InvalidOid, BOOLOID, 0, NULL); op = makeOper(oproid, InvalidOid, BOOLOID, 0, NULL);
expr = make_opclause(op, leftop, (Var *) con); expr = make_opclause(op, leftop, (Var *) con);
result = lcons(expr, NIL); result = lcons(expr, NIL);
return result; return result;
...@@ -1919,19 +1972,15 @@ prefix_quals(Var *leftop, Oid expr_op, ...@@ -1919,19 +1972,15 @@ prefix_quals(Var *leftop, Oid expr_op,
* *
* We can always say "x >= prefix". * We can always say "x >= prefix".
*/ */
optup = SearchSysCacheTuple(OPERNAME, oproid = find_operator(">=", datatype);
PointerGetDatum(">="), if (oproid == InvalidOid)
ObjectIdGetDatum(datatype),
ObjectIdGetDatum(datatype),
CharGetDatum('b'));
if (!HeapTupleIsValid(optup))
elog(ERROR, "prefix_quals: no >= operator for type %u", datatype); elog(ERROR, "prefix_quals: no >= operator for type %u", datatype);
conval = (datatype == NAMEOID) ? conval = (datatype == NAMEOID) ?
(void*) namein(prefix) : (void*) textin(prefix); (void*) namein(prefix) : (void*) textin(prefix);
con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1), con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
PointerGetDatum(conval), PointerGetDatum(conval),
false, false, false, false); false, false, false, false);
op = makeOper(optup->t_data->t_oid, InvalidOid, BOOLOID, 0, NULL); op = makeOper(oproid, InvalidOid, BOOLOID, 0, NULL);
expr = make_opclause(op, leftop, (Var *) con); expr = make_opclause(op, leftop, (Var *) con);
result = lcons(expr, NIL); result = lcons(expr, NIL);
...@@ -1947,22 +1996,34 @@ prefix_quals(Var *leftop, Oid expr_op, ...@@ -1947,22 +1996,34 @@ prefix_quals(Var *leftop, Oid expr_op,
prefix[prefixlen] = '\377'; prefix[prefixlen] = '\377';
prefix[prefixlen+1] = '\0'; prefix[prefixlen+1] = '\0';
optup = SearchSysCacheTuple(OPERNAME, oproid = find_operator("<=", datatype);
PointerGetDatum("<="), if (oproid == InvalidOid)
ObjectIdGetDatum(datatype),
ObjectIdGetDatum(datatype),
CharGetDatum('b'));
if (!HeapTupleIsValid(optup))
elog(ERROR, "prefix_quals: no <= operator for type %u", datatype); elog(ERROR, "prefix_quals: no <= operator for type %u", datatype);
conval = (datatype == NAMEOID) ? conval = (datatype == NAMEOID) ?
(void*) namein(prefix) : (void*) textin(prefix); (void*) namein(prefix) : (void*) textin(prefix);
con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1), con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
PointerGetDatum(conval), PointerGetDatum(conval),
false, false, false, false); false, false, false, false);
op = makeOper(optup->t_data->t_oid, InvalidOid, BOOLOID, 0, NULL); op = makeOper(oproid, InvalidOid, BOOLOID, 0, NULL);
expr = make_opclause(op, leftop, (Var *) con); expr = make_opclause(op, leftop, (Var *) con);
result = lappend(result, expr); result = lappend(result, expr);
#endif #endif
return result; return result;
} }
/* See if there is a binary op of the given name for the given datatype */
static Oid
find_operator(const char * opname, Oid datatype)
{
HeapTuple optup;
optup = SearchSysCacheTuple(OPERNAME,
PointerGetDatum(opname),
ObjectIdGetDatum(datatype),
ObjectIdGetDatum(datatype),
CharGetDatum('b'));
if (!HeapTupleIsValid(optup))
return InvalidOid;
return optup->t_data->t_oid;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment