2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-09-04 07:55:18 +00:00

[#2792] Check that mysql pointer is non-null

This is a workaround for the libmysqlclient that dereferences mysql ptr
in the MYSQL_STMT after reconnect. Kea checks that this pointer is not
NULL before using the statement.
This commit is contained in:
Marcin Siodelski
2023-07-17 19:17:30 +02:00
parent 53f3d241c8
commit d3971afa6e
6 changed files with 91 additions and 75 deletions

View File

@@ -82,18 +82,6 @@ MySqlConfigBackendImpl(const DatabaseConnection::ParameterMap& parameters,
} }
} }
MySqlConfigBackendImpl::~MySqlConfigBackendImpl() {
// Free up the prepared statements, ignoring errors. (What would we do
// about them? We're destroying this object and are not really concerned
// with errors on a database connection that is about to go away.)
for (int i = 0; i < conn_.statements_.size(); ++i) {
if (conn_.statements_[i] != NULL) {
(void) mysql_stmt_close(conn_.statements_[i]);
conn_.statements_[i] = NULL;
}
}
}
MySqlBindingPtr MySqlBindingPtr
MySqlConfigBackendImpl::createBinding(const Triplet<uint32_t>& triplet) { MySqlConfigBackendImpl::createBinding(const Triplet<uint32_t>& triplet) {
if (triplet.unspecified()) { if (triplet.unspecified()) {

View File

@@ -113,7 +113,7 @@ public:
const db::DbCallback db_reconnect_callback); const db::DbCallback db_reconnect_callback);
/// @brief Destructor. /// @brief Destructor.
virtual ~MySqlConfigBackendImpl(); virtual ~MySqlConfigBackendImpl() {};
/// @brief Creates MySQL binding from an @c Optional of integer type. /// @brief Creates MySQL binding from an @c Optional of integer type.
/// ///

View File

@@ -3042,11 +3042,11 @@ MySqlHostDataSourceImpl::addStatement(MySqlHostContextPtr& ctx,
StatementIndex stindex, StatementIndex stindex,
std::vector<MYSQL_BIND>& bind) { std::vector<MYSQL_BIND>& bind) {
// Bind the parameters to the statement // Bind the parameters to the statement
int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], &bind[0]); int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), &bind[0]);
checkError(ctx, status, stindex, "unable to bind parameters"); checkError(ctx, status, stindex, "unable to bind parameters");
// Execute the statement // Execute the statement
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
if (status != 0) { if (status != 0) {
// Failure: check for the special case of duplicate entry. // Failure: check for the special case of duplicate entry.
@@ -3061,7 +3061,7 @@ MySqlHostDataSourceImpl::addStatement(MySqlHostContextPtr& ctx,
// index in the database. Unique indexes are not created in the database // index in the database. Unique indexes are not created in the database
// when it may be sometimes allowed to insert duplicated records per // when it may be sometimes allowed to insert duplicated records per
// server's configuration. // server's configuration.
my_ulonglong numrows = mysql_stmt_affected_rows(ctx->conn_.statements_[stindex]); my_ulonglong numrows = mysql_stmt_affected_rows(ctx->conn_.getStatement(stindex));
if (numrows == 0) { if (numrows == 0) {
isc_throw(DuplicateEntry, "Database duplicate entry error"); isc_throw(DuplicateEntry, "Database duplicate entry error");
} }
@@ -3072,18 +3072,18 @@ MySqlHostDataSourceImpl::delStatement(MySqlHostContextPtr& ctx,
StatementIndex stindex, StatementIndex stindex,
MYSQL_BIND* bind) { MYSQL_BIND* bind) {
// Bind the parameters to the statement // Bind the parameters to the statement
int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], &bind[0]); int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), &bind[0]);
checkError(ctx, status, stindex, "unable to bind parameters"); checkError(ctx, status, stindex, "unable to bind parameters");
// Execute the statement // Execute the statement
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
if (status != 0) { if (status != 0) {
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
} }
// Let's check how many hosts were deleted. // Let's check how many hosts were deleted.
my_ulonglong numrows = mysql_stmt_affected_rows(ctx->conn_.statements_[stindex]); my_ulonglong numrows = mysql_stmt_affected_rows(ctx->conn_.getStatement(stindex));
return (numrows != 0); return (numrows != 0);
} }
@@ -3151,30 +3151,30 @@ MySqlHostDataSourceImpl::getHostCollection(MySqlHostContextPtr& ctx,
bool single) const { bool single) const {
// Bind the selection parameters to the statement // Bind the selection parameters to the statement
int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind); int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
checkError(ctx, status, stindex, "unable to bind WHERE clause parameter"); checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
// Set up the MYSQL_BIND array for the data being returned and bind it to // Set up the MYSQL_BIND array for the data being returned and bind it to
// the statement. // the statement.
std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive(); std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
status = mysql_stmt_bind_result(ctx->conn_.statements_[stindex], &outbind[0]); status = mysql_stmt_bind_result(ctx->conn_.getStatement(stindex), &outbind[0]);
checkError(ctx, status, stindex, "unable to bind SELECT clause parameters"); checkError(ctx, status, stindex, "unable to bind SELECT clause parameters");
// Execute the statement // Execute the statement
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
// Ensure that all the lease information is retrieved in one go to avoid // Ensure that all the lease information is retrieved in one go to avoid
// overhead of going back and forth between client and server. // overhead of going back and forth between client and server.
status = mysql_stmt_store_result(ctx->conn_.statements_[stindex]); status = mysql_stmt_store_result(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to set up for storing all results"); checkError(ctx, status, stindex, "unable to set up for storing all results");
// Set up the fetch "release" object to release resources associated // Set up the fetch "release" object to release resources associated
// with the call to mysql_stmt_fetch when this method exits, then // with the call to mysql_stmt_fetch when this method exits, then
// retrieve the data. mysql_stmt_fetch return value equal to 0 represents // retrieve the data. mysql_stmt_fetch return value equal to 0 represents
// successful data fetch. // successful data fetch.
MySqlFreeResult fetch_release(ctx->conn_.statements_[stindex]); MySqlFreeResult fetch_release(ctx->conn_.getStatement(stindex));
while ((status = mysql_stmt_fetch(ctx->conn_.statements_[stindex])) == while ((status = mysql_stmt_fetch(ctx->conn_.getStatement(stindex))) ==
MLM_MYSQL_FETCH_SUCCESS) { MLM_MYSQL_FETCH_SUCCESS) {
try { try {
exchange->processFetchedData(result); exchange->processFetchedData(result);

View File

@@ -2081,7 +2081,7 @@ private:
" - invalid statement index" << statement_index_); " - invalid statement index" << statement_index_);
} }
statement_ = conn_.statements_[statement_index_]; statement_ = conn_.getStatement(statement_index_);
} }
/// @brief Database connection to use to execute the query /// @brief Database connection to use to execute the query
@@ -2366,11 +2366,11 @@ MySqlLeaseMgr::addLeaseCommon(MySqlLeaseContextPtr& ctx,
StatementIndex stindex, StatementIndex stindex,
std::vector<MYSQL_BIND>& bind) { std::vector<MYSQL_BIND>& bind) {
// Bind the parameters to the statement // Bind the parameters to the statement
int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], &bind[0]); int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), &bind[0]);
checkError(ctx, status, stindex, "unable to bind parameters"); checkError(ctx, status, stindex, "unable to bind parameters");
// Execute the statement // Execute the statement
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
if (status != 0) { if (status != 0) {
// Failure: check for the special case of duplicate entry. If this is // Failure: check for the special case of duplicate entry. If this is
@@ -2484,31 +2484,31 @@ MySqlLeaseMgr::getLeaseCollection(MySqlLeaseContextPtr& ctx,
if (bind) { if (bind) {
// Bind the selection parameters to the statement // Bind the selection parameters to the statement
status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind); status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
checkError(ctx, status, stindex, "unable to bind WHERE clause parameter"); checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
} }
// Set up the MYSQL_BIND array for the data being returned and bind it to // Set up the MYSQL_BIND array for the data being returned and bind it to
// the statement. // the statement.
std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive(); std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
status = mysql_stmt_bind_result(ctx->conn_.statements_[stindex], &outbind[0]); status = mysql_stmt_bind_result(ctx->conn_.getStatement(stindex), &outbind[0]);
checkError(ctx, status, stindex, "unable to bind SELECT clause parameters"); checkError(ctx, status, stindex, "unable to bind SELECT clause parameters");
// Execute the statement // Execute the statement
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
// Ensure that all the lease information is retrieved in one go to avoid // Ensure that all the lease information is retrieved in one go to avoid
// overhead of going back and forth between client and server. // overhead of going back and forth between client and server.
status = mysql_stmt_store_result(ctx->conn_.statements_[stindex]); status = mysql_stmt_store_result(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to set up for storing all results"); checkError(ctx, status, stindex, "unable to set up for storing all results");
// Set up the fetch "release" object to release resources associated // Set up the fetch "release" object to release resources associated
// with the call to mysql_stmt_fetch when this method exits, then // with the call to mysql_stmt_fetch when this method exits, then
// retrieve the data. // retrieve the data.
MySqlFreeResult fetch_release(ctx->conn_.statements_[stindex]); MySqlFreeResult fetch_release(ctx->conn_.getStatement(stindex));
int count = 0; int count = 0;
while ((status = mysql_stmt_fetch(ctx->conn_.statements_[stindex])) == 0) { while ((status = mysql_stmt_fetch(ctx->conn_.getStatement(stindex))) == 0) {
try { try {
result.push_back(exchange->getLeaseData()); result.push_back(exchange->getLeaseData());
@@ -3241,16 +3241,16 @@ MySqlLeaseMgr::updateLeaseCommon(MySqlLeaseContextPtr& ctx,
const LeasePtr& lease) { const LeasePtr& lease) {
// Bind the parameters to the statement // Bind the parameters to the statement
int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind); int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
checkError(ctx, status, stindex, "unable to bind parameters"); checkError(ctx, status, stindex, "unable to bind parameters");
// Execute // Execute
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
// See how many rows were affected. The statement should only update a // See how many rows were affected. The statement should only update a
// single row. // single row.
int affected_rows = mysql_stmt_affected_rows(ctx->conn_.statements_[stindex]); int affected_rows = mysql_stmt_affected_rows(ctx->conn_.getStatement(stindex));
// Check success case first as it is the most likely outcome. // Check success case first as it is the most likely outcome.
if (affected_rows == 1) { if (affected_rows == 1) {
@@ -3412,16 +3412,16 @@ MySqlLeaseMgr::deleteLeaseCommon(MySqlLeaseContextPtr& ctx,
StatementIndex stindex, StatementIndex stindex,
MYSQL_BIND* bind) { MYSQL_BIND* bind) {
// Bind the input parameters to the statement // Bind the input parameters to the statement
int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind); int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
checkError(ctx, status, stindex, "unable to bind WHERE clause parameter"); checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
// Execute // Execute
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
// See how many rows were affected. Note that the statement may delete // See how many rows were affected. Note that the statement may delete
// multiple rows. // multiple rows.
return (static_cast<uint64_t>(mysql_stmt_affected_rows(ctx->conn_.statements_[stindex]))); return (static_cast<uint64_t>(mysql_stmt_affected_rows(ctx->conn_.getStatement(stindex))));
} }
bool bool
@@ -3903,11 +3903,11 @@ MySqlLeaseMgr::deleteRelayId6(const IOAddress& addr) {
StatementIndex stindex = DELETE_RELAY_ID6; StatementIndex stindex = DELETE_RELAY_ID6;
// Bind the input parameters to the statement. // Bind the input parameters to the statement.
int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind); int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
checkError(ctx, status, stindex, "unable to bind WHERE clause parameter"); checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
// Execute. // Execute.
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
} }
@@ -3933,11 +3933,11 @@ MySqlLeaseMgr::deleteRemoteId6(const IOAddress& addr) {
StatementIndex stindex = DELETE_REMOTE_ID6; StatementIndex stindex = DELETE_REMOTE_ID6;
// Bind the input parameters to the statement. // Bind the input parameters to the statement.
int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind); int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
checkError(ctx, status, stindex, "unable to bind WHERE clause parameter"); checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
// Execute. // Execute.
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
} }
@@ -3977,11 +3977,11 @@ MySqlLeaseMgr::addRelayId6(const IOAddress& lease_addr,
StatementIndex stindex = ADD_RELAY_ID6; StatementIndex stindex = ADD_RELAY_ID6;
// Bind the input parameters to the statement. // Bind the input parameters to the statement.
int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind); int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
checkError(ctx, status, stindex, "unable to bind WHERE clause parameter"); checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
// Execute. // Execute.
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
} }
@@ -4021,11 +4021,11 @@ MySqlLeaseMgr::addRemoteId6(const IOAddress& lease_addr,
StatementIndex stindex = ADD_REMOTE_ID6; StatementIndex stindex = ADD_REMOTE_ID6;
// Bind the input parameters to the statement. // Bind the input parameters to the statement.
int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind); int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
checkError(ctx, status, stindex, "unable to bind WHERE clause parameter"); checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
// Execute. // Execute.
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
} }
@@ -4807,13 +4807,13 @@ MySqlLeaseMgr::wipeExtendedInfoTables6() {
MySqlLeaseContextPtr ctx = get_context.ctx_; MySqlLeaseContextPtr ctx = get_context.ctx_;
StatementIndex stindex = WIPE_RELAY_ID6; StatementIndex stindex = WIPE_RELAY_ID6;
int status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); int status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
if (status != 0) { if (status != 0) {
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
} }
stindex = WIPE_REMOTE_ID6; stindex = WIPE_REMOTE_ID6;
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
if (status != 0) { if (status != 0) {
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
} }
@@ -4835,22 +4835,22 @@ MySqlLeaseMgr::byRelayId6size() const {
bind[0].buffer_type = MYSQL_TYPE_LONGLONG; bind[0].buffer_type = MYSQL_TYPE_LONGLONG;
bind[0].buffer = reinterpret_cast<char*>(&count); bind[0].buffer = reinterpret_cast<char*>(&count);
int status = mysql_stmt_bind_result(ctx->conn_.statements_[stindex], &bind[0]); int status = mysql_stmt_bind_result(ctx->conn_.getStatement(stindex), &bind[0]);
checkError(ctx, status, stindex, "unable to bind SELECT clause parameters"); checkError(ctx, status, stindex, "unable to bind SELECT clause parameters");
// Execute. // Execute.
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
if (status != 0) { if (status != 0) {
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
} }
status = mysql_stmt_store_result(ctx->conn_.statements_[stindex]); status = mysql_stmt_store_result(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to store result"); checkError(ctx, status, stindex, "unable to store result");
// Fetch the result. // Fetch the result.
MySqlFreeResult fetch_release(ctx->conn_.statements_[stindex]); MySqlFreeResult fetch_release(ctx->conn_.getStatement(stindex));
status = mysql_stmt_fetch(ctx->conn_.statements_[stindex]); status = mysql_stmt_fetch(ctx->conn_.getStatement(stindex));
if (status != 0) { if (status != 0) {
checkError(ctx, status, stindex, "unable to fetch results"); checkError(ctx, status, stindex, "unable to fetch results");
} }
@@ -4873,22 +4873,22 @@ MySqlLeaseMgr::byRemoteId6size() const {
bind[0].buffer_type = MYSQL_TYPE_LONGLONG; bind[0].buffer_type = MYSQL_TYPE_LONGLONG;
bind[0].buffer = reinterpret_cast<char*>(&count); bind[0].buffer = reinterpret_cast<char*>(&count);
int status = mysql_stmt_bind_result(ctx->conn_.statements_[stindex], &bind[0]); int status = mysql_stmt_bind_result(ctx->conn_.getStatement(stindex), &bind[0]);
checkError(ctx, status, stindex, "unable to bind SELECT clause parameters"); checkError(ctx, status, stindex, "unable to bind SELECT clause parameters");
// Execute. // Execute.
status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]); status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
if (status != 0) { if (status != 0) {
checkError(ctx, status, stindex, "unable to execute"); checkError(ctx, status, stindex, "unable to execute");
} }
status = mysql_stmt_store_result(ctx->conn_.statements_[stindex]); status = mysql_stmt_store_result(ctx->conn_.getStatement(stindex));
checkError(ctx, status, stindex, "unable to store result"); checkError(ctx, status, stindex, "unable to store result");
// Fetch the result. // Fetch the result.
MySqlFreeResult fetch_release(ctx->conn_.statements_[stindex]); MySqlFreeResult fetch_release(ctx->conn_.getStatement(stindex));
status = mysql_stmt_fetch(ctx->conn_.statements_[stindex]); status = mysql_stmt_fetch(ctx->conn_.getStatement(stindex));
if (status != 0) { if (status != 0) {
checkError(ctx, status, stindex, "unable to fetch results"); checkError(ctx, status, stindex, "unable to fetch results");
} }

View File

@@ -304,6 +304,24 @@ public:
/// @brief Clears prepared statements and text statements. /// @brief Clears prepared statements and text statements.
void clearStatements(); void clearStatements();
/// @brief Returns a prepared statement by an index
///
/// @tparam StatementIndex Type of the statement index enum.
///
/// @param index Statement index.
/// @return Pointer to the prepared statement.
/// @throw isc::db::DbConnectionUnusable when the @c mysql pointer in the
/// returned statement is NULL; it may be the result of the database
/// connectivity loss.
template<typename StatementIndex>
MYSQL_STMT* getStatement(StatementIndex index) const {
if (statements_[index]->mysql == 0) {
isc_throw(db::DbConnectionUnusable,
"MySQL pointer for the prepared statement is NULL as a result of connectivity loss");
}
return (statements_[index]);
}
/// @brief Open Database /// @brief Open Database
/// ///
/// Opens the database using the information supplied in the parameters /// Opens the database using the information supplied in the parameters
@@ -436,7 +454,7 @@ public:
int status = 0; int status = 0;
if (!in_bind_vec.empty()) { if (!in_bind_vec.empty()) {
// Bind parameters to the prepared statement. // Bind parameters to the prepared statement.
status = mysql_stmt_bind_param(statements_[index], status = mysql_stmt_bind_param(getStatement(index),
in_bind_vec.empty() ? 0 : &in_bind_vec[0]); in_bind_vec.empty() ? 0 : &in_bind_vec[0]);
checkError(status, index, "unable to bind parameters for select"); checkError(status, index, "unable to bind parameters for select");
} }
@@ -447,20 +465,20 @@ public:
out_bind_vec.push_back(out_binding->getMySqlBinding()); out_bind_vec.push_back(out_binding->getMySqlBinding());
} }
if (!out_bind_vec.empty()) { if (!out_bind_vec.empty()) {
status = mysql_stmt_bind_result(statements_[index], &out_bind_vec[0]); status = mysql_stmt_bind_result(getStatement(index), &out_bind_vec[0]);
checkError(status, index, "unable to bind result parameters for select"); checkError(status, index, "unable to bind result parameters for select");
} }
// Execute query. // Execute query.
status = MysqlExecuteStatement(statements_[index]); status = MysqlExecuteStatement(getStatement(index));
checkError(status, index, "unable to execute"); checkError(status, index, "unable to execute");
status = mysql_stmt_store_result(statements_[index]); status = mysql_stmt_store_result(getStatement(index));
checkError(status, index, "unable to set up for storing all results"); checkError(status, index, "unable to set up for storing all results");
// Fetch results. // Fetch results.
MySqlFreeResult fetch_release(statements_[index]); MySqlFreeResult fetch_release(getStatement(index));
while ((status = mysql_stmt_fetch(statements_[index])) == while ((status = mysql_stmt_fetch(getStatement(index))) ==
MLM_MYSQL_FETCH_SUCCESS) { MLM_MYSQL_FETCH_SUCCESS) {
try { try {
// For each returned row call user function which should // For each returned row call user function which should
@@ -511,12 +529,12 @@ public:
} }
// Bind the parameters to the statement // Bind the parameters to the statement
int status = mysql_stmt_bind_param(statements_[index], int status = mysql_stmt_bind_param(getStatement(index),
in_bind_vec.empty() ? 0 : &in_bind_vec[0]); in_bind_vec.empty() ? 0 : &in_bind_vec[0]);
checkError(status, index, "unable to bind parameters"); checkError(status, index, "unable to bind parameters");
// Execute the statement // Execute the statement
status = MysqlExecuteStatement(statements_[index]); status = MysqlExecuteStatement(getStatement(index));
if (status != 0) { if (status != 0) {
// Failure: check for the special case of duplicate entry. // Failure: check for the special case of duplicate entry.
@@ -555,12 +573,12 @@ public:
} }
// Bind the parameters to the statement // Bind the parameters to the statement
int status = mysql_stmt_bind_param(statements_[index], int status = mysql_stmt_bind_param(getStatement(index),
in_bind_vec.empty() ? 0 : &in_bind_vec[0]); in_bind_vec.empty() ? 0 : &in_bind_vec[0]);
checkError(status, index, "unable to bind parameters"); checkError(status, index, "unable to bind parameters");
// Execute the statement // Execute the statement
status = MysqlExecuteStatement(statements_[index]); status = MysqlExecuteStatement(getStatement(index));
if (status != 0) { if (status != 0) {
// Failure: check for the special case of duplicate entry. // Failure: check for the special case of duplicate entry.
@@ -581,7 +599,7 @@ public:
} }
// Let's return how many rows were affected. // Let's return how many rows were affected.
return (static_cast<uint64_t>(mysql_stmt_affected_rows(statements_[index]))); return (static_cast<uint64_t>(mysql_stmt_affected_rows(getStatement(index))));
} }
/// @brief Commits current transaction /// @brief Commits current transaction
@@ -731,14 +749,14 @@ private:
template<typename T> template<typename T>
void setIntParameterValue(const std::string& name, int64_t min, int64_t max, T& value); void setIntParameterValue(const std::string& name, int64_t min, int64_t max, T& value);
public:
/// @brief Prepared statements /// @brief Prepared statements
/// ///
/// This field is public, because it is used heavily from MySqlConnection /// The statements should be accessed using the @c getStatement method because
/// and will be from MySqlHostDataSource. /// it checks whether the returned statement is valid.
std::vector<MYSQL_STMT*> statements_; std::vector<MYSQL_STMT*> statements_;
public:
/// @brief Raw text of statements /// @brief Raw text of statements
/// ///
/// This field is public, because it is used heavily from MySqlConnection /// This field is public, because it is used heavily from MySqlConnection

View File

@@ -6,6 +6,7 @@
#include <config.h> #include <config.h>
#include <database/database_connection.h>
#include <exceptions/exceptions.h> #include <exceptions/exceptions.h>
#include <mysql/mysql_connection.h> #include <mysql/mysql_connection.h>
#include <mysql/testutils/mysql_schema.h> #include <mysql/testutils/mysql_schema.h>
@@ -741,6 +742,15 @@ TEST_F(MySqlConnectionTest, writeTimeoutZero) {
#endif // HAVE_MYSQL_GET_OPTION #endif // HAVE_MYSQL_GET_OPTION
// Tests that the statement can be accessed by index.
TEST_F(MySqlConnectionTest, getStatement) {
auto statement0 = conn_.getStatement(0);
ASSERT_TRUE(statement0);
auto statement1 = conn_.getStatement(1);
ASSERT_TRUE(statement1);
EXPECT_NE(statement0, statement1);
}
TEST_F(MySqlConnectionWithPrimaryKeyTest, select) { TEST_F(MySqlConnectionWithPrimaryKeyTest, select) {
select(); select();
} }