Fix use of prepared statement in async module

Broken code caused the async connection module to never send queries
using prepared statements. Instead, queries were sent using the
parameterized query statement instead.

Fix this so that prepared statements are used when created.
This commit is contained in:
Erik Nordström 2023-01-24 18:18:22 +01:00 committed by Erik Nordström
parent 1a3e7ad7d1
commit d489ed6f32
2 changed files with 65 additions and 42 deletions

View File

@ -15,6 +15,7 @@ accidentally triggering the load of a previous DB version.**
* #4804 Skip bucketing when start or end of refresh job is null * #4804 Skip bucketing when start or end of refresh job is null
* #4926 Fix corruption when inserting into compressed chunks * #4926 Fix corruption when inserting into compressed chunks
* #5218 Add role-level security to job error log * #5218 Add role-level security to job error log
* #5214 Fix use of prepared statement in async module
## 2.9.2 (2023-01-26) ## 2.9.2 (2023-01-26)

View File

@ -152,6 +152,8 @@ async_request_set_state(AsyncRequest *req, AsyncRequestState new_state)
static AsyncRequest * static AsyncRequest *
async_request_send_internal(AsyncRequest *req, int elevel) async_request_send_internal(AsyncRequest *req, int elevel)
{ {
int ret;
if (req->state != DEFERRED) if (req->state != DEFERRED)
elog(elevel, "can't send async request in state \"%d\"", req->state); elog(elevel, "can't send async request in state \"%d\"", req->state);
@ -159,9 +161,20 @@ async_request_send_internal(AsyncRequest *req, int elevel)
return req; return req;
/* Send configuration parameters if necessary */ /* Send configuration parameters if necessary */
remote_connection_configure_if_changed(req->conn); if (!remote_connection_configure_if_changed(req->conn))
elog(elevel, "could not configure connection when preparing statement");
if (req->stmt_name) if (req->stmt_name)
{
ret = PQsendQueryPrepared(remote_connection_get_pg_conn(req->conn),
req->stmt_name,
stmt_params_total_values(req->params),
stmt_params_values(req->params),
stmt_params_lengths(req->params),
stmt_params_formats(req->params),
req->res_format);
}
else
{ {
/* /*
* We intentionally do not specify parameter types here, but leave the * We intentionally do not specify parameter types here, but leave the
@ -170,39 +183,26 @@ async_request_send_internal(AsyncRequest *req, int elevel)
* the prepared statements we use in this module are simple enough that * the prepared statements we use in this module are simple enough that
* the data node will make the right choices. * the data node will make the right choices.
*/ */
if (0 == PQsendPrepare(remote_connection_get_pg_conn(req->conn), ret = PQsendQueryParams(remote_connection_get_pg_conn(req->conn),
req->stmt_name, req->sql,
req->sql, stmt_params_total_values(req->params),
req->prep_stmt_params, /* param types - see note above */ NULL,
NULL)) stmt_params_values(req->params),
{ stmt_params_lengths(req->params),
/* stmt_params_formats(req->params),
* null is fine to pass down as the res, the connection error message req->res_format);
* will get through
*/
remote_connection_elog(req->conn, elevel);
return NULL;
}
} }
else
if (ret == 0)
{ {
if (0 == PQsendQueryParams(remote_connection_get_pg_conn(req->conn), /*
req->sql, * null is fine to pass down as the res, the connection error message
stmt_params_total_values(req->params), * will get through
/* param types - see note above */ NULL, */
stmt_params_values(req->params), remote_connection_elog(req->conn, elevel);
stmt_params_lengths(req->params), return NULL;
stmt_params_formats(req->params),
req->res_format))
{
/*
* null is fine to pass down as the res, the connection error message
* will get through
*/
remote_connection_elog(req->conn, elevel);
return NULL;
}
} }
async_request_set_state(req, EXECUTING); async_request_set_state(req, EXECUTING);
remote_connection_set_status(req->conn, CONN_PROCESSING); remote_connection_set_status(req->conn, CONN_PROCESSING);
return req; return req;
@ -222,19 +222,37 @@ AsyncRequest *
async_request_send_prepare(TSConnection *conn, const char *sql, int n_params) async_request_send_prepare(TSConnection *conn, const char *sql, int n_params)
{ {
AsyncRequest *req; AsyncRequest *req;
size_t stmt_name_len = NAMEDATALEN; char *stmt_name;
char *stmt_name = palloc(sizeof(char) * stmt_name_len); int ret;
int written;
Assert(!remote_connection_is_processing(conn));
/* Construct name we'll use for the prepared statement. */ /* Construct name we'll use for the prepared statement. */
written = stmt_name = psprintf("ts_prep_%u", remote_connection_get_prep_stmt_number());
snprintf(stmt_name, stmt_name_len, "ts_prep_%u", remote_connection_get_prep_stmt_number());
if (written < 0 || (size_t) written >= stmt_name_len) /* Send configuration parameters if necessary */
elog(ERROR, "cannot create prepared statement name"); if (!remote_connection_configure_if_changed(conn))
elog(ERROR, "could not configure connection when preparing statement");
req = async_request_create(conn, sql, stmt_name, n_params, NULL, FORMAT_TEXT); req = async_request_create(conn, sql, stmt_name, n_params, NULL, FORMAT_TEXT);
req = async_request_send_internal(req, ERROR);
/* Do not specify parameter types, see note above in
* async_request_send_internal */
ret = PQsendPrepare(remote_connection_get_pg_conn(req->conn),
req->stmt_name,
req->sql,
req->prep_stmt_params,
NULL);
if (ret == 0)
{
pfree(req);
remote_connection_elog(req->conn, ERROR);
return NULL;
}
async_request_set_state(req, EXECUTING);
remote_connection_set_status(req->conn, CONN_PROCESSING);
return req; return req;
} }
@ -245,7 +263,7 @@ async_request_send_prepared_stmt(PreparedStmt *stmt, const char *const *param_va
AsyncRequest *req = AsyncRequest *req =
async_request_create(stmt->conn, async_request_create(stmt->conn,
stmt->sql, stmt->sql,
NULL, stmt->stmt_name,
stmt->n_params, stmt->n_params,
stmt_params_create_from_values((const char **) param_values, stmt_params_create_from_values((const char **) param_values,
stmt->n_params), stmt->n_params),
@ -256,8 +274,12 @@ async_request_send_prepared_stmt(PreparedStmt *stmt, const char *const *param_va
AsyncRequest * AsyncRequest *
async_request_send_prepared_stmt_with_params(PreparedStmt *stmt, StmtParams *params, int res_format) async_request_send_prepared_stmt_with_params(PreparedStmt *stmt, StmtParams *params, int res_format)
{ {
AsyncRequest *req = AsyncRequest *req = async_request_create(stmt->conn,
async_request_create(stmt->conn, stmt->sql, NULL, stmt->n_params, params, res_format); stmt->sql,
stmt->stmt_name,
stmt->n_params,
params,
res_format);
return async_request_send_internal(req, ERROR); return async_request_send_internal(req, ERROR);
} }