2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-09-03 15:35:17 +00:00

[3681_rebase] MySQLLeaseMgr uses, but does not derive from MySqlConnection.

This commit is contained in:
Tomek Mrugalski
2015-08-21 18:27:41 +02:00
parent 8a8b86056e
commit e626cf0d38
6 changed files with 92 additions and 68 deletions

View File

@@ -185,5 +185,21 @@ MySqlConnection::prepareStatements(const TaggedStatement tagged_statements[],
}
}
/// @brief Destructor
MySqlConnection::~MySqlConnection() {
// 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 < statements_.size(); ++i) {
if (statements_[i] != NULL) {
(void) mysql_stmt_close(statements_[i]);
statements_[i] = NULL;
}
}
statements_.clear();
text_statements_.clear();
}
} // namespace isc::dhcp
} // namespace isc

View File

@@ -136,10 +136,11 @@ private:
/// @brief Common MySQL Connector Pool
///
/// This class provides common operations for MySQL database connection
/// used by both MySqlLeaseMgr and MySqlHostDataSource. It manages connecting
/// to the database and preparing compiled statements.
/// This class provides common operations for MySQL database connection
/// used by both MySqlLeaseMgr and MySqlHostDataSource. It manages connecting
/// to the database and preparing compiled statements. Its fields are
/// public, because they are used (both set and retrieved) in classes
/// that use instances of MySqlConnection.
class MySqlConnection : public DatabaseConnection {
public:
@@ -151,8 +152,7 @@ public:
}
/// @brief Destructor
virtual ~MySqlConnection() {
}
virtual ~MySqlConnection();
/// @brief Prepare Single Statement
///
@@ -190,12 +190,22 @@ public:
/// @throw DbOpenError Error opening the database
void openDatabase();
protected:
/// @brief Prepared statements
///
/// This field is public, because it is used heavily from MySqlConnection
/// and will be from MySqlHostDataSource.
std::vector<MYSQL_STMT*> statements_;
std::vector<MYSQL_STMT*> statements_; ///< Prepared statements
std::vector<std::string> text_statements_; ///< Raw text of statements
/// @brief Raw text of statements
///
/// This field is public, because it is used heavily from MySqlConnection
/// and will be from MySqlHostDataSource.
std::vector<std::string> text_statements_;
/// @brief MySQL connection handle
///
/// This field is public, because it is used heavily from MySqlConnection
/// and will be from MySqlHostDataSource.
MySqlHolder mysql_;
};

View File

