@@ -65,6 +65,7 @@ typedef struct
6565int last_len1 ;/* Length of last buf1 string/strxfrm() blob */
6666int last_len2 ;/* Length of last buf2 string/strxfrm() blob */
6767int last_returned ;/* Last comparison result (cache) */
68+ bool cache_blob ;/* Does buf2 contain strxfrm() blob, etc? */
6869bool collate_c ;
6970hyperLogLogState abbr_card ;/* Abbreviated key cardinality state */
7071hyperLogLogState full_card ;/* Full key cardinality state */
@@ -1838,17 +1839,26 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
18381839/* Start with invalid values */
18391840tss -> last_len1 = -1 ;
18401841tss -> last_len2 = -1 ;
1842+ /* Initialize */
1843+ tss -> last_returned = 0 ;
18411844#ifdef HAVE_LOCALE_T
18421845tss -> locale = locale ;
18431846#endif
18441847/*
1845- * To avoid somehow confusing a strxfrm() blob and an original string
1846- * within bttextfastcmp_locale(), initialize last returned cache to a
1847- * sentinel value. A platform-specific actual strcoll() return value
1848- * of INT_MIN seems unlikely, but if that occurs it will not cause
1849- * wrong answers.
1848+ * To avoid somehow confusing a strxfrm() blob and an original string,
1849+ * constantly keep track of the variety of data that buf1 and buf2
1850+ * currently contain.
1851+ *
1852+ * Comparisons may be interleaved with conversion calls. Frequently,
1853+ * conversions and comparisons are batched into two distinct phases,
1854+ * but the correctness of caching cannot hinge upon this. For
1855+ * comparison caching, buffer state is only trusted if cache_blob is
1856+ * found set to false, whereas strxfrm() caching only trusts the state
1857+ * when cache_blob is found set to true.
1858+ *
1859+ * Arbitrarily initialize cache_blob to true.
18501860 */
1851- tss -> last_returned = INT_MIN ;
1861+ tss -> cache_blob = true ;
18521862tss -> collate_c = collate_c ;
18531863ssup -> ssup_extra = tss ;
18541864
@@ -1983,7 +1993,7 @@ bttextfastcmp_locale(Datum x, Datum y, SortSupport ssup)
19831993tss -> buf2 [len2 ]= '\0' ;
19841994tss -> last_len2 = len2 ;
19851995}
1986- else if (arg1_match && tss -> last_returned != INT_MIN )
1996+ else if (arg1_match && ! tss -> cache_blob )
19871997{
19881998/* Use result cached following last actual strcoll() call */
19891999result = tss -> last_returned ;
@@ -2006,6 +2016,7 @@ bttextfastcmp_locale(Datum x, Datum y, SortSupport ssup)
20062016result = strcmp (tss -> buf1 ,tss -> buf2 );
20072017
20082018/* Cache result, perhaps saving an expensive strcoll() call next time */
2019+ tss -> cache_blob = false;
20092020tss -> last_returned = result ;
20102021done :
20112022/* We can't afford to leak memory here. */
@@ -2086,7 +2097,7 @@ bttext_abbrev_convert(Datum original, SortSupport ssup)
20862097}
20872098
20882099/* Might be able to reuse strxfrm() blob from last call */
2089- if (tss -> last_len1 == len &&
2100+ if (tss -> last_len1 == len && tss -> cache_blob &&
20902101memcmp (tss -> buf1 ,authoritative_data ,len )== 0 )
20912102{
20922103memcpy (pres ,tss -> buf2 ,Min (sizeof (Datum ),tss -> last_len2 ));
@@ -2167,6 +2178,8 @@ bttext_abbrev_convert(Datum original, SortSupport ssup)
21672178
21682179addHyperLogLog (& tss -> abbr_card ,hash );
21692180
2181+ /* Cache result, perhaps saving an expensive strxfrm() call next time */
2182+ tss -> cache_blob = true;
21702183done :
21712184/*
21722185 * Byteswap on little-endian machines.