@@ -63,6 +63,7 @@ typedef struct
6363char * buf2 ;/* 2nd string, or abbreviation strxfrm() buf */
6464int buflen1 ;
6565int buflen2 ;
66+ bool collate_c ;
6667hyperLogLogState abbr_card ;/* Abbreviated key cardinality state */
6768hyperLogLogState full_card ;/* Full key cardinality state */
6869#ifdef HAVE_LOCALE_T
@@ -1744,7 +1745,7 @@ static void
17441745btsortsupport_worker (SortSupport ssup ,Oid collid )
17451746{
17461747bool abbreviate = ssup -> abbreviate ;
1747- bool locale_aware = false;
1748+ bool collate_c = false;
17481749TextSortSupport * tss ;
17491750
17501751#ifdef HAVE_LOCALE_T
@@ -1769,15 +1770,17 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
17691770 * bttextcmp() via the fmgr trampoline.
17701771 */
17711772if (lc_collate_is_c (collid ))
1773+ {
17721774ssup -> comparator = bttextfastcmp_c ;
1775+ collate_c = true;
1776+ }
17731777#ifdef WIN32
17741778else if (GetDatabaseEncoding ()== PG_UTF8 )
17751779return ;
17761780#endif
17771781else
17781782{
17791783ssup -> comparator = bttextfastcmp_locale ;
1780- locale_aware = true;
17811784
17821785/*
17831786 * We need a collation-sensitive comparison. To make things faster,
@@ -1798,7 +1801,7 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
17981801errhint ("Use the COLLATE clause to set the collation explicitly." )));
17991802}
18001803#ifdef HAVE_LOCALE_T
1801- tss -> locale = pg_newlocale_from_collation (collid );
1804+ locale = pg_newlocale_from_collation (collid );
18021805#endif
18031806}
18041807}
@@ -1828,7 +1831,7 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
18281831 * will make use of the temporary buffers we initialize here for scratch
18291832 * space, and the abbreviation case requires additional state.
18301833 */
1831- if (abbreviate || locale_aware )
1834+ if (abbreviate || ! collate_c )
18321835{
18331836tss = palloc (sizeof (TextSortSupport ));
18341837tss -> buf1 = palloc (TEXTBUFLEN );
@@ -1838,6 +1841,7 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
18381841#ifdef HAVE_LOCALE_T
18391842tss -> locale = locale ;
18401843#endif
1844+ tss -> collate_c = collate_c ;
18411845ssup -> ssup_extra = tss ;
18421846
18431847/*
@@ -2011,45 +2015,58 @@ bttext_abbrev_convert(Datum original, SortSupport ssup)
20112015memset (pres ,0 ,sizeof (Datum ));
20122016len = VARSIZE_ANY_EXHDR (authoritative );
20132017
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
20162027{
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+ */
20212031
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+ }
20252039
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' ;
20292043
2030- retry :
2044+ /* Don't leak memory here */
2045+ if (PointerGetDatum (authoritative )!= original )
2046+ pfree (authoritative );
20312047
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+ {
20362050#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
20402055#endif
2041- bsize = strxfrm (tss -> buf2 ,tss -> buf1 ,tss -> buflen2 );
2056+ bsize = strxfrm (tss -> buf2 ,tss -> buf1 ,tss -> buflen2 );
20422057
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- gotoretry ;
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+ }
20532070}
20542071
20552072/*