mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
psql: Clean up more aggressively state of \bind[_named], \parse and \close
This fixes a couple of issues with the psql meta-commands mentioned above when called repeatedly: - The statement name is reset for each call. If a command errors out, its send_mode would still be set, causing an incorrect path to be taken when processing a query. For \bind_named, this could trigger an assertion failure as a statement name is always expected for this meta-command. This issue has been introduced byd55322b0da
. - The memory allocated for bind parameters can be leaked. This is a bug enlarged byd55322b0da
that exists since5b66de3433
, as it is also possible to leak memory with \bind in v16 and v17. This requires a fix that will be done on the affected branches separately. This issue is taken care of here for HEAD. This patch tightens the cleanup of the state used for the extended protocol meta-commands (bind parameters, send mode, statement name) by doing it before running each meta-command on top of doing it once a query has been processed, avoiding any leaks and the inconsistencies when mixing calls, by refactoring the cleanup in a single routine used in all the code paths where this step is required. Reported-by: Alexander Lakhin Author: Anthonin Bonnefoy Discussion: https://postgr.es/m/2e5b89af-a351-ff0a-000c-037ac28314ab@gmail.com
This commit is contained in:
@ -483,8 +483,7 @@ exec_command_bind(PsqlScanState scan_state, bool active_branch)
|
||||
int nparams = 0;
|
||||
int nalloc = 0;
|
||||
|
||||
pset.bind_params = NULL;
|
||||
pset.stmtName = NULL;
|
||||
clean_extended_state();
|
||||
|
||||
while ((opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false)))
|
||||
{
|
||||
@ -521,8 +520,7 @@ exec_command_bind_named(PsqlScanState scan_state, bool active_branch,
|
||||
int nparams = 0;
|
||||
int nalloc = 0;
|
||||
|
||||
pset.bind_params = NULL;
|
||||
pset.stmtName = NULL;
|
||||
clean_extended_state();
|
||||
|
||||
/* get the mandatory prepared statement name */
|
||||
opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
|
||||
@ -719,7 +717,8 @@ exec_command_close(PsqlScanState scan_state, bool active_branch, const char *cmd
|
||||
char *opt = psql_scan_slash_option(scan_state,
|
||||
OT_NORMAL, NULL, false);
|
||||
|
||||
pset.stmtName = NULL;
|
||||
clean_extended_state();
|
||||
|
||||
if (!opt)
|
||||
{
|
||||
pg_log_error("\\%s: missing required argument", cmd);
|
||||
@ -2205,7 +2204,8 @@ exec_command_parse(PsqlScanState scan_state, bool active_branch,
|
||||
char *opt = psql_scan_slash_option(scan_state,
|
||||
OT_NORMAL, NULL, false);
|
||||
|
||||
pset.stmtName = NULL;
|
||||
clean_extended_state();
|
||||
|
||||
if (!opt)
|
||||
{
|
||||
pg_log_error("\\%s: missing required argument", cmd);
|
||||
|
@ -1275,27 +1275,7 @@ sendquery_cleanup:
|
||||
}
|
||||
|
||||
/* clean up after extended protocol queries */
|
||||
switch (pset.send_mode)
|
||||
{
|
||||
case PSQL_SEND_EXTENDED_CLOSE: /* \close */
|
||||
free(pset.stmtName);
|
||||
break;
|
||||
case PSQL_SEND_EXTENDED_PARSE: /* \parse */
|
||||
free(pset.stmtName);
|
||||
break;
|
||||
case PSQL_SEND_EXTENDED_QUERY_PARAMS: /* \bind */
|
||||
case PSQL_SEND_EXTENDED_QUERY_PREPARED: /* \bind_named */
|
||||
for (i = 0; i < pset.bind_nparams; i++)
|
||||
free(pset.bind_params[i]);
|
||||
free(pset.bind_params);
|
||||
free(pset.stmtName);
|
||||
pset.bind_params = NULL;
|
||||
break;
|
||||
case PSQL_SEND_QUERY:
|
||||
break;
|
||||
}
|
||||
pset.stmtName = NULL;
|
||||
pset.send_mode = PSQL_SEND_QUERY;
|
||||
clean_extended_state();
|
||||
|
||||
/* reset \gset trigger */
|
||||
if (pset.gset_prefix)
|
||||
@ -2287,6 +2267,43 @@ uri_prefix_length(const char *connstr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset state related to extended query protocol
|
||||
*
|
||||
* Clean up any state related to bind parameters, statement name and
|
||||
* PSQL_SEND_MODE. This needs to be called after processing a query or when
|
||||
* running a new meta-command that uses the extended query protocol, like
|
||||
* \parse, \bind, etc.
|
||||
*/
|
||||
void
|
||||
clean_extended_state(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (pset.send_mode)
|
||||
{
|
||||
case PSQL_SEND_EXTENDED_CLOSE: /* \close */
|
||||
free(pset.stmtName);
|
||||
break;
|
||||
case PSQL_SEND_EXTENDED_PARSE: /* \parse */
|
||||
free(pset.stmtName);
|
||||
break;
|
||||
case PSQL_SEND_EXTENDED_QUERY_PARAMS: /* \bind */
|
||||
case PSQL_SEND_EXTENDED_QUERY_PREPARED: /* \bind_named */
|
||||
for (i = 0; i < pset.bind_nparams; i++)
|
||||
free(pset.bind_params[i]);
|
||||
free(pset.bind_params);
|
||||
free(pset.stmtName);
|
||||
pset.bind_params = NULL;
|
||||
break;
|
||||
case PSQL_SEND_QUERY:
|
||||
break;
|
||||
}
|
||||
|
||||
pset.stmtName = NULL;
|
||||
pset.send_mode = PSQL_SEND_QUERY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recognized connection string either starts with a valid URI prefix or
|
||||
* contains a "=" in it.
|
||||
|
@ -41,6 +41,7 @@ extern bool standard_strings(void);
|
||||
extern const char *session_username(void);
|
||||
|
||||
extern void expand_tilde(char **filename);
|
||||
extern void clean_extended_state(void);
|
||||
|
||||
extern bool recognized_connection_string(const char *connstr);
|
||||
|
||||
|
@ -132,6 +132,15 @@ SELECT $1, $2 \parse stmt3
|
||||
foo | bar
|
||||
(1 row)
|
||||
|
||||
-- Repeated calls. The second call generates an error, cleaning up the
|
||||
-- statement name set by the first call.
|
||||
\bind_named stmt4
|
||||
\bind_named
|
||||
\bind_named: missing required argument
|
||||
\g
|
||||
ERROR: there is no parameter $1
|
||||
LINE 1: SELECT $1, $2
|
||||
^
|
||||
-- \close (extended query protocol)
|
||||
\close
|
||||
\close: missing required argument
|
||||
|
@ -58,6 +58,11 @@ SELECT $1, $2 \parse stmt3
|
||||
\bind_named stmt1 \g
|
||||
\bind_named stmt2 'foo' \g
|
||||
\bind_named stmt3 'foo' 'bar' \g
|
||||
-- Repeated calls. The second call generates an error, cleaning up the
|
||||
-- statement name set by the first call.
|
||||
\bind_named stmt4
|
||||
\bind_named
|
||||
\g
|
||||
|
||||
-- \close (extended query protocol)
|
||||
\close
|
||||
|
Reference in New Issue
Block a user