]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
> Okay. When you get back to the original issue, the gold is hidden in
authorBruce Momjian <bruce@momjian.us>
Mon, 2 Sep 2002 06:22:20 +0000 (06:22 +0000)
committerBruce Momjian <bruce@momjian.us>
Mon, 2 Sep 2002 06:22:20 +0000 (06:22 +0000)
> src/backend/optimizer/path/indxpath.c; see the "special indexable
> operators" stuff near the bottom of that file.  (It's a bit of a crock
> that this code is hardwired there, and not somehow accessed through a
> system catalog, but it's what we've got at the moment.)

The attached patch re-enables a bytea right hand argument (as compared
to a text right hand argument), and enables index usage, for bytea LIKE

Joe Conway

src/backend/optimizer/path/indxpath.c
src/backend/utils/adt/like.c
src/backend/utils/adt/selfuncs.c
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/utils/selfuncs.h

index bce39f1166e53a6b9913b31d714d0416d7cee8bc..3d9ec2eb23af4ba0bfa7ba7a11d4643f4ce2426f 100644 (file)
@@ -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));
 }
index 3e67e947a9d7ef900442c20929eb13d8c0a2c928..fab47e37fa25900829dd258707a5fb4717c0d79a 100644 (file)
@@ -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;
index 4835b0c3a5e339a7aecfe2d9dcb44113711b6a2e..dc0b520b925a02205acaff9929840e063dd2bf30 100644 (file)
@@ -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 <locale.h>
 
 #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));
 }
index ed71bae3bbed0b59b15eb862653e620de113e36f..ccf32bb2eadc58c3aa6cc457d638e16d6a73d9be 100644 (file)
@@ -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 */
index e0b7c2beeea9e1b1619c996624873b4ca27bdd98..0106132f59fe420ee32619684b7388292cfb37d8 100644 (file)
@@ -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");
index 18047f5dbf9a2ca7b35108754c9b38c86e2a3556..b85500dfde7ac33823f743ced77b4b132ce68cb8 100644 (file)
@@ -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);