diff --git a/configure b/configure index cb575e7d23d..ca3a60df9f8 100755 --- a/configure +++ b/configure @@ -13157,7 +13157,7 @@ fi LIBS_including_readline="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` -for ac_func in cbrt clock_gettime dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll posix_fallocate pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l +for ac_func in cbrt clock_gettime dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll posix_fallocate pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower uselocale utime utimes wcstombs wcstombs_l do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -13911,6 +13911,17 @@ fi # Win32 (really MinGW) support if test "$PORTNAME" = "win32"; then + for ac_func in _configthreadlocale +do : + ac_fn_c_check_func "$LINENO" "_configthreadlocale" "ac_cv_func__configthreadlocale" +if test "x$ac_cv_func__configthreadlocale" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__CONFIGTHREADLOCALE 1 +_ACEOF + +fi +done + ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" if test "x$ac_cv_func_gettimeofday" = xyes; then : $as_echo "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h diff --git a/configure.in b/configure.in index 81000838cf7..f365e6d2fc2 100644 --- a/configure.in +++ b/configure.in @@ -1476,7 +1476,33 @@ PGAC_FUNC_WCSTOMBS_L LIBS_including_readline="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` -AC_CHECK_FUNCS([cbrt clock_gettime dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll posix_fallocate pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l]) +AC_CHECK_FUNCS(m4_normalize([ + cbrt + clock_gettime + dlopen + fdatasync + getifaddrs + getpeerucred + getrlimit + mbstowcs_l + memmove + poll + posix_fallocate + pstat + pthread_is_threaded_np + readlink + setproctitle + setsid + shm_open + symlink + sync_file_range + towlower + uselocale + utime + utimes + wcstombs + wcstombs_l +])) AC_REPLACE_FUNCS(fseeko) case $host_os in @@ -1640,6 +1666,7 @@ fi # Win32 (really MinGW) support if test "$PORTNAME" = "win32"; then + AC_CHECK_FUNCS(_configthreadlocale) AC_REPLACE_FUNCS(gettimeofday) AC_LIBOBJ(dirmod) AC_LIBOBJ(kill) diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index a7c1874c226..3c82718bf99 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -644,6 +644,9 @@ /* Define to 1 if the system has the type `unsigned long long int'. */ #undef HAVE_UNSIGNED_LONG_LONG_INT +/* Define to 1 if you have the `uselocale' function. */ +#undef HAVE_USELOCALE + /* Define to 1 if you have the `utime' function. */ #undef HAVE_UTIME @@ -701,6 +704,9 @@ /* Define to 1 if your compiler understands __builtin_unreachable. */ #undef HAVE__BUILTIN_UNREACHABLE +/* Define to 1 if you have the `_configthreadlocale' function. */ +#undef HAVE__CONFIGTHREADLOCALE + /* Define to 1 if you have __cpuid. */ #undef HAVE__CPUID diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32 index a86261f5bbf..9c2d98f12fc 100644 --- a/src/include/pg_config.h.win32 +++ b/src/include/pg_config.h.win32 @@ -494,6 +494,9 @@ /* Define to 1 if you have the `unsetenv' function. */ /* #undef HAVE_UNSETENV */ +/* Define to 1 if you have the `uselocale' function. */ +/* #undef HAVE_USELOCALE */ + /* Define to 1 if you have the `utime' function. */ #define HAVE_UTIME 1 @@ -536,6 +539,9 @@ /* Define to 1 if your compiler understands __builtin_unreachable. */ /* #undef HAVE__BUILTIN_UNREACHABLE */ +/* Define to 1 if you have the `_configthreadlocale' function. */ +#define HAVE__CONFIGTHREADLOCALE 1 + /* Define to 1 if you have __cpuid. */ #define HAVE__CPUID 1 diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c index 72b0646aa6b..cf8657e9c00 100644 --- a/src/interfaces/ecpg/ecpglib/descriptor.c +++ b/src/interfaces/ecpg/ecpglib/descriptor.c @@ -482,22 +482,45 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...) if (data_var.type != ECPGt_EORT) { struct statement stmt; - char *oldlocale; - - /* Make sure we do NOT honor the locale for numeric input */ - /* since the database gives the standard decimal point */ - oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno); - setlocale(LC_NUMERIC, "C"); memset(&stmt, 0, sizeof stmt); stmt.lineno = lineno; + /* Make sure we do NOT honor the locale for numeric input */ + /* since the database gives the standard decimal point */ + /* (see comments in execute.c) */ +#ifdef HAVE_USELOCALE + stmt.clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); + if (stmt.clocale != (locale_t) 0) + stmt.oldlocale = uselocale(stmt.clocale); +#else +#ifdef HAVE__CONFIGTHREADLOCALE + stmt.oldthreadlocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); +#endif + stmt.oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno); + setlocale(LC_NUMERIC, "C"); +#endif + /* desperate try to guess something sensible */ stmt.connection = ecpg_get_connection(NULL); ecpg_store_result(ECPGresult, index, &stmt, &data_var); - setlocale(LC_NUMERIC, oldlocale); - ecpg_free(oldlocale); +#ifdef HAVE_USELOCALE + if (stmt.oldlocale != (locale_t) 0) + uselocale(stmt.oldlocale); + if (stmt.clocale) + freelocale(stmt.clocale); +#else + if (stmt.oldlocale) + { + setlocale(LC_NUMERIC, stmt.oldlocale); + ecpg_free(stmt.oldlocale); + } +#ifdef HAVE__CONFIGTHREADLOCALE + if (stmt.oldthreadlocale != -1) + _configthreadlocale(stmt.oldthreadlocale); +#endif +#endif } else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL) diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index 6f20cc412a2..adc4470d9a2 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -103,7 +103,12 @@ free_statement(struct statement *stmt) free_variable(stmt->outlist); ecpg_free(stmt->command); ecpg_free(stmt->name); +#ifdef HAVE_USELOCALE + if (stmt->clocale) + freelocale(stmt->clocale); +#else ecpg_free(stmt->oldlocale); +#endif ecpg_free(stmt); } @@ -1778,8 +1783,32 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator, /* * Make sure we do NOT honor the locale for numeric input/output since the - * database wants the standard decimal point + * database wants the standard decimal point. If available, use + * uselocale() for this because it's thread-safe. Windows doesn't have + * that, but it usually does have _configthreadlocale(). */ +#ifdef HAVE_USELOCALE + stmt->clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); + if (stmt->clocale == (locale_t) 0) + { + ecpg_do_epilogue(stmt); + return false; + } + stmt->oldlocale = uselocale(stmt->clocale); + if (stmt->oldlocale == (locale_t) 0) + { + ecpg_do_epilogue(stmt); + return false; + } +#else +#ifdef HAVE__CONFIGTHREADLOCALE + stmt->oldthreadlocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); + if (stmt->oldthreadlocale == -1) + { + ecpg_do_epilogue(stmt); + return false; + } +#endif stmt->oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno); if (stmt->oldlocale == NULL) { @@ -1787,6 +1816,7 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator, return false; } setlocale(LC_NUMERIC, "C"); +#endif #ifdef ENABLE_THREAD_SAFETY ecpg_pthreads_init(); @@ -1989,8 +2019,18 @@ ecpg_do_epilogue(struct statement *stmt) if (stmt == NULL) return; +#ifdef HAVE_USELOCALE + if (stmt->oldlocale != (locale_t) 0) + uselocale(stmt->oldlocale); +#else if (stmt->oldlocale) + { setlocale(LC_NUMERIC, stmt->oldlocale); +#ifdef HAVE__CONFIGTHREADLOCALE + _configthreadlocale(stmt->oldthreadlocale); +#endif + } +#endif free_statement(stmt); } diff --git a/src/interfaces/ecpg/ecpglib/extern.h b/src/interfaces/ecpg/ecpglib/extern.h index 91c7367b8b0..4a524392046 100644 --- a/src/interfaces/ecpg/ecpglib/extern.h +++ b/src/interfaces/ecpg/ecpglib/extern.h @@ -12,6 +12,9 @@ #ifndef CHAR_BIT #include #endif +#ifdef LOCALE_T_IN_XLOCALE +#include +#endif enum COMPAT_MODE { @@ -60,7 +63,15 @@ struct statement bool questionmarks; struct variable *inlist; struct variable *outlist; +#ifdef HAVE_USELOCALE + locale_t clocale; + locale_t oldlocale; +#else char *oldlocale; +#ifdef HAVE__CONFIGTHREADLOCALE + int oldthreadlocale; +#endif +#endif int nparams; char **paramvalues; PGresult *results;