@@ -1151,23 +1151,23 @@ private:
// MySqlLeaseMgr Constructor and Destructor
MySqlLeaseMgr::MySqlLeaseMgr(const MySqlConnection::ParameterMap& parameters)
: MySqlConnection(parameters) {
: conn_(parameters) {
// Open the database.
openDatabase();
conn_.openDatabase();
// Enable autocommit. To avoid a flush to disk on every commit, the global
// parameter innodb_flush_log_at_trx_commit should be set to 2. This will
// cause the changes to be written to the log, but flushed to disk in the
// background every second. Setting the parameter to that value will speed
// up the system, but at the risk of losing data if the system crashes.
my_bool result = mysql_autocommit(mysql_, 1);
my_bool result = mysql_autocommit(conn_.mysql_, 1);
if (result != 0) {
isc_throw(DbOperationError, mysql_error(mysql_));
isc_throw(DbOperationError, mysql_error(conn_.mysql_));
}
// Prepare all statements likely to be used.
prepareStatements(tagged_statements, MySqlLeaseMgr::NUM_STATEMENTS);
conn_.prepareStatements(tagged_statements, MySqlLeaseMgr::NUM_STATEMENTS);
// Create the exchange objects for use in exchanging data between the
// program and the database.
@@ -1177,16 +1177,6 @@ MySqlLeaseMgr::MySqlLeaseMgr(const MySqlConnection::ParameterMap& parameters)
MySqlLeaseMgr::~MySqlLeaseMgr() {
// 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 < statements_.size(); ++i) {
if (statements_[i] != NULL) {
(void) mysql_stmt_close(statements_[i]);
statements_[i] = NULL;
}
}
// There is no need to close the database in this destructor: it is
// closed in the destructor of the mysql_ member variable.
}
@@ -1275,17 +1265,17 @@ MySqlLeaseMgr::addLeaseCommon(StatementIndex stindex,
std::vector<MYSQL_BIND>& bind) {
// Bind the parameters to the statement
int status = mysql_stmt_bind_param(statements_[stindex], &bind[0]);
int status = mysql_stmt_bind_param(conn_.statements_[stindex], &bind[0]);
checkError(status, stindex, "unable to bind parameters");
// Execute the statement
status = mysql_stmt_execute(statements_[stindex]);
status = mysql_stmt_execute(conn_.statements_[stindex]);
if (status != 0) {
// Failure: check for the special case of duplicate entry. If this is
// the case, we return false to indicate that the row was not added.
// Otherwise we throw an exception.
if (mysql_errno(mysql_) == ER_DUP_ENTRY) {
if (mysql_errno(conn_.mysql_) == ER_DUP_ENTRY) {
return (false);
}
checkError(status, stindex, "unable to execute");
@@ -1353,43 +1343,43 @@ void MySqlLeaseMgr::getLeaseCollection(StatementIndex stindex,
bool single) const {
// Bind the selection parameters to the statement
int status = mysql_stmt_bind_param(statements_[stindex], bind);
int status = mysql_stmt_bind_param(conn_.statements_[stindex], bind);
checkError(status, stindex, "unable to bind WHERE clause parameter");
// Set up the MYSQL_BIND array for the data being returned and bind it to
// the statement.
std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]);
status = mysql_stmt_bind_result(conn_.statements_[stindex], &outbind[0]);
checkError(status, stindex, "unable to bind SELECT clause parameters");
// Execute the statement
status = mysql_stmt_execute(statements_[stindex]);
status = mysql_stmt_execute(conn_.statements_[stindex]);
checkError(status, stindex, "unable to execute");
// Ensure that all the lease information is retrieved in one go to avoid
// overhead of going back and forth between client and server.
status = mysql_stmt_store_result(statements_[stindex]);
status = mysql_stmt_store_result(conn_.statements_[stindex]);
checkError(status, stindex, "unable to set up for storing all results");
// Set up the fetch "release" object to release resources associated
// with the call to mysql_stmt_fetch when this method exits, then
// retrieve the data.
MySqlFreeResult fetch_release(statements_[stindex]);
MySqlFreeResult fetch_release(conn_.statements_[stindex]);
int count = 0;
while ((status = mysql_stmt_fetch(statements_[stindex])) == 0) {
while ((status = mysql_stmt_fetch(conn_.statements_[stindex])) == 0) {
try {
result.push_back(exchange->getLeaseData());
} catch (const isc::BadValue& ex) {
// Rethrow the exception with a bit more data.
isc_throw(BadValue, ex.what() << ". Statement is <" <<
text_statements_[stindex] << ">");
conn_.text_statements_[stindex] << ">");
}
if (single && (++count > 1)) {
isc_throw(MultipleRecords, "multiple records were found in the "
"database where only one was expected for query "
<< text_statements_[stindex]);
<< conn_.text_statements_[stindex]);
}
}
@@ -1399,7 +1389,7 @@ void MySqlLeaseMgr::getLeaseCollection(StatementIndex stindex,
checkError(status, stindex, "unable to fetch results");
} else if (status == MYSQL_DATA_TRUNCATED) {
// Data truncated - throw an exception indicating what was at fault
isc_throw(DataTruncated, text_statements_[stindex]
isc_throw(DataTruncated, conn_.text_statements_[stindex]
<< " returned truncated data: columns affected are "
<< exchange->getErrorColumns());
}
@@ -1732,16 +1722,16 @@ MySqlLeaseMgr::updateLeaseCommon(StatementIndex stindex, MYSQL_BIND* bind,
const LeasePtr& lease) {
// Bind the parameters to the statement
int status = mysql_stmt_bind_param(statements_[stindex], bind);
int status = mysql_stmt_bind_param(conn_.statements_[stindex], bind);
checkError(status, stindex, "unable to bind parameters");
// Execute
status = mysql_stmt_execute(statements_[stindex]);
status = mysql_stmt_execute(conn_.statements_[stindex]);
checkError(status, stindex, "unable to execute");
// See how many rows were affected. The statement should only update a
// single row.
int affected_rows = mysql_stmt_affected_rows(statements_[stindex]);
int affected_rows = mysql_stmt_affected_rows(conn_.statements_[stindex]);
if (affected_rows == 0) {
isc_throw(NoSuchLease, "unable to update lease for address " <<
lease->addr_ << " as it does not exist");
@@ -1818,16 +1808,16 @@ bool
MySqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex, MYSQL_BIND* bind) {
// Bind the input parameters to the statement
int status = mysql_stmt_bind_param(statements_[stindex], bind);
int status = mysql_stmt_bind_param(conn_.statements_[stindex], bind);
checkError(status, stindex, "unable to bind WHERE clause parameter");
// Execute
status = mysql_stmt_execute(statements_[stindex]);
status = mysql_stmt_execute(conn_.statements_[stindex]);
checkError(status, stindex, "unable to execute");
// See how many rows were affected. Note that the statement may delete
// multiple rows.
return (mysql_stmt_affected_rows(statements_[stindex]) > 0);
return (mysql_stmt_affected_rows(conn_.statements_[stindex]) > 0);
}
@@ -1870,7 +1860,7 @@ std::string
MySqlLeaseMgr::getName() const {
std::string name = "";
try {
name = getParameter("name");
name = conn_.getParameter("name");
} catch (...) {
// Return an empty name
}
@@ -1895,11 +1885,11 @@ MySqlLeaseMgr::getVersion() const {
uint32_t minor; // Minor version number
// Execute the prepared statement
int status = mysql_stmt_execute(statements_[stindex]);
int status = mysql_stmt_execute(conn_.statements_[stindex]);
if (status != 0) {
isc_throw(DbOperationError, "unable to execute <"
<< text_statements_[stindex] << "> - reason: " <<
mysql_error(mysql_));
<< conn_.text_statements_[stindex] << "> - reason: " <<
mysql_error(conn_.mysql_));
}
// Bind the output of the statement to the appropriate variables.
@@ -1916,19 +1906,19 @@ MySqlLeaseMgr::getVersion() const {
bind[1].buffer = &minor;
bind[1].buffer_length = sizeof(minor);
status = mysql_stmt_bind_result(statements_[stindex], bind);
status = mysql_stmt_bind_result(conn_.statements_[stindex], bind);
if (status != 0) {
isc_throw(DbOperationError, "unable to bind result set: " <<
mysql_error(mysql_));
mysql_error(conn_.mysql_));
}
// Fetch the data and set up the "release" object to release associated
// resources when this method exits then retrieve the data.
MySqlFreeResult fetch_release(statements_[stindex]);
status = mysql_stmt_fetch(statements_[stindex]);
MySqlFreeResult fetch_release(conn_.statements_[stindex]);
status = mysql_stmt_fetch(conn_.statements_[stindex]);
if (status != 0) {
isc_throw(DbOperationError, "unable to obtain result set: " <<
mysql_error(mysql_));
mysql_error(conn_.mysql_));
}
return (std::make_pair(major, minor));
@@ -1938,8 +1928,8 @@ MySqlLeaseMgr::getVersion() const {
void
MySqlLeaseMgr::commit() {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_COMMIT);
if (mysql_commit(mysql_) != 0) {
isc_throw(DbOperationError, "commit failed: " << mysql_error(mysql_));
if (mysql_commit(conn_.mysql_) != 0) {
isc_throw(DbOperationError, "commit failed: " << mysql_error(conn_.mysql_));
}
}
@@ -1947,8 +1937,8 @@ MySqlLeaseMgr::commit() {
void
MySqlLeaseMgr::rollback() {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_ROLLBACK);
if (mysql_rollback(mysql_) != 0) {
isc_throw(DbOperationError, "rollback failed: " << mysql_error(mysql_));
if (mysql_rollback(conn_.mysql_) != 0) {
isc_throw(DbOperationError, "rollback failed: " << mysql_error(conn_.mysql_));
}
}

View File

@@ -46,7 +46,7 @@ class MySqlLease6Exchange;
/// database. Use of this backend presupposes that a MySQL database is
/// available and that the Kea schema has been created within it.
class MySqlLeaseMgr : public LeaseMgr, public MySqlConnection {
class MySqlLeaseMgr : public LeaseMgr {
public:
/// @brief Constructor
@@ -71,7 +71,7 @@ public:
/// @throw isc::dhcp::DbOpenError Error opening the database
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
MySqlLeaseMgr(const ParameterMap& parameters);
MySqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters);
/// @brief Destructor (closes database)
virtual ~MySqlLeaseMgr();
@@ -432,6 +432,8 @@ public:
};
private:
/// @brief MySQL connection
MySqlConnection conn_;
/// @brief Add Lease Common Code
///
@@ -594,9 +596,9 @@ private:
const char* what) const {
if (status != 0) {
isc_throw(DbOperationError, what << " for <" <<
text_statements_[index] << ">, reason: " <<
mysql_error(mysql_) << " (error code " <<
mysql_errno(mysql_) << ")");
conn_.text_statements_[index] << ">, reason: " <<
mysql_error(conn_.mysql_) << " (error code " <<
mysql_errno(conn_.mysql_) << ")");
}
}

View File

@@ -943,8 +943,8 @@ private:
};
PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
: LeaseMgr(), DatabaseConnection(parameters), exchange4_(new PgSqlLease4Exchange()),
exchange6_(new PgSqlLease6Exchange()), conn_(NULL) {
: LeaseMgr(), exchange4_(new PgSqlLease4Exchange()),
exchange6_(new PgSqlLease6Exchange()), dbconn_(parameters), conn_(NULL) {
openDatabase();
prepareStatements();
}
@@ -1000,7 +1000,7 @@ PgSqlLeaseMgr::openDatabase() {
string dbconnparameters;
string shost = "localhost";
try {
shost = getParameter("host");
shost = dbconn_.getParameter("host");
} catch(...) {
// No host. Fine, we'll use "localhost"
}
@@ -1009,7 +1009,7 @@ PgSqlLeaseMgr::openDatabase() {
string suser;
try {
suser = getParameter("user");
suser = dbconn_.getParameter("user");
dbconnparameters += " user = '" + suser + "'";
} catch(...) {
// No user. Fine, we'll use NULL
@@ -1017,7 +1017,7 @@ PgSqlLeaseMgr::openDatabase() {
string spassword;
try {
spassword = getParameter("password");
spassword = dbconn_.getParameter("password");
dbconnparameters += " password = '" + spassword + "'";
} catch(...) {
// No password. Fine, we'll use NULL
@@ -1025,7 +1025,7 @@ PgSqlLeaseMgr::openDatabase() {
string sname;
try {
sname= getParameter("name");
sname= dbconn_.getParameter("name");
dbconnparameters += " dbname = '" + sname + "'";
} catch(...) {
// No database name. Throw a "NoDatabaseName" exception
@@ -1498,7 +1498,7 @@ string
PgSqlLeaseMgr::getName() const {
string name = "";
try {
name = getParameter("name");
name = dbconn_.getParameter("name");
} catch (...) {
// Return an empty name
}

View File

@@ -121,7 +121,7 @@ const uint32_t PG_CURRENT_MINOR = 0;
/// This class provides the \ref isc::dhcp::LeaseMgr interface to the PostgreSQL
/// database. Use of this backend presupposes that a PostgreSQL database is
/// available and that the Kea schema has been created within it.
class PgSqlLeaseMgr : public LeaseMgr, DatabaseConnection {
class PgSqlLeaseMgr : public LeaseMgr {
public:
/// @brief Constructor
@@ -619,6 +619,12 @@ private:
boost::scoped_ptr<PgSqlLease4Exchange> exchange4_; ///< Exchange object
boost::scoped_ptr<PgSqlLease6Exchange> exchange6_; ///< Exchange object
/// Database connection object
///
/// @todo: Implement PgSQLConnection object and collapse
/// dbconn_ and conn_ into a single object.
DatabaseConnection dbconn_;
/// PostgreSQL connection handle
PGconn* conn_;
};