// PERFORMANCE OF THIS SOFTWARE.
#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/mysql_connection.h>
#include <exceptions/exceptions.h>
#include <boost/foreach.hpp>
#include <time.h>
+
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 {
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:
/// 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<std::string, std::string> 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
/// 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.
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
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/lease_file_loader.h>
#include <dhcpsrv/memfile_lease_mgr.h>
+#include <dhcpsrv/mysql_connection.h>
#include <exceptions/exceptions.h>
#include <util/pid_file.h>
#include <util/process_spawn.h>
Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
- : LeaseMgr(parameters),
+ : MySqlConnection(parameters),
lfc_setup_(new LFCSetup(boost::bind(&Memfile_LeaseMgr::lfcCallback, this),
*getIOService()))
{
#include <dhcpsrv/csv_lease_file6.h>
#include <dhcpsrv/memfile_lease_storage.h>
#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/mysql_connection.h>
#include <util/process_spawn.h>
#include <boost/scoped_ptr.hpp>
/// 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.
--- /dev/null
+// 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 <dhcpsrv/dhcpsrv_log.h>
+#include <dhcpsrv/mysql_connection.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <time.h>
+
+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<int>(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<uint32_t, uint32_t>
+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
--- /dev/null
+// 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 <dhcp/hwaddr.h>
+#include <dhcpsrv/lease_mgr.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <boost/utility.hpp>
+#include <mysql/mysql.h> // TODO poprawić przed oddaniem
+
+#include <time.h>
+
+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<std::string, std::string> 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<uint32_t, uint32_t> 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<MYSQL_STMT*> statements_; ///< Prepared statements
+ std::vector<std::string> 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
#include <dhcp/hwaddr.h>
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/mysql_lease_mgr.h>
+#include <dhcpsrv/mysql_connection.h>
#include <boost/static_assert.hpp>
#include <mysqld_error.h>
/// - 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 {
};
-/// @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();
}
-
-// 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<int>(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.
}
}
-// 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<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
-
- // 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
#include <dhcp/hwaddr.h>
#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/mysql_connection.h>
#include <boost/scoped_ptr.hpp>
#include <boost/utility.hpp>
/// 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
/// 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<uint32_t, uint32_t> 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
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
///
/// declare them as "mutable".)
boost::scoped_ptr<MySqlLease4Exchange> exchange4_; ///< Exchange object
boost::scoped_ptr<MySqlLease6Exchange> exchange6_; ///< Exchange object
- MySqlHolder mysql_;
- std::vector<MYSQL_STMT*> statements_; ///< Prepared statements
- std::vector<std::string> text_statements_; ///< Raw text of statements
+
+
};
}; // end of isc::dhcp namespace