Skip to content

Commit 5f68d5c

Browse files
committed
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.)
1 parent 2784a5a commit 5f68d5c

File tree

1 file changed

+115
-54
lines changed

1 file changed

+115
-54
lines changed

src/backend/optimizer/path/indxpath.c

Lines changed: 115 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.73 1999/11/22 17:56:07 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.74 1999/12/31 03:41:03 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -44,24 +44,30 @@ typedef enum {
4444
Prefix_None, Prefix_Partial, Prefix_Exact
4545
} Prefix_Status;
4646

47-
static void match_index_orclauses(RelOptInfo *rel, RelOptInfo *index, int indexkey,
48-
int xclass, List *restrictinfo_list);
49-
static List *match_index_orclause(RelOptInfo *rel, RelOptInfo *index, int indexkey,
50-
int xclass, List *or_clauses, List *other_matching_indices);
47+
static void match_index_orclauses(RelOptInfo *rel, RelOptInfo *index,
48+
int indexkey, Oid opclass,
49+
List *restrictinfo_list);
50+
static List *match_index_orclause(RelOptInfo *rel, RelOptInfo *index,
51+
int indexkey, Oid opclass,
52+
List *or_clauses,
53+
List *other_matching_indices);
5154
static bool match_or_subclause_to_indexkey(RelOptInfo *rel, RelOptInfo *index,
52-
int indexkey, int xclass,
55+
int indexkey, Oid opclass,
5356
Expr *clause);
5457
static List *group_clauses_by_indexkey(RelOptInfo *rel, RelOptInfo *index,
55-
int *indexkeys, Oid *classes, List *restrictinfo_list);
58+
int *indexkeys, Oid *classes,
59+
List *restrictinfo_list);
5660
static List *group_clauses_by_ikey_for_joins(RelOptInfo *rel, RelOptInfo *index,
57-
int *indexkeys, Oid *classes, List *join_cinfo_list, List *restr_cinfo_list);
61+
int *indexkeys, Oid *classes,
62+
List *join_cinfo_list,
63+
List *restr_cinfo_list);
5864
static bool match_clause_to_indexkey(RelOptInfo *rel, RelOptInfo *index,
59-
int indexkey, int xclass,
65+
int indexkey, Oid opclass,
6066
Expr *clause, bool join);
61-
static bool indexable_operator(Expr *clause, int xclass, Oid relam,
67+
static bool indexable_operator(Expr *clause, Oid opclass, Oid relam,
6268
bool indexkey_on_left);
6369
static bool pred_test(List *predicate_list, List *restrictinfo_list,
64-
List *joininfo_list);
70+
List *joininfo_list);
6571
static bool one_pred_test(Expr *predicate, List *restrictinfo_list);
6672
static bool one_pred_clause_expr_test(Expr *predicate, Node *clause);
6773
static bool one_pred_clause_test(Expr *predicate, Node *clause);
@@ -77,13 +83,16 @@ static bool useful_for_ordering(Query *root, RelOptInfo *rel,
7783
RelOptInfo *index);
7884
static bool match_index_to_operand(int indexkey, Var *operand,
7985
RelOptInfo *rel, RelOptInfo *index);
80-
static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index);
81-
static bool match_special_index_operator(Expr *clause, bool indexkey_on_left);
86+
static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel,
87+
RelOptInfo *index);
88+
static bool match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
89+
bool indexkey_on_left);
8290
static Prefix_Status like_fixed_prefix(char *patt, char **prefix);
8391
static Prefix_Status regex_fixed_prefix(char *patt, bool case_insensitive,
8492
char **prefix);
8593
static List *prefix_quals(Var *leftop, Oid expr_op,
8694
char *prefix, Prefix_Status pstatus);
95+
static Oid find_operator(const char * opname, Oid datatype);
8796

8897

