@@ -63,6 +63,7 @@ typedef struct
63
63
char * buf2 ; /* 2nd string, or abbreviation strxfrm() buf */
64
64
int buflen1 ;
65
65
int buflen2 ;
66
+ bool collate_c ;
66
67
hyperLogLogState abbr_card ; /* Abbreviated key cardinality state */
67
68
hyperLogLogState full_card ; /* Full key cardinality state */
68
69
#ifdef HAVE_LOCALE_T
@@ -1744,7 +1745,7 @@ static void
1744
1745
btsortsupport_worker (SortSupport ssup , Oid collid )
1745
1746
{
1746
1747
bool abbreviate = ssup -> abbreviate ;
1747
- bool locale_aware = false;
1748
+ bool collate_c = false;
1748
1749
TextSortSupport * tss ;
1749
1750
1750
1751
#ifdef HAVE_LOCALE_T
@@ -1769,15 +1770,17 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
1769
1770
* bttextcmp() via the fmgr trampoline.
1770
1771
*/
1771
1772
if (lc_collate_is_c (collid ))
1773
+ {
1772
1774
ssup -> comparator = bttextfastcmp_c ;
1775
+ collate_c = true;
1776
+ }
1773
1777
#ifdef WIN32
1774
1778
else if (GetDatabaseEncoding () == PG_UTF8 )
1775
1779
return ;
1776
1780
#endif
1777
1781
else
1778
1782
{
1779
1783
ssup -> comparator = bttextfastcmp_locale ;
1780
- locale_aware = true;
1781
1784
1782
1785
/*
1783
1786
* We need a collation-sensitive comparison. To make things faster,
@@ -1798,7 +1801,7 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
1798
1801
errhint ("Use the COLLATE clause to set the collation explicitly." )));
1799
1802
}
1800
1803
#ifdef HAVE_LOCALE_T
1801
- tss -> locale = pg_newlocale_from_collation (collid );
1804
+ locale = pg_newlocale_from_collation (collid );
1802
1805
#endif
1803
1806
}
1804
1807
}
@@ -1828,7 +1831,7 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
1828
1831
* will make use of the temporary buffers we initialize here for scratch
1829
1832
* space, and the abbreviation case requires additional state.
1830
1833
*/
1831
- if (abbreviate || locale_aware )
1834
+ if (abbreviate || ! collate_c )
1832
1835
{
1833
1836
tss = palloc (sizeof (TextSortSupport ));
1834
1837
tss -> buf1 = palloc (TEXTBUFLEN );
@@ -1838,6 +1841,7 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
1838
1841
#ifdef HAVE_LOCALE_T
1839
1842
tss -> locale = locale ;
1840
1843
#endif
1844
+ tss -> collate_c = collate_c ;
1841
1845
ssup -> ssup_extra = tss ;
1842
1846
1843
1847
/*
@@ -2011,45 +2015,58 @@ bttext_abbrev_convert(Datum original, SortSupport ssup)
2011
2015
memset (pres , 0 , sizeof (Datum ));
2012
2016
len = VARSIZE_ANY_EXHDR (authoritative );
2013
2017
2014
- /* By convention, we use buffer 1 to store and NUL-terminate text */
2015
- if (len >= tss -> buflen1 )
2018
+ /*
2019
+ * If we're using the C collation, use memcmp(), rather than strxfrm(),
2020
+ * to abbreviated keys. The full comparator for the C locale is always
2021
+ * memcmp(), and we can't risk having this give a different answer.
2022
+ * Besides, this should be faster, too.
2023
+ */
2024
+ if (tss -> collate_c )
2025
+ memcpy (pres , VARDATA_ANY (authoritative ), Min (len , sizeof (Datum )));
2026
+ else
2016
2027
{
2017
- pfree (tss -> buf1 );
2018
- tss -> buflen1 = Max (len + 1 , Min (tss -> buflen1 * 2 , MaxAllocSize ));
2019
- tss -> buf1 = palloc (tss -> buflen1 );
2020
- }
2028
+ /*
2029
+ * We're not using the C collation, so fall back on strxfrm.
2030
+ */
2021
2031
2022
- /* Just like strcoll(), strxfrm() expects a NUL-terminated string */
2023
- memcpy (tss -> buf1 , VARDATA_ANY (authoritative ), len );
2024
- tss -> buf1 [len ] = '\0' ;
2032
+ /* By convention, we use buffer 1 to store and NUL-terminate text */
2033
+ if (len >= tss -> buflen1 )
2034
+ {
2035
+ pfree (tss -> buf1 );
2036
+ tss -> buflen1 = Max (len + 1 , Min (tss -> buflen1 * 2 , MaxAllocSize ));
2037
+ tss -> buf1 = palloc (tss -> buflen1 );
2038
+ }
2025
2039
2026
- /* Don't leak memory here */
2027
- if ( PointerGetDatum ( authoritative ) != original )
2028
- pfree ( authoritative ) ;
2040
+ /* Just like strcoll(), strxfrm() expects a NUL-terminated string */
2041
+ memcpy ( tss -> buf1 , VARDATA_ANY ( authoritative ), len );
2042
+ tss -> buf1 [ len ] = '\0' ;
2029
2043
2030
- retry :
2044
+ /* Don't leak memory here */
2045
+ if (PointerGetDatum (authoritative ) != original )
2046
+ pfree (authoritative );
2031
2047
2032
- /*
2033
- * There is no special handling of the C locale here, unlike with
2034
- * varstr_cmp(). strxfrm() is used indifferently.
2035
- */
2048
+ for (;;)
2049
+ {
2036
2050
#ifdef HAVE_LOCALE_T
2037
- if (tss -> locale )
2038
- bsize = strxfrm_l (tss -> buf2 , tss -> buf1 , tss -> buflen2 , tss -> locale );
2039
- else
2051
+ if (tss -> locale )
2052
+ bsize = strxfrm_l (tss -> buf2 , tss -> buf1 ,
2053
+ tss -> buflen2 , tss -> locale );
2054
+ else
2040
2055
#endif
2041
- bsize = strxfrm (tss -> buf2 , tss -> buf1 , tss -> buflen2 );
2056
+ bsize = strxfrm (tss -> buf2 , tss -> buf1 , tss -> buflen2 );
2042
2057
2043
- if (bsize >= tss -> buflen2 )
2044
- {
2045
- /*
2046
- * The C standard states that the contents of the buffer is now
2047
- * unspecified. Grow buffer, and retry.
2048
- */
2049
- pfree (tss -> buf2 );
2050
- tss -> buflen2 = Max (bsize + 1 , Min (tss -> buflen2 * 2 , MaxAllocSize ));
2051
- tss -> buf2 = palloc (tss -> buflen2 );
2052
- goto retry ;
2058
+ if (bsize < tss -> buflen2 )
2059
+ break ;
2060
+
2061
+ /*
2062
+ * The C standard states that the contents of the buffer is now
2063
+ * unspecified. Grow buffer, and retry.
2064
+ */
2065
+ pfree (tss -> buf2 );
2066
+ tss -> buflen2 = Max (bsize + 1 ,
2067
+ Min (tss -> buflen2 * 2 , MaxAllocSize ));
2068
+ tss -> buf2 = palloc (tss -> buflen2 );
2069
+ }
2053
2070
}
2054
2071
2055
2072
/*
0 commit comments