Re: bytea operator bugs (was Re: [GENERAL] BYTEA, indexes - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: bytea operator bugs (was Re: [GENERAL] BYTEA, indexes |
Date | |
Msg-id | 200209020621.g826LSv25089@candle.pha.pa.us Whole thread Raw |
In response to | Re: bytea operator bugs (was Re: [GENERAL] BYTEA, indexes (Joe Conway <mail@joeconway.com>) |
List | pgsql-patches |
Patch applied. Thanks. --------------------------------------------------------------------------- Joe Conway wrote: > Tom Lane wrote: > > Joe Conway <mail@joeconway.com> writes: > >>OK. I'll look at both options and make another diff -c proposal ;-) Once > >>that's resolved I'll go back to original issue Alvar raised. > > > > Okay. When you get back to the original issue, the gold is hidden in > > 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 > -- e.g.: > > > parts=# explain select * from bombytea where parent_part like '05-05%'; > QUERY PLAN > ------------------------------------------------------------------------------------- > Index Scan using bombytea_idx1 on bombytea (cost=0.00..3479.67 > rows=1118 width=34) > Index Cond: ((parent_part >= '05-05'::bytea) AND (parent_part < > '05-06'::bytea)) > Filter: (parent_part ~~ '05-05%'::bytea) > (3 rows) > > > Passes all regression tests, and as far as I can tell does not break or > change the behavior of anything else. Please review and apply if there > are no objections (I'd like to see this applied for 7.3, before the > freeze, if possible, but I'll certainly understand if I'm told there's > not enough time left). > > Thanks, > > Joe > Index: src/backend/optimizer/path/indxpath.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/optimizer/path/indxpath.c,v > retrieving revision 1.120 > diff -c -r1.120 indxpath.c > *** src/backend/optimizer/path/indxpath.c 13 Jul 2002 19:20:34 -0000 1.120 > --- src/backend/optimizer/path/indxpath.c 1 Sep 2002 22:19:16 -0000 > *************** > *** 97,103 **** > 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); > 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); > --- 97,103 ---- > static bool match_special_index_operator(Expr *clause, Oid opclass, > bool indexkey_on_left); > static List *prefix_quals(Var *leftop, Oid expr_op, > ! 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,1684 **** > Var *leftop, > *rightop; > Oid expr_op; > ! Datum constvalue; > ! char *patt; > ! char *prefix; > ! char *rest; > > /* > * Currently, all known special operators require the indexkey on the > --- 1675,1683 ---- > Var *leftop, > *rightop; > Oid expr_op; > ! Const *patt = NULL; > ! Const *prefix = NULL; > ! Const *rest = NULL; > > /* > * Currently, all known special operators require the indexkey on the > *************** > *** 1697,1703 **** > if (!IsA(rightop, Const) || > ((Const *) rightop)->constisnull) > return false; > ! constvalue = ((Const *) rightop)->constvalue; > > switch (expr_op) > { > --- 1696,1702 ---- > if (!IsA(rightop, Const) || > ((Const *) rightop)->constisnull) > return false; > ! patt = (Const *) rightop; > > switch (expr_op) > { > *************** > *** 1705,1772 **** > case OID_BPCHAR_LIKE_OP: > case OID_VARCHAR_LIKE_OP: > case OID_NAME_LIKE_OP: > 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_TEXT_ICLIKE_OP: > case OID_BPCHAR_ICLIKE_OP: > case OID_VARCHAR_ICLIKE_OP: > case OID_NAME_ICLIKE_OP: > 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: > 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: > 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: > --- 1704,1748 ---- > 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()) > isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like, > &prefix, &rest) != Pattern_Prefix_None; > ! 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()) > isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like_IC, > &prefix, &rest) != Pattern_Prefix_None; > 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()) > isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex, > &prefix, &rest) != Pattern_Prefix_None; > 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()) > isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC, > &prefix, &rest) != Pattern_Prefix_None; > break; > > case OID_INET_SUB_OP: > *************** > *** 1777,1782 **** > --- 1753,1764 ---- > break; > } > > + if (prefix) > + { > + pfree(DatumGetPointer(prefix->constvalue)); > + pfree(prefix); > + } > + > /* done if the expression doesn't look indexable */ > if (!isIndexable) > return false; > *************** > *** 1798,1803 **** > --- 1780,1791 ---- > 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,1876 **** > 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; > Pattern_Prefix_Status pstatus; > > switch (expr_op) > --- 1855,1863 ---- > Var *leftop = get_leftop(clause); > Var *rightop = get_rightop(clause); > Oid expr_op = ((Oper *) clause->oper)->opno; > ! Const *patt = (Const *) rightop; > ! Const *prefix = NULL; > ! Const *rest = NULL; > Pattern_Prefix_Status pstatus; > > switch (expr_op) > *************** > *** 1885,1902 **** > 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)); > 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: > --- 1872,1883 ---- > case OID_BPCHAR_LIKE_OP: > case OID_VARCHAR_LIKE_OP: > case OID_NAME_LIKE_OP: > ! 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)); > break; > > case OID_TEXT_ICLIKE_OP: > *************** > *** 1904,1920 **** > 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: > --- 1885,1895 ---- > *************** > *** 1922,1938 **** > 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: > --- 1897,1907 ---- > *************** > *** 1940,1966 **** > 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)); > break; > > default: > --- 1909,1928 ---- > case OID_VARCHAR_ICREGEXEQ_OP: > case OID_NAME_ICREGEXEQ_OP: > /* the right-hand const is type text for all of these */ > pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC, > &prefix, &rest); > resultquals = nconc(resultquals, > prefix_quals(leftop, expr_op, > prefix, pstatus)); > break; > > case OID_INET_SUB_OP: > case OID_INET_SUBEQ_OP: > case OID_CIDR_SUB_OP: > case OID_CIDR_SUBEQ_OP: > resultquals = nconc(resultquals, > network_prefix_quals(leftop, expr_op, > ! patt->constvalue)); > break; > > default: > *************** > *** 1980,1994 **** > */ > static List * > prefix_quals(Var *leftop, Oid expr_op, > ! char *prefix, Pattern_Prefix_Status pstatus) > { > List *result; > Oid datatype; > Oid oproid; > Const *con; > Oper *op; > Expr *expr; > ! char *greaterstr; > > Assert(pstatus != Pattern_Prefix_None); > > --- 1942,1957 ---- > */ > static List * > prefix_quals(Var *leftop, Oid expr_op, > ! Const *prefix_const, Pattern_Prefix_Status pstatus) > { > List *result; > Oid datatype; > Oid oproid; > + char *prefix; > Const *con; > Oper *op; > Expr *expr; > ! Const *greaterstr = NULL; > > Assert(pstatus != Pattern_Prefix_None); > > *************** > *** 2001,2006 **** > --- 1964,1973 ---- > 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,2032 **** > --- 1994,2004 ---- > 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,2076 **** > * "x < greaterstr". > *------- > */ > ! greaterstr = make_greater_string(prefix, datatype); > 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); > result = lappend(result, expr); > - pfree(greaterstr); > } > > return result; > --- 2032,2046 ---- > * "x < greaterstr". > *------- > */ > ! greaterstr = make_greater_string(con); > if (greaterstr) > { > oproid = find_operator("<", datatype); > if (oproid == InvalidOid) > elog(ERROR, "prefix_quals: no < operator for type %u", datatype); > op = makeOper(oproid, InvalidOid, BOOLOID, false); > ! expr = make_opclause(op, leftop, (Var *) greaterstr); > result = lappend(result, expr); > } > > return result; > *************** > *** 2186,2191 **** > --- 2156,2163 ---- > */ > if (datatype == NAMEOID) > return DirectFunctionCall1(namein, CStringGetDatum(str)); > + else if (datatype == BYTEAOID) > + return DirectFunctionCall1(byteain, CStringGetDatum(str)); > else > return DirectFunctionCall1(textin, CStringGetDatum(str)); > } > Index: src/backend/utils/adt/like.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/like.c,v > retrieving revision 1.51 > diff -c -r1.51 like.c > *** src/backend/utils/adt/like.c 29 Aug 2002 07:22:26 -0000 1.51 > --- src/backend/utils/adt/like.c 1 Sep 2002 21:46:27 -0000 > *************** > *** 242,248 **** > bytealike(PG_FUNCTION_ARGS) > { > bytea *str = PG_GETARG_BYTEA_P(0); > ! text *pat = PG_GETARG_TEXT_P(1); > bool result; > unsigned char *s, > *p; > --- 242,248 ---- > bytealike(PG_FUNCTION_ARGS) > { > bytea *str = PG_GETARG_BYTEA_P(0); > ! bytea *pat = PG_GETARG_BYTEA_P(1); > bool result; > unsigned char *s, > *p; > *************** > *** 263,269 **** > byteanlike(PG_FUNCTION_ARGS) > { > bytea *str = PG_GETARG_BYTEA_P(0); > ! text *pat = PG_GETARG_TEXT_P(1); > bool result; > unsigned char *s, > *p; > --- 263,269 ---- > byteanlike(PG_FUNCTION_ARGS) > { > bytea *str = PG_GETARG_BYTEA_P(0); > ! bytea *pat = PG_GETARG_BYTEA_P(1); > bool result; > unsigned char *s, > *p; > Index: src/backend/utils/adt/selfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/selfuncs.c,v > retrieving revision 1.114 > diff -c -r1.114 selfuncs.c > *** src/backend/utils/adt/selfuncs.c 29 Aug 2002 07:22:27 -0000 1.114 > --- src/backend/utils/adt/selfuncs.c 1 Sep 2002 23:14:57 -0000 > *************** > *** 73,78 **** > --- 73,79 ---- > #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,175 **** > 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 bool string_lessthan(const char *str1, const char *str2, > Oid datatype); > static Oid find_operator(const char *opname, Oid datatype); > --- 169,176 ---- > 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, 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,835 **** > bool varonleft; > Oid relid; > Datum constval; > - char *patt; > Pattern_Prefix_Status pstatus; > ! char *prefix; > ! char *rest; > double result; > > /* > --- 827,836 ---- > bool varonleft; > Oid relid; > Datum constval; > Pattern_Prefix_Status pstatus; > ! Const *patt = NULL; > ! Const *prefix = NULL; > ! Const *rest = NULL; > double result; > > /* > *************** > *** 853,863 **** > 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)); > > /* divide pattern into fixed prefix and remainder */ > pstatus = pattern_fixed_prefix(patt, ptype, &prefix, &rest); > > if (pstatus == Pattern_Prefix_Exact) > --- 854,866 ---- > if (((Const *) other)->constisnull) > return 0.0; > constval = ((Const *) other)->constvalue; > ! > ! /* 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,879 **** > * 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); > result = DatumGetFloat8(DirectFunctionCall4(eqsel, > PointerGetDatum(root), > ObjectIdGetDatum(eqopr), > --- 869,880 ---- > * Pattern specifies an exact match, so pretend operator is '=' > */ > Oid eqopr = find_operator("=", var->vartype); > List *eqargs; > > if (eqopr == InvalidOid) > elog(ERROR, "patternsel: no = operator for type %u", > var->vartype); > ! eqargs = makeList2(var, prefix); > result = DatumGetFloat8(DirectFunctionCall4(eqsel, > PointerGetDatum(root), > ObjectIdGetDatum(eqopr), > *************** > *** 903,910 **** > } > > if (prefix) > pfree(prefix); > ! pfree(patt); > > return result; > } > --- 904,913 ---- > } > > if (prefix) > + { > + pfree(DatumGetPointer(prefix->constvalue)); > pfree(prefix); > ! } > > return result; > } > *************** > *** 2693,2709 **** > */ > > static Pattern_Prefix_Status > ! like_fixed_prefix(char *patt, bool case_insensitive, > ! char **prefix, char **rest) > { > char *match; > int pos, > match_pos; > > ! *prefix = match = palloc(strlen(patt) + 1); > match_pos = 0; > > ! for (pos = 0; patt[pos]; pos++) > { > /* % and _ are wildcard characters in LIKE */ > if (patt[pos] == '%' || > --- 2696,2734 ---- > */ > > static Pattern_Prefix_Status > ! 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; > > ! /* 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; pos < pattlen; pos++) > { > /* % and _ are wildcard characters in LIKE */ > if (patt[pos] == '%' || > *************** > *** 2713,2719 **** > if (patt[pos] == '\\') > { > pos++; > ! if (patt[pos] == '\0') > break; > } > > --- 2738,2744 ---- > if (patt[pos] == '\\') > { > pos++; > ! if (patt[pos] == '\0' && typeid != BYTEAOID) > break; > } > > *************** > *** 2733,2767 **** > } > > match[match_pos] = '\0'; > ! *rest = &patt[pos]; > > /* in LIKE, an empty pattern is an exact match! */ > ! if (patt[pos] == '\0') > 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) > { > char *match; > int pos, > match_pos, > paren_depth; > > /* Pattern must be anchored left */ > if (patt[0] != '^') > { > ! *prefix = NULL; > ! *rest = patt; > return Pattern_Prefix_None; > } > > --- 2758,2815 ---- > } > > match[match_pos] = '\0'; > ! 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 (pos == pattlen) > return Pattern_Prefix_Exact; /* reached end of pattern, so > * exact */ > > if (match_pos > 0) > return Pattern_Prefix_Partial; > > return Pattern_Prefix_None; > } > > static Pattern_Prefix_Status > ! 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] != '^') > { > ! rest = patt; > ! > ! *prefix_const = NULL; > ! *rest_const = string_to_const(rest, typeid); > ! > return Pattern_Prefix_None; > } > > *************** > *** 2774,2781 **** > { > if (patt[pos] == '|' && paren_depth == 0) > { > ! *prefix = NULL; > ! *rest = patt; > return Pattern_Prefix_None; > } > else if (patt[pos] == '(') > --- 2822,2832 ---- > { > if (patt[pos] == '|' && paren_depth == 0) > { > ! rest = patt; > ! > ! *prefix_const = NULL; > ! *rest_const = string_to_const(rest, typeid); > ! > return Pattern_Prefix_None; > } > else if (patt[pos] == '(') > *************** > *** 2792,2798 **** > } > > /* OK, allocate space for pattern */ > ! *prefix = match = palloc(strlen(patt) + 1); > match_pos = 0; > > /* note start at pos 1 to skip leading ^ */ > --- 2843,2849 ---- > } > > /* OK, allocate space for pattern */ > ! prefix = match = palloc(strlen(patt) + 1); > match_pos = 0; > > /* note start at pos 1 to skip leading ^ */ > *************** > *** 2841,2865 **** > } > > match[match_pos] = '\0'; > ! *rest = &patt[pos]; > > if (patt[pos] == '$' && patt[pos + 1] == '\0') > { > ! *rest = &patt[pos + 1]; > return Pattern_Prefix_Exact; /* pattern specifies exact match */ > } > > 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_Prefix_Status result; > > --- 2892,2925 ---- > } > > match[match_pos] = '\0'; > ! rest = &patt[pos]; > > if (patt[pos] == '$' && patt[pos + 1] == '\0') > { > ! 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; > > return Pattern_Prefix_None; > } > > Pattern_Prefix_Status > ! pattern_fixed_prefix(Const *patt, Pattern_Type ptype, > ! Const **prefix, Const **rest) > { > Pattern_Prefix_Status result; > > *************** > *** 2897,2915 **** > * more useful to use the upper-bound code than not. > */ > static Selectivity > ! prefix_selectivity(Query *root, Var *var, char *prefix) > { > Selectivity prefixsel; > Oid cmpopr; > ! Const *prefixcon; > List *cmpargs; > ! char *greaterstr; > > 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); > cmpargs = makeList2(var, prefixcon); > /* Assume scalargtsel is appropriate for all supported types */ > prefixsel = DatumGetFloat8(DirectFunctionCall4(scalargtsel, > --- 2957,2979 ---- > * more useful to use the upper-bound code than not. > */ > static Selectivity > ! prefix_selectivity(Query *root, Var *var, Const *prefixcon) > { > Selectivity prefixsel; > Oid cmpopr; > ! char *prefix; > List *cmpargs; > ! Const *greaterstrcon; > > cmpopr = find_operator(">=", var->vartype); > if (cmpopr == InvalidOid) > elog(ERROR, "prefix_selectivity: no >= operator for type %u", > 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,2930 **** > * "x < greaterstr". > *------- > */ > ! greaterstr = make_greater_string(prefix, var->vartype); > ! if (greaterstr) > { > Selectivity topsel; > > --- 2987,2994 ---- > * "x < greaterstr". > *------- > */ > ! greaterstrcon = make_greater_string(prefixcon); > ! if (greaterstrcon) > { > Selectivity topsel; > > *************** > *** 2932,2939 **** > 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); > /* Assume scalarltsel is appropriate for all supported types */ > topsel = DatumGetFloat8(DirectFunctionCall4(scalarltsel, > PointerGetDatum(root), > --- 2996,3002 ---- > if (cmpopr == InvalidOid) > elog(ERROR, "prefix_selectivity: no < operator for type %u", > var->vartype); > ! cmpargs = makeList2(var, greaterstrcon); > /* Assume scalarltsel is appropriate for all supported types */ > topsel = DatumGetFloat8(DirectFunctionCall4(scalarltsel, > PointerGetDatum(root), > *************** > *** 2997,3010 **** > #define PARTIAL_WILDCARD_SEL 2.0 > > static Selectivity > ! like_selectivity(char *patt, bool case_insensitive) > { > Selectivity sel = 1.0; > int pos; > > /* Skip any leading %; it's already factored into initial sel */ > ! pos = (*patt == '%') ? 1 : 0; > ! for (; patt[pos]; pos++) > { > /* % and _ are wildcard characters in LIKE */ > if (patt[pos] == '%') > --- 3060,3094 ---- > #define PARTIAL_WILDCARD_SEL 2.0 > > static Selectivity > ! 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 */ > ! start = (*patt == '%') ? 1 : 0; > ! for (pos = start; pos < pattlen; pos++) > { > /* % and _ are wildcard characters in LIKE */ > if (patt[pos] == '%') > *************** > *** 3015,3021 **** > { > /* Backslash quotes the next character */ > pos++; > ! if (patt[pos] == '\0') > break; > sel *= FIXED_CHAR_SEL; > } > --- 3099,3105 ---- > { > /* Backslash quotes the next character */ > pos++; > ! if (patt[pos] == '\0' && typeid != BYTEAOID) > break; > sel *= FIXED_CHAR_SEL; > } > *************** > *** 3122,3131 **** > } > > static Selectivity > ! regex_selectivity(char *patt, bool case_insensitive) > { > Selectivity sel; > ! int pattlen = strlen(patt); > > /* If patt doesn't end with $, consider it to have a trailing wildcard */ > if (pattlen > 0 && patt[pattlen - 1] == '$' && > --- 3206,3229 ---- > } > > static Selectivity > ! regex_selectivity(Const *patt_const, bool case_insensitive) > { > Selectivity sel; > ! char *patt; > ! int pattlen; > ! Oid typeid = patt_const->consttype; > ! > ! /* > ! * Should be unnecessary, there are no bytea regex operators defined. > ! * As such, it should be noted that the rest of this function has *not* > ! * been made safe for binary (possibly NULL containing) strings. > ! */ > ! if (typeid == BYTEAOID) > ! 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,3152 **** > } > > static Selectivity > ! pattern_selectivity(char *patt, Pattern_Type ptype) > { > Selectivity result; > > --- 3244,3250 ---- > } > > static Selectivity > ! pattern_selectivity(Const *patt, Pattern_Type ptype) > { > Selectivity result; > > *************** > *** 3220,3238 **** > * 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) > { > char *workstr; > int len; > > ! /* > ! * Make a modifiable copy, which will be our return value if > ! * successful > ! */ > ! workstr = pstrdup((char *) str); > > ! while ((len = strlen(workstr)) > 0) > { > unsigned char *lastchar = (unsigned char *) (workstr + len - 1); > > --- 3318,3350 ---- > * sort passes, etc. For now, we just shut down the whole thing in locales > * that do such things :-( > */ > ! 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); > ! } > ! 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 > 0) > { > unsigned char *lastchar = (unsigned char *) (workstr + len - 1); > > *************** > *** 3243,3262 **** > { > (*lastchar)++; > if (string_lessthan(str, workstr, datatype)) > ! return workstr; /* Success! */ > } > > /* > * 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'; > } > > /* Failed... */ > pfree(workstr); > ! return NULL; > } > > /* > --- 3355,3388 ---- > { > (*lastchar)++; > if (string_lessthan(str, workstr, datatype)) > ! { > ! /* 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. > */ > ! 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 (Const *) NULL; > } > > /* > *************** > *** 3330,3341 **** > --- 3456,3471 ---- > 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: src/include/catalog/pg_operator.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_operator.h,v > retrieving revision 1.107 > diff -c -r1.107 pg_operator.h > *** src/include/catalog/pg_operator.h 22 Aug 2002 04:45:11 -0000 1.107 > --- src/include/catalog/pg_operator.h 1 Sep 2002 21:46:27 -0000 > *************** > *** 827,835 **** > 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)); > #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 = 2018 ( "||" PGNSP PGUID b f 17 17 17 0 0 0 0 0 0 byteacat - - )); > > /* timestamp operators */ > --- 827,835 ---- > 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 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 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: src/include/catalog/pg_proc.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_proc.h,v > retrieving revision 1.267 > diff -c -r1.267 pg_proc.h > *** src/include/catalog/pg_proc.h 1 Sep 2002 00:58:06 -0000 1.267 > --- src/include/catalog/pg_proc.h 1 Sep 2002 21:46:27 -0000 > *************** > *** 2770,2782 **** > 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_ )); > DESCR("matches LIKE expression"); > ! DATA(insert OID = 2006 ( byteanlike PGNSP PGUID 12 f f t f i 2 16 "17 25" 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_ )); > DESCR("matches LIKE expression"); > ! DATA(insert OID = 2008 ( notlike PGNSP PGUID 12 f f t f i 2 16 "17 25" 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"); > --- 2770,2782 ---- > 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 17" bytealike - _null_ )); > DESCR("matches LIKE expression"); > ! 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 17" bytealike - _null_ )); > DESCR("matches LIKE expression"); > ! 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: src/include/utils/selfuncs.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/utils/selfuncs.h,v > retrieving revision 1.6 > diff -c -r1.6 selfuncs.h > *** src/include/utils/selfuncs.h 20 Jun 2002 20:29:53 -0000 1.6 > --- src/include/utils/selfuncs.h 1 Sep 2002 21:46:27 -0000 > *************** > *** 33,44 **** > > /* selfuncs.c */ > > ! extern Pattern_Prefix_Status pattern_fixed_prefix(char *patt, > Pattern_Type ptype, > ! char **prefix, > ! char **rest); > extern bool locale_is_like_safe(void); > ! extern char *make_greater_string(const char *str, Oid datatype); > > extern Datum eqsel(PG_FUNCTION_ARGS); > extern Datum neqsel(PG_FUNCTION_ARGS); > --- 33,44 ---- > > /* selfuncs.c */ > > ! extern Pattern_Prefix_Status pattern_fixed_prefix(Const *patt, > Pattern_Type ptype, > ! Const **prefix, > ! Const **rest); > extern bool locale_is_like_safe(void); > ! extern Const *make_greater_string(const Const *str_const); > > extern Datum eqsel(PG_FUNCTION_ARGS); > extern Datum neqsel(PG_FUNCTION_ARGS); > > ---------------------------(end of broadcast)--------------------------- > TIP 4: Don't 'kill -9' the postmaster -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
pgsql-patches by date: