aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/indxpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/indxpath.c')
-rw-r--r--src/backend/optimizer/path/indxpath.c277
1 files changed, 22 insertions, 255 deletions
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 98c5112f7c3..06f9cd0247f 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,22 +9,20 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.82 2000/04/12 17:15:19 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.83 2000/04/16 04:41:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
-#include <ctype.h>
-#include <math.h>
-
#include "postgres.h"
+#include <math.h>
+
#include "access/heapam.h"
#include "access/nbtree.h"
#include "catalog/catname.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_operator.h"
#include "executor/executor.h"
-#include "mb/pg_wchar.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
@@ -46,11 +44,6 @@
#define is_indexable_operator(clause,opclass,relam,indexkey_on_left) \
(indexable_operator(clause,opclass,relam,indexkey_on_left) != InvalidOid)
-typedef enum
-{
- Prefix_None, Prefix_Partial, Prefix_Exact
-} Prefix_Status;
-
static void match_index_orclauses(RelOptInfo *rel, IndexOptInfo *index,
List *restrictinfo_list);
static List *match_index_orclause(RelOptInfo *rel, IndexOptInfo *index,
@@ -92,17 +85,11 @@ static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel,
IndexOptInfo *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 regex_fixed_prefix(char *patt, bool case_insensitive,
- char **prefix);
static List *prefix_quals(Var *leftop, Oid expr_op,
- char *prefix, Prefix_Status pstatus);
-static char *make_greater_string(const char *str, Oid datatype);
+ char *prefix, Pattern_Prefix_Status pstatus);
static Oid find_operator(const char *opname, Oid datatype);
static Datum string_to_datum(const char *str, Oid datatype);
static Const *string_to_const(const char *str, Oid datatype);
-static bool string_lessthan(const char *str1, const char *str2,
- Oid datatype);
/*
@@ -1644,6 +1631,7 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
Datum constvalue;
char *patt;
char *prefix;
+ char *rest;
/*
* Currently, all known special operators require the indexkey on the
@@ -1672,7 +1660,8 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
case OID_NAME_LIKE_OP:
/* the right-hand const is type text for all of these */
patt = textout((text *) DatumGetPointer(constvalue));
- isIndexable = like_fixed_prefix(patt, &prefix) != Prefix_None;
+ isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like,
+ &prefix, &rest) != Pattern_Prefix_None;
if (prefix)
pfree(prefix);
pfree(patt);
@@ -1684,7 +1673,8 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
case OID_NAME_REGEXEQ_OP:
/* the right-hand const is type text for all of these */
patt = textout((text *) DatumGetPointer(constvalue));
- isIndexable = regex_fixed_prefix(patt, false, &prefix) != Prefix_None;
+ isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex,
+ &prefix, &rest) != Pattern_Prefix_None;
if (prefix)
pfree(prefix);
pfree(patt);
@@ -1696,7 +1686,8 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
case OID_NAME_ICREGEXEQ_OP:
/* the right-hand const is type text for all of these */
patt = textout((text *) DatumGetPointer(constvalue));
- isIndexable = regex_fixed_prefix(patt, true, &prefix) != Prefix_None;
+ isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,
+ &prefix, &rest) != Pattern_Prefix_None;
if (prefix)
pfree(prefix);
pfree(patt);
@@ -1776,7 +1767,8 @@ expand_indexqual_conditions(List *indexquals)
Datum constvalue;
char *patt;
char *prefix;
- Prefix_Status pstatus;
+ char *rest;
+ Pattern_Prefix_Status pstatus;
switch (expr_op)
{
@@ -1794,7 +1786,8 @@ expand_indexqual_conditions(List *indexquals)
/* the right-hand const is type text for all of these */
constvalue = ((Const *) rightop)->constvalue;
patt = textout((text *) DatumGetPointer(constvalue));
- pstatus = like_fixed_prefix(patt, &prefix);
+ pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like,
+ &prefix, &rest);
resultquals = nconc(resultquals,
prefix_quals(leftop, expr_op,
prefix, pstatus));
@@ -1810,7 +1803,8 @@ expand_indexqual_conditions(List *indexquals)
/* the right-hand const is type text for all of these */
constvalue = ((Const *) rightop)->constvalue;
patt = textout((text *) DatumGetPointer(constvalue));
- pstatus = regex_fixed_prefix(patt, false, &prefix);
+ pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex,
+ &prefix, &rest);
resultquals = nconc(resultquals,
prefix_quals(leftop, expr_op,
prefix, pstatus));
@@ -1826,7 +1820,8 @@ expand_indexqual_conditions(List *indexquals)
/* the right-hand const is type text for all of these */
constvalue = ((Const *) rightop)->constvalue;
patt = textout((text *) DatumGetPointer(constvalue));
- pstatus = regex_fixed_prefix(patt, true, &prefix);
+ pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,
+ &prefix, &rest);
resultquals = nconc(resultquals,
prefix_quals(leftop, expr_op,
prefix, pstatus));
@@ -1845,130 +1840,6 @@ expand_indexqual_conditions(List *indexquals)
}
/*
- * Extract the fixed prefix, if any, for a LIKE pattern.
- * *prefix is set to a palloc'd prefix string,
- * or to NULL if no fixed prefix exists for the pattern.
- * The return value distinguishes no fixed prefix, a partial prefix,
- * or an exact-match-only pattern.
- */
-static Prefix_Status
-like_fixed_prefix(char *patt, char **prefix)
-{
- char *match;
- int pos,
- match_pos;
-
- *prefix = match = palloc(strlen(patt) + 1);
- match_pos = 0;
-
- for (pos = 0; patt[pos]; pos++)
- {
- /* % and _ are wildcard characters in LIKE */
- if (patt[pos] == '%' ||
- patt[pos] == '_')
- break;
- /* Backslash quotes the next character */
- if (patt[pos] == '\\')
- {
- pos++;
- if (patt[pos] == '\0')
- break;
- }
-
- /*
- * NOTE: this code used to think that %% meant a literal %, but
- * textlike() itself does not think that, and the SQL92 spec
- * doesn't say any such thing either.
- */
- match[match_pos++] = patt[pos];
- }
-
- match[match_pos] = '\0';
-
- /* in LIKE, an empty pattern is an exact match! */
- if (patt[pos] == '\0')
- return Prefix_Exact; /* reached end of pattern, so exact */
-
- if (match_pos > 0)
- return Prefix_Partial;
- return Prefix_None;
-}
-
-/*
- * Extract the fixed prefix, if any, for a regex pattern.
- * *prefix is set to a palloc'd prefix string,
- * or to NULL if no fixed prefix exists for the pattern.
- * The return value distinguishes no fixed prefix, a partial prefix,
- * or an exact-match-only pattern.
- */
-static Prefix_Status
-regex_fixed_prefix(char *patt, bool case_insensitive,
- char **prefix)
-{
- char *match;
- int pos,
- match_pos;
-
- *prefix = NULL;
-
- /* Pattern must be anchored left */
- if (patt[0] != '^')
- return Prefix_None;
-
- /* Cannot optimize if unquoted | { } is present in pattern */
- for (pos = 1; patt[pos]; pos++)
- {
- if (patt[pos] == '|' ||
- patt[pos] == '{' ||
- patt[pos] == '}')
- return Prefix_None;
- if (patt[pos] == '\\')
- {
- pos++;
- if (patt[pos] == '\0')
- break;
- }
- }
-
- /* OK, allocate space for pattern */
- *prefix = match = palloc(strlen(patt) + 1);
- match_pos = 0;
-
- /* note start at pos 1 to skip leading ^ */
- for (pos = 1; patt[pos]; pos++)
- {
- if (patt[pos] == '.' ||
- patt[pos] == '?' ||
- patt[pos] == '*' ||
- patt[pos] == '[' ||
- patt[pos] == '$' ||
-
- /*
- * XXX I suspect isalpha() is not an adequately locale-sensitive
- * test for characters that can vary under case folding?
- */
- (case_insensitive && isalpha(patt[pos])))
- break;
- if (patt[pos] == '\\')
- {
- pos++;
- if (patt[pos] == '\0')
- break;
- }
- match[match_pos++] = patt[pos];
- }
-
- match[match_pos] = '\0';
-
- if (patt[pos] == '$' && patt[pos + 1] == '\0')
- return Prefix_Exact; /* pattern specifies exact match */
-
- if (match_pos > 0)
- return Prefix_Partial;
- return Prefix_None;
-}
-
-/*
* Given a fixed prefix that all the "leftop" values must have,
* generate suitable indexqual condition(s). expr_op is the original
* LIKE or regex operator; we use it to deduce the appropriate comparison
@@ -1976,7 +1847,7 @@ regex_fixed_prefix(char *patt, bool case_insensitive,
*/
static List *
prefix_quals(Var *leftop, Oid expr_op,
- char *prefix, Prefix_Status pstatus)
+ char *prefix, Pattern_Prefix_Status pstatus)
{
List *result;
Oid datatype;
@@ -1986,7 +1857,7 @@ prefix_quals(Var *leftop, Oid expr_op,
Expr *expr;
char *greaterstr;
- Assert(pstatus != Prefix_None);
+ Assert(pstatus != Pattern_Prefix_None);
switch (expr_op)
{
@@ -2022,7 +1893,7 @@ prefix_quals(Var *leftop, Oid expr_op,
/*
* If we found an exact-match pattern, generate an "=" indexqual.
*/
- if (pstatus == Prefix_Exact)
+ if (pstatus == Pattern_Prefix_Exact)
{
oproid = find_operator("=", datatype);
if (oproid == InvalidOid)
@@ -2068,68 +1939,6 @@ prefix_quals(Var *leftop, Oid expr_op,
}
/*
- * Try to generate a string greater than the given string or any string it is
- * a prefix of. If successful, return a palloc'd string; else return NULL.
- *
- * To work correctly in non-ASCII locales with weird collation orders,
- * we cannot simply increment "foo" to "fop" --- we have to check whether
- * we actually produced a string greater than the given one. If not,
- * increment the righthand byte again and repeat. If we max out the righthand
- * byte, truncate off the last character and start incrementing the next.
- * For example, if "z" were the last character in the sort order, then we
- * could produce "foo" as a string greater than "fonz".
- *
- * This could be rather slow in the worst case, but in most cases we won't
- * have to try more than one or two strings before succeeding.
- *
- * XXX in a sufficiently weird locale, this might produce incorrect results?
- * For example, in German I believe "ss" is treated specially --- if we are
- * given "foos" and return "foot", will this actually be greater than "fooss"?
- */
-static char *
-make_greater_string(const char *str, Oid datatype)
-{
- char *workstr;
- int len;
-
- /*
- * Make a modifiable copy, which will be our return value if
- * successful
- */
- workstr = pstrdup((char *) str);
-
- while ((len = strlen(workstr)) > 0)
- {
- unsigned char *lastchar = (unsigned char *) (workstr + len - 1);
-
- /*
- * Try to generate a larger string by incrementing the last byte.
- */
- while (*lastchar < (unsigned char) 255)
- {
- (*lastchar)++;
- if (string_lessthan(str, workstr, datatype))
- return workstr; /* Success! */
- }
-
- /*
- * Truncate off the last character, which might be more than 1
- * byte in MULTIBYTE case.
- */
-#ifdef MULTIBYTE
- len = pg_mbcliplen((const unsigned char *) workstr, len, len - 1);
- workstr[len] = '\0';
-#else
- *lastchar = '\0';
-#endif
- }
-
- /* Failed... */
- pfree(workstr);
- return NULL;
-}
-
-/*
* Handy subroutines for match_special_index_operator() and friends.
*/
@@ -2179,45 +1988,3 @@ string_to_const(const char *str, Oid datatype)
return makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
conval, false, false, false, false);
}
-
-/*
- * Test whether two strings are "<" according to the rules of the given
- * datatype. We do this the hard way, ie, actually calling the type's
- * "<" operator function, to ensure we get the right result...
- */
-static bool
-string_lessthan(const char *str1, const char *str2, Oid datatype)
-{
- Datum datum1 = string_to_datum(str1, datatype);
- Datum datum2 = string_to_datum(str2, datatype);
- bool result;
-
- switch (datatype)
- {
- case TEXTOID:
- result = text_lt((text *) datum1, (text *) datum2);
- break;
-
- case BPCHAROID:
- result = bpcharlt((char *) datum1, (char *) datum2);
- break;
-
- case VARCHAROID:
- result = varcharlt((char *) datum1, (char *) datum2);
- break;
-
- case NAMEOID:
- result = namelt((NameData *) datum1, (NameData *) datum2);
- break;
-
- default:
- elog(ERROR, "string_lessthan: unexpected datatype %u", datatype);
- result = false;
- break;
- }
-
- pfree(DatumGetPointer(datum1));
- pfree(DatumGetPointer(datum2));
-
- return result;
-}