diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 2cd8ca0c138..f5dfbc2c3f7 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.191.2.12 2007/07/31 19:54:00 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.191.2.13 2007/11/07 22:37:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2374,6 +2374,7 @@ prefix_quals(Node *leftop, Oid opclass, Oid datatype; Oid oproid; Expr *expr; + FmgrInfo ltproc; Const *greaterstr; Assert(pstatus != Pattern_Prefix_None); @@ -2470,13 +2471,14 @@ prefix_quals(Node *leftop, Oid opclass, * "x < greaterstr". *------- */ - greaterstr = make_greater_string(prefix_const); + oproid = get_opclass_member(opclass, InvalidOid, + BTLessStrategyNumber); + if (oproid == InvalidOid) + elog(ERROR, "no < operator for opclass %u", opclass); + fmgr_info(get_opcode(oproid), <proc); + greaterstr = make_greater_string(prefix_const, <proc); if (greaterstr) { - oproid = get_opclass_member(opclass, InvalidOid, - BTLessStrategyNumber); - if (oproid == InvalidOid) - elog(ERROR, "no < operator for opclass %u", opclass); expr = make_opclause(oproid, BOOLOID, false, (Expr *) leftop, (Expr *) greaterstr); result = lappend(result, make_restrictinfo(expr, true, false, NULL)); diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 8afb2a1cbe8..5f708a02558 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.191.2.3 2007/01/03 22:39:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.191.2.4 2007/11/07 22:37:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -3747,6 +3747,7 @@ prefix_selectivity(PlannerInfo *root, Node *variable, Selectivity prefixsel; Oid cmpopr; List *cmpargs; + FmgrInfo ltproc; Const *greaterstrcon; cmpopr = get_opclass_member(opclass, InvalidOid, @@ -3766,15 +3767,17 @@ prefix_selectivity(PlannerInfo *root, Node *variable, * "x < greaterstr". *------- */ - greaterstrcon = make_greater_string(prefixcon); + cmpopr = get_opclass_member(opclass, InvalidOid, + BTLessStrategyNumber); + if (cmpopr == InvalidOid) + elog(ERROR, "no < operator for opclass %u", opclass); + fmgr_info(get_opcode(cmpopr), <proc); + + greaterstrcon = make_greater_string(prefixcon, <proc); if (greaterstrcon) { Selectivity topsel; - cmpopr = get_opclass_member(opclass, InvalidOid, - BTLessStrategyNumber); - if (cmpopr == InvalidOid) - elog(ERROR, "no < operator for opclass %u", opclass); cmpargs = list_make2(variable, greaterstrcon); /* Assume scalarltsel is appropriate for all supported types */ topsel = DatumGetFloat8(DirectFunctionCall4(scalarltsel, @@ -4074,8 +4077,17 @@ pattern_selectivity(Const *patt, Pattern_Type ptype) * 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 - * than all strings "foobar" starting with "foo". + * we must be able to generate another string "fop" that is greater than + * all strings "foobar" starting with "foo". We can test that we have + * generated a string greater than the prefix string, but in non-C locales + * that is not a bulletproof guarantee that an extension of the string might + * not sort after it; an example is that "foo " is less than "foo!", but it + * is not clear that a "dictionary" sort ordering will consider "foo!" less + * than "foo bar". Therefore, this function should be used only for + * estimation purposes when working in a non-C locale. + * + * The caller must provide the appropriate "less than" comparison function + * for testing the strings. * * If we max out the righthand byte, truncate off the last character * and start incrementing the next. For example, if "z" were the last @@ -4084,20 +4096,15 @@ pattern_selectivity(Const *patt, Pattern_Type ptype) * * This could be rather slow in the worst case, but in most cases we * won't have to try more than one or two strings before succeeding. - * - * NOTE: at present this assumes we are in the C locale, so that simple - * bytewise comparison applies. However, we might be in a multibyte - * encoding such as UTF8, so we do have to watch out for generating - * invalid encoding sequences. */ Const * -make_greater_string(const Const *str_const) +make_greater_string(const Const *str_const, FmgrInfo *ltproc) { Oid datatype = str_const->consttype; char *workstr; int len; - /* Get the string and a modifiable copy */ + /* Get a modifiable copy of the string in C-string format */ if (datatype == NAMEOID) { workstr = DatumGetCString(DirectFunctionCall1(nameout, @@ -4151,8 +4158,18 @@ make_greater_string(const Const *str_const) else workstr_const = string_to_bytea_const(workstr, len); - pfree(workstr); - return workstr_const; + if (DatumGetBool(FunctionCall2(ltproc, + str_const->constvalue, + workstr_const->constvalue))) + { + /* Successfully made a string larger than the input */ + pfree(workstr); + return workstr_const; + } + + /* No good, release unusable value and try again */ + pfree(DatumGetPointer(workstr_const->constvalue)); + pfree(workstr_const); } /* restore last byte so we don't confuse pg_mbcliplen */ diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h index ba91b0b4022..a39f06c1390 100644 --- a/src/include/utils/selfuncs.h +++ b/src/include/utils/selfuncs.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/selfuncs.h,v 1.24 2005/10/15 02:49:46 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/selfuncs.h,v 1.24.2.1 2007/11/07 22:37:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -80,7 +80,7 @@ extern Pattern_Prefix_Status pattern_fixed_prefix(Const *patt, Pattern_Type ptype, Const **prefix, Const **rest); -extern Const *make_greater_string(const Const *str_const); +extern Const *make_greater_string(const Const *str_const, FmgrInfo *ltproc); extern Datum eqsel(PG_FUNCTION_ARGS); extern Datum neqsel(PG_FUNCTION_ARGS);