*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
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
if (!IsA(rightop, Const) ||
((Const *) rightop)->constisnull)
return false;
- constvalue = ((Const *) rightop)->constvalue;
+ patt = (Const *) rightop;
switch (expr_op)
{
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:
break;
}
+ if (prefix)
+ {
+ pfree(DatumGetPointer(prefix->constvalue));
+ pfree(prefix);
+ }
+
/* done if the expression doesn't look indexable */
if (!isIndexable)
return false;
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:
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)
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:
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:
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:
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:
*/
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);
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:
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.
*/
* "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;
*/
if (datatype == NAMEOID)
return DirectFunctionCall1(namein, CStringGetDatum(str));
+ else if (datatype == BYTEAOID)
+ return DirectFunctionCall1(byteain, CStringGetDatum(str));
else
return DirectFunctionCall1(textin, CStringGetDatum(str));
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include
#include "access/heapam.h"
+#include "access/tuptoaster.h"
#include "catalog/catname.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
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);
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;
/*
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)
* 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),
}
if (prefix)
+ {
+ pfree(DatumGetPointer(prefix->constvalue));
pfree(prefix);
- pfree(patt);
+ }
return result;
}
*/
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] == '%' ||
if (patt[pos] == '\\')
{
pos++;
- if (patt[pos] == '\0')
+ if (patt[pos] == '\0' && typeid != BYTEAOID)
break;
}
}
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;
}
{
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] == '(')
}
/* 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 ^ */
}
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;
* 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,
* "x < greaterstr".
*-------
*/
- greaterstr = make_greater_string(prefix, var->vartype);
- if (greaterstr)
+ greaterstrcon = make_greater_string(prefixcon);
+ if (greaterstrcon)
{
Selectivity topsel;
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),
#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] == '%')
{
/* Backslash quotes the next character */
pos++;
- if (patt[pos] == '\0')
+ if (patt[pos] == '\0' && typeid != BYTEAOID)
break;
sel *= FIXED_CHAR_SEL;
}
}
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] == '$' &&
}
static Selectivity
-pattern_selectivity(char *patt, Pattern_Type ptype)
+pattern_selectivity(Const *patt, Pattern_Type ptype)
{
Selectivity result;
* 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);
{
(*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;
}
/*
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));
}