@@ -65,6 +65,7 @@ typedef struct
65
65
int last_len1 ; /* Length of last buf1 string/strxfrm() blob */
66
66
int last_len2 ; /* Length of last buf2 string/strxfrm() blob */
67
67
int last_returned ; /* Last comparison result (cache) */
68
+ bool cache_blob ; /* Does buf2 contain strxfrm() blob, etc? */
68
69
bool collate_c ;
69
70
hyperLogLogState abbr_card ; /* Abbreviated key cardinality state */
70
71
hyperLogLogState full_card ; /* Full key cardinality state */
@@ -1838,17 +1839,26 @@ btsortsupport_worker(SortSupport ssup, Oid collid)
1838
1839
/* Start with invalid values */
1839
1840
tss -> last_len1 = -1 ;
1840
1841
tss -> last_len2 = -1 ;
1842
+ /* Initialize */
1843
+ tss -> last_returned = 0 ;
1841
1844
#ifdef HAVE_LOCALE_T
1842
1845
tss -> locale = locale ;
1843
1846
#endif
1844
1847
/*
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.
1850
1860
*/
1851
- tss -> last_returned = INT_MIN ;
1861
+ tss -> cache_blob = true ;
1852
1862
tss -> collate_c = collate_c ;
1853
1863
ssup -> ssup_extra = tss ;
1854
1864
@@ -1983,7 +1993,7 @@ bttextfastcmp_locale(Datum x, Datum y, SortSupport ssup)
1983
1993
tss -> buf2 [len2 ] = '\0' ;
1984
1994
tss -> last_len2 = len2 ;
1985
1995
}
1986
- else if (arg1_match && tss -> last_returned != INT_MIN )
1996
+ else if (arg1_match && ! tss -> cache_blob )
1987
1997
{
1988
1998
/* Use result cached following last actual strcoll() call */
1989
1999
result = tss -> last_returned ;
@@ -2006,6 +2016,7 @@ bttextfastcmp_locale(Datum x, Datum y, SortSupport ssup)
2006
2016
result = strcmp (tss -> buf1 , tss -> buf2 );
2007
2017
2008
2018
/* Cache result, perhaps saving an expensive strcoll() call next time */
2019
+ tss -> cache_blob = false;
2009
2020
tss -> last_returned = result ;
2010
2021
done :
2011
2022
/* We can't afford to leak memory here. */
@@ -2086,7 +2097,7 @@ bttext_abbrev_convert(Datum original, SortSupport ssup)
2086
2097
}
2087
2098
2088
2099
/* 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 &&
2090
2101
memcmp (tss -> buf1 , authoritative_data , len ) == 0 )
2091
2102
{
2092
2103
memcpy (pres , tss -> buf2 , Min (sizeof (Datum ), tss -> last_len2 ));
@@ -2167,6 +2178,8 @@ bttext_abbrev_convert(Datum original, SortSupport ssup)
2167
2178
2168
2179
addHyperLogLog (& tss -> abbr_card , hash );
2169
2180
2181
+ /* Cache result, perhaps saving an expensive strxfrm() call next time */
2182
+ tss -> cache_blob = true;
2170
2183
done :
2171
2184
/*
2172
2185
* Byteswap on little-endian machines.
0 commit comments