1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-22 14:32:25 +03:00

Revert "Tidy up locale thread safety in ECPG library."

This reverts commit 8e993bff53.

It causes various build failures on the buildfarm, to be investigated.

Discussion: https://postgr.es/m/CWZBBRR6YA8D.8EHMDRGLCKCD%40neon.tech
This commit is contained in:
Peter Eisentraut
2025-03-28 21:27:37 +01:00
parent 6be53c2767
commit 3c8e463b0d
18 changed files with 148 additions and 192 deletions

View File

@@ -10,6 +10,10 @@
#include "ecpgtype.h"
#include "sqlca.h"
#ifdef HAVE_USELOCALE
locale_t ecpg_clocale = (locale_t) 0;
#endif
static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t actual_connection_key;
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
const char **conn_keywords;
const char **conn_values;
if (sqlca == NULL || !pg_ensure_c_locale())
if (sqlca == NULL)
{
ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
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
/* add connection to our list */
pthread_mutex_lock(&connections_mutex);
/*
* ... but first, make certain we have created ecpg_clocale. Rely on
* holding connections_mutex to ensure this is done by only one thread.
*/
#ifdef HAVE_USELOCALE
if (!ecpg_clocale)
{
ecpg_clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
if (!ecpg_clocale)
{
pthread_mutex_unlock(&connections_mutex);
ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
if (host)
ecpg_free(host);
if (port)
ecpg_free(port);
if (options)
ecpg_free(options);
if (realname)
ecpg_free(realname);
if (dbname)
ecpg_free(dbname);
if (conn_keywords)
ecpg_free(conn_keywords);
if (conn_values)
ecpg_free(conn_values);
free(this);
return false;
}
}
#endif
if (connection_name != NULL)
this->name = ecpg_strdup(connection_name, lineno);
else

View File

@@ -466,7 +466,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
pval++;
if (!check_special_value(pval, &dres, &scan_length))
dres = strtod_l(pval, &scan_length, PG_C_LOCALE);
dres = strtod(pval, &scan_length);
if (isarray && *scan_length == '"')
scan_length++;

View File

@@ -475,9 +475,46 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...)
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
/*
* To get here, the above PQnfields() test must have found nonzero
* fields. One needs a connection to create such a descriptor. (EXEC
* SQL SET DESCRIPTOR can populate the descriptor's "items", but it
* can't change the descriptor's PQnfields().) Any successful
* connection initializes ecpg_clocale.
*/
Assert(ecpg_clocale);
stmt.oldlocale = uselocale(ecpg_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);
#ifdef HAVE_USELOCALE
if (stmt.oldlocale != (locale_t) 0)
uselocale(stmt.oldlocale);
#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)

View File

@@ -56,6 +56,10 @@ struct ECPGtype_information_cache
enum ARRAY_TYPE isarray;
};
#ifdef HAVE_USELOCALE
extern locale_t ecpg_clocale; /* LC_NUMERIC=C */
#endif
/* structure to store one statement */
struct statement
{
@@ -69,6 +73,14 @@ struct statement
bool questionmarks;
struct variable *inlist;
struct variable *outlist;
#ifdef HAVE_USELOCALE
locale_t oldlocale;
#else
char *oldlocale;
#ifdef WIN32
int oldthreadlocale;
#endif
#endif
int nparams;
char **paramvalues;
int *paramlengths;

View File

@@ -101,6 +101,9 @@ free_statement(struct statement *stmt)
free_variable(stmt->outlist);
ecpg_free(stmt->command);
ecpg_free(stmt->name);
#ifndef HAVE_USELOCALE
ecpg_free(stmt->oldlocale);
#endif
ecpg_free(stmt);
}
@@ -1970,6 +1973,43 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
if (stmt == NULL)
return false;
/*
* Make sure we do NOT honor the locale for numeric input/output since the
* 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
/*
* Since ecpg_init() succeeded, we have a connection. Any successful
* connection initializes ecpg_clocale.
*/
Assert(ecpg_clocale);
stmt->oldlocale = uselocale(ecpg_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)
{
ecpg_do_epilogue(stmt);
return false;
}
setlocale(LC_NUMERIC, "C");
#endif
/*
* If statement type is ECPGst_prepnormal we are supposed to prepare the
* statement before executing them
@@ -2176,6 +2216,19 @@ 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);
}

View File

@@ -1218,7 +1218,7 @@ DecodeNumber(int flen, char *str, int fmask,
return DecodeNumberField(flen, str, (fmask | DTK_DATE_M),
tmask, tm, fsec, is2digits);
*fsec = strtod_l(cp, &cp, PG_C_LOCALE);
*fsec = strtod(cp, &cp);
if (*cp != '\0')
return -1;
}
@@ -2030,7 +2030,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
{
double frac;
frac = strtod_l(cp, &cp, PG_C_LOCALE);
frac = strtod(cp, &cp);
if (*cp != '\0')
return -1;
*fsec = frac * 1000000;
@@ -2054,7 +2054,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
{
double time;
time = strtod_l(cp, &cp, PG_C_LOCALE);
time = strtod(cp, &cp);
if (*cp != '\0')
return -1;

View File

@@ -60,7 +60,7 @@ ParseISO8601Number(const char *str, char **endptr, int *ipart, double *fpart)
if (!(isdigit((unsigned char) *str) || *str == '-' || *str == '.'))
return DTERR_BAD_FORMAT;
errno = 0;
val = strtod_l(str, endptr, PG_C_LOCALE);
val = strtod(str, endptr);
/* did we not see anything that looks like a double? */
if (*endptr == str || errno != 0)
return DTERR_BAD_FORMAT;
@@ -455,7 +455,7 @@ DecodeInterval(char **field, int *ftype, int nf, /* int range, */
else if (*cp == '.')
{
errno = 0;
fval = strtod_l(cp, &cp, PG_C_LOCALE);
fval = strtod(cp, &cp);
if (*cp != '\0' || errno != 0)
return DTERR_BAD_FORMAT;

View File

@@ -1455,7 +1455,7 @@ numericvar_to_double(numeric *var, double *dp)
* strtod does not reset errno to 0 in case of success.
*/
errno = 0;
val = strtod_l(tmp, &endptr, PG_C_LOCALE);
val = strtod(tmp, &endptr);
if (errno == ERANGE)
{
free(tmp);