diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index bce39f1166..3d9ec2eb23 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.120 2002/07/13 19:20:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.121 2002/09/02 06:22:18 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -97,7 +97,7 @@ static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, static bool match_special_index_operator(Expr *clause, Oid opclass, bool indexkey_on_left); static List *prefix_quals(Var *leftop, Oid expr_op, - char *prefix, Pattern_Prefix_Status pstatus); + Const *prefix, Pattern_Prefix_Status pstatus); static List *network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop); static Oid find_operator(const char *opname, Oid datatype); static Datum string_to_datum(const char *str, Oid datatype); @@ -1675,10 +1675,9 @@ match_special_index_operator(Expr *clause, Oid opclass, Var *leftop, *rightop; Oid expr_op; - Datum constvalue; - char *patt; - char *prefix; - char *rest; + Const *patt = NULL; + Const *prefix = NULL; + Const *rest = NULL; /* * Currently, all known special operators require the indexkey on the @@ -1697,7 +1696,7 @@ match_special_index_operator(Expr *clause, Oid opclass, if (!IsA(rightop, Const) || ((Const *) rightop)->constisnull) return false; - constvalue = ((Const *) rightop)->constvalue; + patt = (Const *) rightop; switch (expr_op) { @@ -1705,68 +1704,45 @@ match_special_index_operator(Expr *clause, Oid opclass, case OID_BPCHAR_LIKE_OP: case OID_VARCHAR_LIKE_OP: case OID_NAME_LIKE_OP: + /* the right-hand const is type text for all of these */ if (locale_is_like_safe()) - { - /* the right-hand const is type text for all of these */ - patt = DatumGetCString(DirectFunctionCall1(textout, - constvalue)); isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like, &prefix, &rest) != Pattern_Prefix_None; - if (prefix) - pfree(prefix); - pfree(patt); - } + break; + + case OID_BYTEA_LIKE_OP: + isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like, + &prefix, &rest) != Pattern_Prefix_None; break; case OID_TEXT_ICLIKE_OP: case OID_BPCHAR_ICLIKE_OP: case OID_VARCHAR_ICLIKE_OP: case OID_NAME_ICLIKE_OP: + /* the right-hand const is type text for all of these */ if (locale_is_like_safe()) - { - /* the right-hand const is type text for all of these */ - patt = DatumGetCString(DirectFunctionCall1(textout, - constvalue)); isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like_IC, &prefix, &rest) != Pattern_Prefix_None; - if (prefix) - pfree(prefix); - pfree(patt); - } break; case OID_TEXT_REGEXEQ_OP: case OID_BPCHAR_REGEXEQ_OP: case OID_VARCHAR_REGEXEQ_OP: case OID_NAME_REGEXEQ_OP: + /* the right-hand const is type text for all of these */ if (locale_is_like_safe()) - { - /* the right-hand const is type text for all of these */ - patt = DatumGetCString(DirectFunctionCall1(textout, - constvalue)); isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex, &prefix, &rest) != Pattern_Prefix_None; - if (prefix) - pfree(prefix); - pfree(patt); - } break; case OID_TEXT_ICREGEXEQ_OP: case OID_BPCHAR_ICREGEXEQ_OP: case OID_VARCHAR_ICREGEXEQ_OP: case OID_NAME_ICREGEXEQ_OP: + /* the right-hand const is type text for all of these */ if (locale_is_like_safe()) - { - /* the right-hand const is type text for all of these */ - patt = DatumGetCString(DirectFunctionCall1(textout, - constvalue)); isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC, &prefix, &rest) != Pattern_Prefix_None; - if (prefix) - pfree(prefix); - pfree(patt); - } break; case OID_INET_SUB_OP: @@ -1777,6 +1753,12 @@ match_special_index_operator(Expr *clause, Oid opclass, break; } + if (prefix) + { + pfree(DatumGetPointer(prefix->constvalue)); + pfree(prefix); + } + /* done if the expression doesn't look indexable */ if (!isIndexable) return false; @@ -1798,6 +1780,12 @@ match_special_index_operator(Expr *clause, Oid opclass, isIndexable = false; break; + case OID_BYTEA_LIKE_OP: + if (!op_in_opclass(find_operator(">=", BYTEAOID), opclass) || + !op_in_opclass(find_operator("<", BYTEAOID), opclass)) + isIndexable = false; + break; + case OID_BPCHAR_LIKE_OP: case OID_BPCHAR_ICLIKE_OP: case OID_BPCHAR_REGEXEQ_OP: @@ -1867,10 +1855,9 @@ expand_indexqual_conditions(List *indexquals) Var *leftop = get_leftop(clause); Var *rightop = get_rightop(clause); Oid expr_op = ((Oper *) clause->oper)->opno; - Datum constvalue; - char *patt; - char *prefix; - char *rest; + Const *patt = (Const *) rightop; + Const *prefix = NULL; + Const *rest = NULL; Pattern_Prefix_Status pstatus; switch (expr_op) @@ -1885,18 +1872,12 @@ expand_indexqual_conditions(List *indexquals) case OID_BPCHAR_LIKE_OP: case OID_VARCHAR_LIKE_OP: case OID_NAME_LIKE_OP: - /* the right-hand const is type text for all of these */ - constvalue = ((Const *) rightop)->constvalue; - patt = DatumGetCString(DirectFunctionCall1(textout, - constvalue)); + case OID_BYTEA_LIKE_OP: pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like, &prefix, &rest); resultquals = nconc(resultquals, prefix_quals(leftop, expr_op, prefix, pstatus)); - if (prefix) - pfree(prefix); - pfree(patt); break; case OID_TEXT_ICLIKE_OP: @@ -1904,17 +1885,11 @@ expand_indexqual_conditions(List *indexquals) case OID_VARCHAR_ICLIKE_OP: case OID_NAME_ICLIKE_OP: /* the right-hand const is type text for all of these */ - constvalue = ((Const *) rightop)->constvalue; - patt = DatumGetCString(DirectFunctionCall1(textout, - constvalue)); pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC, &prefix, &rest); resultquals = nconc(resultquals, prefix_quals(leftop, expr_op, prefix, pstatus)); - if (prefix) - pfree(prefix); - pfree(patt); break; case OID_TEXT_REGEXEQ_OP: @@ -1922,17 +1897,11 @@ expand_indexqual_conditions(List *indexquals) case OID_VARCHAR_REGEXEQ_OP: case OID_NAME_REGEXEQ_OP: /* the right-hand const is type text for all of these */ - constvalue = ((Const *) rightop)->constvalue; - patt = DatumGetCString(DirectFunctionCall1(textout, - constvalue)); pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex, &prefix, &rest); resultquals = nconc(resultquals, prefix_quals(leftop, expr_op, prefix, pstatus)); - if (prefix) - pfree(prefix); - pfree(patt); break; case OID_TEXT_ICREGEXEQ_OP: @@ -1940,27 +1909,20 @@ expand_indexqual_conditions(List *indexquals) case OID_VARCHAR_ICREGEXEQ_OP: case OID_NAME_ICREGEXEQ_OP: /* the right-hand const is type text for all of these */ - constvalue = ((Const *) rightop)->constvalue; - patt = DatumGetCString(DirectFunctionCall1(textout, - constvalue)); pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC, &prefix, &rest); resultquals = nconc(resultquals, prefix_quals(leftop, expr_op, prefix, pstatus)); - if (prefix) - pfree(prefix); - pfree(patt); break; case OID_INET_SUB_OP: case OID_INET_SUBEQ_OP: case OID_CIDR_SUB_OP: case OID_CIDR_SUBEQ_OP: - constvalue = ((Const *) rightop)->constvalue; resultquals = nconc(resultquals, network_prefix_quals(leftop, expr_op, - constvalue)); + patt->constvalue)); break; default: @@ -1980,15 +1942,16 @@ expand_indexqual_conditions(List *indexquals) */ static List * prefix_quals(Var *leftop, Oid expr_op, - char *prefix, Pattern_Prefix_Status pstatus) + Const *prefix_const, Pattern_Prefix_Status pstatus) { List *result; Oid datatype; Oid oproid; + char *prefix; Const *con; Oper *op; Expr *expr; - char *greaterstr; + Const *greaterstr = NULL; Assert(pstatus != Pattern_Prefix_None); @@ -2001,6 +1964,10 @@ prefix_quals(Var *leftop, Oid expr_op, datatype = TEXTOID; break; + case OID_BYTEA_LIKE_OP: + datatype = BYTEAOID; + break; + case OID_BPCHAR_LIKE_OP: case OID_BPCHAR_ICLIKE_OP: case OID_BPCHAR_REGEXEQ_OP: @@ -2027,6 +1994,11 @@ prefix_quals(Var *leftop, Oid expr_op, return NIL; } + if (prefix_const->consttype != BYTEAOID) + prefix = DatumGetCString(DirectFunctionCall1(textout, prefix_const->constvalue)); + else + prefix = DatumGetCString(DirectFunctionCall1(byteaout, prefix_const->constvalue)); + /* * If we found an exact-match pattern, generate an "=" indexqual. */ @@ -2060,17 +2032,15 @@ prefix_quals(Var *leftop, Oid expr_op, * "x < greaterstr". *------- */ - greaterstr = make_greater_string(prefix, datatype); + greaterstr = make_greater_string(con); if (greaterstr) { oproid = find_operator("<", datatype); if (oproid == InvalidOid) elog(ERROR, "prefix_quals: no < operator for type %u", datatype); - con = string_to_const(greaterstr, datatype); op = makeOper(oproid, InvalidOid, BOOLOID, false); - expr = make_opclause(op, leftop, (Var *) con); + expr = make_opclause(op, leftop, (Var *) greaterstr); result = lappend(result, expr); - pfree(greaterstr); } return result; @@ -2186,6 +2156,8 @@ string_to_datum(const char *str, Oid datatype) */ if (datatype == NAMEOID) return DirectFunctionCall1(namein, CStringGetDatum(str)); + else if (datatype == BYTEAOID) + return DirectFunctionCall1(byteain, CStringGetDatum(str)); else return DirectFunctionCall1(textin, CStringGetDatum(str)); } diff --git a/src/backend/utils/adt/like.c b/src/backend/utils/adt/like.c index 3e67e947a9..fab47e37fa 100644 --- a/src/backend/utils/adt/like.c +++ b/src/backend/utils/adt/like.c @@ -11,7 +11,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.51 2002/08/29 07:22:26 ishii Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.52 2002/09/02 06:22:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -242,7 +242,7 @@ Datum bytealike(PG_FUNCTION_ARGS) { bytea *str = PG_GETARG_BYTEA_P(0); - text *pat = PG_GETARG_TEXT_P(1); + bytea *pat = PG_GETARG_BYTEA_P(1); bool result; unsigned char *s, *p; @@ -263,7 +263,7 @@ Datum byteanlike(PG_FUNCTION_ARGS) { bytea *str = PG_GETARG_BYTEA_P(0); - text *pat = PG_GETARG_TEXT_P(1); + bytea *pat = PG_GETARG_BYTEA_P(1); bool result; unsigned char *s, *p; diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 4835b0c3a5..dc0b520b92 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.114 2002/08/29 07:22:27 ishii Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.115 2002/09/02 06:22:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -73,6 +73,7 @@ #include #include "access/heapam.h" +#include "access/tuptoaster.h" #include "catalog/catname.h" #include "catalog/pg_namespace.h" #include "catalog/pg_operator.h" @@ -168,8 +169,8 @@ static bool get_restriction_var(List *args, int varRelid, Var **var, Node **other, bool *varonleft); static void get_join_vars(List *args, Var **var1, Var **var2); -static Selectivity prefix_selectivity(Query *root, Var *var, char *prefix); -static Selectivity pattern_selectivity(char *patt, Pattern_Type ptype); +static Selectivity prefix_selectivity(Query *root, Var *var, Const *prefix); +static Selectivity pattern_selectivity(Const *patt, Pattern_Type ptype); static bool string_lessthan(const char *str1, const char *str2, Oid datatype); static Oid find_operator(const char *opname, Oid datatype); @@ -826,10 +827,10 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype) bool varonleft; Oid relid; Datum constval; - char *patt; Pattern_Prefix_Status pstatus; - char *prefix; - char *rest; + Const *patt = NULL; + Const *prefix = NULL; + Const *rest = NULL; double result; /* @@ -853,11 +854,13 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype) if (((Const *) other)->constisnull) return 0.0; constval = ((Const *) other)->constvalue; - /* the right-hand const is type text for all supported operators */ - Assert(((Const *) other)->consttype == TEXTOID); - patt = DatumGetCString(DirectFunctionCall1(textout, constval)); + + /* the right-hand const is type text or bytea for all supported operators */ + Assert(((Const *) other)->consttype == TEXTOID || + ((Const *) other)->consttype == BYTEAOID); /* divide pattern into fixed prefix and remainder */ + patt = (Const *) other; pstatus = pattern_fixed_prefix(patt, ptype, &prefix, &rest); if (pstatus == Pattern_Prefix_Exact) @@ -866,14 +869,12 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype) * Pattern specifies an exact match, so pretend operator is '=' */ Oid eqopr = find_operator("=", var->vartype); - Const *eqcon; List *eqargs; if (eqopr == InvalidOid) elog(ERROR, "patternsel: no = operator for type %u", var->vartype); - eqcon = string_to_const(prefix, var->vartype); - eqargs = makeList2(var, eqcon); + eqargs = makeList2(var, prefix); result = DatumGetFloat8(DirectFunctionCall4(eqsel, PointerGetDatum(root), ObjectIdGetDatum(eqopr), @@ -903,8 +904,10 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype) } if (prefix) + { + pfree(DatumGetPointer(prefix->constvalue)); pfree(prefix); - pfree(patt); + } return result; } @@ -2693,17 +2696,39 @@ get_join_vars(List *args, Var **var1, Var **var2) */ static Pattern_Prefix_Status -like_fixed_prefix(char *patt, bool case_insensitive, - char **prefix, char **rest) +like_fixed_prefix(Const *patt_const, bool case_insensitive, + Const **prefix_const, Const **rest_const) { char *match; + char *patt; + int pattlen; + char *prefix; + char *rest; + Oid typeid = patt_const->consttype; int pos, match_pos; - *prefix = match = palloc(strlen(patt) + 1); + /* the right-hand const is type text or bytea */ + Assert(typeid == BYTEAOID || typeid == TEXTOID); + + if (typeid == BYTEAOID && case_insensitive) + elog(ERROR, "Cannot perform case insensitive matching on type BYTEA"); + + if (typeid != BYTEAOID) + { + patt = DatumGetCString(DirectFunctionCall1(textout, patt_const->constvalue)); + pattlen = strlen(patt); + } + else + { + patt = DatumGetCString(DirectFunctionCall1(byteaout, patt_const->constvalue)); + pattlen = toast_raw_datum_size(patt_const->constvalue) - VARHDRSZ; + } + + prefix = match = palloc(pattlen + 1); match_pos = 0; - for (pos = 0; patt[pos]; pos++) + for (pos = 0; pos < pattlen; pos++) { /* % and _ are wildcard characters in LIKE */ if (patt[pos] == '%' || @@ -2713,7 +2738,7 @@ like_fixed_prefix(char *patt, bool case_insensitive, if (patt[pos] == '\\') { pos++; - if (patt[pos] == '\0') + if (patt[pos] == '\0' && typeid != BYTEAOID) break; } @@ -2733,35 +2758,58 @@ like_fixed_prefix(char *patt, bool case_insensitive, } match[match_pos] = '\0'; - *rest = &patt[pos]; + rest = &patt[pos]; + + *prefix_const = string_to_const(prefix, typeid); + *rest_const = string_to_const(rest, typeid); + + pfree(patt); + pfree(match); + prefix = NULL; /* in LIKE, an empty pattern is an exact match! */ - if (patt[pos] == '\0') + if (pos == pattlen) return Pattern_Prefix_Exact; /* reached end of pattern, so * exact */ if (match_pos > 0) return Pattern_Prefix_Partial; - pfree(match); - *prefix = NULL; return Pattern_Prefix_None; } static Pattern_Prefix_Status -regex_fixed_prefix(char *patt, bool case_insensitive, - char **prefix, char **rest) +regex_fixed_prefix(Const *patt_const, bool case_insensitive, + Const **prefix_const, Const **rest_const) { char *match; int pos, match_pos, paren_depth; + char *patt; + char *prefix; + char *rest; + 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) + elog(ERROR, "Regex matching not supported on type BYTEA"); + + /* the right-hand const is type text for all of these */ + patt = DatumGetCString(DirectFunctionCall1(textout, patt_const->constvalue)); /* Pattern must be anchored left */ if (patt[0] != '^') { - *prefix = NULL; - *rest = patt; + rest = patt; + + *prefix_const = NULL; + *rest_const = string_to_const(rest, typeid); + return Pattern_Prefix_None; } @@ -2774,8 +2822,11 @@ regex_fixed_prefix(char *patt, bool case_insensitive, { if (patt[pos] == '|' && paren_depth == 0) { - *prefix = NULL; - *rest = patt; + rest = patt; + + *prefix_const = NULL; + *rest_const = string_to_const(rest, typeid); + return Pattern_Prefix_None; } else if (patt[pos] == '(') @@ -2792,7 +2843,7 @@ regex_fixed_prefix(char *patt, bool case_insensitive, } /* OK, allocate space for pattern */ - *prefix = match = palloc(strlen(patt) + 1); + prefix = match = palloc(strlen(patt) + 1); match_pos = 0; /* note start at pos 1 to skip leading ^ */ @@ -2841,25 +2892,34 @@ regex_fixed_prefix(char *patt, bool case_insensitive, } match[match_pos] = '\0'; - *rest = &patt[pos]; + rest = &patt[pos]; if (patt[pos] == '$' && patt[pos + 1] == '\0') { - *rest = &patt[pos + 1]; + rest = &patt[pos + 1]; + + *prefix_const = string_to_const(prefix, typeid); + *rest_const = string_to_const(rest, typeid); + return Pattern_Prefix_Exact; /* pattern specifies exact match */ } + *prefix_const = string_to_const(prefix, typeid); + *rest_const = string_to_const(rest, typeid); + + pfree(patt); + pfree(match); + prefix = NULL; + if (match_pos > 0) return Pattern_Prefix_Partial; - pfree(match); - *prefix = NULL; return Pattern_Prefix_None; } Pattern_Prefix_Status -pattern_fixed_prefix(char *patt, Pattern_Type ptype, - char **prefix, char **rest) +pattern_fixed_prefix(Const *patt, Pattern_Type ptype, + Const **prefix, Const **rest) { Pattern_Prefix_Status result; @@ -2897,19 +2957,23 @@ pattern_fixed_prefix(char *patt, Pattern_Type ptype, * more useful to use the upper-bound code than not. */ static Selectivity -prefix_selectivity(Query *root, Var *var, char *prefix) +prefix_selectivity(Query *root, Var *var, Const *prefixcon) { Selectivity prefixsel; Oid cmpopr; - Const *prefixcon; + char *prefix; List *cmpargs; - char *greaterstr; + Const *greaterstrcon; cmpopr = find_operator(">=", var->vartype); if (cmpopr == InvalidOid) elog(ERROR, "prefix_selectivity: no >= operator for type %u", var->vartype); - prefixcon = string_to_const(prefix, var->vartype); + if (prefixcon->consttype != BYTEAOID) + prefix = DatumGetCString(DirectFunctionCall1(textout, prefixcon->constvalue)); + else + prefix = DatumGetCString(DirectFunctionCall1(byteaout, prefixcon->constvalue)); + cmpargs = makeList2(var, prefixcon); /* Assume scalargtsel is appropriate for all supported types */ prefixsel = DatumGetFloat8(DirectFunctionCall4(scalargtsel, @@ -2923,8 +2987,8 @@ prefix_selectivity(Query *root, Var *var, char *prefix) * "x < greaterstr". *------- */ - greaterstr = make_greater_string(prefix, var->vartype); - if (greaterstr) + greaterstrcon = make_greater_string(prefixcon); + if (greaterstrcon) { Selectivity topsel; @@ -2932,8 +2996,7 @@ prefix_selectivity(Query *root, Var *var, char *prefix) if (cmpopr == InvalidOid) elog(ERROR, "prefix_selectivity: no < operator for type %u", var->vartype); - prefixcon = string_to_const(greaterstr, var->vartype); - cmpargs = makeList2(var, prefixcon); + cmpargs = makeList2(var, greaterstrcon); /* Assume scalarltsel is appropriate for all supported types */ topsel = DatumGetFloat8(DirectFunctionCall4(scalarltsel, PointerGetDatum(root), @@ -2997,14 +3060,35 @@ prefix_selectivity(Query *root, Var *var, char *prefix) #define PARTIAL_WILDCARD_SEL 2.0 static Selectivity -like_selectivity(char *patt, bool case_insensitive) +like_selectivity(Const *patt_const, bool case_insensitive) { Selectivity sel = 1.0; int pos; + int start; + 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) + elog(ERROR, "Cannot perform case insensitive matching on type BYTEA"); + + if (typeid != BYTEAOID) + { + patt = DatumGetCString(DirectFunctionCall1(textout, patt_const->constvalue)); + pattlen = strlen(patt); + } + else + { + patt = DatumGetCString(DirectFunctionCall1(byteaout, patt_const->constvalue)); + pattlen = toast_raw_datum_size(patt_const->constvalue) - VARHDRSZ; + } /* Skip any leading %; it's already factored into initial sel */ - pos = (*patt == '%') ? 1 : 0; - for (; patt[pos]; pos++) + start = (*patt == '%') ? 1 : 0; + for (pos = start; pos < pattlen; pos++) { /* % and _ are wildcard characters in LIKE */ if (patt[pos] == '%') @@ -3015,7 +3099,7 @@ like_selectivity(char *patt, bool case_insensitive) { /* Backslash quotes the next character */ pos++; - if (patt[pos] == '\0') + if (patt[pos] == '\0' && typeid != BYTEAOID) break; sel *= FIXED_CHAR_SEL; } @@ -3122,10 +3206,24 @@ regex_selectivity_sub(char *patt, int pattlen, bool case_insensitive) } static Selectivity -regex_selectivity(char *patt, bool case_insensitive) +regex_selectivity(Const *patt_const, bool case_insensitive) { Selectivity sel; - int pattlen = strlen(patt); + 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) + elog(ERROR, "Regex 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] == '$' && @@ -3146,7 +3244,7 @@ regex_selectivity(char *patt, bool case_insensitive) } static Selectivity -pattern_selectivity(char *patt, Pattern_Type ptype) +pattern_selectivity(Const *patt, Pattern_Type ptype) { Selectivity result; @@ -3220,19 +3318,33 @@ locale_is_like_safe(void) * sort passes, etc. For now, we just shut down the whole thing in locales * that do such things :-( */ -char * -make_greater_string(const char *str, Oid datatype) +Const * +make_greater_string(const Const *str_const) { + Oid datatype = str_const->consttype; + char *str; char *workstr; int len; - /* - * Make a modifiable copy, which will be our return value if - * successful - */ - workstr = pstrdup((char *) str); + /* Get the string and a modifiable copy */ + if (datatype == NAMEOID) + { + str = DatumGetCString(DirectFunctionCall1(nameout, str_const->constvalue)); + len = strlen(str); + } + else if (datatype == BYTEAOID) + { + str = DatumGetCString(DirectFunctionCall1(byteaout, str_const->constvalue)); + len = toast_raw_datum_size(str_const->constvalue) - VARHDRSZ; + } + else + { + str = DatumGetCString(DirectFunctionCall1(textout, str_const->constvalue)); + len = strlen(str); + } + workstr = pstrdup(str); - while ((len = strlen(workstr)) > 0) + while (len > 0) { unsigned char *lastchar = (unsigned char *) (workstr + len - 1); @@ -3243,20 +3355,34 @@ make_greater_string(const char *str, Oid datatype) { (*lastchar)++; if (string_lessthan(str, workstr, datatype)) - return workstr; /* Success! */ + { + /* Success! */ + Const *workstr_const = string_to_const(workstr, datatype); + + pfree(str); + pfree(workstr); + return workstr_const; + } } /* * Truncate off the last character, which might be more than 1 * byte in MULTIBYTE case. */ - len = pg_mbcliplen((const unsigned char *) workstr, len, len - 1); - workstr[len] = '\0'; + if (datatype != BYTEAOID && pg_database_encoding_max_length() > 1) + len = pg_mbcliplen((const unsigned char *) workstr, len, len - 1); + else + len -= - 1; + + if (datatype != BYTEAOID) + workstr[len] = '\0'; } /* Failed... */ + pfree(str); pfree(workstr); - return NULL; + + return (Const *) NULL; } /* @@ -3330,12 +3456,16 @@ find_operator(const char *opname, Oid datatype) static Datum string_to_datum(const char *str, Oid datatype) { + Assert(str != NULL); + /* * We cheat a little by assuming that textin() will do for bpchar and * varchar constants too... */ if (datatype == NAMEOID) return DirectFunctionCall1(namein, CStringGetDatum(str)); + else if (datatype == BYTEAOID) + return DirectFunctionCall1(byteain, CStringGetDatum(str)); else return DirectFunctionCall1(textin, CStringGetDatum(str)); } diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index ed71bae3bb..ccf32bb2ea 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_operator.h,v 1.107 2002/08/22 04:45:11 momjian Exp $ + * $Id: pg_operator.h,v 1.108 2002/09/02 06:22:19 momjian Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -827,9 +827,9 @@ DATA(insert OID = 1957 ( "<" PGNSP PGUID b f 17 17 16 1959 1960 0 0 0 0 DATA(insert OID = 1958 ( "<=" PGNSP PGUID b f 17 17 16 1960 1959 0 0 0 0 byteale scalarltsel scalarltjoinsel )); DATA(insert OID = 1959 ( ">" PGNSP PGUID b f 17 17 16 1957 1958 0 0 0 0 byteagt scalargtsel scalargtjoinsel )); DATA(insert OID = 1960 ( ">=" PGNSP PGUID b f 17 17 16 1958 1957 0 0 0 0 byteage scalargtsel scalargtjoinsel )); -DATA(insert OID = 2016 ( "~~" PGNSP PGUID b f 17 25 16 0 2017 0 0 0 0 bytealike likesel likejoinsel )); +DATA(insert OID = 2016 ( "~~" PGNSP PGUID b f 17 17 16 0 2017 0 0 0 0 bytealike likesel likejoinsel )); #define OID_BYTEA_LIKE_OP 2016 -DATA(insert OID = 2017 ( "!~~" PGNSP PGUID b f 17 25 16 0 2016 0 0 0 0 byteanlike nlikesel nlikejoinsel )); +DATA(insert OID = 2017 ( "!~~" PGNSP PGUID b f 17 17 16 0 2016 0 0 0 0 byteanlike nlikesel nlikejoinsel )); DATA(insert OID = 2018 ( "||" PGNSP PGUID b f 17 17 17 0 0 0 0 0 0 byteacat - - )); /* timestamp operators */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index e0b7c2beee..0106132f59 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.267 2002/09/01 00:58:06 tgl Exp $ + * $Id: pg_proc.h,v 1.268 2002/09/02 06:22:19 momjian Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2770,13 +2770,13 @@ DESCR("adjust time precision"); DATA(insert OID = 1969 ( timetz PGNSP PGUID 12 f f t f i 2 1266 "1266 23" timetz_scale - _null_ )); DESCR("adjust time with time zone precision"); -DATA(insert OID = 2005 ( bytealike PGNSP PGUID 12 f f t f i 2 16 "17 25" bytealike - _null_ )); +DATA(insert OID = 2005 ( bytealike PGNSP PGUID 12 f f t f i 2 16 "17 17" bytealike - _null_ )); DESCR("matches LIKE expression"); -DATA(insert OID = 2006 ( byteanlike PGNSP PGUID 12 f f t f i 2 16 "17 25" byteanlike - _null_ )); +DATA(insert OID = 2006 ( byteanlike PGNSP PGUID 12 f f t f i 2 16 "17 17" byteanlike - _null_ )); DESCR("does not match LIKE expression"); -DATA(insert OID = 2007 ( like PGNSP PGUID 12 f f t f i 2 16 "17 25" bytealike - _null_ )); +DATA(insert OID = 2007 ( like PGNSP PGUID 12 f f t f i 2 16 "17 17" bytealike - _null_ )); DESCR("matches LIKE expression"); -DATA(insert OID = 2008 ( notlike PGNSP PGUID 12 f f t f i 2 16 "17 25" byteanlike - _null_ )); +DATA(insert OID = 2008 ( notlike PGNSP PGUID 12 f f t f i 2 16 "17 17" byteanlike - _null_ )); DESCR("does not match LIKE expression"); DATA(insert OID = 2009 ( like_escape PGNSP PGUID 12 f f t f i 2 17 "17 17" like_escape_bytea - _null_ )); DESCR("convert match pattern to use backslash escapes"); diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h index 18047f5dbf..b85500dfde 100644 --- a/src/include/utils/selfuncs.h +++ b/src/include/utils/selfuncs.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: selfuncs.h,v 1.6 2002/06/20 20:29:53 momjian Exp $ + * $Id: selfuncs.h,v 1.7 2002/09/02 06:22:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -33,12 +33,12 @@ typedef enum /* selfuncs.c */ -extern Pattern_Prefix_Status pattern_fixed_prefix(char *patt, +extern Pattern_Prefix_Status pattern_fixed_prefix(Const *patt, Pattern_Type ptype, - char **prefix, - char **rest); + Const **prefix, + Const **rest); extern bool locale_is_like_safe(void); -extern char *make_greater_string(const char *str, Oid datatype); +extern Const *make_greater_string(const Const *str_const); extern Datum eqsel(PG_FUNCTION_ARGS); extern Datum neqsel(PG_FUNCTION_ARGS);