1515 *
1616 *
1717 * IDENTIFICATION
18- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.238 2007/11/07 22:37:24 tgl Exp $
18+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.239 2007/11/09 20:10:02 tgl Exp $
1919 *
2020 *-------------------------------------------------------------------------
2121 */
@@ -4586,7 +4586,10 @@ pattern_selectivity(Const *patt, Pattern_Type ptype)
45864586/*
45874587 * Try to generate a string greater than the given string or any
45884588 * string it is a prefix of. If successful, return a palloc'd string
4589- * in the form of a Const pointer; else return NULL.
4589+ * in the form of a Const node; else return NULL.
4590+ *
4591+ * The caller must provide the appropriate "less than" comparison function
4592+ * for testing the strings.
45904593 *
45914594 * The key requirement here is that given a prefix string, say "foo",
45924595 * we must be able to generate another string "fop" that is greater than
@@ -4595,11 +4598,13 @@ pattern_selectivity(Const *patt, Pattern_Type ptype)
45954598 * that is not a bulletproof guarantee that an extension of the string might
45964599 * not sort after it; an example is that "foo " is less than "foo!", but it
45974600 * is not clear that a "dictionary" sort ordering will consider "foo!" less
4598- * than "foo bar". Therefore, this function should be used only for
4601+ * than "foo bar".CAUTION: Therefore, this function should be used only for
45994602 * estimation purposes when working in a non-C locale.
46004603 *
4601- * The caller must provide the appropriate "less than" comparison function
4602- * for testing the strings.
4604+ * To try to catch most cases where an extended string might otherwise sort
4605+ * before the result value, we determine which of the strings "Z", "z", "y",
4606+ * and "9" is seen as largest by the locale, and append that to the given
4607+ * prefix before trying to find a string that compares as larger.
46034608 *
46044609 * If we max out the righthand byte, truncate off the last character
46054610 * and start incrementing the next. For example, if "z" were the last
@@ -4615,13 +4620,22 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc)
46154620Oid datatype = str_const -> consttype ;
46164621char * workstr ;
46174622int len ;
4623+ Datum cmpstr ;
4624+ text * cmptxt = NULL ;
46184625
4619- /* Get a modifiable copy of the string in C-string format */
4626+ /*
4627+ * Get a modifiable copy of the prefix string in C-string format,
4628+ * and set up the string we will compare to as a Datum. In C locale
4629+ * this can just be the given prefix string, otherwise we need to add
4630+ * a suffix. Types NAME and BYTEA sort bytewise so they don't need
4631+ * a suffix either.
4632+ */
46204633if (datatype == NAMEOID )
46214634{
46224635workstr = DatumGetCString (DirectFunctionCall1 (nameout ,
46234636str_const -> constvalue ));
46244637len = strlen (workstr );
4638+ cmpstr = str_const -> constvalue ;
46254639}
46264640else if (datatype == BYTEAOID )
46274641{
@@ -4632,12 +4646,41 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc)
46324646memcpy (workstr ,VARDATA (bstr ),len );
46334647if ((Pointer )bstr != DatumGetPointer (str_const -> constvalue ))
46344648pfree (bstr );
4649+ cmpstr = str_const -> constvalue ;
46354650}
46364651else
46374652{
46384653workstr = DatumGetCString (DirectFunctionCall1 (textout ,
46394654str_const -> constvalue ));
46404655len = strlen (workstr );
4656+ if (lc_collate_is_c ()|| len == 0 )
4657+ cmpstr = str_const -> constvalue ;
4658+ else
4659+ {
4660+ /* If first time through, determine the suffix to use */
4661+ static char suffixchar = 0 ;
4662+
4663+ if (!suffixchar )
4664+ {
4665+ char * best ;
4666+
4667+ best = "Z" ;
4668+ if (varstr_cmp (best ,1 ,"z" ,1 )< 0 )
4669+ best = "z" ;
4670+ if (varstr_cmp (best ,1 ,"y" ,1 )< 0 )
4671+ best = "y" ;
4672+ if (varstr_cmp (best ,1 ,"9" ,1 )< 0 )
4673+ best = "9" ;
4674+ suffixchar = * best ;
4675+ }
4676+
4677+ /* And build the string to compare to */
4678+ cmptxt = (text * )palloc (VARHDRSZ + len + 1 );
4679+ SET_VARSIZE (cmptxt ,VARHDRSZ + len + 1 );
4680+ memcpy (VARDATA (cmptxt ),workstr ,len );
4681+ * (VARDATA (cmptxt )+ len )= suffixchar ;
4682+ cmpstr = PointerGetDatum (cmptxt );
4683+ }
46414684}
46424685
46434686while (len > 0 )
@@ -4665,10 +4708,12 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc)
46654708workstr_const = string_to_bytea_const (workstr ,len );
46664709
46674710if (DatumGetBool (FunctionCall2 (ltproc ,
4668- str_const -> constvalue ,
4711+ cmpstr ,
46694712workstr_const -> constvalue )))
46704713{
4671- /* Successfully made a string larger than the input */
4714+ /* Successfully made a string larger than cmpstr */
4715+ if (cmptxt )
4716+ pfree (cmptxt );
46724717pfree (workstr );
46734718return workstr_const ;
46744719}
@@ -4695,6 +4740,8 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc)
46954740}
46964741
46974742/* Failed... */
4743+ if (cmptxt )
4744+ pfree (cmptxt );
46984745pfree (workstr );
46994746
47004747return NULL ;