Skip to content

Commit 3c8e463

Browse files
committed
Revert "Tidy up locale thread safety in ECPG library."
This reverts commit 8e993bf. It causes various build failures on the buildfarm, to be investigated. Discussion: https://postgr.es/m/CWZBBRR6YA8D.8EHMDRGLCKCD%40neon.tech
1 parent 6be53c2 commit 3c8e463

18 files changed

+148
-192
lines changed

configure

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15401,7 +15401,7 @@ fi
1540115401
LIBS_including_readline="$LIBS"
1540215402
LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
1540315403

15404-
for ac_func in backtrace_symbols copyfile copy_file_range elf_aux_info getauxval getifaddrs getpeerucred inet_pton kqueue localeconv_l mbstowcs_l memset_s posix_fallocate ppoll pthread_is_threaded_np setproctitle setproctitle_fast snprintf_l strchrnul strsignal strtod_l syncfs sync_file_range uselocale wcstombs_l
15404+
for ac_func in backtrace_symbols copyfile copy_file_range elf_aux_info getauxval getifaddrs getpeerucred inet_pton kqueue localeconv_l mbstowcs_l memset_s posix_fallocate ppoll pthread_is_threaded_np setproctitle setproctitle_fast strchrnul strsignal syncfs sync_file_range uselocale wcstombs_l
1540515405
do :
1540615406
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
1540715407
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"