8998
/*
@@ -255,7 +264,7 @@ static void
255264
match_index_orclauses(RelOptInfo *rel,
256265
RelOptInfo *index,
257266
int indexkey,
258-
int xclass,
267+
Oid opclass,
259268
List *restrictinfo_list)
260269
{
261270
List *i;
@@ -272,7 +281,7 @@ match_index_orclauses(RelOptInfo *rel,
272281
*/
273282
restrictinfo->subclauseindices =
274283
match_index_orclause(rel, index,
275-
indexkey, xclass,
284+
indexkey, opclass,
276285
restrictinfo->clause->args,
277286
restrictinfo->subclauseindices);
278287
}
@@ -304,7 +313,7 @@ static List *
304313
match_index_orclause(RelOptInfo *rel,
305314
RelOptInfo *index,
306315
int indexkey,
307-
int xclass,
316+
Oid opclass,
308317
List *or_clauses,
309318
List *other_matching_indices)
310319
{
@@ -330,7 +339,7 @@ match_index_orclause(RelOptInfo *rel,
330339
{
331340
Expr *clause = lfirst(clist);
332341

333-
if (match_or_subclause_to_indexkey(rel, index, indexkey, xclass,
342+
if (match_or_subclause_to_indexkey(rel, index, indexkey, opclass,
334343
clause))
335344
{
336345
/* OK to add this index to sublist for this subclause */
@@ -355,7 +364,7 @@ static bool
355364
match_or_subclause_to_indexkey(RelOptInfo *rel,
356365
RelOptInfo *index,
357366
int indexkey,
358-
int xclass,
367+
Oid opclass,
359368
Expr *clause)
360369
{
361370
if (and_clause((Node *) clause))
@@ -364,14 +373,14 @@ match_or_subclause_to_indexkey(RelOptInfo *rel,
364373

365374
foreach(item, clause->args)
366375
{
367-
if (! match_clause_to_indexkey(rel, index, indexkey, xclass,
376+
if (! match_clause_to_indexkey(rel, index, indexkey, opclass,
368377
lfirst(item), false))
369378
return false;
370379
}
371380
return true;
372381
}
373382
else
374-
return match_clause_to_indexkey(rel, index, indexkey, xclass,
383+
return match_clause_to_indexkey(rel, index, indexkey, opclass,
375384
clause, false);
376385
}
377386

@@ -588,7 +597,7 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
588597
* 'rel' is the relation of interest.
589598
* 'index' is an index on 'rel'.
590599
* 'indexkey' is a key of 'index'.
591-
* 'xclass' is the corresponding operator class.
600+
* 'opclass' is the corresponding operator class.
592601
* 'clause' is the clause to be tested.
593602
* 'join' is true if we are considering this clause for joins.
594603
*
@@ -601,7 +610,7 @@ static bool
601610
match_clause_to_indexkey(RelOptInfo *rel,
602611
RelOptInfo *index,
603612
int indexkey,
604-
int xclass,
613+
Oid opclass,
605614
Expr *clause,
606615
bool join)
607616
{
@@ -627,26 +636,28 @@ match_clause_to_indexkey(RelOptInfo *rel,
627636
if ((IsA(rightop, Const) || IsA(rightop, Param)) &&
628637
match_index_to_operand(indexkey, leftop, rel, index))
629638
{
630-
if (indexable_operator(clause, xclass, index->relam, true))
639+
if (indexable_operator(clause, opclass, index->relam, true))
631640
return true;
632641
/*
633642
* If we didn't find a member of the index's opclass,
634643
* see whether it is a "special" indexable operator.
635644
*/
636-
if (match_special_index_operator(clause, true))
645+
if (match_special_index_operator(clause, opclass, index->relam,
646+
true))
637647
return true;
638648
return false;
639649
}
640650
if ((IsA(leftop, Const) || IsA(leftop, Param)) &&
641651
match_index_to_operand(indexkey, rightop, rel, index))
642652
{
643-
if (indexable_operator(clause, xclass, index->relam, false))
653+
if (indexable_operator(clause, opclass, index->relam, false))
644654
return true;
645655
/*
646656
* If we didn't find a member of the index's opclass,
647657
* see whether it is a "special" indexable operator.
648658
*/
649-
if (match_special_index_operator(clause, false))
659+
if (match_special_index_operator(clause, opclass, index->relam,
660+
false))
650661
return true;
651662
return false;
652663
}
@@ -666,7 +677,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
666677
isIndexable = ! intMember(lfirsti(rel->relids), othervarnos);
667678
freeList(othervarnos);
668679
if (isIndexable &&
669-
indexable_operator(clause, xclass, index->relam, true))
680+
indexable_operator(clause, opclass, index->relam, true))
670681
return true;
671682
}
672683
else if (match_index_to_operand(indexkey, rightop, rel, index))
@@ -677,7 +688,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
677688
isIndexable = ! intMember(lfirsti(rel->relids), othervarnos);
678689
freeList(othervarnos);
679690
if (isIndexable &&
680-
indexable_operator(clause, xclass, index->relam, false))
691+
indexable_operator(clause, opclass, index->relam, false))
681692
return true;
682693
}
683694
}
@@ -706,7 +717,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
706717
* a tad ugly...
707718
*/
708719
static bool
709-
indexable_operator(Expr *clause, int xclass, Oid relam,
720+
indexable_operator(Expr *clause, Oid opclass, Oid relam,
710721
bool indexkey_on_left)
711722
{
712723
Oid expr_op = ((Oper *) clause->oper)->opno;
@@ -723,7 +734,7 @@ indexable_operator(Expr *clause, int xclass, Oid relam,
723734
return false;
724735

725736
/* Done if the (commuted) operator is a member of the index's AM */
726-
if (op_class(commuted_op, xclass, relam))
737+
if (op_class(commuted_op, opclass, relam))
727738
return true;
728739

729740
/*
@@ -766,7 +777,7 @@ indexable_operator(Expr *clause, int xclass, Oid relam,
766777
if (commuted_op == InvalidOid)
767778
return false;
768779

769-
if (op_class(commuted_op, xclass, relam))
780+
if (op_class(commuted_op, opclass, relam))
770781
{
771782
/*
772783
* Success! Change the opclause to use the
@@ -1561,7 +1572,8 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index)
15611572
* Return 'true' if we can do something with it anyway.
15621573
*/
15631574
static bool
1564-
match_special_index_operator(Expr *clause, bool indexkey_on_left)
1575+
match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
1576+
bool indexkey_on_left)
15651577
{
15661578
bool isIndexable = false;
15671579
Var *leftop,
@@ -1625,6 +1637,51 @@ match_special_index_operator(Expr *clause, bool indexkey_on_left)
16251637
break;
16261638
}
16271639

1640+
/* done if the expression doesn't look indexable */
1641+
if (! isIndexable)
1642+
return false;
1643+
1644+
/*
1645+
* Must also check that index's opclass supports the operators we will
1646+
* want to apply. (A hash index, for example, will not support ">=".)
1647+
* We cheat a little by not checking for availability of "=" ... any
1648+
* index type should support "=", methinks.
1649+
*/
1650+
switch (expr_op)
1651+
{
1652+
case OID_TEXT_LIKE_OP:
1653+
case OID_TEXT_REGEXEQ_OP:
1654+
case OID_TEXT_ICREGEXEQ_OP:
1655+
if (! op_class(find_operator(">=", TEXTOID), opclass, relam) ||
1656+
! op_class(find_operator("<=", TEXTOID), opclass, relam))
1657+
isIndexable = false;
1658+
break;
1659+
1660+
case OID_BPCHAR_LIKE_OP:
1661+
case OID_BPCHAR_REGEXEQ_OP:
1662+
case OID_BPCHAR_ICREGEXEQ_OP:
1663+
if (! op_class(find_operator(">=", BPCHAROID), opclass, relam) ||
1664+
! op_class(find_operator("<=", BPCHAROID), opclass, relam))
1665+
isIndexable = false;
1666+
break;
1667+
1668+
case OID_VARCHAR_LIKE_OP:
1669+
case OID_VARCHAR_REGEXEQ_OP:
1670+
case OID_VARCHAR_ICREGEXEQ_OP:
1671+
if (! op_class(find_operator(">=", VARCHAROID), opclass, relam) ||
1672+
! op_class(find_operator("<=", VARCHAROID), opclass, relam))
1673+
isIndexable = false;
1674+
break;
1675+
1676+
case OID_NAME_LIKE_OP:
1677+
case OID_NAME_REGEXEQ_OP:
1678+
case OID_NAME_ICREGEXEQ_OP:
1679+
if (! op_class(find_operator(">=", NAMEOID), opclass, relam) ||
1680+
! op_class(find_operator("<=", NAMEOID), opclass, relam))
1681+
isIndexable = false;
1682+
break;
1683+
}
1684+
16281685
return isIndexable;
16291686
}
16301687

@@ -1848,7 +1905,7 @@ prefix_quals(Var *leftop, Oid expr_op,
18481905
{
18491906
List *result;
18501907
Oid datatype;
1851-
HeapTuple optup;
1908+
Oid oproid;
18521909
void *conval;
18531910
Const *con;
18541911
Oper *op;
@@ -1893,12 +1950,8 @@ prefix_quals(Var *leftop, Oid expr_op,
18931950
*/
18941951
if (pstatus == Prefix_Exact)
18951952
{
1896-
optup = SearchSysCacheTuple(OPERNAME,
1897-
PointerGetDatum("="),
1898-
ObjectIdGetDatum(datatype),
1899-
ObjectIdGetDatum(datatype),
1900-
CharGetDatum('b'));
1901-
if (!HeapTupleIsValid(optup))
1953+
oproid = find_operator("=", datatype);
1954+
if (oproid == InvalidOid)
19021955
elog(ERROR, "prefix_quals: no = operator for type %u", datatype);
19031956
/* Note: we cheat a little by assuming that textin() will do for
19041957
* bpchar and varchar constants too...
@@ -1908,7 +1961,7 @@ prefix_quals(Var *leftop, Oid expr_op,
19081961
con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
19091962
PointerGetDatum(conval),
19101963
false, false, false, false);
1911-
op = makeOper(optup->t_data->t_oid, InvalidOid, BOOLOID, 0, NULL);
1964+
op = makeOper(oproid, InvalidOid, BOOLOID, 0, NULL);
19121965
expr = make_opclause(op, leftop, (Var *) con);
19131966
result = lcons(expr, NIL);
19141967
return result;
@@ -1919,19 +1972,15 @@ prefix_quals(Var *leftop, Oid expr_op,
19191972
*
19201973
* We can always say "x >= prefix".
19211974
*/
1922-
optup = SearchSysCacheTuple(OPERNAME,
1923-
PointerGetDatum(">="),
1924-
ObjectIdGetDatum(datatype),
1925-
ObjectIdGetDatum(datatype),
1926-
CharGetDatum('b'));
1927-
if (!HeapTupleIsValid(optup))
1975+
oproid = find_operator(">=", datatype);
1976+
if (oproid == InvalidOid)
19281977
elog(ERROR, "prefix_quals: no >= operator for type %u", datatype);
19291978
conval = (datatype == NAMEOID) ?
19301979
(void*) namein(prefix) : (void*) textin(prefix);
19311980
con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
19321981
PointerGetDatum(conval),
19331982
false, false, false, false);
1934-
op = makeOper(optup->t_data->t_oid, InvalidOid, BOOLOID, 0, NULL);
1983+
op = makeOper(oproid, InvalidOid, BOOLOID, 0, NULL);
19351984
expr = make_opclause(op, leftop, (Var *) con);
19361985
result = lcons(expr, NIL);
19371986

@@ -1947,22 +1996,34 @@ prefix_quals(Var *leftop, Oid expr_op,
19471996
prefix[prefixlen] = '\377';
19481997
prefix[prefixlen+1] = '\0';
19491998

1950-
optup = SearchSysCacheTuple(OPERNAME,
1951-
PointerGetDatum("<="),
1952-
ObjectIdGetDatum(datatype),
1953-
ObjectIdGetDatum(datatype),
1954-
CharGetDatum('b'));
1955-
if (!HeapTupleIsValid(optup))
1999+
oproid = find_operator("<=", datatype);
2000+
if (oproid == InvalidOid)
19562001
elog(ERROR, "prefix_quals: no <= operator for type %u", datatype);
19572002
conval = (datatype == NAMEOID) ?
19582003
(void*) namein(prefix) : (void*) textin(prefix);
19592004
con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
19602005
PointerGetDatum(conval),
19612006
false, false, false, false);
1962-
op = makeOper(optup->t_data->t_oid, InvalidOid, BOOLOID, 0, NULL);
2007+
op = makeOper(oproid, InvalidOid, BOOLOID, 0, NULL);
19632008
expr = make_opclause(op, leftop, (Var *) con);
19642009
result = lappend(result, expr);
19652010
#endif
19662011

19672012
return result;
19682013
}
2014+
2015+
/* See if there is a binary op of the given name for the given datatype */
2016+
static Oid
2017+
find_operator(const char * opname, Oid datatype)
2018+
{
2019+
HeapTuple optup;
2020+
2021+
optup = SearchSysCacheTuple(OPERNAME,
2022+
PointerGetDatum(opname),
2023+
ObjectIdGetDatum(datatype),
2024+
ObjectIdGetDatum(datatype),
2025+
CharGetDatum('b'));
2026+
if (!HeapTupleIsValid(optup))
2027+
return InvalidOid;
2028+
return optup->t_data->t_oid;
2029+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy