1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-19 23:22:23 +03:00

ecpglib: call newlocale() once per process.

ecpglib has been calling it once per SQL query and once per EXEC SQL GET
DESCRIPTOR.  Instead, if newlocale() has not succeeded before, call it
while establishing a connection.  This mitigates three problems:
- If newlocale() failed in EXEC SQL GET DESCRIPTOR, the command silently
  proceeded without the intended locale change.
- On AIX, each newlocale()+freelocale() cycle leaked memory.
- newlocale() CPU usage may have been nontrivial.

Fail the connection attempt if newlocale() fails.  Rearrange
ecpg_do_prologue() to validate the connection before its uselocale().

The sort of program that may regress is one running in an environment
where newlocale() fails.  If that program establishes connections
without running SQL statements, it will stop working in response to this
change.  I'm betting against the importance of such an ECPG use case.
Most SQL execution (any using ECPGdo()) has long required newlocale()
success, so there's little a connection could do without newlocale().

Back-patch to v10 (all supported versions).

Reviewed by Tom Lane.  Reported by Guillaume Lelarge.

Discussion: https://postgr.es/m/20220101074055.GA54621@rfd.leadboat.com
This commit is contained in:
Noah Misch
2022-07-02 13:00:30 -07:00
parent facfd04678
commit d68b731a15
4 changed files with 71 additions and 29 deletions

View File

@@ -10,6 +10,10 @@
#include "extern.h"
#include "sqlca.h"
#ifdef HAVE_USELOCALE
locale_t ecpg_clocale;
#endif
#ifdef ENABLE_THREAD_SAFETY
static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t actual_connection_key;
@@ -531,6 +535,42 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
#ifdef ENABLE_THREAD_SAFETY
pthread_mutex_lock(&connections_mutex);
#endif
/*
* ... 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)
{
#ifdef ENABLE_THREAD_SAFETY
pthread_mutex_unlock(&connections_mutex);
#endif
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