diff --git a/configure b/configure index 7602e65416..1e69edacde 100755 --- a/configure +++ b/configure @@ -15209,7 +15209,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 copyfile fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll posix_fallocate ppoll pstat pthread_is_threaded_np readlink setproctitle setproctitle_fast setsid shm_open strchrnul strsignal symlink sync_file_range utime utimes wcstombs_l +for ac_func in cbrt clock_gettime copyfile fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll posix_fallocate ppoll pstat pthread_is_threaded_np readlink setproctitle setproctitle_fast setsid shm_open strchrnul strsignal symlink sync_file_range uselocale utime utimes 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" diff --git a/configure.in b/configure.in index d599ad85cc..556186cf2d 100644 --- a/configure.in +++ b/configure.in @@ -1618,6 +1618,7 @@ AC_CHECK_FUNCS(m4_normalize([ strsignal symlink sync_file_range + uselocale utime utimes wcstombs_l diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 9d99816eae..2c899a1569 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -691,6 +691,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 diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32 index 8a560ef0f3..396443386a 100644 --- a/src/include/pg_config.h.win32 +++ b/src/include/pg_config.h.win32 @@ -545,6 +545,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 diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c index 186f92cc3e..71cef15172 100644 --- a/src/interfaces/ecpg/ecpglib/descriptor.c +++ b/src/interfaces/ecpg/ecpglib/descriptor.c @@ -483,22 +483,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 WIN32 + 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 WIN32 + 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/ecpglib_extern.h b/src/interfaces/ecpg/ecpglib/ecpglib_extern.h index 1c9bce1456..41851d5900 100644 --- a/src/interfaces/ecpg/ecpglib/ecpglib_extern.h +++ b/src/interfaces/ecpg/ecpglib/ecpglib_extern.h @@ -12,6 +12,9 @@ #ifndef CHAR_BIT #include #endif +#ifdef LOCALE_T_IN_XLOCALE +#include +#endif enum COMPAT_MODE { @@ -61,7 +64,15 @@ struct statement bool questionmarks; struct variable *inlist; struct variable *outlist; +#ifdef HAVE_USELOCALE + locale_t clocale; + locale_t oldlocale; +#else char *oldlocale; +#ifdef WIN32 + int oldthreadlocale; +#endif +#endif int nparams; char **paramvalues; PGresult *results; diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index 3f5034e792..81aaf10f08 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -102,7 +102,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); } @@ -1771,8 +1776,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 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 WIN32 + 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) { @@ -1780,6 +1809,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(); @@ -1982,8 +2012,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 WIN32 + _configthreadlocale(stmt->oldthreadlocale); +#endif + } +#endif free_statement(stmt); }