From deb4994144dfdea67cdd24558bd24dbacdd3392e Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Mon, 23 Jan 2017 22:51:58 +0300 Subject: [PATCH] Fix prepared statements for PostgreSQL driver. libpq requires zero-terminated strings for text arguments. --- sysbench/drivers/pgsql/drv_pgsql.c | 21 ++++++++++++++++----- sysbench/lua/internal/sysbench.sql.lua | 2 +- tests/include/api_sql_common.sh | 4 ++++ tests/t/api_sql_mysql.t | 3 +++ tests/t/api_sql_pgsql.t | 6 ++++++ 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/sysbench/drivers/pgsql/drv_pgsql.c b/sysbench/drivers/pgsql/drv_pgsql.c index b7c9db0..9ab6eda 100644 --- a/sysbench/drivers/pgsql/drv_pgsql.c +++ b/sysbench/drivers/pgsql/drv_pgsql.c @@ -34,7 +34,7 @@ #include "sb_rand.h" /* Maximum length of text representation of bind parameters */ -#define MAX_PARAM_LENGTH 256 +#define MAX_PARAM_LENGTH 256UL /* PostgreSQL driver arguments */ @@ -359,6 +359,11 @@ int pgsql_drv_prepare(db_stmt_t *stmt, const char *query, size_t len) if (PQresultStatus(pgres) != PGRES_COMMAND_OK) { log_text(LOG_FATAL, "PQprepare() failed: %s", PQerrorMessage(con)); + + free(stmt->query); + free(pgstmt->name); + free(pgstmt); + return 1; } pgstmt->prepared = 1; @@ -440,9 +445,8 @@ int pgsql_drv_bind_param(db_stmt_t *stmt, db_bind_t *params, size_t len) if (pgstmt->pvalues[i] != NULL) { free(pgstmt->pvalues[i]); - pgstmt->pvalues[i] = NULL; } - + pgstmt->pvalues[i] = (char *)malloc(MAX_PARAM_LENGTH); if (pgstmt->pvalues[i] == NULL) return 1; @@ -547,6 +551,7 @@ db_error_t pgsql_drv_execute(db_stmt_t *stmt, db_result_t *rs) char need_realloc; int n; db_error_t rc; + unsigned long len; if (!stmt->emulated) { @@ -567,8 +572,14 @@ db_error_t pgsql_drv_execute(db_stmt_t *stmt, db_result_t *rs) switch (stmt->bound_param[i].type) { case DB_TYPE_CHAR: case DB_TYPE_VARCHAR: - strncpy(pgstmt->pvalues[i], stmt->bound_param[i].buffer, - MAX_PARAM_LENGTH); + + len = stmt->bound_param[i].data_len[0]; + + memcpy(pgstmt->pvalues[i], stmt->bound_param[i].buffer, + SB_MIN(MAX_PARAM_LENGTH, len)); + /* PostgreSQL requires a zero-terminated string */ + pgstmt->pvalues[i][len] = '\0'; + break; default: db_print_value(stmt->bound_param + i, pgstmt->pvalues[i], diff --git a/sysbench/lua/internal/sysbench.sql.lua b/sysbench/lua/internal/sysbench.sql.lua index 3172cc9..f385b84 100644 --- a/sysbench/lua/internal/sysbench.sql.lua +++ b/sysbench/lua/internal/sysbench.sql.lua @@ -392,7 +392,7 @@ function statement_methods.bind_param(self, ...) for i, param in ipairs({...}) do binds[i-1].type = param.type binds[i-1].buffer = param.buffer - binds[i-1].data_len = param.datalen + binds[i-1].data_len = param.data_len binds[i-1].max_len = param.max_len binds[i-1].is_null = param.is_null end diff --git a/tests/include/api_sql_common.sh b/tests/include/api_sql_common.sh index 541ff72..8bd9a83 100644 --- a/tests/include/api_sql_common.sh +++ b/tests/include/api_sql_common.sh @@ -60,6 +60,10 @@ function event() con:query("DROP TABLE t2") con:query("ALTER TABLE t ADD COLUMN b CHAR(10)") + e, m = pcall(con.prepare, con, "SELECT * FROM nonexisting") + print(m) + print('--') + local stmt = con:prepare("UPDATE t SET a = a + ?, b = ?") local a = stmt:bind_create(sysbench.sql.type.INT) local b = stmt:bind_create(sysbench.sql.type.CHAR, 10) diff --git a/tests/t/api_sql_mysql.t b/tests/t/api_sql_mysql.t index c3b4ca2..5357591 100644 --- a/tests/t/api_sql_mysql.t +++ b/tests/t/api_sql_mysql.t @@ -37,6 +37,9 @@ SQL Lua API + MySQL tests -- nil 2 -- + FATAL: mysql_stmt_prepare() failed + FATAL: MySQL error: 1146 "Table 'sbtest.nonexisting' doesn't exist" + SQL API error Unsupported argument type: 8 diff --git a/tests/t/api_sql_pgsql.t b/tests/t/api_sql_pgsql.t index 835923b..9691296 100644 --- a/tests/t/api_sql_pgsql.t +++ b/tests/t/api_sql_pgsql.t @@ -37,6 +37,12 @@ SQL Lua API + PostgreSQL tests -- bar nil -- + FATAL: PQprepare() failed: ERROR: relation "nonexisting" does not exist + LINE 1: SELECT * FROM nonexisting + ^ + + SQL API error + -- Unsupported argument type: 8