2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-31 05:55:28 +00:00

[5629] MySQL Lease back end now validates schema after connecting

src/lib/dhcpsrv/mysql_lease_mgr.*
    MySqlLeaseMgr::MySqlLeaseMgr() - now validates schema
    after connecting

    MySqlLeaseMgr::getVersion()  - no longer relies on
    pre-prepared statement or formal statement execution
    error handling

src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
    LeaseMgrDbLostCallbackTest::testDbLostCallback() - replaced
    use of getVersion() with getLease4() for testing DB usability
This commit is contained in:
Thomas Markwalder
2018-05-31 09:41:46 -04:00
parent 1d0a651363
commit 7614eb8d2b
3 changed files with 58 additions and 22 deletions

View File

@@ -209,8 +209,6 @@ tagged_statements = { {
"WHERE state != ? AND expire < ? "
"ORDER BY expire ASC "
"LIMIT ?"},
{MySqlLeaseMgr::GET_VERSION,
"SELECT version, minor FROM schema_version"},
{MySqlLeaseMgr::INSERT_LEASE4,
"INSERT INTO lease4(address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
@@ -1501,6 +1499,16 @@ MySqlLeaseMgr::MySqlLeaseMgr(const MySqlConnection::ParameterMap& parameters)
// Open the database.
conn_.openDatabase();
// Test schema version before we try to prepare statements.
std::pair<uint32_t, uint32_t> version = getVersion();
if (version.first != MYSQL_SCHEMA_VERSION_MAJOR ||
version.second != MYSQL_SCHEMA_VERSION_MINOR) {
isc_throw(DbOpenError, "MySQL schema version is: "
<< version.first << "." << version.second << ", need version: "
<< MYSQL_SCHEMA_VERSION_MAJOR << "."
<< MYSQL_SCHEMA_VERSION_MINOR);
}
// 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
@@ -2372,40 +2380,60 @@ MySqlLeaseMgr::getDescription() const {
std::pair<uint32_t, uint32_t>
MySqlLeaseMgr::getVersion() const {
const StatementIndex stindex = GET_VERSION;
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
DHCPSRV_MYSQL_GET_VERSION);
uint32_t major; // Major version number
uint32_t minor; // Minor version number
// Allocate a new statement.
MYSQL_STMT *stmt = mysql_stmt_init(conn_.mysql_);
if (stmt == NULL) {
isc_throw(DbOperationError, "unable to allocate MySQL prepared "
"statement structure, reason: " << mysql_error(conn_.mysql_));
}
// Execute the prepared statement
int status = mysql_stmt_execute(conn_.statements_[stindex]);
checkError(status, stindex, "unable to execute statement");
// Prepare the statement from SQL text.
const char* version_sql = "SELECT version, minor FROM schema_version";
int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
if (status != 0) {
isc_throw(DbOperationError, "unable to prepare MySQL statement <"
<< version_sql << ">, reason: " << mysql_error(conn_.mysql_));
}
// Execute the prepared statement.
if (mysql_stmt_execute(stmt) != 0) {
isc_throw(DbOperationError, "cannot execute schema version query:"
<< version_sql << ">, reason: " << mysql_errno(conn_.mysql_) << ")");
}
// Bind the output of the statement to the appropriate variables.
MYSQL_BIND bind[2];
memset(bind, 0, sizeof(bind));
uint32_t major;
bind[0].buffer_type = MYSQL_TYPE_LONG;
bind[0].is_unsigned = 1;
bind[0].buffer = &major;
bind[0].buffer_length = sizeof(major);
uint32_t minor;
bind[1].buffer_type = MYSQL_TYPE_LONG;
bind[1].is_unsigned = 1;
bind[1].buffer = &minor;
bind[1].buffer_length = sizeof(minor);
status = mysql_stmt_bind_result(conn_.statements_[stindex], bind);
checkError(status, stindex, "unable to bind result set");
if (mysql_stmt_bind_result(stmt, bind)) {
isc_throw(DbOperationError, "unable to bind result set for:"
<< version_sql << ">, reason: " << mysql_errno(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(conn_.statements_[stindex]);
status = mysql_stmt_fetch(conn_.statements_[stindex]);
checkError(status, stindex, "unable to fetch result set");
// Fetch the data.
if (mysql_stmt_fetch(stmt)) {
mysql_stmt_close(stmt);
isc_throw(DbOperationError, "unable to bind result set for:"
<< version_sql << ">, reason: " << mysql_errno(conn_.mysql_) << ")");
}
// Discard the statement and its resources
mysql_stmt_close(stmt);
return (std::make_pair(major, minor));
}