From: Tomek Mrugalski Date: Fri, 17 Apr 2015 11:39:45 +0000 (+0200) Subject: [3681] MySQLConnection class implemented X-Git-Tag: trac3874_base~33^2~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a3ac3ef7d0198f251680101686020e40ecdfa60;p=thirdparty%2Fkea.git [3681] MySQLConnection class implemented - patch as sent by Adam Kalmus --- diff --git a/src/lib/dhcpsrv/lease.cc b/src/lib/dhcpsrv/lease.cc old mode 100644 new mode 100755 diff --git a/src/lib/dhcpsrv/lease_mgr.cc b/src/lib/dhcpsrv/lease_mgr.cc old mode 100644 new mode 100755 index 57b64f0dfe..df1a540908 --- a/src/lib/dhcpsrv/lease_mgr.cc +++ b/src/lib/dhcpsrv/lease_mgr.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -29,21 +30,12 @@ #include + using namespace std; namespace isc { namespace dhcp { -const time_t LeaseMgr::MAX_DB_TIME = 2147483647; - -std::string LeaseMgr::getParameter(const std::string& name) const { - ParameterMap::const_iterator param = parameters_.find(name); - if (param == parameters_.end()) { - isc_throw(BadValue, "Parameter not found"); - } - return (param->second); -} - Lease6Ptr LeaseMgr::getLease6(Lease::Type type, const DUID& duid, uint32_t iaid, SubnetID subnet_id) const { diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h old mode 100644 new mode 100755 index edacec1c57..dd657d8485 --- a/src/lib/dhcpsrv/lease_mgr.h +++ b/src/lib/dhcpsrv/lease_mgr.h @@ -68,27 +68,6 @@ namespace isc { namespace dhcp { -/// @brief Exception thrown if name of database is not specified -class NoDatabaseName : public Exception { -public: - NoDatabaseName(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} -}; - -/// @brief Exception thrown on failure to open database -class DbOpenError : public Exception { -public: - DbOpenError(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} -}; - -/// @brief Exception thrown on failure to execute a database function -class DbOperationError : public Exception { -public: - DbOperationError(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} -}; - /// @brief Multiple lease records found where one expected class MultipleRecords : public Exception { public: @@ -133,19 +112,11 @@ public: /// of those classes for details. class LeaseMgr { public: - /// @brief Defines maximum value for time that can be reliably stored. - // If I'm still alive I'll be too old to care. You fix it. - static const time_t MAX_DB_TIME; - - /// Database configuration parameter map - typedef std::map ParameterMap; - /// @brief Constructor /// /// @param parameters A data structure relating keywords and values /// concerned with the database. - LeaseMgr(const ParameterMap& parameters) - : parameters_(parameters), io_service_(new asiolink::IOService()) + LeaseMgr() : io_service_(new asiolink::IOService()) {} /// @brief Destructor @@ -392,8 +363,6 @@ public: /// As host reservation is outside of scope for 2012, support for hosts /// is currently postponed. - /// @brief returns value of the parameter - virtual std::string getParameter(const std::string& name) const; /// @brief Returns the interval at which the @c IOService events should /// be released. @@ -420,17 +389,13 @@ public: return (io_service_); } + private: - /// @brief list of parameters passed in dbconfig - /// - /// That will be mostly used for storing database name, username, - /// password and other parameters required for DB access. It is not - /// intended to keep any DHCP-related parameters. - ParameterMap parameters_; /// @brief Pointer to the IO service object used by the derived classes /// to trigger interval timers. asiolink::IOServicePtr io_service_; + }; }; // end of isc::dhcp namespace diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc old mode 100644 new mode 100755 index 631edf1eaa..9c416a5c78 --- a/src/lib/dhcpsrv/memfile_lease_mgr.cc +++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -222,7 +223,7 @@ LFCSetup::getExitStatus() const { Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters) - : LeaseMgr(parameters), + : MySqlConnection(parameters), lfc_setup_(new LFCSetup(boost::bind(&Memfile_LeaseMgr::lfcCallback, this), *getIOService())) { diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.h b/src/lib/dhcpsrv/memfile_lease_mgr.h old mode 100644 new mode 100755 index 053b13ce66..8383dc7c9f --- a/src/lib/dhcpsrv/memfile_lease_mgr.h +++ b/src/lib/dhcpsrv/memfile_lease_mgr.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -85,7 +86,7 @@ class LFCSetup; /// is not specified, the default location in the installation /// directory is used: var/kea/kea-leases4.csv and /// var/kea/kea-leases6.csv. -class Memfile_LeaseMgr : public LeaseMgr { +class Memfile_LeaseMgr : public LeaseMgr, public MySqlConnection { public: /// @defgroup versions Specified memfile backend version. diff --git a/src/lib/dhcpsrv/mysql_connection.cc b/src/lib/dhcpsrv/mysql_connection.cc new file mode 100644 index 0000000000..26f125fc36 --- /dev/null +++ b/src/lib/dhcpsrv/mysql_connection.cc @@ -0,0 +1,416 @@ +// Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace isc; +using namespace isc::dhcp; +using namespace std; + + +namespace { + +const time_t MySqlConnection::MAX_DB_TIME = 2147483647; + +/// @brief MySQL Selection Statements +/// +/// Each statement is associated with an index, which is used to reference the +/// associated prepared statement. + +struct TaggedStatement { + MySqlConnection::StatementIndex index; + const char* text; +}; + +TaggedStatement tagged_statements[] = { + {MySqlLeaseMgr::DELETE_LEASE4, + "DELETE FROM lease4 WHERE address = ?"}, + {MySqlLeaseMgr::DELETE_LEASE6, + "DELETE FROM lease6 WHERE address = ?"}, + {MySqlLeaseMgr::GET_LEASE4_ADDR, + "SELECT address, hwaddr, client_id, " + "valid_lifetime, expire, subnet_id, " + "fqdn_fwd, fqdn_rev, hostname " + "FROM lease4 " + "WHERE address = ?"}, + {MySqlLeaseMgr::GET_LEASE4_CLIENTID, + "SELECT address, hwaddr, client_id, " + "valid_lifetime, expire, subnet_id, " + "fqdn_fwd, fqdn_rev, hostname " + "FROM lease4 " + "WHERE client_id = ?"}, + {MySqlLeaseMgr::GET_LEASE4_CLIENTID_SUBID, + "SELECT address, hwaddr, client_id, " + "valid_lifetime, expire, subnet_id, " + "fqdn_fwd, fqdn_rev, hostname " + "FROM lease4 " + "WHERE client_id = ? AND subnet_id = ?"}, + {MySqlLeaseMgr::GET_LEASE4_HWADDR, + "SELECT address, hwaddr, client_id, " + "valid_lifetime, expire, subnet_id, " + "fqdn_fwd, fqdn_rev, hostname " + "FROM lease4 " + "WHERE hwaddr = ?"}, + {MySqlLeaseMgr::GET_LEASE4_HWADDR_SUBID, + "SELECT address, hwaddr, client_id, " + "valid_lifetime, expire, subnet_id, " + "fqdn_fwd, fqdn_rev, hostname " + "FROM lease4 " + "WHERE hwaddr = ? AND subnet_id = ?"}, + {MySqlLeaseMgr::GET_LEASE6_ADDR, + "SELECT address, duid, valid_lifetime, " + "expire, subnet_id, pref_lifetime, " + "lease_type, iaid, prefix_len, " + "fqdn_fwd, fqdn_rev, hostname, " + "hwaddr, hwtype, hwaddr_source " + "FROM lease6 " + "WHERE address = ? AND lease_type = ?"}, + {MySqlLeaseMgr::GET_LEASE6_DUID_IAID, + "SELECT address, duid, valid_lifetime, " + "expire, subnet_id, pref_lifetime, " + "lease_type, iaid, prefix_len, " + "fqdn_fwd, fqdn_rev, hostname, " + "hwaddr, hwtype, hwaddr_source " + "FROM lease6 " + "WHERE duid = ? AND iaid = ? AND lease_type = ?"}, + {MySqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID, + "SELECT address, duid, valid_lifetime, " + "expire, subnet_id, pref_lifetime, " + "lease_type, iaid, prefix_len, " + "fqdn_fwd, fqdn_rev, hostname, " + "hwaddr, hwtype, hwaddr_source " + "FROM lease6 " + "WHERE duid = ? AND iaid = ? AND subnet_id = ? " + "AND lease_type = ?"}, + {MySqlLeaseMgr::GET_VERSION, + "SELECT version, minor FROM schema_version"}, + {MySqlLeaseMgr::INSERT_LEASE4, + "INSERT INTO lease4(address, hwaddr, client_id, " + "valid_lifetime, expire, subnet_id, " + "fqdn_fwd, fqdn_rev, hostname) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"}, + {MySqlLeaseMgr::INSERT_LEASE6, + "INSERT INTO lease6(address, duid, valid_lifetime, " + "expire, subnet_id, pref_lifetime, " + "lease_type, iaid, prefix_len, " + "fqdn_fwd, fqdn_rev, hostname, " + "hwaddr, hwtype, hwaddr_source) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"}, + {MySqlLeaseMgr::UPDATE_LEASE4, + "UPDATE lease4 SET address = ?, hwaddr = ?, " + "client_id = ?, valid_lifetime = ?, expire = ?, " + "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, " + "hostname = ? " + "WHERE address = ?"}, + {MySqlLeaseMgr::UPDATE_LEASE6, + "UPDATE lease6 SET address = ?, duid = ?, " + "valid_lifetime = ?, expire = ?, subnet_id = ?, " + "pref_lifetime = ?, lease_type = ?, iaid = ?, " + "prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, " + "hostname = ?, hwaddr = ?, hwtype = ?, hwaddr_source = ? " + "WHERE address = ?"}, + // End of list sentinel + {MySqlLeaseMgr::NUM_STATEMENTS, NULL} +}; + + +}; // Anonymous namespace + +namespace isc { +namespace dhcp { + +/// @brief Maximum size of database fields +/// +/// The following constants define buffer sizes for variable length database +/// fields. The values should be greater than or equal to the length set in +/// the schema definition. +/// +/// The exception is the length of any VARCHAR fields: buffers for these should +/// be set greater than or equal to the length of the field plus 1: this allows +/// for the insertion of a trailing null whatever data is returned. + +/// @brief Maximum size of an IPv6 address represented as a text string. +/// +/// This is 32 hexadecimal characters written in 8 groups of four, plus seven +/// colon separators. +const size_t ADDRESS6_TEXT_MAX_LEN = 39; + +/// @brief MySQL True/False constants +/// +/// Declare typed values so as to avoid problems of data conversion. These +/// are local to the file but are given the prefix MLM (MySql Lease Manager) to +/// avoid any likely conflicts with variables in header files named TRUE or +/// FALSE. + +const my_bool MLM_FALSE = 0; ///< False value +const my_bool MLM_TRUE = 1; ///< True value + +/// @brief Maximum length of the hostname stored in DNS. +/// +/// This length is restricted by the length of the domain-name carried +/// in the Client FQDN %Option (see RFC4702 and RFC4704). +const size_t HOSTNAME_MAX_LEN = 255; + +///@} + + +std::string MySqlConnection::getParameter(const std::string& name) const { + ParameterMap::const_iterator param = parameters_.find(name); + if (param == parameters_.end()) { + isc_throw(BadValue, "Parameter not found"); + } + return (param->second); +} + +// Open the database using the parameters passed to the constructor. + +void +MySqlConnection::openDatabase() { + + // Set up the values of the parameters + const char* host = "localhost"; + string shost; + try { + shost = getParameter("host"); + host = shost.c_str(); + } catch (...) { + // No host. Fine, we'll use "localhost" + } + + const char* user = NULL; + string suser; + try { + suser = getParameter("user"); + user = suser.c_str(); + } catch (...) { + // No user. Fine, we'll use NULL + } + + const char* password = NULL; + string spassword; + try { + spassword = getParameter("password"); + password = spassword.c_str(); + } catch (...) { + // No password. Fine, we'll use NULL + } + + const char* name = NULL; + string sname; + try { + sname = getParameter("name"); + name = sname.c_str(); + } catch (...) { + // No database name. Throw a "NoName" exception + isc_throw(NoDatabaseName, "must specified a name for the database"); + } + + // Set options for the connection: + // + // Automatic reconnection: after a period of inactivity, the client will + // disconnect from the database. This option causes it to automatically + // reconnect when another operation is about to be done. + my_bool auto_reconnect = MLM_TRUE; + int result = mysql_options(mysql_, MYSQL_OPT_RECONNECT, &auto_reconnect); + if (result != 0) { + isc_throw(DbOpenError, "unable to set auto-reconnect option: " << + mysql_error(mysql_)); + } + + // Set SQL mode options for the connection: SQL mode governs how what + // constitutes insertable data for a given column, and how to handle + // invalid data. We want to ensure we get the strictest behavior and + // to reject invalid data with an error. + const char *sql_mode = "SET SESSION sql_mode ='STRICT_ALL_TABLES'"; + result = mysql_options(mysql_, MYSQL_INIT_COMMAND, sql_mode); + if (result != 0) { + isc_throw(DbOpenError, "unable to set SQL mode options: " << + mysql_error(mysql_)); + } + + // Open the database. + // + // The option CLIENT_FOUND_ROWS is specified so that in an UPDATE, + // the affected rows are the number of rows found that match the + // WHERE clause of the SQL statement, not the rows changed. The reason + // here is that MySQL apparently does not update a row if data has not + // changed and so the "affected rows" (retrievable from MySQL) is zero. + // This makes it hard to distinguish whether the UPDATE changed no rows + // because no row matching the WHERE clause was found, or because a + // row was found but no data was altered. + MYSQL* status = mysql_real_connect(mysql_, host, user, password, name, + 0, NULL, CLIENT_FOUND_ROWS); + if (status != mysql_) { + isc_throw(DbOpenError, mysql_error(mysql_)); + } +} + + +// Prepared statement setup. The textual form of an SQL statement is stored +// in a vector of strings (text_statements_) and is used in the output of +// error messages. The SQL statement is also compiled into a "prepared +// statement" (stored in statements_), which avoids the overhead of compilation +// during use. As prepared statements have resources allocated to them, the +// class destructor explicitly destroys them. + +void +MySqlConnection::prepareStatement(StatementIndex index, const char* text) { + // Validate that there is space for the statement in the statements array + // and that nothing has been placed there before. + if ((index >= this->statements_.size()) || (this->statements_[index] != NULL)) { + isc_throw(InvalidParameter, "invalid prepared statement index (" << + static_cast(index) << ") or indexed prepared " << + "statement is not null"); + } + + // All OK, so prepare the statement + this->text_statements_[index] = std::string(text); + this->statements_[index] = mysql_stmt_init(mysql_); + if (this->statements_[index] == NULL) { + isc_throw(DbOperationError, "unable to allocate MySQL prepared " + "statement structure, reason: " << mysql_error(mysql_)); + } + + int status = mysql_stmt_prepare(this->statements_[index], text, strlen(text)); + if (status != 0) { + isc_throw(DbOperationError, "unable to prepare MySQL statement <" << + text << ">, reason: " << mysql_error(mysql_)); + } +} + + +void +MySqlConnection::prepareStatements() { + // Allocate space for all statements + statements_.clear(); + statements_.resize(NUM_STATEMENTS, NULL); + + text_statements_.clear(); + text_statements_.resize(NUM_STATEMENTS, std::string("")); + + + // Created the MySQL prepared statements for each DML statement. + for (int i = 0; tagged_statements[i].text != NULL; ++i) { + prepareStatement(tagged_statements[i].index, + tagged_statements[i].text); + } +} + + + +// Miscellaneous database methods. + +std::string +MySqlConnection::getName() const { + std::string name = ""; + try { + name = getParameter("name"); + } catch (...) { + // Return an empty name + } + return (name); +} + + +std::string +MySqlConnection::getDescription() const { + return (std::string("MySQL Database")); +} + + +std::pair +MySqlConnection::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 + + // Execute the prepared statement + int status = mysql_stmt_execute(statements_[stindex]); + if (status != 0) { + isc_throw(DbOperationError, "unable to execute <" + << text_statements_[stindex] << "> - reason: " << + mysql_error(mysql_)); + } + + // Bind the output of the statement to the appropriate variables. + MYSQL_BIND bind[2]; + memset(bind, 0, sizeof(bind)); + + bind[0].buffer_type = MYSQL_TYPE_LONG; + bind[0].is_unsigned = 1; + bind[0].buffer = &major; + bind[0].buffer_length = sizeof(major); + + 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(statements_[stindex], bind); + if (status != 0) { + isc_throw(DbOperationError, "unable to bind result set: " << + mysql_error(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]); + if (status != 0) { + isc_throw(DbOperationError, "unable to obtain result set: " << + mysql_error(mysql_)); + } + + return (std::make_pair(major, minor)); +} + + +void +MySqlConnection::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_)); + } +} + + +void +MySqlConnection::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_)); + } +} + +} // namespace isc::dhcp +} // namespace isc diff --git a/src/lib/dhcpsrv/mysql_connection.h b/src/lib/dhcpsrv/mysql_connection.h new file mode 100644 index 0000000000..ff4edbf7ba --- /dev/null +++ b/src/lib/dhcpsrv/mysql_connection.h @@ -0,0 +1,294 @@ +// Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#ifndef MYSQL_CONNECTION_H +#define MYSQL_CONNECTION_H + +#include +#include + +#include +#include +#include // TODO poprawić przed oddaniem + +#include + +namespace isc { +namespace dhcp { + +/// @brief Exception thrown if name of database is not specified +class NoDatabaseName : public Exception { +public: + NoDatabaseName(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) {} +}; + +/// @brief Exception thrown on failure to open database +class DbOpenError : public Exception { +public: + DbOpenError(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) {} +}; + +/// @brief Exception thrown on failure to execute a database function +class DbOperationError : public Exception { +public: + DbOperationError(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) {} +}; + +/// @brief Fetch and Release MySQL Results +/// +/// When a MySQL statement is expected, to fetch the results the function +/// mysql_stmt_fetch() must be called. As well as getting data, this +/// allocates internal state. Subsequent calls to mysql_stmt_fetch can be +/// made, but when all the data is retrieved, mysql_stmt_free_result must be +/// called to free up the resources allocated. +/// +/// Created prior to the first fetch, this class's destructor calls +/// mysql_stmt_free_result, so eliminating the need for an explicit release +/// in the method calling mysql_stmt_free_result. In this way, it guarantees +/// that the resources are released even if the MySqlLeaseMgr method concerned +/// exits via an exception. + +class MySqlFreeResult { +public: + + /// @brief Constructor + /// + /// Store the pointer to the statement for which data is being fetched. + /// + /// Note that according to the MySQL documentation, mysql_stmt_free_result + /// only releases resources if a cursor has been allocated for the + /// statement. This implies that it is a no-op if none have been. Either + /// way, any error from mysql_stmt_free_result is ignored. (Generating + /// an exception is not much help, as it will only confuse things if the + /// method calling mysql_stmt_fetch is exiting via an exception.) + MySqlFreeResult(MYSQL_STMT* statement) : statement_(statement) + {} + + /// @brief Destructor + /// + /// Frees up fetch context if a fetch has been successfully executed. + ~MySqlFreeResult() { + (void) mysql_stmt_free_result(statement_); + } + +private: + MYSQL_STMT* statement_; ///< Statement for which results are freed +}; + +/// @brief MySQL Handle Holder +/// +/// Small RAII object for safer initialization, will close the database +/// connection upon destruction. This means that if an exception is thrown +/// during database initialization, resources allocated to the database are +/// guaranteed to be freed. +/// +/// It makes no sense to copy an object of this class. After the copy, both +/// objects would contain pointers to the same MySql context object. The +/// destruction of one would invalid the context in the remaining object. +/// For this reason, the class is declared noncopyable. +class MySqlHolder : public boost::noncopyable { +public: + + /// @brief Constructor + /// + /// Initialize MySql and store the associated context object. + /// + /// @throw DbOpenError Unable to initialize MySql handle. + MySqlHolder() : mysql_(mysql_init(NULL)) { + if (mysql_ == NULL) { + isc_throw(DbOpenError, "unable to initialize MySQL"); + } + } + + /// @brief Destructor + /// + /// Frees up resources allocated by the initialization of MySql. + ~MySqlHolder() { + if (mysql_ != NULL) { + mysql_close(mysql_); + } + // The library itself shouldn't be needed anymore + mysql_library_end(); + } + + /// @brief Conversion Operator + /// + /// Allows the MySqlHolder object to be passed as the context argument to + /// mysql_xxx functions. + operator MYSQL*() const { + return (mysql_); + } + +private: + MYSQL* mysql_; ///< Initialization context +}; + +// Define the current database schema values + +const uint32_t CURRENT_VERSION_VERSION = 3; // version 3: adding host managment features +const uint32_t CURRENT_VERSION_MINOR = 0; + + + +class MySqlConnection { +public: + + /// @brief Defines maximum value for time that can be reliably stored. + // If I'm still alive I'll be too old to care. You fix it. + static const time_t MAX_DB_TIME; + + /// Database configuration parameter map + typedef std::map ParameterMap; + + MySqlConnection(const ParameterMap& parameters) + : parameters_(parameters) + {} + + virtual ~MySqlConnection() + {} + + /// @brief Statement Tags + /// + /// The contents of the enum are indexes into the list of SQL statements + enum StatementIndex { + DELETE_LEASE4, // Delete from lease4 by address + DELETE_LEASE6, // Delete from lease6 by address + GET_LEASE4_ADDR, // Get lease4 by address + GET_LEASE4_CLIENTID, // Get lease4 by client ID + GET_LEASE4_CLIENTID_SUBID, // Get lease4 by client ID & subnet ID + GET_LEASE4_HWADDR, // Get lease4 by HW address + GET_LEASE4_HWADDR_SUBID, // Get lease4 by HW address & subnet ID + GET_LEASE6_ADDR, // Get lease6 by address + GET_LEASE6_DUID_IAID, // Get lease6 by DUID and IAID + GET_LEASE6_DUID_IAID_SUBID, // Get lease6 by DUID, IAID and subnet ID + GET_VERSION, // Obtain version number + INSERT_LEASE4, // Add entry to lease4 table + INSERT_LEASE6, // Add entry to lease6 table + UPDATE_LEASE4, // Update a Lease4 entry + UPDATE_LEASE6, // Update a Lease6 entry + NUM_STATEMENTS // Number of statements + }; + + /// @brief returns value of the parameter + virtual std::string getParameter(const std::string& name) const; + + /// @brief Return backend type + /// + /// Returns the type of the backend (e.g. "mysql", "memfile" etc.) + /// + /// @return Type of the backend. + virtual std::string getType() const { + return (std::string("mysql")); + } + + /// @brief Returns backend name. + /// + /// Each backend have specific name, e.g. "mysql" or "sqlite". + /// + /// @return Name of the backend. + virtual std::string getName() const; + + /// @brief Returns description of the backend. + /// + /// This description may be multiline text that describes the backend. + /// + /// @return Description of the backend. + virtual std::string getDescription() const; + + /// @brief Returns backend version. + /// + /// @return Version number as a pair of unsigned integers. "first" is the + /// major version number, "second" the minor number. + /// + /// @throw isc::dhcp::DbOperationError An operation on the open database has + /// failed. + virtual std::pair getVersion() const; + + /// @brief Commit Transactions + /// + /// Commits all pending database operations. On databases that don't + /// support transactions, this is a no-op. + /// + /// @throw DbOperationError Iif the commit failed. + virtual void commit(); + + /// @brief Rollback Transactions + /// + /// Rolls back all pending database operations. On databases that don't + /// support transactions, this is a no-op. + /// + /// @throw DbOperationError If the rollback failed. + virtual void rollback(); + + /// @brief Prepare Single Statement + /// + /// Creates a prepared statement from the text given and adds it to the + /// statements_ vector at the given index. + /// + /// @param index Index into the statements_ vector into which the text + /// should be placed. The vector must be big enough for the index + /// to be valid, else an exception will be thrown. + /// @param text Text of the SQL statement to be prepared. + /// + /// @throw isc::dhcp::DbOperationError An operation on the open database has + /// failed. + /// @throw isc::InvalidParameter 'index' is not valid for the vector. + void prepareStatement(StatementIndex index, const char* text); + + /// @brief Prepare statements + /// + /// Creates the prepared statements for all of the SQL statements used + /// by the MySQL backend. + /// + /// @throw isc::dhcp::DbOperationError An operation on the open database has + /// failed. + /// @throw isc::InvalidParameter 'index' is not valid for the vector. This + /// represents an internal error within the code. + void prepareStatements(); + + /// @brief Open Database + /// + /// Opens the database using the information supplied in the parameters + /// passed to the constructor. + /// + /// @throw NoDatabaseName Mandatory database name not given + /// @throw DbOpenError Error opening the database + void openDatabase(); + + std::vector statements_; ///< Prepared statements + std::vector text_statements_; ///< Raw text of statements + + +private: + /// @brief list of parameters passed in dbconfig + /// + /// That will be mostly used for storing database name, username, + /// password and other parameters required for DB access. It is not + /// intended to keep any DHCP-related parameters. + ParameterMap parameters_; + + + MySqlHolder mysql_; + +}; + + + +}; // end of isc::dhcp namespace +}; // end of isc namespace + +#endif // MYSQL_CONNECTION_H diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc old mode 100644 new mode 100755 index 63a4cb3972..00b3a02682 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -75,147 +76,6 @@ using namespace std; /// - If there is output, copy the data from the bound variables to the output /// lease object. -namespace { -///@{ - -/// @brief Maximum size of database fields -/// -/// The following constants define buffer sizes for variable length database -/// fields. The values should be greater than or equal to the length set in -/// the schema definition. -/// -/// The exception is the length of any VARCHAR fields: buffers for these should -/// be set greater than or equal to the length of the field plus 1: this allows -/// for the insertion of a trailing null whatever data is returned. - -/// @brief Maximum size of an IPv6 address represented as a text string. -/// -/// This is 32 hexadecimal characters written in 8 groups of four, plus seven -/// colon separators. -const size_t ADDRESS6_TEXT_MAX_LEN = 39; - -/// @brief MySQL True/False constants -/// -/// Declare typed values so as to avoid problems of data conversion. These -/// are local to the file but are given the prefix MLM (MySql Lease Manager) to -/// avoid any likely conflicts with variables in header files named TRUE or -/// FALSE. - -const my_bool MLM_FALSE = 0; ///< False value -const my_bool MLM_TRUE = 1; ///< True value - -/// @brief Maximum length of the hostname stored in DNS. -/// -/// This length is restricted by the length of the domain-name carried -/// in the Client FQDN %Option (see RFC4702 and RFC4704). -const size_t HOSTNAME_MAX_LEN = 255; - -///@} - -/// @brief MySQL Selection Statements -/// -/// Each statement is associated with an index, which is used to reference the -/// associated prepared statement. - -struct TaggedStatement { - MySqlLeaseMgr::StatementIndex index; - const char* text; -}; - -TaggedStatement tagged_statements[] = { - {MySqlLeaseMgr::DELETE_LEASE4, - "DELETE FROM lease4 WHERE address = ?"}, - {MySqlLeaseMgr::DELETE_LEASE6, - "DELETE FROM lease6 WHERE address = ?"}, - {MySqlLeaseMgr::GET_LEASE4_ADDR, - "SELECT address, hwaddr, client_id, " - "valid_lifetime, expire, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname " - "FROM lease4 " - "WHERE address = ?"}, - {MySqlLeaseMgr::GET_LEASE4_CLIENTID, - "SELECT address, hwaddr, client_id, " - "valid_lifetime, expire, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname " - "FROM lease4 " - "WHERE client_id = ?"}, - {MySqlLeaseMgr::GET_LEASE4_CLIENTID_SUBID, - "SELECT address, hwaddr, client_id, " - "valid_lifetime, expire, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname " - "FROM lease4 " - "WHERE client_id = ? AND subnet_id = ?"}, - {MySqlLeaseMgr::GET_LEASE4_HWADDR, - "SELECT address, hwaddr, client_id, " - "valid_lifetime, expire, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname " - "FROM lease4 " - "WHERE hwaddr = ?"}, - {MySqlLeaseMgr::GET_LEASE4_HWADDR_SUBID, - "SELECT address, hwaddr, client_id, " - "valid_lifetime, expire, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname " - "FROM lease4 " - "WHERE hwaddr = ? AND subnet_id = ?"}, - {MySqlLeaseMgr::GET_LEASE6_ADDR, - "SELECT address, duid, valid_lifetime, " - "expire, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len, " - "fqdn_fwd, fqdn_rev, hostname, " - "hwaddr, hwtype, hwaddr_source " - "FROM lease6 " - "WHERE address = ? AND lease_type = ?"}, - {MySqlLeaseMgr::GET_LEASE6_DUID_IAID, - "SELECT address, duid, valid_lifetime, " - "expire, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len, " - "fqdn_fwd, fqdn_rev, hostname, " - "hwaddr, hwtype, hwaddr_source " - "FROM lease6 " - "WHERE duid = ? AND iaid = ? AND lease_type = ?"}, - {MySqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID, - "SELECT address, duid, valid_lifetime, " - "expire, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len, " - "fqdn_fwd, fqdn_rev, hostname, " - "hwaddr, hwtype, hwaddr_source " - "FROM lease6 " - "WHERE duid = ? AND iaid = ? AND subnet_id = ? " - "AND lease_type = ?"}, - {MySqlLeaseMgr::GET_VERSION, - "SELECT version, minor FROM schema_version"}, - {MySqlLeaseMgr::INSERT_LEASE4, - "INSERT INTO lease4(address, hwaddr, client_id, " - "valid_lifetime, expire, subnet_id, " - "fqdn_fwd, fqdn_rev, hostname) " - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"}, - {MySqlLeaseMgr::INSERT_LEASE6, - "INSERT INTO lease6(address, duid, valid_lifetime, " - "expire, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len, " - "fqdn_fwd, fqdn_rev, hostname, " - "hwaddr, hwtype, hwaddr_source) " - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"}, - {MySqlLeaseMgr::UPDATE_LEASE4, - "UPDATE lease4 SET address = ?, hwaddr = ?, " - "client_id = ?, valid_lifetime = ?, expire = ?, " - "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, " - "hostname = ? " - "WHERE address = ?"}, - {MySqlLeaseMgr::UPDATE_LEASE6, - "UPDATE lease6 SET address = ?, duid = ?, " - "valid_lifetime = ?, expire = ?, subnet_id = ?, " - "pref_lifetime = ?, lease_type = ?, iaid = ?, " - "prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, " - "hostname = ?, hwaddr = ?, hwtype = ?, hwaddr_source = ? " - "WHERE address = ?"}, - // End of list sentinel - {MySqlLeaseMgr::NUM_STATEMENTS, NULL} -}; - -}; // Anonymous namespace - - namespace isc { namespace dhcp { @@ -1181,51 +1041,12 @@ private: }; -/// @brief Fetch and Release MySQL Results -/// -/// When a MySQL statement is expected, to fetch the results the function -/// mysql_stmt_fetch() must be called. As well as getting data, this -/// allocates internal state. Subsequent calls to mysql_stmt_fetch can be -/// made, but when all the data is retrieved, mysql_stmt_free_result must be -/// called to free up the resources allocated. -/// -/// Created prior to the first fetch, this class's destructor calls -/// mysql_stmt_free_result, so eliminating the need for an explicit release -/// in the method calling mysql_stmt_free_result. In this way, it guarantees -/// that the resources are released even if the MySqlLeaseMgr method concerned -/// exits via an exception. - -class MySqlFreeResult { -public: - - /// @brief Constructor - /// - /// Store the pointer to the statement for which data is being fetched. - /// - /// Note that according to the MySQL documentation, mysql_stmt_free_result - /// only releases resources if a cursor has been allocated for the - /// statement. This implies that it is a no-op if none have been. Either - /// way, any error from mysql_stmt_free_result is ignored. (Generating - /// an exception is not much help, as it will only confuse things if the - /// method calling mysql_stmt_fetch is exiting via an exception.) - MySqlFreeResult(MYSQL_STMT* statement) : statement_(statement) - {} - - /// @brief Destructor - /// - /// Frees up fetch context if a fetch has been successfully executed. - ~MySqlFreeResult() { - (void) mysql_stmt_free_result(statement_); - } -private: - MYSQL_STMT* statement_; ///< Statement for which results are freed -}; // MySqlLeaseMgr Constructor and Destructor -MySqlLeaseMgr::MySqlLeaseMgr(const LeaseMgr::ParameterMap& parameters) - : LeaseMgr(parameters) { +MySqlLeaseMgr::MySqlLeaseMgr(const MySqlConnection::ParameterMap& parameters) + : MySqlConnection(parameters) { // Open the database. openDatabase(); @@ -1340,139 +1161,6 @@ MySqlLeaseMgr::convertFromDatabaseTime(const MYSQL_TIME& expire, } - -// Open the database using the parameters passed to the constructor. - -void -MySqlLeaseMgr::openDatabase() { - - // Set up the values of the parameters - const char* host = "localhost"; - string shost; - try { - shost = getParameter("host"); - host = shost.c_str(); - } catch (...) { - // No host. Fine, we'll use "localhost" - } - - const char* user = NULL; - string suser; - try { - suser = getParameter("user"); - user = suser.c_str(); - } catch (...) { - // No user. Fine, we'll use NULL - } - - const char* password = NULL; - string spassword; - try { - spassword = getParameter("password"); - password = spassword.c_str(); - } catch (...) { - // No password. Fine, we'll use NULL - } - - const char* name = NULL; - string sname; - try { - sname = getParameter("name"); - name = sname.c_str(); - } catch (...) { - // No database name. Throw a "NoName" exception - isc_throw(NoDatabaseName, "must specified a name for the database"); - } - - // Set options for the connection: - // - // Automatic reconnection: after a period of inactivity, the client will - // disconnect from the database. This option causes it to automatically - // reconnect when another operation is about to be done. - my_bool auto_reconnect = MLM_TRUE; - int result = mysql_options(mysql_, MYSQL_OPT_RECONNECT, &auto_reconnect); - if (result != 0) { - isc_throw(DbOpenError, "unable to set auto-reconnect option: " << - mysql_error(mysql_)); - } - - // Set SQL mode options for the connection: SQL mode governs how what - // constitutes insertable data for a given column, and how to handle - // invalid data. We want to ensure we get the strictest behavior and - // to reject invalid data with an error. - const char *sql_mode = "SET SESSION sql_mode ='STRICT_ALL_TABLES'"; - result = mysql_options(mysql_, MYSQL_INIT_COMMAND, sql_mode); - if (result != 0) { - isc_throw(DbOpenError, "unable to set SQL mode options: " << - mysql_error(mysql_)); - } - - // Open the database. - // - // The option CLIENT_FOUND_ROWS is specified so that in an UPDATE, - // the affected rows are the number of rows found that match the - // WHERE clause of the SQL statement, not the rows changed. The reason - // here is that MySQL apparently does not update a row if data has not - // changed and so the "affected rows" (retrievable from MySQL) is zero. - // This makes it hard to distinguish whether the UPDATE changed no rows - // because no row matching the WHERE clause was found, or because a - // row was found but no data was altered. - MYSQL* status = mysql_real_connect(mysql_, host, user, password, name, - 0, NULL, CLIENT_FOUND_ROWS); - if (status != mysql_) { - isc_throw(DbOpenError, mysql_error(mysql_)); - } -} - -// Prepared statement setup. The textual form of an SQL statement is stored -// in a vector of strings (text_statements_) and is used in the output of -// error messages. The SQL statement is also compiled into a "prepared -// statement" (stored in statements_), which avoids the overhead of compilation -// during use. As prepared statements have resources allocated to them, the -// class destructor explicitly destroys them. - -void -MySqlLeaseMgr::prepareStatement(StatementIndex index, const char* text) { - // Validate that there is space for the statement in the statements array - // and that nothing has been placed there before. - if ((index >= statements_.size()) || (statements_[index] != NULL)) { - isc_throw(InvalidParameter, "invalid prepared statement index (" << - static_cast(index) << ") or indexed prepared " << - "statement is not null"); - } - - // All OK, so prepare the statement - text_statements_[index] = std::string(text); - statements_[index] = mysql_stmt_init(mysql_); - if (statements_[index] == NULL) { - isc_throw(DbOperationError, "unable to allocate MySQL prepared " - "statement structure, reason: " << mysql_error(mysql_)); - } - - int status = mysql_stmt_prepare(statements_[index], text, strlen(text)); - if (status != 0) { - isc_throw(DbOperationError, "unable to prepare MySQL statement <" << - text << ">, reason: " << mysql_error(mysql_)); - } -} - - -void -MySqlLeaseMgr::prepareStatements() { - // Allocate space for all statements - statements_.clear(); - statements_.resize(NUM_STATEMENTS, NULL); - - text_statements_.clear(); - text_statements_.resize(NUM_STATEMENTS, std::string("")); - - // Created the MySQL prepared statements for each DML statement. - for (int i = 0; tagged_statements[i].text != NULL; ++i) { - prepareStatement(tagged_statements[i].index, - tagged_statements[i].text); - } -} - // Add leases to the database. The two public methods accept a lease object // (either V4 of V6), bind the contents to the appropriate prepared // statement, then call common code to execute the statement. @@ -2071,93 +1759,7 @@ MySqlLeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) { } } -// Miscellaneous database methods. - -std::string -MySqlLeaseMgr::getName() const { - std::string name = ""; - try { - name = getParameter("name"); - } catch (...) { - // Return an empty name - } - return (name); -} - -std::string -MySqlLeaseMgr::getDescription() const { - return (std::string("MySQL Database")); -} - - -std::pair -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 - - // Execute the prepared statement - int status = mysql_stmt_execute(statements_[stindex]); - if (status != 0) { - isc_throw(DbOperationError, "unable to execute <" - << text_statements_[stindex] << "> - reason: " << - mysql_error(mysql_)); - } - - // Bind the output of the statement to the appropriate variables. - MYSQL_BIND bind[2]; - memset(bind, 0, sizeof(bind)); - - bind[0].buffer_type = MYSQL_TYPE_LONG; - bind[0].is_unsigned = 1; - bind[0].buffer = &major; - bind[0].buffer_length = sizeof(major); - - 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(statements_[stindex], bind); - if (status != 0) { - isc_throw(DbOperationError, "unable to bind result set: " << - mysql_error(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]); - if (status != 0) { - isc_throw(DbOperationError, "unable to obtain result set: " << - mysql_error(mysql_)); - } - - return (std::make_pair(major, minor)); -} - - -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_)); - } -} - - -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_)); - } -} }; // end of isc::dhcp namespace }; // end of isc namespace diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.h b/src/lib/dhcpsrv/mysql_lease_mgr.h old mode 100644 new mode 100755 index 66dbbe1f2c..65fdcef8ad --- a/src/lib/dhcpsrv/mysql_lease_mgr.h +++ b/src/lib/dhcpsrv/mysql_lease_mgr.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -93,8 +94,9 @@ 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 { +class MySqlLeaseMgr : public LeaseMgr, public MySqlConnection { public: + /// @brief Constructor /// /// Uses the following keywords in the parameters passed to it to @@ -354,54 +356,6 @@ public: /// failed. virtual bool deleteLease(const isc::asiolink::IOAddress& addr); - /// @brief Return backend type - /// - /// Returns the type of the backend (e.g. "mysql", "memfile" etc.) - /// - /// @return Type of the backend. - virtual std::string getType() const { - return (std::string("mysql")); - } - - /// @brief Returns backend name. - /// - /// Each backend have specific name, e.g. "mysql" or "sqlite". - /// - /// @return Name of the backend. - virtual std::string getName() const; - - /// @brief Returns description of the backend. - /// - /// This description may be multiline text that describes the backend. - /// - /// @return Description of the backend. - virtual std::string getDescription() const; - - /// @brief Returns backend version. - /// - /// @return Version number as a pair of unsigned integers. "first" is the - /// major version number, "second" the minor number. - /// - /// @throw isc::dhcp::DbOperationError An operation on the open database has - /// failed. - virtual std::pair getVersion() const; - - /// @brief Commit Transactions - /// - /// Commits all pending database operations. On databases that don't - /// support transactions, this is a no-op. - /// - /// @throw DbOperationError Iif the commit failed. - virtual void commit(); - - /// @brief Rollback Transactions - /// - /// Rolls back all pending database operations. On databases that don't - /// support transactions, this is a no-op. - /// - /// @throw DbOperationError If the rollback failed. - virtual void rollback(); - ///@{ /// The following methods are used to convert between times and time /// intervals stored in the Lease object, and the times stored in the @@ -455,63 +409,9 @@ public: uint32_t valid_lifetime, time_t& cltt); ///@} - /// @brief Statement Tags - /// - /// The contents of the enum are indexes into the list of SQL statements - enum StatementIndex { - DELETE_LEASE4, // Delete from lease4 by address - DELETE_LEASE6, // Delete from lease6 by address - GET_LEASE4_ADDR, // Get lease4 by address - GET_LEASE4_CLIENTID, // Get lease4 by client ID - GET_LEASE4_CLIENTID_SUBID, // Get lease4 by client ID & subnet ID - GET_LEASE4_HWADDR, // Get lease4 by HW address - GET_LEASE4_HWADDR_SUBID, // Get lease4 by HW address & subnet ID - GET_LEASE6_ADDR, // Get lease6 by address - GET_LEASE6_DUID_IAID, // Get lease6 by DUID and IAID - GET_LEASE6_DUID_IAID_SUBID, // Get lease6 by DUID, IAID and subnet ID - GET_VERSION, // Obtain version number - INSERT_LEASE4, // Add entry to lease4 table - INSERT_LEASE6, // Add entry to lease6 table - UPDATE_LEASE4, // Update a Lease4 entry - UPDATE_LEASE6, // Update a Lease6 entry - NUM_STATEMENTS // Number of statements - }; -private: - /// @brief Prepare Single Statement - /// - /// Creates a prepared statement from the text given and adds it to the - /// statements_ vector at the given index. - /// - /// @param index Index into the statements_ vector into which the text - /// should be placed. The vector must be big enough for the index - /// to be valid, else an exception will be thrown. - /// @param text Text of the SQL statement to be prepared. - /// - /// @throw isc::dhcp::DbOperationError An operation on the open database has - /// failed. - /// @throw isc::InvalidParameter 'index' is not valid for the vector. - void prepareStatement(StatementIndex index, const char* text); - /// @brief Prepare statements - /// - /// Creates the prepared statements for all of the SQL statements used - /// by the MySQL backend. - /// - /// @throw isc::dhcp::DbOperationError An operation on the open database has - /// failed. - /// @throw isc::InvalidParameter 'index' is not valid for the vector. This - /// represents an internal error within the code. - void prepareStatements(); - - /// @brief Open Database - /// - /// Opens the database using the information supplied in the parameters - /// passed to the constructor. - /// - /// @throw NoDatabaseName Mandatory database name not given - /// @throw DbOpenError Error opening the database - void openDatabase(); +private: /// @brief Add Lease Common Code /// @@ -688,9 +588,8 @@ private: /// declare them as "mutable".) boost::scoped_ptr exchange4_; ///< Exchange object boost::scoped_ptr exchange6_; ///< Exchange object - MySqlHolder mysql_; - std::vector statements_; ///< Prepared statements - std::vector text_statements_; ///< Raw text of statements + + }; }; // end of isc::dhcp namespace