# PGAC_TYPE_LOCALE_T
# ------------------
# Check for the locale_t type and find the right header file. macOS
-# needs xlocale.h; standard is locale.h, but glibc also has an
-# xlocale.h file that we should not use.
-#
+# needs xlocale.h; standard is locale.h, but glibc <= 2.25 also had an
+# xlocale.h file that we should not use, so we check the standard
+# header first.
AC_DEFUN([PGAC_TYPE_LOCALE_T],
[AC_CACHE_CHECK([for locale_t], pgac_cv_type_locale_t,
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[])],
[pgac_cv_type_locale_t='yes (in xlocale.h)'],
[pgac_cv_type_locale_t=no])])])
-if test "$pgac_cv_type_locale_t" != no; then
- AC_DEFINE(HAVE_LOCALE_T, 1,
- [Define to 1 if the system has the type `locale_t'.])
-fi
if test "$pgac_cv_type_locale_t" = 'yes (in xlocale.h)'; then
AC_DEFINE(LOCALE_T_IN_XLOCALE, 1,
[Define to 1 if `locale_t' requires <xlocale.h>.])
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_type_locale_t" >&5
$as_echo "$pgac_cv_type_locale_t" >&6; }
-if test "$pgac_cv_type_locale_t" != no; then
-
-$as_echo "#define HAVE_LOCALE_T 1" >>confdefs.h
-
-fi
if test "$pgac_cv_type_locale_t" = 'yes (in xlocale.h)'; then
$as_echo "#define LOCALE_T_IN_XLOCALE 1" >>confdefs.h
cdata.set('STRERROR_R_INT', false)
endif
-# Check for the locale_t type and find the right header file. macOS
-# needs xlocale.h; standard is locale.h, but glibc also has an
-# xlocale.h file that we should not use. MSVC has a replacement
-# defined in src/include/port/win32_port.h.
-if cc.has_type('locale_t', prefix: '#include <locale.h>')
- cdata.set('HAVE_LOCALE_T', 1)
-elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
- cdata.set('HAVE_LOCALE_T', 1)
+# Find the right header file for the locale_t type. macOS needs xlocale.h;
+# standard is locale.h, but glibc <= 2.25 also had an xlocale.h file that
+# we should not use so we check the standard header first. MSVC has a
+# replacement defined in src/include/port/win32_port.h.
+if not cc.has_type('locale_t', prefix: '#include <locale.h>') and \
+ cc.has_type('locale_t', prefix: '#include <xlocale.h>')
cdata.set('LOCALE_T_IN_XLOCALE', 1)
-elif cc.get_id() == 'msvc'
- cdata.set('HAVE_LOCALE_T', 1)
endif
# Check if the C compiler understands typeof or a variant. Define
endif
-# MSVC has replacements defined in src/include/port/win32_port.h.
-if cc.get_id() == 'msvc'
- cdata.set('HAVE_WCSTOMBS_L', 1)
- cdata.set('HAVE_MBSTOWCS_L', 1)
-endif
-
-
# if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
# semaphores
if sema_kind == 'unnamed_posix' and \
/* will we use "locale -a" in pg_import_system_collations? */
-#if defined(HAVE_LOCALE_T) && !defined(WIN32)
+#if !defined(WIN32)
#define READ_LOCALE_A_OUTPUT
#endif
* the platform's wchar_t representation matches what we do in pg_wchar
* conversions.
*
- * 3. Other collations are only supported on platforms that HAVE_LOCALE_T.
- * Here, we use the locale_t-extended forms of the <wctype.h> and <ctype.h>
+ * 3. Here, we use the locale_t-extended forms of the <wctype.h> and <ctype.h>
* functions, under exactly the same cases as #2.
*
* There is one notable difference between cases 2 and 3: in the "default"
}
else
{
- /*
- * NB: pg_newlocale_from_collation will fail if not HAVE_LOCALE_T; the
- * case of pg_regex_locale != 0 but not HAVE_LOCALE_T does not have to
- * be considered below.
- */
pg_regex_locale = pg_newlocale_from_collation(collation);
if (!pg_locale_deterministic(pg_regex_locale))
return (c <= (pg_wchar) UCHAR_MAX &&
isdigit((unsigned char) c));
case PG_REGEX_LOCALE_WIDE_L:
-#ifdef HAVE_LOCALE_T
if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
return iswdigit_l((wint_t) c, pg_regex_locale->info.lt);
-#endif
/* FALL THRU */
case PG_REGEX_LOCALE_1BYTE_L:
-#ifdef HAVE_LOCALE_T
return (c <= (pg_wchar) UCHAR_MAX &&
isdigit_l((unsigned char) c, pg_regex_locale->info.lt));
-#endif
break;
case PG_REGEX_LOCALE_ICU:
#ifdef USE_ICU
return (c <= (pg_wchar) UCHAR_MAX &&
isalpha((unsigned char) c));
case PG_REGEX_LOCALE_WIDE_L:
-#ifdef HAVE_LOCALE_T
if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
return iswalpha_l((wint_t) c, pg_regex_locale->info.lt);
-#endif
/* FALL THRU */
case PG_REGEX_LOCALE_1BYTE_L:
-#ifdef HAVE_LOCALE_T
return (c <= (pg_wchar) UCHAR_MAX &&
isalpha_l((unsigned char) c, pg_regex_locale->info.lt));
-#endif
break;
case PG_REGEX_LOCALE_ICU:
#ifdef USE_ICU
return (c <= (pg_wchar) UCHAR_MAX &&
isalnum((unsigned char) c));
case PG_REGEX_LOCALE_WIDE_L:
-#ifdef HAVE_LOCALE_T
if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
return iswalnum_l((wint_t) c, pg_regex_locale->info.lt);
-#endif
/* FALL THRU */
case PG_REGEX_LOCALE_1BYTE_L:
-#ifdef HAVE_LOCALE_T
return (c <= (pg_wchar) UCHAR_MAX &&
isalnum_l((unsigned char) c, pg_regex_locale->info.lt));
-#endif
break;
case PG_REGEX_LOCALE_ICU:
#ifdef USE_ICU
return (c <= (pg_wchar) UCHAR_MAX &&
isupper((unsigned char) c));
case PG_REGEX_LOCALE_WIDE_L:
-#ifdef HAVE_LOCALE_T
if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
return iswupper_l((wint_t) c, pg_regex_locale->info.lt);
-#endif
/* FALL THRU */
case PG_REGEX_LOCALE_1BYTE_L:
-#ifdef HAVE_LOCALE_T
return (c <= (pg_wchar) UCHAR_MAX &&
isupper_l((unsigned char) c, pg_regex_locale->info.lt));
-#endif
break;
case PG_REGEX_LOCALE_ICU:
#ifdef USE_ICU
return (c <= (pg_wchar) UCHAR_MAX &&
islower((unsigned char) c));
case PG_REGEX_LOCALE_WIDE_L:
-#ifdef HAVE_LOCALE_T
if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
return iswlower_l((wint_t) c, pg_regex_locale->info.lt);
-#endif
/* FALL THRU */
case PG_REGEX_LOCALE_1BYTE_L:
-#ifdef HAVE_LOCALE_T
return (c <= (pg_wchar) UCHAR_MAX &&
islower_l((unsigned char) c, pg_regex_locale->info.lt));
-#endif
break;
case PG_REGEX_LOCALE_ICU:
#ifdef USE_ICU
return (c <= (pg_wchar) UCHAR_MAX &&
isgraph((unsigned char) c));
case PG_REGEX_LOCALE_WIDE_L:
-#ifdef HAVE_LOCALE_T
if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
return iswgraph_l((wint_t) c, pg_regex_locale->info.lt);
-#endif
/* FALL THRU */
case PG_REGEX_LOCALE_1BYTE_L:
-#ifdef HAVE_LOCALE_T
return (c <= (pg_wchar) UCHAR_MAX &&
isgraph_l((unsigned char) c, pg_regex_locale->info.lt));
-#endif
break;
case PG_REGEX_LOCALE_ICU:
#ifdef USE_ICU
return (c <= (pg_wchar) UCHAR_MAX &&
isprint((unsigned char) c));
case PG_REGEX_LOCALE_WIDE_L:
-#ifdef HAVE_LOCALE_T
if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
return iswprint_l((wint_t) c, pg_regex_locale->info.lt);
-#endif
/* FALL THRU */
case PG_REGEX_LOCALE_1BYTE_L:
-#ifdef HAVE_LOCALE_T
return (c <= (pg_wchar) UCHAR_MAX &&
isprint_l((unsigned char) c, pg_regex_locale->info.lt));
-#endif
break;
case PG_REGEX_LOCALE_ICU:
#ifdef USE_ICU
return (c <= (pg_wchar) UCHAR_MAX &&
ispunct((unsigned char) c));
case PG_REGEX_LOCALE_WIDE_L:
-#ifdef HAVE_LOCALE_T
if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
return iswpunct_l((wint_t) c, pg_regex_locale->info.lt);
-#endif
/* FALL THRU */
case PG_REGEX_LOCALE_1BYTE_L:
-#ifdef HAVE_LOCALE_T
return (c <= (pg_wchar) UCHAR_MAX &&
ispunct_l((unsigned char) c, pg_regex_locale->info.lt));
-#endif
break;
case PG_REGEX_LOCALE_ICU:
#ifdef USE_ICU
return (c <= (pg_wchar) UCHAR_MAX &&
isspace((unsigned char) c));
case PG_REGEX_LOCALE_WIDE_L:
-#ifdef HAVE_LOCALE_T
if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
return iswspace_l((wint_t) c, pg_regex_locale->info.lt);
-#endif
/* FALL THRU */
case PG_REGEX_LOCALE_1BYTE_L:
-#ifdef HAVE_LOCALE_T
return (c <= (pg_wchar) UCHAR_MAX &&
isspace_l((unsigned char) c, pg_regex_locale->info.lt));
-#endif
break;
case PG_REGEX_LOCALE_ICU:
#ifdef USE_ICU
return toupper((unsigned char) c);
return c;
case PG_REGEX_LOCALE_WIDE_L:
-#ifdef HAVE_LOCALE_T
if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
return towupper_l((wint_t) c, pg_regex_locale->info.lt);
-#endif
/* FALL THRU */
case PG_REGEX_LOCALE_1BYTE_L:
-#ifdef HAVE_LOCALE_T
if (c <= (pg_wchar) UCHAR_MAX)
return toupper_l((unsigned char) c, pg_regex_locale->info.lt);
-#endif
return c;
case PG_REGEX_LOCALE_ICU:
#ifdef USE_ICU
return tolower((unsigned char) c);
return c;
case PG_REGEX_LOCALE_WIDE_L:
-#ifdef HAVE_LOCALE_T
if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
return towlower_l((wint_t) c, pg_regex_locale->info.lt);
-#endif
/* FALL THRU */
case PG_REGEX_LOCALE_1BYTE_L:
-#ifdef HAVE_LOCALE_T
if (c <= (pg_wchar) UCHAR_MAX)
return tolower_l((unsigned char) c, pg_regex_locale->info.lt);
-#endif
return c;
case PG_REGEX_LOCALE_ICU:
#ifdef USE_ICU
* in multibyte character sets. Note that in either case we are effectively
* assuming that the database character encoding matches the encoding implied
* by LC_CTYPE.
- *
- * If the system provides locale_t and associated functions (which are
- * standardized by Open Group's XBD), we can support collations that are
- * neither default nor C. The code is written to handle both combinations
- * of have-wide-characters and have-locale_t, though it's rather unlikely
- * a platform would have the latter without the former.
*/
/*
for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
{
-#ifdef HAVE_LOCALE_T
if (mylocale)
workspace[curr_char] = towlower_l(workspace[curr_char], mylocale->info.lt);
else
-#endif
workspace[curr_char] = towlower(workspace[curr_char]);
}
*/
for (p = result; *p; p++)
{
-#ifdef HAVE_LOCALE_T
if (mylocale)
*p = tolower_l((unsigned char) *p, mylocale->info.lt);
else
-#endif
*p = pg_tolower((unsigned char) *p);
}
}
for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
{
-#ifdef HAVE_LOCALE_T
if (mylocale)
workspace[curr_char] = towupper_l(workspace[curr_char], mylocale->info.lt);
else
-#endif
workspace[curr_char] = towupper(workspace[curr_char]);
}
*/
for (p = result; *p; p++)
{
-#ifdef HAVE_LOCALE_T
if (mylocale)
*p = toupper_l((unsigned char) *p, mylocale->info.lt);
else
-#endif
*p = pg_toupper((unsigned char) *p);
}
}
for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
{
-#ifdef HAVE_LOCALE_T
if (mylocale)
{
if (wasalnum)
wasalnum = iswalnum_l(workspace[curr_char], mylocale->info.lt);
}
else
-#endif
{
if (wasalnum)
workspace[curr_char] = towlower(workspace[curr_char]);
*/
for (p = result; *p; p++)
{
-#ifdef HAVE_LOCALE_T
if (mylocale)
{
if (wasalnum)
wasalnum = isalnum_l((unsigned char) *p, mylocale->info.lt);
}
else
-#endif
{
if (wasalnum)
*p = pg_tolower((unsigned char) *p);
{
if (locale_is_c)
return pg_ascii_tolower(c);
-#ifdef HAVE_LOCALE_T
else if (locale)
return tolower_l(c, locale->info.lt);
-#endif
else
return pg_tolower(c);
}
else if (locale && locale->provider == COLLPROVIDER_ICU)
return IS_HIGHBIT_SET(c) ||
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
-#ifdef HAVE_LOCALE_T
else if (locale && locale->provider == COLLPROVIDER_LIBC)
return isalpha_l((unsigned char) c, locale->info.lt);
-#endif
else
return isalpha((unsigned char) c);
}
UErrorCode *status);
#endif
+#ifndef WIN32
+/*
+ * POSIX doesn't define _l-variants of these functions, but several systems
+ * have them. We provide our own replacements here. For Windows, we have
+ * macros in win32_port.h.
+ */
+#ifndef HAVE_MBSTOWCS_L
+static size_t
+mbstowcs_l(wchar_t *dest, const char *src, size_t n, locale_t loc)
+{
+ size_t result;
+ locale_t save_locale = uselocale(loc);
+
+ result = mbstowcs(dest, src, n);
+ uselocale(save_locale);
+ return result;
+}
+#endif
+#ifndef HAVE_WCSTOMBS_L
+static size_t
+wcstombs_l(char *dest, const wchar_t *src, size_t n, locale_t loc)
+{
+ size_t result;
+ locale_t save_locale = uselocale(loc);
+
+ result = wcstombs(dest, src, n);
+ uselocale(save_locale);
+ return result;
+}
+#endif
+#endif
+
/*
* pg_perm_setlocale
*
/* simple subroutine for reporting errors from newlocale() */
-#ifdef HAVE_LOCALE_T
static void
report_newlocale_failure(const char *localename)
{
errdetail("The operating system could not find any locale data for the locale name \"%s\".",
localename) : 0)));
}
-#endif /* HAVE_LOCALE_T */
bool
pg_locale_deterministic(pg_locale_t locale)
* lifetime of the backend. Thus, do not free the result with freelocale().
*
* As a special optimization, the default/database collation returns 0.
- * Callers should then revert to the non-locale_t-enabled code path.
- * Also, callers should avoid calling this before going down a C/POSIX
- * fastpath, because such a fastpath should work even on platforms without
- * locale_t support in the C library.
*
* For simplicity, we always generate COLLATE + CTYPE even though we
* might only need one of them. Since this is called only once per session,
if (collform->collprovider == COLLPROVIDER_LIBC)
{
-#ifdef HAVE_LOCALE_T
const char *collcollate;
const char *collctype pg_attribute_unused();
locale_t loc;
}
result.info.lt = loc;
-#else /* not HAVE_LOCALE_T */
- /* platform that doesn't support locale_t */
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("collation provider LIBC is not supported on this platform")));
-#endif /* not HAVE_LOCALE_T */
}
else if (collform->collprovider == COLLPROVIDER_ICU)
{
((LPWSTR) a2p)[r] = 0;
errno = 0;
-#ifdef HAVE_LOCALE_T
if (locale)
result = wcscoll_l((LPWSTR) a1p, (LPWSTR) a2p, locale->info.lt);
else
-#endif
result = wcscoll((LPWSTR) a1p, (LPWSTR) a2p);
if (result == 2147483647) /* _NLSCMPERROR; missing from mingw headers */
ereport(ERROR,
else
#endif /* WIN32 */
if (locale)
- {
-#ifdef HAVE_LOCALE_T
result = strcoll_l(arg1, arg2, locale->info.lt);
-#else
- /* shouldn't happen */
- elog(ERROR, "unsupported collprovider: %c", locale->provider);
-#endif
- }
else
result = strcoll(arg1, arg2);
Assert(!locale || locale->provider == COLLPROVIDER_LIBC);
#ifdef TRUST_STRXFRM
-#ifdef HAVE_LOCALE_T
if (locale)
return strxfrm_l(dest, src, destsize, locale->info.lt);
else
-#endif
return strxfrm(dest, src, destsize);
#else
/* shouldn't happen */
}
else
{
-#ifdef HAVE_LOCALE_T
-#ifdef HAVE_WCSTOMBS_L
/* Use wcstombs_l for nondefault locales */
result = wcstombs_l(to, from, tolen, locale->info.lt);
-#else /* !HAVE_WCSTOMBS_L */
- /* We have to temporarily set the locale as current ... ugh */
- locale_t save_locale = uselocale(locale->info.lt);
-
- result = wcstombs(to, from, tolen);
-
- uselocale(save_locale);
-#endif /* HAVE_WCSTOMBS_L */
-#else /* !HAVE_LOCALE_T */
- /* Can't have locale != 0 without HAVE_LOCALE_T */
- elog(ERROR, "wcstombs_l is not available");
- result = 0; /* keep compiler quiet */
-#endif /* HAVE_LOCALE_T */
}
return result;
}
else
{
-#ifdef HAVE_LOCALE_T
-#ifdef HAVE_MBSTOWCS_L
/* Use mbstowcs_l for nondefault locales */
result = mbstowcs_l(to, str, tolen, locale->info.lt);
-#else /* !HAVE_MBSTOWCS_L */
- /* We have to temporarily set the locale as current ... ugh */
- locale_t save_locale = uselocale(locale->info.lt);
-
- result = mbstowcs(to, str, tolen);
-
- uselocale(save_locale);
-#endif /* HAVE_MBSTOWCS_L */
-#else /* !HAVE_LOCALE_T */
- /* Can't have locale != 0 without HAVE_LOCALE_T */
- elog(ERROR, "mbstowcs_l is not available");
- result = 0; /* keep compiler quiet */
-#endif /* HAVE_LOCALE_T */
}
pfree(str);
/* Define to 1 if you have the `zstd' library (-lzstd). */
#undef HAVE_LIBZSTD
-/* Define to 1 if the system has the type `locale_t'. */
-#undef HAVE_LOCALE_T
-
/* Define to 1 if `long int' works and is 64 bits. */
#undef HAVE_LONG_INT_64
/*
- * We define our own wrapper around locale_t so we can keep the same
- * function signatures for all builds, while not having to create a
- * fake version of the standard type locale_t in the global namespace.
+ * We use a discriminated union to hold either a locale_t or an ICU collator.
* pg_locale_t is occasionally checked for truth, so make it a pointer.
*/
struct pg_locale_struct
bool deterministic;
union
{
-#ifdef HAVE_LOCALE_T
locale_t lt;
-#endif
#ifdef USE_ICU
struct
{
UCollator *ucol;
} icu;
#endif
- int dummy; /* in case we have neither LOCALE_T nor ICU */
} info;
};
HAVE_LIBXSLT => undef,
HAVE_LIBZ => $self->{options}->{zlib} ? 1 : undef,
HAVE_LIBZSTD => undef,
- HAVE_LOCALE_T => 1,
HAVE_LONG_INT_64 => undef,
HAVE_LONG_LONG_INT_64 => 1,
HAVE_MBARRIER_H => undef,
- HAVE_MBSTOWCS_L => 1,
+ HAVE_MBSTOWCS_L => undef,
HAVE_MEMORY_H => 1,
HAVE_MEMSET_S => undef,
HAVE_MKDTEMP => undef,
HAVE_UUID_OSSP => undef,
HAVE_UUID_H => undef,
HAVE_UUID_UUID_H => undef,
- HAVE_WCSTOMBS_L => 1,
+ HAVE_WCSTOMBS_L => undef,
HAVE_VISIBILITY_ATTRIBUTE => undef,
HAVE_X509_GET_SIGNATURE_INFO => undef,
HAVE_X86_64_POPCNTQ => undef,