15
15
*
16
16
*
17
17
* 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 $
19
19
*
20
20
*-------------------------------------------------------------------------
21
21
*/
@@ -4586,7 +4586,10 @@ pattern_selectivity(Const *patt, Pattern_Type ptype)
4586
4586
/*
4587
4587
* Try to generate a string greater than the given string or any
4588
4588
* 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.
4590
4593
*
4591
4594
* The key requirement here is that given a prefix string, say "foo",
4592
4595
* we must be able to generate another string "fop" that is greater than
@@ -4595,11 +4598,13 @@ pattern_selectivity(Const *patt, Pattern_Type ptype)
4595
4598
* that is not a bulletproof guarantee that an extension of the string might
4596
4599
* not sort after it; an example is that "foo " is less than "foo!", but it
4597
4600
* 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
4599
4602
* estimation purposes when working in a non-C locale.
4600
4603
*
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.
4603
4608
*
4604
4609
* If we max out the righthand byte, truncate off the last character
4605
4610
* 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)
4615
4620
Oid datatype = str_const -> consttype ;
4616
4621
char * workstr ;
4617
4622
int len ;
4623
+ Datum cmpstr ;
4624
+ text * cmptxt = NULL ;
4618
4625
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
+ */
4620
4633
if (datatype == NAMEOID )
4621
4634
{
4622
4635
workstr = DatumGetCString (DirectFunctionCall1 (nameout ,
4623
4636
str_const -> constvalue ));
4624
4637
len = strlen (workstr );
4638
+ cmpstr = str_const -> constvalue ;
4625
4639
}
4626
4640
else if (datatype == BYTEAOID )
4627
4641
{
@@ -4632,12 +4646,41 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc)
4632
4646
memcpy (workstr ,VARDATA (bstr ),len );
4633
4647
if ((Pointer )bstr != DatumGetPointer (str_const -> constvalue ))
4634
4648
pfree (bstr );
4649
+ cmpstr = str_const -> constvalue ;
4635
4650
}
4636
4651
else
4637
4652
{
4638
4653
workstr = DatumGetCString (DirectFunctionCall1 (textout ,
4639
4654
str_const -> constvalue ));
4640
4655
len = 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
+ }
4641
4684
}
4642
4685
4643
4686
while (len > 0 )
@@ -4665,10 +4708,12 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc)
4665
4708
workstr_const = string_to_bytea_const (workstr ,len );
4666
4709
4667
4710
if (DatumGetBool (FunctionCall2 (ltproc ,
4668
- str_const -> constvalue ,
4711
+ cmpstr ,
4669
4712
workstr_const -> constvalue )))
4670
4713
{
4671
- /* Successfully made a string larger than the input */
4714
+ /* Successfully made a string larger than cmpstr */
4715
+ if (cmptxt )
4716
+ pfree (cmptxt );
4672
4717
pfree (workstr );
4673
4718
return workstr_const ;
4674
4719
}
@@ -4695,6 +4740,8 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc)
4695
4740
}
4696
4741
4697
4742
/* Failed... */
4743
+ if (cmptxt )
4744
+ pfree (cmptxt );
4698
4745
pfree (workstr );
4699
4746
4700
4747
return NULL ;