@@ -1743,137 +1743,118 @@ bttextsortsupport(PG_FUNCTION_ARGS)
1743
1743
static void
1744
1744
btsortsupport_worker (SortSupport ssup , Oid collid )
1745
1745
{
1746
- TextSortSupport * tss ;
1747
1746
bool abbreviate = ssup -> abbreviate ;
1747
+ bool locale_aware = false;
1748
+ TextSortSupport * tss ;
1748
1749
1749
- /*
1750
- * WIN32 requires complex hacks when the database encoding is UTF-8 (except
1751
- * when using the "C" collation). For now, we don't optimize that case.
1752
- * The use of abbreviated keys is also disabled on Windows, because
1753
- * strxfrm() doesn't appear to work properly on some Windows systems.
1754
- * Ideally, we would use it on those systems where it's reliable and
1755
- * skip it only for the rest, but at the moment we don't know how to
1756
- * distinguish between the ones where it works and the ones where it
1757
- * doesn't.
1758
- */
1759
- #ifdef WIN32
1760
- if (GetDatabaseEncoding () == PG_UTF8 && !lc_collate_is_c (collid ))
1761
- return ;
1762
- abbreviate = false;
1750
+ #ifdef HAVE_LOCALE_T
1751
+ pg_locale_t locale = 0 ;
1763
1752
#endif
1764
1753
1765
1754
/*
1766
- * On platforms where the abbreviated key for text optimization might have
1767
- * bad worst case performance, it may be useful to avoid it entirely by
1768
- * disabling it at compile time. Having only 4 byte datums could make
1769
- * worst-case performance drastically more likely, for example. Moreover,
1770
- * Darwin's strxfrm() implementations is known to not effectively
1771
- * concentrate a significant amount of entropy from the original string in
1772
- * earlier transformed blobs. It's possible that other supported platforms
1773
- * are similarly encumbered.
1774
- *
1775
- * Any reasonable implementation will pack primary weights into the start
1776
- * of returned blobs. The canonical algorithm's implementation is
1777
- * discussed by Unicode Technical Standard #10 ("UNICODE COLLATION
1778
- * ALGORITHM"), section 4, "Main algorithm". Section 4.3, "Form Sort Key"
1779
- * is of particular interest:
1780
- *
1781
- * http://www.unicode.org/reports/tr10/#Step_3
1782
- *
1783
- * The collation algorithm standard goes on to state:
1784
- *
1785
- * "By default, the algorithm makes use of three fully-customizable levels.
1786
- * For the Latin script, these levels correspond roughly to:
1787
- *
1788
- * alphabetic ordering
1789
- *
1790
- * diacritic ordering
1791
- *
1792
- * case ordering.
1755
+ * If possible, set ssup->comparator to a function which can be used to
1756
+ * directly compare two datums. If we can do this, we'll avoid the
1757
+ * overhead of a trip through the fmgr layer for every comparison,
1758
+ * which can be substantial.
1793
1759
*
1794
- * A final level may be used for tie-breaking between strings not otherwise
1795
- * distinguished."
1760
+ * Most typically, we'll set the comparator to bttextfastcmp_locale,
1761
+ * which uses strcoll() to perform comparisons. However, if LC_COLLATE
1762
+ * = C, we can make things quite a bit faster with bttextfastcmp_c,
1763
+ * which uses memcmp() rather than strcoll().
1796
1764
*
1797
- * It is generally expected that most non-equal keys will have their
1798
- * comparisons resolved at the primary level. If enough comparisons can be
1799
- * resolved with just 4 or 8 byte abbreviated keys, this optimization is
1800
- * very effective (although if there are many tie-breakers that largely
1801
- * only perform cheap memcmp() calls, that is also much faster than the
1802
- * unoptimized case - see bttext_abbrev_abort()).
1803
- *
1804
- * We may need a collation-sensitive comparison. To make things faster,
1805
- * we'll figure out the collation based on the locale id and cache the
1806
- * result. Also, since strxfrm()/strcoll() require NUL-terminated inputs,
1807
- * prepare one or two palloc'd buffers to use as temporary workspace. In
1808
- * the ad-hoc comparison case we only use palloc'd buffers when we need
1809
- * more space than we're comfortable allocating on the stack, but here we
1810
- * can keep the buffers around for the whole sort, so it makes sense to
1811
- * allocate them once and use them unconditionally.
1765
+ * There is a further exception on Windows. When the database encoding
1766
+ * is UTF-8 and we are not using the C collation, complex hacks are
1767
+ * required. We don't currently have a comparator that handles that case,
1768
+ * so we fall back on the slow method of having the sort code invoke
1769
+ * bttextcmp() via the fmgr trampoline.
1812
1770
*/
1813
- tss = palloc (sizeof (TextSortSupport ));
1814
- #ifdef HAVE_LOCALE_T
1815
- tss -> locale = 0 ;
1771
+ if (lc_collate_is_c (collid ))
1772
+ ssup -> comparator = bttextfastcmp_c ;
1773
+ #ifdef WIN32
1774
+ else if (GetDatabaseEncoding () == PG_UTF8 )
1775
+ return ;
1816
1776
#endif
1817
-
1818
- if (collid != DEFAULT_COLLATION_OID )
1777
+ else
1819
1778
{
1820
- if (!OidIsValid (collid ))
1779
+ ssup -> comparator = bttextfastcmp_locale ;
1780
+ locale_aware = true;
1781
+
1782
+ /*
1783
+ * We need a collation-sensitive comparison. To make things faster,
1784
+ * we'll figure out the collation based on the locale id and cache the
1785
+ * result.
1786
+ */
1787
+ if (collid != DEFAULT_COLLATION_OID )
1821
1788
{
1822
- /*
1823
- * This typically means that the parser could not resolve a
1824
- * conflict of implicit collations, so report it that way.
1825
- */
1826
- ereport (ERROR ,
1827
- (errcode (ERRCODE_INDETERMINATE_COLLATION ),
1828
- errmsg ("could not determine which collation to use for string comparison" ),
1829
- errhint ("Use the COLLATE clause to set the collation explicitly." )));
1830
- }
1789
+ if (!OidIsValid (collid ))
1790
+ {
1791
+ /*
1792
+ * This typically means that the parser could not resolve a
1793
+ * conflict of implicit collations, so report it that way.
1794
+ */
1795
+ ereport (ERROR ,
1796
+ (errcode (ERRCODE_INDETERMINATE_COLLATION ),
1797
+ errmsg ("could not determine which collation to use for string comparison" ),
1798
+ errhint ("Use the COLLATE clause to set the collation explicitly." )));
1799
+ }
1831
1800
#ifdef HAVE_LOCALE_T
1832
- tss -> locale = pg_newlocale_from_collation (collid );
1801
+ tss -> locale = pg_newlocale_from_collation (collid );
1833
1802
#endif
1803
+ }
1834
1804
}
1835
1805
1836
1806
/*
1837
- * If LC_COLLATE = C, we can make things quite a bit faster by using
1838
- * memcmp() rather than strcoll(). To minimize the per-comparison
1839
- * overhead, we make this decision just once for the whole sort.
1807
+ * It's possible that there are platforms where the use of abbreviated
1808
+ * keys should be disabled at compile time. Having only 4 byte datums
1809
+ * could make worst-case performance drastically more likely, for example.
1810
+ * Moreover, Darwin's strxfrm() implementations is known to not effectively
1811
+ * concentrate a significant amount of entropy from the original string in
1812
+ * earlier transformed blobs. It's possible that other supported platforms
1813
+ * are similarly encumbered. However, even in those cases, the abbreviated
1814
+ * keys optimization may win, and if it doesn't, the "abort abbreviation"
1815
+ * code may rescue us. So, for now, we don't disable this anywhere on the
1816
+ * basis of performance.
1840
1817
*
1841
- * There is no reason to not at least perform fmgr elision on builds where
1842
- * abbreviation is disabled .
1818
+ * On Windows, however, strxfrm() seems to be unreliable on some machines,
1819
+ * so we categorically disable this optimization there .
1843
1820
*/
1844
- if (lc_collate_is_c (collid ))
1845
- ssup -> abbrev_full_comparator = ssup -> comparator = bttextfastcmp_c ;
1846
- else
1847
- ssup -> abbrev_full_comparator = ssup -> comparator = bttextfastcmp_locale ;
1821
+ #ifdef WIN32
1822
+ abbreviate = false;
1823
+ #endif
1848
1824
1849
- if (!lc_collate_is_c (collid ) || abbreviate )
1825
+ /*
1826
+ * If we're using abbreviated keys, or if we're using a locale-aware
1827
+ * comparison, we need to initialize a TextSortSupport object. Both cases
1828
+ * will make use of the temporary buffers we initialize here for scratch
1829
+ * space, and the abbreviation case requires additional state.
1830
+ */
1831
+ if (abbreviate || locale_aware )
1850
1832
{
1851
- /*
1852
- * Abbreviated case requires temp buffers for strxfrm() copying.
1853
- * bttextfastcmp_locale() also uses these buffers (even if abbreviation
1854
- * isn't used), while bttextfast_c() does not.
1855
- */
1833
+ tss = palloc (sizeof (TextSortSupport ));
1856
1834
tss -> buf1 = palloc (TEXTBUFLEN );
1857
1835
tss -> buflen1 = TEXTBUFLEN ;
1858
1836
tss -> buf2 = palloc (TEXTBUFLEN );
1859
1837
tss -> buflen2 = TEXTBUFLEN ;
1838
+ #ifdef HAVE_LOCALE_T
1839
+ tss -> locale = locale ;
1840
+ #endif
1860
1841
ssup -> ssup_extra = tss ;
1861
- }
1862
-
1863
- if (!abbreviate )
1864
- return ;
1865
1842
1866
- initHyperLogLog (& tss -> abbr_card , 10 );
1867
- initHyperLogLog (& tss -> full_card , 10 );
1868
-
1869
- /*
1870
- * Change comparator to be abbreviation-based -- abbreviated version will
1871
- * probably ultimately be used during sorting proper, but core code may
1872
- * switch back to authoritative comparator should abbreviation be aborted
1873
- */
1874
- ssup -> comparator = bttextcmp_abbrev ;
1875
- ssup -> abbrev_converter = bttext_abbrev_convert ;
1876
- ssup -> abbrev_abort = bttext_abbrev_abort ;
1843
+ /*
1844
+ * If possible, plan to use the abbreviated keys optimization. The
1845
+ * core code may switch back to authoritative comparator should
1846
+ * abbreviation be aborted.
1847
+ */
1848
+ if (abbreviate )
1849
+ {
1850
+ initHyperLogLog (& tss -> abbr_card , 10 );
1851
+ initHyperLogLog (& tss -> full_card , 10 );
1852
+ ssup -> abbrev_full_comparator = ssup -> comparator ;
1853
+ ssup -> comparator = bttextcmp_abbrev ;
1854
+ ssup -> abbrev_converter = bttext_abbrev_convert ;
1855
+ ssup -> abbrev_abort = bttext_abbrev_abort ;
1856
+ }
1857
+ }
1877
1858
}
1878
1859
1879
1860
/*
0 commit comments