summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/optimizer/path/indxpath.c20
-rw-r--r--src/backend/utils/adt/selfuncs.c162
-rw-r--r--src/include/utils/selfuncs.h2
3 files changed, 57 insertions, 127 deletions
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 856e399fa2e..d598d66dd73 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -2081,7 +2081,6 @@ match_special_index_operator(Expr *clause, Oid opfamily,
Oid expr_op;
Const *patt;
Const *prefix = NULL;
- Const *rest = NULL;
/*
* Currently, all known special operators require the indexkey on the
@@ -2108,12 +2107,12 @@ match_special_index_operator(Expr *clause, Oid opfamily,
case OID_NAME_LIKE_OP:
/* the right-hand const is type text for all of these */
isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like,
- &prefix, &rest) != Pattern_Prefix_None;
+ &prefix, NULL) != Pattern_Prefix_None;
break;
case OID_BYTEA_LIKE_OP:
isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like,
- &prefix, &rest) != Pattern_Prefix_None;
+ &prefix, NULL) != Pattern_Prefix_None;
break;
case OID_TEXT_ICLIKE_OP:
@@ -2121,7 +2120,7 @@ match_special_index_operator(Expr *clause, Oid opfamily,
case OID_NAME_ICLIKE_OP:
/* the right-hand const is type text for all of these */
isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like_IC,
- &prefix, &rest) != Pattern_Prefix_None;
+ &prefix, NULL) != Pattern_Prefix_None;
break;
case OID_TEXT_REGEXEQ_OP:
@@ -2129,7 +2128,7 @@ match_special_index_operator(Expr *clause, Oid opfamily,
case OID_NAME_REGEXEQ_OP:
/* the right-hand const is type text for all of these */
isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex,
- &prefix, &rest) != Pattern_Prefix_None;
+ &prefix, NULL) != Pattern_Prefix_None;
break;
case OID_TEXT_ICREGEXEQ_OP:
@@ -2137,7 +2136,7 @@ match_special_index_operator(Expr *clause, Oid opfamily,
case OID_NAME_ICREGEXEQ_OP:
/* the right-hand const is type text for all of these */
isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,
- &prefix, &rest) != Pattern_Prefix_None;
+ &prefix, NULL) != Pattern_Prefix_None;
break;
case OID_INET_SUB_OP:
@@ -2380,7 +2379,6 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
Oid expr_op = ((OpExpr *) clause)->opno;
Const *patt = (Const *) rightop;
Const *prefix = NULL;
- Const *rest = NULL;
Pattern_Prefix_Status pstatus;
List *result;
@@ -2396,7 +2394,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_NAME_LIKE_OP:
case OID_BYTEA_LIKE_OP:
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like,
- &prefix, &rest);
+ &prefix, NULL);
result = prefix_quals(leftop, opfamily, prefix, pstatus);
break;
@@ -2405,7 +2403,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_NAME_ICLIKE_OP:
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC,
- &prefix, &rest);
+ &prefix, NULL);
result = prefix_quals(leftop, opfamily, prefix, pstatus);
break;
@@ -2414,7 +2412,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_NAME_REGEXEQ_OP:
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex,
- &prefix, &rest);
+ &prefix, NULL);
result = prefix_quals(leftop, opfamily, prefix, pstatus);
break;
@@ -2423,7 +2421,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_NAME_ICREGEXEQ_OP:
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,
- &prefix, &rest);
+ &prefix, NULL);
result = prefix_quals(leftop, opfamily, prefix, pstatus);
break;
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 1455116ce9d..8217628ab96 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -132,7 +132,10 @@ static bool get_variable_range(PlannerInfo *root, VariableStatData *vardata,
Oid sortop, Datum *min, Datum *max);
static Selectivity prefix_selectivity(VariableStatData *vardata,
Oid vartype, Oid opfamily, Const *prefixcon);
-static Selectivity pattern_selectivity(Const *patt, Pattern_Type ptype);
+static Selectivity like_selectivity(const char *patt, int pattlen,
+ bool case_insensitive);
+static Selectivity regex_selectivity(const char *patt, int pattlen,
+ bool case_insensitive);
static Datum string_to_datum(const char *str, Oid datatype);
static Const *string_to_const(const char *str, Oid datatype);
static Const *string_to_bytea_const(const char *str, size_t str_len);
@@ -916,9 +919,9 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype, bool negate)
Oid vartype;
Oid opfamily;
Pattern_Prefix_Status pstatus;
- Const *patt = NULL;
+ Const *patt;
Const *prefix = NULL;
- Const *rest = NULL;
+ Selectivity rest_selec = 0;
double result;
/*
@@ -1008,13 +1011,15 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype, bool negate)
return result;
}
- /* divide pattern into fixed prefix and remainder */
+ /*
+ * Pull out any fixed prefix implied by the pattern, and estimate the
+ * fractional selectivity of the remainder of the pattern.
+ */
patt = (Const *) other;
- pstatus = pattern_fixed_prefix(patt, ptype, &prefix, &rest);
+ pstatus = pattern_fixed_prefix(patt, ptype, &prefix, &rest_selec);
/*
- * If necessary, coerce the prefix constant to the right type. (The "rest"
- * constant need not be changed.)
+ * If necessary, coerce the prefix constant to the right type.
*/
if (prefix && prefix->consttype != vartype)
{
@@ -1088,15 +1093,13 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype, bool negate)
{
/* Nope, so fake it with the heuristic method */
Selectivity prefixsel;
- Selectivity restsel;
if (pstatus == Pattern_Prefix_Partial)
prefixsel = prefix_selectivity(&vardata, vartype,
opfamily, prefix);
else
prefixsel = 1.0;
- restsel = pattern_selectivity(rest, ptype);
- selec = prefixsel * restsel;
+ selec = prefixsel * rest_selec;
}
else
{
@@ -4092,9 +4095,9 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata, Oid sortop,
*
* *prefix is set to a palloc'd prefix string (in the form of a Const node),
* or to NULL if no fixed prefix exists for the pattern.
- * *rest is set to a palloc'd Const representing the remainder of the pattern
- * after the portion describing the fixed prefix.
- * Each of these has the same type (TEXT or BYTEA) as the given pattern Const.
+ * If rest_selec is not NULL, *rest_selec is set to an estimate of the
+ * selectivity of the remainder of the pattern (without any fixed prefix).
+ * The prefix Const has the same type (TEXT or BYTEA) as the input pattern.
*
* The return value distinguishes no fixed prefix, a partial prefix,
* or an exact-match-only pattern.
@@ -4102,12 +4105,11 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata, Oid sortop,
static Pattern_Prefix_Status
like_fixed_prefix(Const *patt_const, bool case_insensitive,
- Const **prefix_const, Const **rest_const)
+ Const **prefix_const, Selectivity *rest_selec)
{
char *match;
char *patt;
int pattlen;
- char *rest;
Oid typeid = patt_const->consttype;
int pos,
match_pos;
@@ -4175,18 +4177,15 @@ like_fixed_prefix(Const *patt_const, bool case_insensitive,
}
match[match_pos] = '\0';
- rest = &patt[pos];
if (typeid != BYTEAOID)
- {
*prefix_const = string_to_const(match, typeid);
- *rest_const = string_to_const(rest, typeid);
- }
else
- {
*prefix_const = string_to_bytea_const(match, match_pos);
- *rest_const = string_to_bytea_const(rest, pattlen - pos);
- }
+
+ if (rest_selec != NULL)
+ *rest_selec = like_selectivity(&patt[pos], pattlen - pos,
+ case_insensitive);
pfree(patt);
pfree(match);
@@ -4203,7 +4202,7 @@ like_fixed_prefix(Const *patt_const, bool case_insensitive,
static Pattern_Prefix_Status
regex_fixed_prefix(Const *patt_const, bool case_insensitive,
- Const **prefix_const, Const **rest_const)
+ Const **prefix_const, Selectivity *rest_selec)
{
char *match;
int pos,
@@ -4244,10 +4243,11 @@ regex_fixed_prefix(Const *patt_const, bool case_insensitive,
/* Pattern must be anchored left */
if (patt[pos] != '^')
{
- rest = patt;
-
*prefix_const = NULL;
- *rest_const = string_to_const(rest, typeid);
+
+ if (rest_selec != NULL)
+ *rest_selec = regex_selectivity(patt, strlen(patt),
+ case_insensitive);
return Pattern_Prefix_None;
}
@@ -4261,10 +4261,11 @@ regex_fixed_prefix(Const *patt_const, bool case_insensitive,
*/
if (strchr(patt + pos, '|') != NULL)
{
- rest = patt;
-
*prefix_const = NULL;
- *rest_const = string_to_const(rest, typeid);
+
+ if (rest_selec != NULL)
+ *rest_selec = regex_selectivity(patt, strlen(patt),
+ case_insensitive);
return Pattern_Prefix_None;
}
@@ -4376,10 +4377,10 @@ regex_fixed_prefix(Const *patt_const, bool case_insensitive,
if (patt[pos] == '$' && patt[pos + 1] == '\0')
{
- rest = &patt[pos + 1];
-
*prefix_const = string_to_const(match, typeid);
- *rest_const = string_to_const(rest, typeid);
+
+ if (rest_selec != NULL)
+ *rest_selec = 1.0;
pfree(patt);
pfree(match);
@@ -4388,7 +4389,10 @@ regex_fixed_prefix(Const *patt_const, bool case_insensitive,
}
*prefix_const = string_to_const(match, typeid);
- *rest_const = string_to_const(rest, typeid);
+
+ if (rest_selec != NULL)
+ *rest_selec = regex_selectivity(rest, strlen(rest),
+ case_insensitive);
pfree(patt);
pfree(match);
@@ -4401,23 +4405,23 @@ regex_fixed_prefix(Const *patt_const, bool case_insensitive,
Pattern_Prefix_Status
pattern_fixed_prefix(Const *patt, Pattern_Type ptype,
- Const **prefix, Const **rest)
+ Const **prefix, Selectivity *rest_selec)
{
Pattern_Prefix_Status result;
switch (ptype)
{
case Pattern_Type_Like:
- result = like_fixed_prefix(patt, false, prefix, rest);
+ result = like_fixed_prefix(patt, false, prefix, rest_selec);
break;
case Pattern_Type_Like_IC:
- result = like_fixed_prefix(patt, true, prefix, rest);
+ result = like_fixed_prefix(patt, true, prefix, rest_selec);
break;
case Pattern_Type_Regex:
- result = regex_fixed_prefix(patt, false, prefix, rest);
+ result = regex_fixed_prefix(patt, false, prefix, rest_selec);
break;
case Pattern_Type_Regex_IC:
- result = regex_fixed_prefix(patt, true, prefix, rest);
+ result = regex_fixed_prefix(patt, true, prefix, rest_selec);
break;
default:
elog(ERROR, "unrecognized ptype: %d", (int) ptype);
@@ -4517,7 +4521,8 @@ prefix_selectivity(VariableStatData *vardata,
/*
* Estimate the selectivity of a pattern of the specified type.
- * Note that any fixed prefix of the pattern will have been removed already.
+ * Note that any fixed prefix of the pattern will have been removed already,
+ * so actually we may be looking at just a fragment of the pattern.
*
* For now, we use a very simplistic approach: fixed characters reduce the
* selectivity a good deal, character ranges reduce it a little,
@@ -4531,37 +4536,10 @@ prefix_selectivity(VariableStatData *vardata,
#define PARTIAL_WILDCARD_SEL 2.0
static Selectivity
-like_selectivity(Const *patt_const, bool case_insensitive)
+like_selectivity(const char *patt, int pattlen, bool case_insensitive)
{
Selectivity sel = 1.0;
int pos;
- Oid typeid = patt_const->consttype;
- char *patt;
- int pattlen;
-
- /* the right-hand const is type text or bytea */
- Assert(typeid == BYTEAOID || typeid == TEXTOID);
-
- if (typeid == BYTEAOID && case_insensitive)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("case insensitive matching not supported on type bytea")));
-
- if (typeid != BYTEAOID)
- {
- patt = DatumGetCString(DirectFunctionCall1(textout, patt_const->constvalue));
- pattlen = strlen(patt);
- }
- else
- {
- bytea *bstr = DatumGetByteaP(patt_const->constvalue);
-
- pattlen = VARSIZE(bstr) - VARHDRSZ;
- patt = (char *) palloc(pattlen);
- memcpy(patt, VARDATA(bstr), pattlen);
- if ((Pointer) bstr != DatumGetPointer(patt_const->constvalue))
- pfree(bstr);
- }
/* Skip any leading wildcard; it's already factored into initial sel */
for (pos = 0; pos < pattlen; pos++)
@@ -4591,13 +4569,11 @@ like_selectivity(Const *patt_const, bool case_insensitive)
/* Could get sel > 1 if multiple wildcards */
if (sel > 1.0)
sel = 1.0;
-
- pfree(patt);
return sel;
}
static Selectivity
-regex_selectivity_sub(char *patt, int pattlen, bool case_insensitive)
+regex_selectivity_sub(const char *patt, int pattlen, bool case_insensitive)
{
Selectivity sel = 1.0;
int paren_depth = 0;
@@ -4690,26 +4666,9 @@ regex_selectivity_sub(char *patt, int pattlen, bool case_insensitive)
}
static Selectivity
-regex_selectivity(Const *patt_const, bool case_insensitive)
+regex_selectivity(const char *patt, int pattlen, bool case_insensitive)
{
Selectivity sel;
- char *patt;
- int pattlen;
- Oid typeid = patt_const->consttype;
-
- /*
- * Should be unnecessary, there are no bytea regex operators defined. As
- * such, it should be noted that the rest of this function has *not* been
- * made safe for binary (possibly NULL containing) strings.
- */
- if (typeid == BYTEAOID)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("regular-expression matching not supported on type bytea")));
-
- /* the right-hand const is type text for all of these */
- patt = DatumGetCString(DirectFunctionCall1(textout, patt_const->constvalue));
- pattlen = strlen(patt);
/* If patt doesn't end with $, consider it to have a trailing wildcard */
if (pattlen > 0 && patt[pattlen - 1] == '$' &&
@@ -4729,33 +4688,6 @@ regex_selectivity(Const *patt_const, bool case_insensitive)
return sel;
}
-static Selectivity
-pattern_selectivity(Const *patt, Pattern_Type ptype)
-{
- Selectivity result;
-
- switch (ptype)
- {
- case Pattern_Type_Like:
- result = like_selectivity(patt, false);
- break;
- case Pattern_Type_Like_IC:
- result = like_selectivity(patt, true);
- break;
- case Pattern_Type_Regex:
- result = regex_selectivity(patt, false);
- break;
- case Pattern_Type_Regex_IC:
- result = regex_selectivity(patt, true);
- break;
- default:
- elog(ERROR, "unrecognized ptype: %d", (int) ptype);
- result = 1.0; /* keep compiler quiet */
- break;
- }
- return result;
-}
-
/*
* Try to generate a string greater than the given string or any
diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h
index 7efe32b60ea..7ca940b7b5a 100644
--- a/src/include/utils/selfuncs.h
+++ b/src/include/utils/selfuncs.h
@@ -117,7 +117,7 @@ extern double histogram_selectivity(VariableStatData *vardata, FmgrInfo *opproc,
extern Pattern_Prefix_Status pattern_fixed_prefix(Const *patt,
Pattern_Type ptype,
Const **prefix,
- Const **rest);
+ Selectivity *rest_selec);
extern Const *make_greater_string(const Const *str_const, FmgrInfo *ltproc);
extern Datum eqsel(PG_FUNCTION_ARGS);