diff options
Diffstat (limited to 'src/backend/utils/adt/selfuncs.c')
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 51 |
1 files changed, 34 insertions, 17 deletions
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 */ |