@@ -65,6 +65,7 @@ typedef struct
6565 int last_len1 ; /* Length of last buf1 string/strxfrm() blob */
6666 int last_len2 ; /* Length of last buf2 string/strxfrm() blob */
6767 int last_returned ; /* Last comparison result (cache) */
68+ bool cache_blob ; /* Does buf2 contain strxfrm() blob, etc? */
6869 bool collate_c ;
6970 hyperLogLogState abbr_card ; /* Abbreviated key cardinality state */
7071 hyperLogLogState full_card ; /* Full key cardinality state */
@@ -1838,17 +1839,26 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
18381839 /* Start with invalid values */
18391840 tss -> last_len1 = -1 ;
18401841 tss -> last_len2 = -1 ;
1842+ /* Initialize */
1843+ tss -> last_returned = 0 ;
18411844#ifdef HAVE_LOCALE_T
18421845 tss -> 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 ;
18521862 tss -> collate_c = collate_c ;
18531863 ssup -> ssup_extra = tss ;
18541864
@@ -1983,7 +1993,7 @@ bttextfastcmp_locale(Datum x, Datum y, SortSupport ssup)
19831993 tss -> buf2 [len2 ] = '\0' ;
19841994 tss -> 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 */
19891999 result = tss -> last_returned ;
@@ -2006,6 +2016,7 @@ bttextfastcmp_locale(Datum x, Datum y, SortSupport ssup)
20062016 result = strcmp (tss -> buf1 , tss -> buf2 );
20072017
20082018 /* Cache result, perhaps saving an expensive strcoll() call next time */
2019+ tss -> cache_blob = false;
20092020 tss -> 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 &&
20902101 memcmp (tss -> buf1 , authoritative_data , len ) == 0 )
20912102 {
20922103 memcpy (pres , tss -> buf2 , Min (sizeof (Datum ), tss -> last_len2 ));
@@ -2167,6 +2178,8 @@ bttext_abbrev_convert(Datum original, SortSupport ssup)
21672178
21682179 addHyperLogLog (& 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.
0 commit comments