Repair indexed bytea like operations, and related selectivity
authorJoe Conway
Sun, 7 Dec 2003 04:14:10 +0000 (04:14 +0000)
committerJoe Conway
Sun, 7 Dec 2003 04:14:10 +0000 (04:14 +0000)
functionality. Per bug report by Alvar Freude:
http://archives.postgresql.org/pgsql-bugs/2003-12/msg00022.php

src/backend/utils/adt/selfuncs.c

index ac78e6e2652e5b6a5a99d45fcbe6107048abafb1..9b2e86224a5473191c2b47bf6653ec3bafafafcb 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.149 2003/11/29 19:51:59 pgsql Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.150 2003/12/07 04:14:10 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -184,6 +184,7 @@ static Selectivity prefix_selectivity(Query *root, Var *var,
 static Selectivity pattern_selectivity(Const *patt, Pattern_Type ptype);
 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);
 
 
 /*
@@ -3135,20 +3136,31 @@ like_fixed_prefix(Const *patt_const, bool case_insensitive,
    }
    else
    {
-       patt = DatumGetCString(DirectFunctionCall1(byteaout, patt_const->constvalue));
-       pattlen = toast_raw_datum_size(patt_const->constvalue) - VARHDRSZ;
+       bytea   *bstr = DatumGetByteaP(patt_const->constvalue);
+
+       pattlen = VARSIZE(bstr) - VARHDRSZ;
+       if (pattlen > 0)
+       {
+           patt = (char *) palloc(pattlen);
+           memcpy(patt, VARDATA(bstr), pattlen);
+       }
+       else
+           patt = NULL;
+
+       if ((Pointer) bstr != DatumGetPointer(patt_const->constvalue))
+           pfree(bstr);
    }
 
    match = palloc(pattlen + 1);
    match_pos = 0;
-
    for (pos = 0; pos < pattlen; pos++)
    {
        /* % and _ are wildcard characters in LIKE */
        if (patt[pos] == '%' ||
            patt[pos] == '_')
            break;
-       /* Backslash quotes the next character */
+
+       /* Backslash escapes the next character */
        if (patt[pos] == '\\')
        {
            pos++;
@@ -3174,10 +3186,19 @@ like_fixed_prefix(Const *patt_const, bool case_insensitive,
    match[match_pos] = '\0';
    rest = &patt[pos];
 
-   *prefix_const = string_to_const(match, typeid);
-   *rest_const = string_to_const(rest, typeid);
+   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);
+   }
 
-   pfree(patt);
+   if (patt != NULL)
+       pfree(patt);
    pfree(match);
 
    /* in LIKE, an empty pattern is an exact match! */
@@ -3500,9 +3521,22 @@ like_selectivity(Const *patt_const, bool case_insensitive)
    }
    else
    {
-       patt = DatumGetCString(DirectFunctionCall1(byteaout, patt_const->constvalue));
-       pattlen = toast_raw_datum_size(patt_const->constvalue) - VARHDRSZ;
+       bytea   *bstr = DatumGetByteaP(patt_const->constvalue);
+
+       pattlen = VARSIZE(bstr) - VARHDRSZ;
+       if (pattlen > 0)
+       {
+           patt = (char *) palloc(pattlen);
+           memcpy(patt, VARDATA(bstr), pattlen);
+       }
+       else
+           patt = NULL;
+
+       if ((Pointer) bstr != DatumGetPointer(patt_const->constvalue))
+           pfree(bstr);
    }
+   /* patt should never be NULL in practice */
+   Assert(patt != NULL);
 
    /* Skip any leading %; it's already factored into initial sel */
    start = (*patt == '%') ? 1 : 0;
@@ -3693,8 +3727,8 @@ pattern_selectivity(Const *patt, Pattern_Type ptype)
 
 /*
  * 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.
+ * string it is a prefix of.  If successful, return a palloc'd string
+ * in the form of a Const pointer; else return NULL.
  *
  * The key requirement here is that given a prefix string, say "foo",
  * we must be able to generate another string "fop" that is greater
@@ -3712,27 +3746,38 @@ Const *
 make_greater_string(const Const *str_const)
 {
    Oid         datatype = str_const->consttype;
-   char       *str;
    char       *workstr;
    int         len;
 
    /* Get the string and a modifiable copy */
    if (datatype == NAMEOID)
    {
-       str = DatumGetCString(DirectFunctionCall1(nameout, str_const->constvalue));
-       len = strlen(str);
+       workstr = DatumGetCString(DirectFunctionCall1(nameout,
+                                                     str_const->constvalue));
+       len = strlen(workstr);
    }
    else if (datatype == BYTEAOID)
    {
-       str = DatumGetCString(DirectFunctionCall1(byteaout, str_const->constvalue));
-       len = toast_raw_datum_size(str_const->constvalue) - VARHDRSZ;
+       bytea   *bstr = DatumGetByteaP(str_const->constvalue);
+
+       len = VARSIZE(bstr) - VARHDRSZ;
+       if (len > 0)
+       {
+           workstr = (char *) palloc(len);
+           memcpy(workstr, VARDATA(bstr), len);
+       }
+       else
+           workstr = NULL;
+
+       if ((Pointer) bstr != DatumGetPointer(str_const->constvalue))
+           pfree(bstr);
    }
    else
    {
-       str = DatumGetCString(DirectFunctionCall1(textout, str_const->constvalue));
-       len = strlen(str);
+       workstr = DatumGetCString(DirectFunctionCall1(textout,
+                                                     str_const->constvalue));
+       len = strlen(workstr);
    }
-   workstr = pstrdup(str);
 
    while (len > 0)
    {
@@ -3747,9 +3792,11 @@ make_greater_string(const Const *str_const)
            Const      *workstr_const;
 
            (*lastchar)++;
-           workstr_const = string_to_const(workstr, datatype);
+           if (datatype != BYTEAOID)
+               workstr_const = string_to_const(workstr, datatype);
+           else
+               workstr_const = string_to_bytea_const(workstr, len);
 
-           pfree(str);
            pfree(workstr);
            return workstr_const;
        }
@@ -3771,8 +3818,8 @@ make_greater_string(const Const *str_const)
    }
 
    /* Failed... */
-   pfree(str);
-   pfree(workstr);
+   if (workstr != NULL)
+       pfree(workstr);
 
    return (Const *) NULL;
 }
@@ -3811,6 +3858,22 @@ string_to_const(const char *str, Oid datatype)
                     conval, false, false);
 }
 
+/*
+ * Generate a Const node of bytea type from a binary C string and a length.
+ */
+static Const *
+string_to_bytea_const(const char *str, size_t str_len)
+{
+   bytea  *bstr = palloc(VARHDRSZ + str_len);
+   Datum   conval;
+
+   memcpy(VARDATA(bstr), str, str_len);
+   VARATT_SIZEP(bstr) = VARHDRSZ + str_len;
+   conval = PointerGetDatum(bstr);
+
+   return makeConst(BYTEAOID, -1, conval, false, false);
+}
+
 /*-------------------------------------------------------------------------
  *
  * Index cost estimation functions