configure.ac

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,10 +1772,8 @@ AC_CHECK_FUNCS(m4_normalize([
17721772
pthread_is_threaded_np
17731773
setproctitle
17741774
setproctitle_fast
1775-
snprintf_l
17761775
strchrnul
17771776
strsignal
1778-
strtod_l
17791777
syncfs
17801778
sync_file_range
17811779
uselocale

meson.build

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2753,7 +2753,6 @@ func_checks = [
27532753
['shm_open', {'dependencies': [rt_dep], 'define': false}],
27542754
['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
27552755
['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2756-
['snprintf_l'],
27572756
['socket', {'dependencies': [socket_dep], 'define': false}],
27582757
['strchrnul'],
27592758
['strerror_r', {'dependencies': [thread_dep]}],
@@ -2762,7 +2761,6 @@ func_checks = [
27622761
['strnlen'],
27632762
['strsep'],
27642763
['strsignal'],
2765-
['strtod_l'],
27662764
['sync_file_range'],
27672765
['syncfs'],
27682766
['uselocale'],

src/include/pg_config.h.in

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,9 +355,6 @@
355355
/* Define to 1 if you have the `setproctitle_fast' function. */
356356
#undef HAVE_SETPROCTITLE_FAST
357357

358-
/* Define to 1 if you have the `snprintf_l' function. */
359-
#undef HAVE_SNPRINTF_L
360-
361358
/* Define to 1 if the system has the type `socklen_t'. */
362359
#undef HAVE_SOCKLEN_T
363360

@@ -403,9 +400,6 @@
403400
/* Define to 1 if you have the `strsignal' function. */
404401
#undef HAVE_STRSIGNAL
405402

406-
/* Define to 1 if you have the `strtod_l' function. */
407-
#undef HAVE_STRTOD_L
408-
409403
/* Define to 1 if the system has the type `struct option'. */
410404
#undef HAVE_STRUCT_OPTION
411405

src/include/port.h

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -218,37 +218,6 @@ extern int pg_fprintf(FILE *stream, const char *fmt,...) pg_attribute_printf(2,
218218
extern int pg_vprintf(const char *fmt, va_list args) pg_attribute_printf(1, 0);
219219
extern int pg_printf(const char *fmt,...) pg_attribute_printf(1, 2);
220220

221-
/*
222-
* A couple of systems offer a fast constant locale_t value representing the
223-
* "C" locale. We use that if possible, but fall back to creating a singleton
224-
* object otherwise. To check that it is available, call pg_ensure_c_locale()
225-
* and assume out of memory if it returns false.
226-
*/
227-
#ifdef LC_C_LOCALE
228-
#define PG_C_LOCALE LC_C_LOCALE
229-
#define pg_ensure_c_locale() true
230-
#else
231-
extern locale_t pg_get_c_locale(void);
232-
#define PG_C_LOCALE pg_get_c_locale()
233-
#define pg_ensure_c_locale() (PG_C_LOCALE != 0)
234-
#endif
235-
236-
#if !defined(HAVE_STRTOD_L) && !defined(WIN32)
237-
/*
238-
* POSIX doesn't define this function, but we can implement it with thread-safe
239-
* save-and-restore.
240-
*/
241-
static inline double
242-
strtod_l(const char *nptr, char **endptr, locale_t loc)
243-
{
244-
locale_t save = uselocale(loc);
245-
double result = strtod(nptr, endptr);
246-
247-
uselocale(save);
248-
return result;
249-
}
250-
#endif
251-
252221
#ifndef WIN32
253222
/*
254223
* We add a pg_ prefix as a warning that the Windows implementations have the

src/include/port/win32_port.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,6 @@ extern int _pglstat64(const char *name, struct stat *buf);
453453
#define isspace_l _isspace_l
454454
#define iswspace_l _iswspace_l
455455
#define strcoll_l _strcoll_l
456-
#define strtod_l _strtod_l
457456
#define strxfrm_l _strxfrm_l
458457
#define wcscoll_l _wcscoll_l
459458

src/interfaces/ecpg/ecpglib/connect.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#include "ecpgtype.h"
1111
#include "sqlca.h"
1212

13+
#ifdef HAVE_USELOCALE
14+
locale_t ecpg_clocale = (locale_t) 0;
15+
#endif
16+
1317
static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
1418
static pthread_key_t actual_connection_key;
1519
static pthread_once_t actual_connection_key_once = PTHREAD_ONCE_INIT;
@@ -264,7 +268,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
264268
const char **conn_keywords;
265269
const char **conn_values;
266270

267-
if (sqlca == NULL || !pg_ensure_c_locale())
271+
if (sqlca == NULL)
268272
{
269273
ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
270274
ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
@@ -479,6 +483,39 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
479483
/* add connection to our list */
480484
pthread_mutex_lock(&connections_mutex);
481485

486+
/*
487+
* ... but first, make certain we have created ecpg_clocale. Rely on
488+
* holding connections_mutex to ensure this is done by only one thread.
489+
*/
490+
#ifdef HAVE_USELOCALE
491+
if (!ecpg_clocale)
492+
{
493+
ecpg_clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
494+
if (!ecpg_clocale)
495+
{
496+
pthread_mutex_unlock(&connections_mutex);
497+
ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
498+
ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
499+
if (host)
500+
ecpg_free(host);
501+
if (port)
502+
ecpg_free(port);
503+
if (options)
504+
ecpg_free(options);
505+
if (realname)
506+
ecpg_free(realname);
507+
if (dbname)
508+
ecpg_free(dbname);
509+
if (conn_keywords)
510+
ecpg_free(conn_keywords);
511+
if (conn_values)
512+
ecpg_free(conn_values);
513+
free(this);
514+
return false;
515+
}
516+
}
517+
#endif
518+
482519
if (connection_name != NULL)
483520
this->name = ecpg_strdup(connection_name, lineno);
484521
else

src/interfaces/ecpg/ecpglib/data.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
466466
pval++;
467467

468468
if (!check_special_value(pval, &dres, &scan_length))
469-
dres = strtod_l(pval, &scan_length, PG_C_LOCALE);
469+
dres = strtod(pval, &scan_length);
470470

471471
if (isarray && *scan_length == '"')
472472
scan_length++;

src/interfaces/ecpg/ecpglib/descriptor.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,9 +475,46 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...)
475475
memset(&stmt, 0, sizeof stmt);
476476
stmt.lineno = lineno;
477477

478+
/* Make sure we do NOT honor the locale for numeric input */
479+
/* since the database gives the standard decimal point */
480+
/* (see comments in execute.c) */
481+
#ifdef HAVE_USELOCALE
482+
483+
/*
484+
* To get here, the above PQnfields() test must have found nonzero
485+
* fields. One needs a connection to create such a descriptor. (EXEC
486+
* SQL SET DESCRIPTOR can populate the descriptor's "items", but it
487+
* can't change the descriptor's PQnfields().) Any successful
488+
* connection initializes ecpg_clocale.
489+
*/
490+
Assert(ecpg_clocale);
491+
stmt.oldlocale = uselocale(ecpg_clocale);
492+
#else
493+
#ifdef WIN32
494+
stmt.oldthreadlocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
495+
#endif
496+
stmt.oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
497+
setlocale(LC_NUMERIC, "C");
498+
#endif
499+
478500
/* desperate try to guess something sensible */
479501
stmt.connection = ecpg_get_connection(NULL);
480502
ecpg_store_result(ECPGresult, index, &stmt, &data_var);
503+
504+
#ifdef HAVE_USELOCALE
505+
if (stmt.oldlocale != (locale_t) 0)
506+
uselocale(stmt.oldlocale);
507+
#else
508+
if (stmt.oldlocale)
509+
{
510+
setlocale(LC_NUMERIC, stmt.oldlocale);
511+
ecpg_free(stmt.oldlocale);
512+
}
513+
#ifdef WIN32
514+
if (stmt.oldthreadlocale != -1)
515+
_configthreadlocale(stmt.oldthreadlocale);
516+
#endif
517+
#endif
481518
}
482519
else if (data_var.ind_type != ECPGt_NO_INDICATOR && data_var.ind_pointer != NULL)
483520

src/interfaces/ecpg/ecpglib/ecpglib_extern.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ struct ECPGtype_information_cache
5656
enum ARRAY_TYPE isarray;
5757
};
5858

59+
#ifdef HAVE_USELOCALE
60+
extern locale_t ecpg_clocale; /* LC_NUMERIC=C */
61+
#endif
62+
5963
/* structure to store one statement */
6064
struct statement
6165
{
@@ -69,6 +73,14 @@ struct statement
6973
bool questionmarks;
7074
struct variable *inlist;
7175
struct variable *outlist;
76+
#ifdef HAVE_USELOCALE
77+
locale_t oldlocale;
78+
#else
79+
char *oldlocale;
80+
#ifdef WIN32
81+
int oldthreadlocale;
82+
#endif
83+
#endif
7284
int nparams;
7385
char **paramvalues;
7486
int *paramlengths;

src/interfaces/ecpg/ecpglib/execute.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ free_statement(struct statement *stmt)
101101
free_variable(stmt->outlist);
102102
ecpg_free(stmt->command);
103103
ecpg_free(stmt->name);
104+
#ifndef HAVE_USELOCALE
105+
ecpg_free(stmt->oldlocale);
106+
#endif
104107
ecpg_free(stmt);
105108
}
106109

@@ -1970,6 +1973,43 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
19701973
if (stmt == NULL)
19711974
return false;
19721975

1976+
/*
1977+
* Make sure we do NOT honor the locale for numeric input/output since the
1978+
* database wants the standard decimal point. If available, use
1979+
* uselocale() for this because it's thread-safe. Windows doesn't have
1980+
* that, but it does have _configthreadlocale().
1981+
*/
1982+
#ifdef HAVE_USELOCALE
1983+
1984+
/*
1985+
* Since ecpg_init() succeeded, we have a connection. Any successful
1986+
* connection initializes ecpg_clocale.
1987+
*/
1988+
Assert(ecpg_clocale);
1989+
stmt->oldlocale = uselocale(ecpg_clocale);
1990+
if (stmt->oldlocale == (locale_t) 0)
1991+
{
1992+
ecpg_do_epilogue(stmt);
1993+
return false;
1994+
}
1995+
#else
1996+
#ifdef WIN32
1997+
stmt->oldthreadlocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
1998+
if (stmt->oldthreadlocale == -1)
1999+
{
2000+
ecpg_do_epilogue(stmt);
2001+
return false;
2002+
}
2003+
#endif
2004+
stmt->oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
2005+
if (stmt->oldlocale == NULL)
2006+
{
2007+
ecpg_do_epilogue(stmt);
2008+
return false;
2009+
}
2010+
setlocale(LC_NUMERIC, "C");
2011+
#endif
2012+
19732013
/*
19742014
* If statement type is ECPGst_prepnormal we are supposed to prepare the
19752015
* statement before executing them
@@ -2176,6 +2216,19 @@ ecpg_do_epilogue(struct statement *stmt)
21762216
if (stmt == NULL)
21772217
return;
21782218

2219+
#ifdef HAVE_USELOCALE
2220+
if (stmt->oldlocale != (locale_t) 0)
2221+
uselocale(stmt->oldlocale);
2222+
#else
2223+
if (stmt->oldlocale)
2224+
{
2225+
setlocale(LC_NUMERIC, stmt->oldlocale);
2226+
#ifdef WIN32
2227+
_configthreadlocale(stmt->oldthreadlocale);
2228+
#endif
2229+
}
2230+
#endif
2231+
21792232
free_statement(stmt);
21802233
}
21812234

src/interfaces/ecpg/pgtypeslib/dt_common.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,7 +1218,7 @@ DecodeNumber(int flen, char *str, int fmask,
12181218
return DecodeNumberField(flen, str, (fmask | DTK_DATE_M),
12191219
tmask, tm, fsec, is2digits);
12201220

1221-
*fsec = strtod_l(cp, &cp, PG_C_LOCALE);
1221+
*fsec = strtod(cp, &cp);
12221222
if (*cp != '\0')
12231223
return -1;
12241224
}
@@ -2030,7 +2030,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
20302030
{
20312031
double frac;
20322032

2033-
frac = strtod_l(cp, &cp, PG_C_LOCALE);
2033+
frac = strtod(cp, &cp);
20342034
if (*cp != '\0')
20352035
return -1;
20362036
*fsec = frac * 1000000;
@@ -2054,7 +2054,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
20542054
{
20552055
double time;
20562056

2057-
time = strtod_l(cp, &cp, PG_C_LOCALE);
2057+
time = strtod(cp, &cp);
20582058
if (*cp != '\0')
20592059
return -1;
20602060

src/interfaces/ecpg/pgtypeslib/interval.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ ParseISO8601Number(const char *str, char **endptr, int *ipart, double *fpart)
6060
if (!(isdigit((unsigned char) *str) || *str == '-' || *str == '.'))
6161
return DTERR_BAD_FORMAT;
6262
errno = 0;
63-
val = strtod_l(str, endptr, PG_C_LOCALE);
63+
val = strtod(str, endptr);
6464
/* did we not see anything that looks like a double? */
6565
if (*endptr == str || errno != 0)
6666
return DTERR_BAD_FORMAT;
@@ -455,7 +455,7 @@ DecodeInterval(char **field, int *ftype, int nf, /* int range, */
455455
else if (*cp == '.')
456456
{
457457
errno = 0;
458-
fval = strtod_l(cp, &cp, PG_C_LOCALE);
458+
fval = strtod(cp, &cp);
459459
if (*cp != '\0' || errno != 0)
460460
return DTERR_BAD_FORMAT;
461461

src/interfaces/ecpg/pgtypeslib/numeric.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1455,7 +1455,7 @@ numericvar_to_double(numeric *var, double *dp)
14551455
* strtod does not reset errno to 0 in case of success.
14561456
*/
14571457
errno = 0;
1458-
val = strtod_l(tmp, &endptr, PG_C_LOCALE);
1458+
val = strtod(tmp, &endptr);
14591459
if (errno == ERANGE)
14601460
{
14611461
free(tmp);

src/port/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ OBJS = \
4141
bsearch_arg.o \
4242
chklocale.o \
4343
inet_net_ntop.o \
44-
locale.o \
4544
noblock.o \
4645
path.o \
4746
pg_bitutils.o \

0 commit comments

Comments
 (0)