aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/ecpglib/execute.c
diff options
context:
space:
mode:
authorNoah Misch <noah@leadboat.com>2022-07-02 13:00:30 -0700
committerNoah Misch <noah@leadboat.com>2022-07-02 13:00:34 -0700
commit5e0b8f3f4f87739b3187c2d3f7e6e3d2bc6a55d6 (patch)
tree5af0a924d908b0ad3e9c63efdb5262912cbeaf52 /src/interfaces/ecpg/ecpglib/execute.c
parentf7b69b1e31eea909aa48c24af64a44b6d55ce060 (diff)
downloadpostgresql-5e0b8f3f4f87739b3187c2d3f7e6e3d2bc6a55d6.tar.gz
postgresql-5e0b8f3f4f87739b3187c2d3f7e6e3d2bc6a55d6.zip
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
Diffstat (limited to 'src/interfaces/ecpg/ecpglib/execute.c')
-rw-r--r--src/interfaces/ecpg/ecpglib/execute.c40
1 files changed, 17 insertions, 23 deletions
diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c
index 6b40ecd910e..39acd588116 100644
--- a/src/interfaces/ecpg/ecpglib/execute.c
+++ b/src/interfaces/ecpg/ecpglib/execute.c
@@ -102,10 +102,7 @@ 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
+#ifndef HAVE_USELOCALE
ecpg_free(stmt->oldlocale);
#endif
ecpg_free(stmt);
@@ -1969,6 +1966,15 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
return false;
}
+#ifdef ENABLE_THREAD_SAFETY
+ ecpg_pthreads_init();
+#endif
+
+ con = ecpg_get_connection(connection_name);
+
+ if (!ecpg_init(con, connection_name, lineno))
+ return false;
+
stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno);
if (stmt == NULL)
@@ -1983,13 +1989,13 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
* treat that situation as if the function doesn't exist.
*/
#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);
+
+ /*
+ * 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);
@@ -2008,18 +2014,6 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
setlocale(LC_NUMERIC, "C");
#endif
-#ifdef ENABLE_THREAD_SAFETY
- ecpg_pthreads_init();
-#endif
-
- con = ecpg_get_connection(connection_name);
-
- if (!ecpg_init(con, connection_name, lineno))
- {
- ecpg_do_epilogue(stmt);
- return false;
- }
-
/*
* If statement type is ECPGst_prepnormal we are supposed to prepare the
* statement before executing them