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:
@@ -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
|
||||
|
@@ -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++;
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user