selfuncs.c: use pg_strxfrm() instead of strxfrm().
pg_strxfrm() takes a pg_locale_t, so it works properly with all providers. This improves estimates for ICU when performing linear interpolation within a histogram bin. Previously, convert_string_datum() always used strxfrm() and relied on setlocale(). That did not produce good estimates for non-default or non-libc collations. Discussion: https://postgr.es/m/89475ee5487d795124f4e25118ea8f1853edb8cb.camel@j-davis.com
This commit is contained in:
parent
a54d4ed183
commit
a890ad2149
@ -2124,14 +2124,7 @@ pg_strxfrm_libc(char *dest, const char *src, size_t destsize,
|
|||||||
pg_locale_t locale)
|
pg_locale_t locale)
|
||||||
{
|
{
|
||||||
Assert(locale->provider == COLLPROVIDER_LIBC);
|
Assert(locale->provider == COLLPROVIDER_LIBC);
|
||||||
|
|
||||||
#ifdef TRUST_STRXFRM
|
|
||||||
return strxfrm_l(dest, src, destsize, locale->info.lt);
|
return strxfrm_l(dest, src, destsize, locale->info.lt);
|
||||||
#else
|
|
||||||
/* shouldn't happen */
|
|
||||||
PGLOCALE_SUPPORT_ERROR(locale->provider);
|
|
||||||
return 0; /* keep compiler quiet */
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
@ -2340,6 +2333,10 @@ pg_strxfrm_enabled(pg_locale_t locale)
|
|||||||
* The provided 'src' must be nul-terminated. If 'destsize' is zero, 'dest'
|
* The provided 'src' must be nul-terminated. If 'destsize' is zero, 'dest'
|
||||||
* may be NULL.
|
* may be NULL.
|
||||||
*
|
*
|
||||||
|
* Not all providers support pg_strxfrm() safely. The caller should check
|
||||||
|
* pg_strxfrm_enabled() first, otherwise this function may return wrong
|
||||||
|
* results or an error.
|
||||||
|
*
|
||||||
* Returns the number of bytes needed (or more) to store the transformed
|
* Returns the number of bytes needed (or more) to store the transformed
|
||||||
* string, excluding the terminating nul byte. If the value returned is
|
* string, excluding the terminating nul byte. If the value returned is
|
||||||
* 'destsize' or greater, the resulting contents of 'dest' are undefined.
|
* 'destsize' or greater, the resulting contents of 'dest' are undefined.
|
||||||
@ -2372,6 +2369,10 @@ pg_strxfrm(char *dest, const char *src, size_t destsize, pg_locale_t locale)
|
|||||||
* 'src' does not need to be nul-terminated. If 'destsize' is zero, 'dest' may
|
* 'src' does not need to be nul-terminated. If 'destsize' is zero, 'dest' may
|
||||||
* be NULL.
|
* be NULL.
|
||||||
*
|
*
|
||||||
|
* Not all providers support pg_strnxfrm() safely. The caller should check
|
||||||
|
* pg_strxfrm_enabled() first, otherwise this function may return wrong
|
||||||
|
* results or an error.
|
||||||
|
*
|
||||||
* Returns the number of bytes needed (or more) to store the transformed
|
* Returns the number of bytes needed (or more) to store the transformed
|
||||||
* string, excluding the terminating nul byte. If the value returned is
|
* string, excluding the terminating nul byte. If the value returned is
|
||||||
* 'destsize' or greater, the resulting contents of 'dest' are undefined.
|
* 'destsize' or greater, the resulting contents of 'dest' are undefined.
|
||||||
@ -2426,6 +2427,10 @@ pg_strxfrm_prefix_enabled(pg_locale_t locale)
|
|||||||
*
|
*
|
||||||
* The provided 'src' must be nul-terminated.
|
* The provided 'src' must be nul-terminated.
|
||||||
*
|
*
|
||||||
|
* Not all providers support pg_strxfrm_prefix() safely. The caller should
|
||||||
|
* check pg_strxfrm_prefix_enabled() first, otherwise this function may return
|
||||||
|
* wrong results or an error.
|
||||||
|
*
|
||||||
* If destsize is not large enough to hold the resulting byte sequence, stores
|
* If destsize is not large enough to hold the resulting byte sequence, stores
|
||||||
* only the first destsize bytes in 'dest'. Returns the number of bytes
|
* only the first destsize bytes in 'dest'. Returns the number of bytes
|
||||||
* actually copied to 'dest'.
|
* actually copied to 'dest'.
|
||||||
@ -2455,6 +2460,10 @@ pg_strxfrm_prefix(char *dest, const char *src, size_t destsize,
|
|||||||
*
|
*
|
||||||
* The provided 'src' must be nul-terminated.
|
* The provided 'src' must be nul-terminated.
|
||||||
*
|
*
|
||||||
|
* Not all providers support pg_strnxfrm_prefix() safely. The caller should
|
||||||
|
* check pg_strxfrm_prefix_enabled() first, otherwise this function may return
|
||||||
|
* wrong results or an error.
|
||||||
|
*
|
||||||
* If destsize is not large enough to hold the resulting byte sequence, stores
|
* If destsize is not large enough to hold the resulting byte sequence, stores
|
||||||
* only the first destsize bytes in 'dest'. Returns the number of bytes
|
* only the first destsize bytes in 'dest'. Returns the number of bytes
|
||||||
* actually copied to 'dest'.
|
* actually copied to 'dest'.
|
||||||
|
@ -4639,7 +4639,7 @@ convert_one_string_to_scalar(char *value, int rangelo, int rangehi)
|
|||||||
* On failure (e.g., unsupported typid), set *failure to true;
|
* On failure (e.g., unsupported typid), set *failure to true;
|
||||||
* otherwise, that variable is not changed. (We'll return NULL on failure.)
|
* otherwise, that variable is not changed. (We'll return NULL on failure.)
|
||||||
*
|
*
|
||||||
* When using a non-C locale, we must pass the string through strxfrm()
|
* When using a non-C locale, we must pass the string through pg_strxfrm()
|
||||||
* before continuing, so as to generate correct locale-specific results.
|
* before continuing, so as to generate correct locale-specific results.
|
||||||
*/
|
*/
|
||||||
static char *
|
static char *
|
||||||
@ -4673,20 +4673,25 @@ convert_string_datum(Datum value, Oid typid, Oid collid, bool *failure)
|
|||||||
|
|
||||||
if (!lc_collate_is_c(collid))
|
if (!lc_collate_is_c(collid))
|
||||||
{
|
{
|
||||||
|
pg_locale_t mylocale = pg_newlocale_from_collation(collid);
|
||||||
char *xfrmstr;
|
char *xfrmstr;
|
||||||
size_t xfrmlen;
|
size_t xfrmlen;
|
||||||
size_t xfrmlen2 PG_USED_FOR_ASSERTS_ONLY;
|
size_t xfrmlen2 PG_USED_FOR_ASSERTS_ONLY;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX: We could guess at a suitable output buffer size and only call
|
* XXX: We could guess at a suitable output buffer size and only call
|
||||||
* strxfrm twice if our guess is too small.
|
* pg_strxfrm() twice if our guess is too small.
|
||||||
*
|
*
|
||||||
* XXX: strxfrm doesn't support UTF-8 encoding on Win32, it can return
|
* XXX: strxfrm doesn't support UTF-8 encoding on Win32, it can return
|
||||||
* bogus data or set an error. This is not really a problem unless it
|
* bogus data or set an error. This is not really a problem unless it
|
||||||
* crashes since it will only give an estimation error and nothing
|
* crashes since it will only give an estimation error and nothing
|
||||||
* fatal.
|
* fatal.
|
||||||
|
*
|
||||||
|
* XXX: we do not check pg_strxfrm_enabled(). On some platforms and in
|
||||||
|
* some cases, libc strxfrm() may return the wrong results, but that
|
||||||
|
* will only lead to an estimation error.
|
||||||
*/
|
*/
|
||||||
xfrmlen = strxfrm(NULL, val, 0);
|
xfrmlen = pg_strxfrm(NULL, val, 0, mylocale);
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4698,7 +4703,7 @@ convert_string_datum(Datum value, Oid typid, Oid collid, bool *failure)
|
|||||||
return val;
|
return val;
|
||||||
#endif
|
#endif
|
||||||
xfrmstr = (char *) palloc(xfrmlen + 1);
|
xfrmstr = (char *) palloc(xfrmlen + 1);
|
||||||
xfrmlen2 = strxfrm(xfrmstr, val, xfrmlen + 1);
|
xfrmlen2 = pg_strxfrm(xfrmstr, val, xfrmlen + 1, mylocale);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some systems (e.g., glibc) can return a smaller value from the
|
* Some systems (e.g., glibc) can return a smaller value from the
|
||||||
|
Loading…
x
Reference in New Issue
Block a user