]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[3682] Adam's patch applied as-is
authorTomek Mrugalski <tomasz@isc.org>
Sun, 18 Oct 2015 22:32:58 +0000 (00:32 +0200)
committerTomek Mrugalski <tomasz@isc.org>
Sun, 18 Oct 2015 22:32:58 +0000 (00:32 +0200)
15 files changed:
src/lib/dhcpsrv/base_host_data_source.h
src/lib/dhcpsrv/cfg_hosts.h
src/lib/dhcpsrv/db_exceptions.h
src/lib/dhcpsrv/host_data_source_factory.cc
src/lib/dhcpsrv/host_data_source_factory.h
src/lib/dhcpsrv/host_mgr.cc
src/lib/dhcpsrv/host_mgr.h
src/lib/dhcpsrv/mysql_connection.cc
src/lib/dhcpsrv/mysql_connection.h
src/lib/dhcpsrv/mysql_host_data_source.cc
src/lib/dhcpsrv/mysql_host_data_source.h
src/lib/dhcpsrv/mysql_lease_mgr.h
src/lib/dhcpsrv/pgsql_lease_mgr.cc
src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h
src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc

index aae1676e3cd38989d4d0e964dac7ad6ba504202a..67c5aed5abc8522b50e89f6116c56b9dec9178f0 100644 (file)
@@ -180,6 +180,13 @@ public:
     /// @param host Pointer to the new @c Host object being added.
     virtual void add(const HostPtr& host) = 0;
 
+    /// @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 = 0;
+
 };
 
 }
index e8b08b0213609c31d3dd251f8538414bdd66733c..c0e4151669e71832c150c0ad0c837a83e17d6520 100644 (file)
@@ -237,6 +237,15 @@ public:
     /// has already been added to the IPv4 or IPv6 subnet.
     virtual void add(const HostPtr& host);
 
+    /// @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("configuration file"));
+    }
+
 private:
 
     /// @brief Returns @c Host objects for the specific identifier and type.
index 06bf97a410fada5fbe38c715c636359c17b13504..3924e117c9e2e99b088df2212b30c989db072923 100644 (file)
@@ -41,6 +41,13 @@ public:
         isc::Exception(file, line, what) {}
 };
 
+/// @brief Database duplicate entry error
+class DuplicateEntry : public Exception {
+public:
+    DuplicateEntry(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
 };
 };
 
index 4c6d755c6182d43e300e701cab69f42232f91850..a0ffb976f5ebadcc079c7effcad99c263ade76a4 100644 (file)
@@ -46,8 +46,10 @@ HostDataSourceFactory::create(const std::string& dbaccess) {
     const std::string type = "type";
 
     // Parse the access string and create a redacted string for logging.
-    DatabaseConnection::ParameterMap parameters = DatabaseConnection::parse(dbaccess);
-    std::string redacted = DatabaseConnection::redactedAccessString(parameters);
+    DatabaseConnection::ParameterMap parameters =
+            DatabaseConnection::parse(dbaccess);
+    std::string redacted =
+            DatabaseConnection::redactedAccessString(parameters);
 
     // Is "type" present?
     if (parameters.find(type) == parameters.end()) {
@@ -84,7 +86,9 @@ HostDataSourceFactory::destroy() {
     // Destroy current host data source instance.  This is a no-op if no host
     // data source is available.
     if (getHostDataSourcePtr()) {
-        LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CLOSE_DB);
+        LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
+                DHCPSRV_CLOSE_HOST_DATA_SOURCE)
+                        .arg(getHostDataSourcePtr()->getType());
     }
     getHostDataSourcePtr().reset();
 }
@@ -93,7 +97,8 @@ BaseHostDataSource&
 HostDataSourceFactory::instance() {
        BaseHostDataSource* hdsptr = getHostDataSourcePtr().get();
     if (hdsptr == NULL) {
-        isc_throw(NoHostDataSourceManager, "no current host data source instance is available");
+        isc_throw(NoHostDataSourceManager,
+                "no current host data source instance is available");
     }
     return (*hdsptr);
 }
index 91b9ec7c4d5129b138acc1beb16f48a505912aa1..27958e65eacb9e30beca3cae4ec6c3b43c8bed46 100644 (file)
@@ -43,25 +43,65 @@ public:
         isc::Exception(file, line, what) {}
 };
 
+/// @brief Host Data Source Factory
+///
+/// This class comprises nothing but static methods used to create a host data source object.
+/// It analyzes the database information passed to the creation function and instantiates
+/// an appropriate host data source object based on the type requested.
+///
+/// Strictly speaking these functions could be stand-alone functions.  However,
+/// it is convenient to encapsulate them in a class for naming purposes.
+
 class HostDataSourceFactory {
 public:
-    /// @brief todo
-       ///
+    /// @brief Create an instance of a host data source.
+    ///
+    /// Each database backend has its own host data source type. This static
+    /// method sets the "current" host data source to be an object of the
+    /// appropriate type.  The actual host data source is returned by the
+    /// "instance" method.
+    ///
+    /// @note When called, the current host data source is <b>always</b> destroyed
+    ///       and a new one created - even if the parameters are the same.
+    ///
+    /// dbaccess is a generic way of passing parameters. Parameters are passed
+    /// in the "name=value" format, separated by spaces.  The data MUST include
+    /// a keyword/value pair of the form "type=dbtype" giving the database
+    /// type, e.q. "mysql" or "sqlite3".
+    ///
+    /// @param dbaccess Database access parameters.  These are in the form of
+    ///        "keyword=value" pairs, separated by spaces. They are backend-
+    ///        -end specific, although must include the "type" keyword which
+    ///        gives the backend in use.
+    ///
+    /// @throw isc::InvalidParameter dbaccess string does not contain the "type"
+    ///        keyword.
+    /// @throw isc::dhcp::InvalidType The "type" keyword in dbaccess does not
+    ///        identify a supported backend.
     static void create(const std::string& dbaccess);
 
-    /// @brief Destroy host data source instance
-       ///
-       /// todo
-       static void destroy();
+    /// @brief Destroy host data source
+    ///
+    /// Destroys the current host data source object. This should have the effect
+    /// of closing the database connection.  The method is a no-op if no
+    /// host data source is available.
+    static void destroy();
 
-       /// @brief Return current host data source instance
-       /// todo
-       static BaseHostDataSource& instance();
+    /// @brief Return current host data source
+    ///
+    /// @returns An instance of the "current" host data source.  An exception
+    /// will be thrown if none is available.
+    ///
+    /// @throw NoHostDataSourceManager No host data source is available: use
+    ///        create() to create one before calling this method.
+    static BaseHostDataSource& instance();
 
 private:
     /// @brief Hold pointer to host data source instance
     ///
-    /// todo
+    /// Holds a pointer to the singleton host data source.  The singleton
+    /// is encapsulated in this method to avoid a "static initialization
+    /// fiasco" if defined in an external static variable.
     static boost::scoped_ptr<BaseHostDataSource>& getHostDataSourcePtr();
 
 };
index 5b7d8577fc1bbcf4e1fc2f60d96292cd8e04975f..64dd65ee09b2ce8aeea244a0ea4a674280015b72 100644 (file)
@@ -17,7 +17,7 @@
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/host_mgr.h>
 #include <dhcpsrv/hosts_log.h>
-#include <dhcpsrv/mysql_host_data_source.h>
+#include <dhcpsrv/host_data_source_factory.h>
 
 namespace {
 
@@ -45,10 +45,19 @@ HostMgr::getHostMgrPtr() {
 }
 
 void
-HostMgr::create(const std::string&) {
+HostMgr::create(const std::string& /*access*/) {
     getHostMgrPtr().reset(new HostMgr());
+/*
+    try {
+        HostDataSourceFactory::create(access);
+    } catch (...) {
+        std::cerr << "Unable to open database.";
+        throw;
+    }
+*/
+    //alternate_source = &(HostDataSourceFactory::instance());
+    //alternate_source.reset(&(HostDataSourceFactory::instance()));
 
-    //alternate_source.reset(new MySqlHostDataSource());
     /// @todo Initialize alternate_source here, using the parameter.
     /// For example: alternate_source.reset(new MysqlHostDataSource(access)).
 }
index 82c6cd6308bb42a5ee8dfbcbacbceaccf453bf17..098468c6b2c5656ad1d6373fc999820e14151274 100644 (file)
@@ -199,6 +199,15 @@ public:
     /// @param host Pointer to the new @c Host object being added.
     virtual void add(const HostPtr& host);
 
+    /// @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("host_mgr"));
+    }
+
 private:
 
     /// @brief Private default constructor.
@@ -207,7 +216,7 @@ private:
     /// @brief Pointer to an alternate host data source.
     ///
     /// If this pointer is NULL, the source is not in use.
-    boost::scoped_ptr<BaseHostDataSource> alternate_source;
+    boost::shared_ptr<BaseHostDataSource> alternate_source;
 
     /// @brief Returns a pointer to the currently used instance of the
     /// @c HostMgr.
index 9ea1afc517dce381ab498ed39ebe24eba0801ccc..c3770f664869cc7cc3cd6348695450f1839631a3 100755 (executable)
@@ -258,5 +258,22 @@ MySqlConnection::convertFromDatabaseTime(const MYSQL_TIME& expire,
     cltt = mktime(&expire_tm) - valid_lifetime;
 }
 
+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
index e940c754fa0ebfb5dd52bea03fb1da884f9813eb..a94e7e253ccef62f266933ff4bc4d344d6c9afdc 100755 (executable)
@@ -32,6 +32,11 @@ namespace dhcp {
 extern const my_bool MLM_FALSE;
 extern const my_bool MLM_TRUE;
 
+// Define the current database schema values
+
+const uint32_t CURRENT_VERSION_VERSION = 3;
+const uint32_t CURRENT_VERSION_MINOR = 0;
+
 /// @brief Fetch and Release MySQL Results
 ///
 /// When a MySQL statement is expected, to fetch the results the function
@@ -190,57 +195,73 @@ public:
     void openDatabase();
 
     ///@{
-        /// The following methods are used to convert between times and time
-        /// intervals stored in the Lease object, and the times stored in the
-        /// database.  The reason for the difference is because in the DHCP server,
-        /// the cltt (Client Time Since Last Transmission) is the natural data; in
-        /// the lease file - which may be read by the user - it is the expiry time
-        /// of the lease.
-
-        /// @brief Convert Lease Time to Database Times
-        ///
-        /// Within the DHCP servers, times are stored as client last transmit time
-        /// and valid lifetime.  In the database, the information is stored as
-        /// valid lifetime and "expire" (time of expiry of the lease).  They are
-        /// related by the equation:
-        ///
-        /// - expire = client last transmit time + valid lifetime
-        ///
-        /// This method converts from the times in the lease object into times
-        /// able to be added to the database.
-        ///
-        /// @param cltt Client last transmit time
-        /// @param valid_lifetime Valid lifetime
-        /// @param expire Reference to MYSQL_TIME object where the expiry time of
-        ///        the lease will be put.
-        ///
-        /// @throw isc::BadValue if the sum of the calculated expiration time is
-        /// greater than the value of @c LeaseMgr::MAX_DB_TIME.
-        static
-        void convertToDatabaseTime(const time_t cltt, const uint32_t valid_lifetime,
-                        MYSQL_TIME& expire);
-
-        /// @brief Convert Database Time to Lease Times
-        ///
-        /// Within the database, time is stored as "expire" (time of expiry of the
-        /// lease) and valid lifetime.  In the DHCP server, the information is
-        /// stored client last transmit time and valid lifetime.  These are related
-        /// by the equation:
-        ///
-        /// - client last transmit time = expire - valid_lifetime
-        ///
-        /// This method converts from the times in the database into times
-        /// able to be inserted into the lease object.
-        ///
-        /// @param expire Reference to MYSQL_TIME object from where the expiry
-        ///        time of the lease is taken.
-        /// @param valid_lifetime lifetime of the lease.
-        /// @param cltt Reference to location where client last transmit time
-        ///        is put.
-        static
-        void convertFromDatabaseTime(const MYSQL_TIME& expire,
-                        uint32_t valid_lifetime, time_t& cltt);
-        ///@}
+    /// The following methods are used to convert between times and time
+    /// intervals stored in the Lease object, and the times stored in the
+    /// database.  The reason for the difference is because in the DHCP server,
+    /// the cltt (Client Time Since Last Transmission) is the natural data; in
+    /// the lease file - which may be read by the user - it is the expiry time
+    /// of the lease.
+
+    /// @brief Convert Lease Time to Database Times
+    ///
+    /// Within the DHCP servers, times are stored as client last transmit time
+    /// and valid lifetime.  In the database, the information is stored as
+    /// valid lifetime and "expire" (time of expiry of the lease).  They are
+    /// related by the equation:
+    ///
+    /// - expire = client last transmit time + valid lifetime
+    ///
+    /// This method converts from the times in the lease object into times
+    /// able to be added to the database.
+    ///
+    /// @param cltt Client last transmit time
+    /// @param valid_lifetime Valid lifetime
+    /// @param expire Reference to MYSQL_TIME object where the expiry time of
+    ///        the lease will be put.
+    ///
+    /// @throw isc::BadValue if the sum of the calculated expiration time is
+    /// greater than the value of @c LeaseMgr::MAX_DB_TIME.
+    static
+    void convertToDatabaseTime(const time_t cltt, const uint32_t valid_lifetime,
+            MYSQL_TIME& expire);
+
+    /// @brief Convert Database Time to Lease Times
+    ///
+    /// Within the database, time is stored as "expire" (time of expiry of the
+    /// lease) and valid lifetime.  In the DHCP server, the information is
+    /// stored client last transmit time and valid lifetime.  These are related
+    /// by the equation:
+    ///
+    /// - client last transmit time = expire - valid_lifetime
+    ///
+    /// This method converts from the times in the database into times
+    /// able to be inserted into the lease object.
+    ///
+    /// @param expire Reference to MYSQL_TIME object from where the expiry
+    ///        time of the lease is taken.
+    /// @param valid_lifetime lifetime of the lease.
+    /// @param cltt Reference to location where client last transmit time
+    ///        is put.
+    static
+    void convertFromDatabaseTime(const MYSQL_TIME& expire,
+            uint32_t valid_lifetime, time_t& cltt);
+
+    /// @brief Commit Transactions
+    ///
+    /// Commits all pending database operations. On databases that don't
+    /// support transactions, this is a no-op.
+    ///
+    /// @throw DbOperationError If the commit failed.
+    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.
+    void rollback();
+    ///@}
 
     /// @brief Prepared statements
     ///
index ea5eeb66fb044e2f865095bb663bec60fc0a701e..f5555dba271c0aa02699b9953a14517d9c3df85e 100644 (file)
@@ -45,49 +45,52 @@ const size_t CLIENT_CLASSES_MAX_LEN = 255;
 /// in the Client FQDN %Option (see RFC4702 and RFC4704).
 const size_t HOSTNAME_MAX_LEN = 255;
 
-/// @brief Maximum length of dhcp identifier field
-///
-const size_t DHCP_IDENTIFIER_MAX_LEN = 128;
 
 TaggedStatement tagged_statements[] = {
-       {MySqlHostDataSource::INSERT_HOST,
-                           "INSERT INTO hosts(host_id, dhcp_identifier, dhcp_identifier_type, "
-                       "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, "
-                                       "hostname, dhcp4_client_classes, dhcp6_client_classes) "
-                                       "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"},
-       {MySqlHostDataSource::GET_HOST_HWADDR_DUID,
-                                       "SELECT host_id, dhcp_identifier, dhcp_identifier_type, dhcp4_subnet_id, "
-                               "dhcp6_subnet_id, ipv4_address, hostname, dhcp4_client_classes, dhcp6_client_classes "
-                               "FROM hosts "
-                               "WHERE dhcp_identifier = ?"},
-       {MySqlHostDataSource::GET_HOST_ADDR,
-                               "SELECT host_id, dhcp_identifier, dhcp_identifier_type, dhcp4_subnet_id, "
-                               "dhcp6_subnet_id, ipv4_address, hostname, dhcp4_client_classes, dhcp6_client_classes "
-                               "FROM hosts "
-                               "WHERE ipv4_address = ?"},
-       {MySqlHostDataSource::GET_HOST_SUBID4_DHCPID,
-                                       "SELECT host_id, dhcp_identifier, dhcp_identifier_type, dhcp4_subnet_id, "
-                                       "dhcp6_subnet_id, ipv4_address, hostname, dhcp4_client_classes, dhcp6_client_classes "
-                                       "FROM hosts "
-                                       "WHERE dhcp4_subnet_id = ? AND dhcp_identifier = ?"},
-       {MySqlHostDataSource::GET_HOST_SUBID6_DHCPID,
-                                       "SELECT host_id, dhcp_identifier, dhcp_identifier_type, dhcp4_subnet_id, "
-                                       "dhcp6_subnet_id, ipv4_address, hostname, dhcp4_client_classes, dhcp6_client_classes "
-                                       "FROM hosts "
-                                       "WHERE dhcp6_subnet_id = ? AND dhcp_identifier = ?"},
-       {MySqlHostDataSource::GET_HOST_SUBID_ADDR,
-                                       "SELECT host_id, dhcp_identifier, dhcp_identifier_type, dhcp4_subnet_id, "
-                                       "dhcp6_subnet_id, ipv4_address, hostname, dhcp4_client_classes, dhcp6_client_classes "
-                                       "FROM hosts "
-                                       "WHERE dhcp4_subnet_id = ? AND ipv4_address = ?"},
-       {MySqlHostDataSource::GET_HOST_PREFIX,
-                                       "SELECT h.host_id, dhcp_identifier, dhcp_identifier_type, dhcp4_subnet_id, "
-                                       "dhcp6_subnet_id, ipv4_address, hostname, dhcp4_client_classes, dhcp6_client_classes "
-                                       "FROM hosts h "
-                               "LEFT JOIN ipv6_reservations r ON h.host_id = r.host_id "
-                               "WHERE r.prefix_len = ? AND r.address = ?"},
+    {MySqlHostDataSource::INSERT_HOST,
+            "INSERT INTO hosts(host_id, dhcp_identifier, dhcp_identifier_type, "
+                "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
+                "dhcp4_client_classes, dhcp6_client_classes) "
+            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"},
+    {MySqlHostDataSource::GET_HOST_HWADDR_DUID,
+            "SELECT host_id, dhcp_identifier, dhcp_identifier_type, "
+                "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
+                "dhcp4_client_classes, dhcp6_client_classes "
+            "FROM hosts "
+            "WHERE dhcp_identifier = ? AND dhcp_identifier_type = ?"},
+    {MySqlHostDataSource::GET_HOST_ADDR,
+            "SELECT host_id, dhcp_identifier, dhcp_identifier_type, "
+                "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
+                "dhcp4_client_classes, dhcp6_client_classes "
+            "FROM hosts "
+            "WHERE ipv4_address = ?"},
+    {MySqlHostDataSource::GET_HOST_SUBID4_DHCPID,
+            "SELECT host_id, dhcp_identifier, dhcp_identifier_type, "
+                "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
+                "dhcp4_client_classes, dhcp6_client_classes "
+            "FROM hosts "
+            "WHERE dhcp4_subnet_id = ? AND dhcp_identifier = ?"},
+    {MySqlHostDataSource::GET_HOST_SUBID6_DHCPID,
+            "SELECT host_id, dhcp_identifier, dhcp_identifier_type, "
+                "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
+                "dhcp4_client_classes, dhcp6_client_classes "
+            "FROM hosts "
+            "WHERE dhcp6_subnet_id = ? AND dhcp_identifier = ?"},
+    {MySqlHostDataSource::GET_HOST_SUBID_ADDR,
+            "SELECT host_id, dhcp_identifier, dhcp_identifier_type, "
+                "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
+                "dhcp4_client_classes, dhcp6_client_classes "
+            "FROM hosts "
+            "WHERE dhcp4_subnet_id = ? AND ipv4_address = ?"},
+    {MySqlHostDataSource::GET_HOST_PREFIX,
+            "SELECT h.host_id, dhcp_identifier, dhcp_identifier_type, "
+                "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
+                "dhcp4_client_classes, dhcp6_client_classes "
+            "FROM hosts h, ipv6_reservations r "
+            "WHERE h.host_id = r.host_id AND r.prefix_len = ? "
+            "   AND r.address = ?"},
     {MySqlHostDataSource::GET_VERSION,
-                    "SELECT version, minor FROM schema_version"},
+            "SELECT version, minor FROM schema_version"},
     {MySqlHostDataSource::NUM_STATEMENTS, NULL}
 };
 
@@ -107,13 +110,12 @@ public:
     /// The initialization of the variables here is only to satisfy cppcheck -
     /// all variables are initialized/set in the methods before they are used.
     MySqlHostReservationExchange() : host_id_(0), dhcp_identifier_length_(0),
-                                                                       dhcp_identifier_type_(0), dhcp4_subnet_id_(0),
-                                                                       dhcp6_subnet_id_(0), ipv4_address_(0),
-                                                                       hostname_length_(0), dhcp4_client_classes_length_(0),
-                                                                       dhcp6_client_classes_length_(0), dhcp4_subnet_id_null_(MLM_FALSE),
-                                                                       dhcp6_subnet_id_null_(MLM_FALSE), ipv4_address_null_(MLM_FALSE),
-                                                                       hostname_null_(MLM_FALSE), dhcp4_client_classes_null_(MLM_FALSE),
-                                                                       dhcp6_client_classes_null_(MLM_FALSE){
+        dhcp_identifier_type_(0), dhcp4_subnet_id_(0), dhcp6_subnet_id_(0),
+        ipv4_address_(0), hostname_length_(0), dhcp4_client_classes_length_(0),
+        dhcp6_client_classes_length_(0), dhcp4_subnet_id_null_(MLM_FALSE),
+        dhcp6_subnet_id_null_(MLM_FALSE), ipv4_address_null_(MLM_FALSE),
+        hostname_null_(MLM_FALSE), dhcp4_client_classes_null_(MLM_FALSE),
+        dhcp6_client_classes_null_(MLM_FALSE){
 
         memset(dhcp_identifier_buffer_, 0, sizeof(dhcp_identifier_buffer_));
         memset(hostname_, 0, sizeof(hostname_));
@@ -136,7 +138,7 @@ public:
 
     /// @brief Set error indicators
     ///
-    /// Sets the error indicator for each of the MYSQL_BIND elements.  It points
+    /// Sets the error indicator for each of the MYSQL_BIND elements. It points
     /// the "error" field within an element of the input array to the
     /// corresponding element of the passed error array.
     ///
@@ -192,8 +194,9 @@ public:
     /// Fills in the MYSQL_BIND array for sending data in the Host object to
     /// the database.
     ///
-    /// @param host Host object to be added to the database.  None of the
-    ///        fields in the host reservation are modified - the host data is only read.
+    /// @param host Host object to be added to the database.
+    ///        None of the fields in the host reservation are modified -
+    ///        the host data is only read.
     ///
     /// @return Vector of MySQL BIND objects representing the data to be added.
     std::vector<MYSQL_BIND> createBindForSend(const HostPtr& host) {
@@ -212,48 +215,51 @@ public:
 
         try {
             // host_id : INT UNSIGNED NOT NULL
-               // The host_id is auto_incremented by MySQL database,
-               // so we need to pass the NULL value
+            // The host_id is auto_incremented by MySQL database,
+            // so we need to pass the NULL value
             host_id_ = static_cast<uint32_t>(NULL);
             bind_[0].buffer_type = MYSQL_TYPE_LONG;
             bind_[0].buffer = reinterpret_cast<char*>(&host_id_);
             bind_[0].is_unsigned = MLM_TRUE;
-            // bind_[0].is_null = &MLM_TRUE;   //compile problems here!
+            //bind_[0].is_null = &MLM_FALSE; // commented out for performance
+            // reasons, see memset() above
 
             // dhcp_identifier : VARBINARY(128) NOT NULL
             // Check which of the identifiers is used and set values accordingly
             if (host_->getDuid()) {
                dhcp_identifier_length_ = host_->getDuid()->getDuid().size();
-                               bind_[1].buffer_type = MYSQL_TYPE_BLOB;
-                               bind_[1].buffer = reinterpret_cast<char*>(host_->getDuid()->getDuid()[0]);
-                               bind_[1].buffer_length = dhcp_identifier_length_;
-                               bind_[1].length = &dhcp_identifier_length_;
-                               // bind_[1].is_null = &MLM_FALSE; // commented out for performance
-                                                 // reasons, see memset() above
+               bind_[1].buffer_type = MYSQL_TYPE_BLOB;
+                bind_[1].buffer = reinterpret_cast<char*>
+                                    (host_->getDuid()->getDuid()[0]);
+                bind_[1].buffer_length = dhcp_identifier_length_;
+                bind_[1].length = &dhcp_identifier_length_;
+                // bind_[1].is_null = &MLM_FALSE; // commented out for performance
+                // reasons, see memset() above
             } else if (host_->getHWAddress()){
-                               dhcp_identifier_length_ = host_->getHWAddress()->hwaddr_.size();
-                               bind_[1].buffer_type = MYSQL_TYPE_BLOB;
-                               bind_[1].buffer = reinterpret_cast<char*>(&(host_->getHWAddress()->hwaddr_[0]));
-                               bind_[1].buffer_length = dhcp_identifier_length_;
-                               bind_[1].length = &dhcp_identifier_length_;
-                               // bind_[1].is_null = &MLM_FALSE; // commented out for performance
-                                                 // reasons, see memset() above
+                dhcp_identifier_length_ = host_->getHWAddress()->hwaddr_.size();
+                bind_[1].buffer_type = MYSQL_TYPE_BLOB;
+                bind_[1].buffer = reinterpret_cast<char*>
+                                    (&(host_->getHWAddress()->hwaddr_[0]));
+                bind_[1].buffer_length = dhcp_identifier_length_;
+                bind_[1].length = &dhcp_identifier_length_;
+                // bind_[1].is_null = &MLM_FALSE; // commented out for performance
+                // reasons, see memset() above
             }
 
             // dhcp_identifier_type : TINYINT NOT NULL
             // Check which of the identifier types is used and set values accordingly
             if (host_->getHWAddress()) {
-                               bind_[2].buffer_type = MYSQL_TYPE_TINY;
-                               bind_[2].buffer = reinterpret_cast<char*>(0);   // 0 = IDENT_HWADDR
-                               bind_[2].is_unsigned = MLM_TRUE;
-                               // bind_[2].is_null = &MLM_FALSE; // commented out for performance
-                                                 // reasons, see memset() above
+                bind_[2].buffer_type = MYSQL_TYPE_TINY;
+                bind_[2].buffer = reinterpret_cast<char*>(0);// 0 = IDENT_HWADDR
+                bind_[2].is_unsigned = MLM_TRUE;
+                // bind_[2].is_null = &MLM_FALSE; // commented out for performance
+                // reasons, see memset() above
             } else if (host_->getDuid()) {
-                               bind_[2].buffer_type = MYSQL_TYPE_TINY;
-                               bind_[2].buffer = reinterpret_cast<char*>(1);   // 1 = IDENT_DUID
-                               bind_[2].is_unsigned = MLM_TRUE;
-                               // bind_[2].is_null = &MLM_FALSE; // commented out for performance
-                                                 // reasons, see memset() above
+                bind_[2].buffer_type = MYSQL_TYPE_TINY;
+                bind_[2].buffer = reinterpret_cast<char*>(1);// 1 = IDENT_DUID
+                bind_[2].is_unsigned = MLM_TRUE;
+                // bind_[2].is_null = &MLM_FALSE; // commented out for performance
+                // reasons, see memset() above
             }
 
             // dhcp4_subnet_id : INT UNSIGNED NULL
@@ -421,8 +427,8 @@ public:
     /// @return Host Pointer to a Lease6 object holding the relevant data.
     HostPtr getHostData(){
 
-        // Set the dhcp identifier type in a variable of the appropriate data type, which
-        // has been initialized with an arbitrary (but valid) value.
+        // Set the dhcp identifier type in a variable of the appropriate data type,
+        // which has been initialized with an arbitrary (but valid) value.
         Host::IdentifierType type = Host::IDENT_HWADDR;
 
         switch (dhcp_identifier_type_) {
@@ -435,17 +441,17 @@ public:
                 break;
 
             default:
-                isc_throw(BadValue, "invalid dhcp identifier type returned (" <<
-                          static_cast<int>(dhcp_identifier_type_) << ") for host with "
-                          << "identifier " << reinterpret_cast<char*>(dhcp_identifier_[0]) << ". Only 0 or 1 are allowed.");
+                isc_throw(BadValue, "invalid dhcp identifier type returned: "
+                        << static_cast<int>(dhcp_identifier_type_)
+                        << ". Only 0 or 1 are allowed.");
         }
 
         // Set subnets ID's if they are given, if not, leave an empty object
-        SubnetID ipv4_subnet_id = static_cast<SubnetID>(NULL);                                 // This is probably wrong way to do it...
+        SubnetID ipv4_subnet_id(0);
         if (dhcp4_subnet_id_null_ == MLM_FALSE)
-               ipv4_subnet_id = static_cast<SubnetID>(dhcp4_subnet_id_);
+            ipv4_subnet_id = static_cast<SubnetID>(dhcp4_subnet_id_);
 
-        SubnetID ipv6_subnet_id = static_cast<SubnetID>(NULL);
+        SubnetID ipv6_subnet_id(0);
         if (dhcp6_subnet_id_null_ == MLM_FALSE)
             ipv6_subnet_id = static_cast<SubnetID>(dhcp6_subnet_id_);
 
@@ -460,7 +466,8 @@ public:
         if (hostname_null_ == MLM_FALSE)
             hostname = std::string (hostname_, hostname_ + hostname_length_);
 
-        // Not sure if this is necessary yet, since Host constructor takes strings, not ClientClasses objects
+        // Not sure if this is necessary yet, since Host constructor takes strings,
+        // not ClientClasses objects
         // Set client classes if they were given, if not, set empty client classes
         ClientClasses dhcp4_client_classes;
         if (dhcp4_client_classes_null_ == MLM_FALSE)
@@ -471,15 +478,10 @@ public:
             dhcp6_client_classes.insert(dhcp6_client_classes_);
 
         // Returning Host object with set fields
-        return (HostPtr(new Host(dhcp_identifier_buffer_,
-                                                               dhcp_identifier_length_,
-                                                               type,
-                                                               ipv4_subnet_id,
-                                                               ipv6_subnet_id,
-                                                               ipv4_reservation,
-                                                               hostname,
-                                                               dhcp4_client_classes_,
-                                                               dhcp6_client_classes_)));
+        return (HostPtr(
+                new Host(dhcp_identifier_buffer_, dhcp_identifier_length_,
+                        type, ipv4_subnet_id, ipv6_subnet_id, ipv4_reservation,
+                        hostname, dhcp4_client_classes_, dhcp6_client_classes_)));
     }
 
     /// @brief Return columns in error
@@ -497,172 +499,155 @@ public:
     }
 
 private:
-    //std::string              addr6_;                         //< String form of address
-    //char                     addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1];  // array form of V6 address
-    uint32_t                           host_id_;                                       // Unique identifier of the host
-    std::vector<uint8_t>       dhcp_identifier_;                       // DHCP identifier, can be HW address (0) or DUID (1)
-    uint8_t                            dhcp_identifier_buffer_[DHCP_IDENTIFIER_MAX_LEN];       // Buffer form of dhcp identifier
-    size_t                                     dhcp_identifier_length_;        // Length of the dhcp identifier
-    uint8_t                            dhcp_identifier_type_;          // Type of the dhcp_identifier (HW address or DUID)
-    uint32_t                           dhcp4_subnet_id_;                       // Subnet identifier for the DHCPv4 client.
-    uint32_t                           dhcp6_subnet_id_;                       // Subnet identifier for the DHCPv6 client.
-    uint32_t                           ipv4_address_;                          // Reserved IPv4 address.
-    IPv6ResrvCollection        ipv6_reservations_;                     // Collection of IPv6 reservations for the host.
-    char                                       hostname_[HOSTNAME_MAX_LEN];// Name reserved for the host.
-    unsigned long              hostname_length_;                       //  hostname length
-    char                                       dhcp4_client_classes_[CLIENT_CLASSES_MAX_LEN];  // Collection of classes associated with a DHCPv4 client.
-    unsigned long              dhcp4_client_classes_length_;// dhcp4_client_classes length
-    char                                       dhcp6_client_classes_[CLIENT_CLASSES_MAX_LEN];  // Collection of classes associated with a DHCPv6 client.
-    unsigned long              dhcp6_client_classes_length_;// dhcp6_client_classes length
-    HWAddrPtr                          hw_address_;                            // Pointer to the hardware address associated with the reservations for the host.
-    DuidPtr                            duid_;                                          // Pointer to the DUID associated with the reservations for the host.
+    uint32_t   host_id_;                       /// Host unique identifier
+    std::vector<uint8_t> dhcp_identifier_;      /// HW address (0) / DUID (1)
+    uint8_t    dhcp_identifier_buffer_[DUID::MAX_DUID_LEN];
+                                                /// Buffer for dhcp identifier
+    size_t     dhcp_identifier_length_;        /// Length of dhcp identifier
+    uint8_t    dhcp_identifier_type_;          /// Type of dhcp_identifier
+    uint32_t   dhcp4_subnet_id_;               /// Subnet DHCPv4 identifier
+    uint32_t   dhcp6_subnet_id_;               /// Subnet DHCPv6 identifier
+    uint32_t   ipv4_address_;                  /// Reserved IPv4 address.
+    IPv6ResrvCollection ipv6_reservations_;    /// IPv6 reservations collection
+    char       hostname_[HOSTNAME_MAX_LEN];    /// Name reserved for the host
+    unsigned long hostname_length_;            /// hostname length
+    char       dhcp4_client_classes_[CLIENT_CLASSES_MAX_LEN];
+                                                /// DHCPv4 client classes
+    unsigned long dhcp4_client_classes_length_; /// dhcp4_client_classes length
+    char       dhcp6_client_classes_[CLIENT_CLASSES_MAX_LEN];
+                                                /// DHCPv6 client classes
+    unsigned long dhcp6_client_classes_length_; /// dhcp6_client_classes length
+    HWAddrPtr  hw_address_;                    /// Pointer to hardware address
+    DuidPtr    duid_;                          /// Pointer to DUID
 
     // NULL flags for subnets id, ipv4 address, hostname and client classes
-    my_bool            dhcp4_subnet_id_null_;
-    my_bool            dhcp6_subnet_id_null_;
-    my_bool                            ipv4_address_null_;
-    my_bool            hostname_null_;
-    my_bool            dhcp4_client_classes_null_;
-    my_bool            dhcp6_client_classes_null_;
-
-    MYSQL_BIND         bind_[HOST_COLUMNS];
-    std::string        columns_[HOST_COLUMNS];                 // Column names
-    my_bool            error_[HOST_COLUMNS];                   // Error array
-    HostPtr                            host_;                                                  // Pointer to Host object
+    my_bool     dhcp4_subnet_id_null_;
+    my_bool     dhcp6_subnet_id_null_;
+    my_bool     ipv4_address_null_;
+    my_bool     hostname_null_;
+    my_bool     dhcp4_client_classes_null_;
+    my_bool     dhcp6_client_classes_null_;
+
+    MYSQL_BIND  bind_[HOST_COLUMNS];
+    std::string columns_[HOST_COLUMNS];        /// Column names
+    my_bool     error_[HOST_COLUMNS];          /// Error array
+    HostPtr     host_;                 // Pointer to Host object
 };
 
 // MySqlHostDataSource Constructor and Destructor
 
 MySqlHostDataSource::MySqlHostDataSource(
-               const MySqlConnection::ParameterMap& parameters) :
-                               MySqlConnection(parameters) {
-
-       // Open the database.
-       openDatabase();
-
-       // Enable autocommit.  To avoid a flush to disk on every commit, the global
-       // parameter innodb_flush_log_at_trx_commit should be set to 2.  This will
-       // cause the changes to be written to the log, but flushed to disk in the
-       // background every second.  Setting the parameter to that value will speed
-       // up the system, but at the risk of losing data if the system crashes.
-       my_bool result = mysql_autocommit(mysql_, 1);
-       if (result != 0) {
-               isc_throw(DbOperationError, mysql_error(mysql_));
-       }
+        const MySqlConnection::ParameterMap& parameters) : conn_(parameters) {
+
+    // Open the database.
+    conn_.openDatabase();
+
+    // Enable autocommit.  To avoid a flush to disk on every commit, the global
+    // parameter innodb_flush_log_at_trx_commit should be set to 2.  This will
+    // cause the changes to be written to the log, but flushed to disk in the
+    // background every second.  Setting the parameter to that value will speed
+    // up the system, but at the risk of losing data if the system crashes.
+    my_bool result = mysql_autocommit(conn_.mysql_, 1);
+    if (result != 0) {
+        isc_throw(DbOperationError, mysql_error(conn_.mysql_));
+    }
 
-       // Prepare all statements likely to be used.
-       prepareStatements(tagged_statements, MySqlHostDataSource::NUM_STATEMENTS);
+    // Prepare all statements likely to be used.
+    conn_.prepareStatements(tagged_statements,
+            MySqlHostDataSource::NUM_STATEMENTS);
 
-       // Create the exchange objects for use in exchanging data between the
-       // program and the database.
-       hostExchange_.reset(new MySqlHostReservationExchange());
+    // Create the exchange objects for use in exchanging data between the
+    // program and the database.
+    hostExchange_.reset(new MySqlHostReservationExchange());
 }
 
 MySqlHostDataSource::~MySqlHostDataSource() {
-       // Free up the prepared statements, ignoring errors. (What would we do
-       // about them? We're destroying this object and are not really concerned
-       // with errors on a database connection that is about to go away.)
-       for (int i = 0; i < statements_.size(); ++i) {
-               if (statements_[i] != NULL) {
-                       (void) mysql_stmt_close(statements_[i]);
-                       statements_[i] = NULL;
-               }
-       }
+    // Free up the prepared statements, ignoring errors. (What would we do
+    // about them? We're destroying this object and are not really concerned
+    // with errors on a database connection that is about to go away.)
+    for (int i = 0; i < conn_.statements_.size(); ++i) {
+        if (conn_.statements_[i] != NULL) {
+            (void) mysql_stmt_close(conn_.statements_[i]);
+            conn_.statements_[i] = NULL;
+        }
+    }
 
-       // There is no need to close the database in this destructor: it is
-       // closed in the destructor of the mysql_ member variable.
+    // There is no need to close the database in this destructor: it is
+    // closed in the destructor of the mysql_ member variable.
 }
 
-// Time conversion methods.
-//
-// Note that the MySQL TIMESTAMP data type (used for "expire") converts data
-// from the current timezone to UTC for storage, and from UTC to the current
-// timezone for retrieval.
-//
-// This causes no problems providing that:
-// a) cltt is given in local time
-// b) We let the system take care of timezone conversion when converting
-//    from a time read from the database into a local time.
-
 void
 MySqlHostDataSource::add(const HostPtr& host) {
        // Create the MYSQL_BIND array for the host
        std::vector<MYSQL_BIND> bind = hostExchange_->createBindForSend(host);
 
        // ... and drop to add code.
-       if (!addHost(INSERT_HOST, bind)) {
-               // Throw an failure exception here
-       }
+       addHost(INSERT_HOST, bind);
 }
 
-bool
+void
 MySqlHostDataSource::addHost(StatementIndex stindex,
                std::vector<MYSQL_BIND>& bind) {
 
        // Bind the parameters to the statement
-       int status = mysql_stmt_bind_param(statements_[stindex], &bind[0]);
+       int status = mysql_stmt_bind_param(conn_.statements_[stindex],
+                                           &bind[0]);
        checkError(status, stindex, "unable to bind parameters");
 
        // Execute the statement
-       status = mysql_stmt_execute(statements_[stindex]);
+       status = mysql_stmt_execute(conn_.statements_[stindex]);
        if (status != 0) {
-
-               // Failure: check for the special case of duplicate entry.  If this is
-               // the case, we return false to indicate that the row was not added.
-               // Otherwise we throw an exception.
-               if (mysql_errno(mysql_) == ER_DUP_ENTRY) {
-                       return (false);
-               }
-               checkError(status, stindex, "unable to execute");
+           // Failure: check for the special case of duplicate entry.
+           if (mysql_errno(conn_.mysql_) == ER_DUP_ENTRY) {
+               isc_throw(DuplicateEntry, "Database duplicate entry error");
+           }
+           checkError(status, stindex, "unable to execute");
        }
-
-       // Insert succeeded
-       return (true);
 }
 
 void
 MySqlHostDataSource::getHostCollection(StatementIndex stindex, MYSQL_BIND* bind,
-                                       boost::shared_ptr<MySqlHostReservationExchange> exchange,
-                                       ConstHostCollection& result, bool single) const {
+        boost::shared_ptr<MySqlHostReservationExchange> exchange,
+        ConstHostCollection& result, bool single) const {
 
     // Bind the selection parameters to the statement
-    int status = mysql_stmt_bind_param(statements_[stindex], bind);
+    int status = mysql_stmt_bind_param(conn_.statements_[stindex], bind);
     checkError(status, stindex, "unable to bind WHERE clause parameter");
 
     // Set up the MYSQL_BIND array for the data being returned and bind it to
     // the statement.
     std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
-    status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]);
+    status = mysql_stmt_bind_result(conn_.statements_[stindex], &outbind[0]);
     checkError(status, stindex, "unable to bind SELECT clause parameters");
 
     // Execute the statement
-    status = mysql_stmt_execute(statements_[stindex]);
+    status = mysql_stmt_execute(conn_.statements_[stindex]);
     checkError(status, stindex, "unable to execute");
 
     // Ensure that all the lease information is retrieved in one go to avoid
     // overhead of going back and forth between client and server.
-    status = mysql_stmt_store_result(statements_[stindex]);
+    status = mysql_stmt_store_result(conn_.statements_[stindex]);
     checkError(status, stindex, "unable to set up for storing all results");
 
     // Set up the fetch "release" object to release resources associated
     // with the call to mysql_stmt_fetch when this method exits, then
     // retrieve the data.
-    MySqlFreeResult fetch_release(statements_[stindex]);
+    MySqlFreeResult fetch_release(conn_.statements_[stindex]);
     int count = 0;
-    while ((status = mysql_stmt_fetch(statements_[stindex])) == 0) {
+    while ((status = mysql_stmt_fetch(conn_.statements_[stindex])) == 0) {
         try {
             result.push_back(exchange->getHostData());
 
         } catch (const isc::BadValue& ex) {
             // Rethrow the exception with a bit more data.
             isc_throw(BadValue, ex.what() << ". Statement is <" <<
-                      text_statements_[stindex] << ">");
+                    conn_.text_statements_[stindex] << ">");
         }
 
         if (single && (++count > 1)) {
             isc_throw(MultipleRecords, "multiple records were found in the "
                       "database where only one was expected for query "
-                      << text_statements_[stindex]);
+                      << conn_.text_statements_[stindex]);
         }
     }
 
@@ -672,7 +657,7 @@ MySqlHostDataSource::getHostCollection(StatementIndex stindex, MYSQL_BIND* bind,
         checkError(status, stindex, "unable to fetch results");
     } else if (status == MYSQL_DATA_TRUNCATED) {
         // Data truncated - throw an exception indicating what was at fault
-        isc_throw(DataTruncated, text_statements_[stindex]
+        isc_throw(DataTruncated, conn_.text_statements_[stindex]
                   << " returned truncated data: columns affected are "
                   << exchange->getErrorColumns());
     }
@@ -685,26 +670,39 @@ MySqlHostDataSource::getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid) const
        MYSQL_BIND inbind[2];
        memset(inbind, 0, sizeof(inbind));
 
-       // DUID
-       const vector<uint8_t>& duid_vector = duid->getDuid();
-       unsigned long duid_length = duid_vector.size();
-       inbind[0].buffer_type = MYSQL_TYPE_BLOB;
-       inbind[0].buffer =
-                       reinterpret_cast<char*>(const_cast<uint8_t*>(&duid_vector[0]));
-       inbind[0].buffer_length = duid_length;
-       inbind[0].length = &duid_length;
-
-       // HW Address
-       const vector<uint8_t>& hwaddr_vector = hwaddr->hwaddr_;
-       unsigned long hwaddr_length = hwaddr_vector.size();
-       inbind[1].buffer_type = MYSQL_TYPE_BLOB;
-       inbind[1].buffer =
-                       reinterpret_cast<char*>(const_cast<uint8_t*>(&hwaddr_vector[0]));
-       inbind[1].buffer_length = hwaddr_length;
-       inbind[1].length = &hwaddr_length;
+       if (duid){
+            // DUID
+            // set proper dhcp_identifier_type
+            inbind[1].buffer = reinterpret_cast<char*>(1);
+
+            const vector<uint8_t>& duid_vector = duid->getDuid();
+            unsigned long duid_length = duid_vector.size();
+            inbind[0].buffer_type = MYSQL_TYPE_BLOB;
+            inbind[0].buffer = reinterpret_cast<char*>
+                                (const_cast<uint8_t*>(&duid_vector[0]));
+            inbind[0].buffer_length = duid_length;
+            inbind[0].length = &duid_length;
+       } else if (hwaddr) {
+            // HW Address
+           // set proper dhcp_identifier_type
+           inbind[1].buffer = reinterpret_cast<char*>(0);
+
+            const vector<uint8_t>& hwaddr_vector = hwaddr->hwaddr_;
+            unsigned long hwaddr_length = hwaddr_vector.size();
+            inbind[0].buffer_type = MYSQL_TYPE_BLOB;
+            inbind[0].buffer = reinterpret_cast<char*>
+                                (const_cast<uint8_t*>(&hwaddr_vector[0]));
+            inbind[0].buffer_length = hwaddr_length;
+            inbind[0].length = &hwaddr_length;
+       }
+
+       // dhcp_identifier_type
+       inbind[1].buffer_type = MYSQL_TYPE_TINY;
+       inbind[1].is_unsigned = MLM_TRUE;
 
        ConstHostCollection result;
-       getHostCollection(GET_HOST_HWADDR_DUID, inbind, hostExchange_, result, false);
+       getHostCollection(GET_HOST_HWADDR_DUID, inbind, hostExchange_,
+                           result, false);
 
        return (result);
 }
@@ -746,8 +744,8 @@ MySqlHostDataSource::get4(const SubnetID& subnet_id,
                const vector<uint8_t>& hwaddr_vector = hwaddr->hwaddr_;
                unsigned long hwaddr_length = hwaddr_vector.size();
                inbind[1].buffer_type = MYSQL_TYPE_BLOB;
-               inbind[1].buffer =
-                               reinterpret_cast<char*>(const_cast<uint8_t*>(&hwaddr_vector[0]));
+               inbind[1].buffer = reinterpret_cast<char*>
+                                   (const_cast<uint8_t*>(&hwaddr_vector[0]));
                inbind[1].buffer_length = hwaddr_length;
                inbind[1].length = &hwaddr_length;
        } else if (duid) {
@@ -755,24 +753,21 @@ MySqlHostDataSource::get4(const SubnetID& subnet_id,
                const vector<uint8_t>& duid_vector = duid->getDuid();
                unsigned long duid_length = duid_vector.size();
                inbind[1].buffer_type = MYSQL_TYPE_BLOB;
-               inbind[1].buffer =
-                               reinterpret_cast<char*>(const_cast<uint8_t*>(&duid_vector[0]));
+               inbind[1].buffer = reinterpret_cast<char*>
+                                   (const_cast<uint8_t*>(&duid_vector[0]));
                inbind[1].buffer_length = duid_length;
                inbind[1].length = &duid_length;
        }
        // if none of the identifiers was given, this field should remain null
 
        ConstHostCollection collection;
-       getHostCollection(GET_HOST_SUBID4_DHCPID, inbind, hostExchange_, collection,
-                       true);
+       getHostCollection(GET_HOST_SUBID4_DHCPID, inbind, hostExchange_,
+               collection, true);
 
        // Return single record if present, else clear the host.
        ConstHostPtr result;
-       if (collection.empty()) {
-               result.reset();
-       } else {
-               result = *collection.begin();
-       }
+       if (!collection.empty())
+           result = *collection.begin();
 
        return (result);
 }
@@ -794,16 +789,13 @@ MySqlHostDataSource::get4(const SubnetID& subnet_id,
        inbind[1].is_unsigned = MLM_TRUE;
 
        ConstHostCollection collection;
-       getHostCollection(GET_HOST_SUBID_ADDR, inbind, hostExchange_, collection,
-                       true);
+       getHostCollection(GET_HOST_SUBID_ADDR, inbind, hostExchange_,
+               collection, true);
 
        // Return single record if present, else clear the host.
        ConstHostPtr result;
-       if (collection.empty()) {
-               result.reset();
-       } else {
-               result = *collection.begin();
-       }
+       if (!collection.empty())
+           result = *collection.begin();
 
        return (result);
 }
@@ -826,8 +818,8 @@ MySqlHostDataSource::get6(const SubnetID& subnet_id,
                const vector<uint8_t>& hwaddr_vector = hwaddr->hwaddr_;
                unsigned long hwaddr_length = hwaddr_vector.size();
                inbind[1].buffer_type = MYSQL_TYPE_BLOB;
-               inbind[1].buffer =
-                               reinterpret_cast<char*>(const_cast<uint8_t*>(&hwaddr_vector[0]));
+               inbind[1].buffer = reinterpret_cast<char*>
+                                   (const_cast<uint8_t*>(&hwaddr_vector[0]));
                inbind[1].buffer_length = hwaddr_length;
                inbind[1].length = &hwaddr_length;
        } else if (duid) {
@@ -835,24 +827,21 @@ MySqlHostDataSource::get6(const SubnetID& subnet_id,
                const vector<uint8_t>& duid_vector = duid->getDuid();
                unsigned long duid_length = duid_vector.size();
                inbind[1].buffer_type = MYSQL_TYPE_BLOB;
-               inbind[1].buffer =
-                               reinterpret_cast<char*>(const_cast<uint8_t*>(&duid_vector[0]));
+               inbind[1].buffer = reinterpret_cast<char*>
+                                   (const_cast<uint8_t*>(&duid_vector[0]));
                inbind[1].buffer_length = duid_length;
                inbind[1].length = &duid_length;
        }
        // if none of the identifiers was given, this field should remain null
 
        ConstHostCollection collection;
-       getHostCollection(GET_HOST_SUBID6_DHCPID, inbind, hostExchange_, collection,
-                       true);
+       getHostCollection(GET_HOST_SUBID6_DHCPID, inbind, hostExchange_,
+               collection, true);
 
        // Return single record if present, else clear the host.
        ConstHostPtr result;
-       if (collection.empty()) {
-               result.reset();
-       } else {
-               result = *collection.begin();
-       }
+       if (!collection.empty())
+           result = *collection.begin();
 
        return (result);
 }
@@ -875,15 +864,13 @@ MySqlHostDataSource::get6(const asiolink::IOAddress& prefix,
        inbind[1].is_unsigned = MLM_TRUE;
 
        ConstHostCollection collection;
-       getHostCollection(GET_HOST_PREFIX, inbind, hostExchange_, collection, true);
+       getHostCollection(GET_HOST_PREFIX, inbind, hostExchange_,
+                           collection, true);
 
        // Return single record if present, else clear the host.
        ConstHostPtr result;
-       if (collection.empty()) {
-               result.reset();
-       } else {
-               result = *collection.begin();
-       }
+       if (!collection.empty())
+           result = *collection.begin();
 
        return (result);
 }
@@ -906,16 +893,13 @@ MySqlHostDataSource::get6(const SubnetID& subnet_id,
        inbind[1].is_unsigned = MLM_TRUE;
 
        ConstHostCollection collection;
-       getHostCollection(GET_HOST_SUBID_ADDR, inbind, hostExchange_, collection,
-                       true);
+       getHostCollection(GET_HOST_SUBID_ADDR, inbind, hostExchange_,
+               collection, true);
 
        // Return single record if present, else clear the host.
        ConstHostPtr result;
-       if (collection.empty()) {
-               result.reset();
-       } else {
-               result = *collection.begin();
-       }
+       if (!collection.empty())
+           result = *collection.begin();
 
        return (result);
 }
@@ -925,7 +909,7 @@ MySqlHostDataSource::get6(const SubnetID& subnet_id,
 std::string MySqlHostDataSource::getName() const {
        std::string name = "";
        try {
-               name = getParameter("name");
+               name = conn_.getParameter("name");
        } catch (...) {
                // Return an empty name
        }
@@ -933,7 +917,8 @@ std::string MySqlHostDataSource::getName() const {
 }
 
 std::string MySqlHostDataSource::getDescription() const {
-       return (std::string("MySQL Database"));
+       return (std::string("Host data source that stores host information"
+               "in MySQL database"));
 }
 
 std::pair<uint32_t, uint32_t> MySqlHostDataSource::getVersion() const {
@@ -946,10 +931,11 @@ std::pair<uint32_t, uint32_t> MySqlHostDataSource::getVersion() const {
        uint32_t minor;      // Minor version number
 
        // Execute the prepared statement
-       int status = mysql_stmt_execute(statements_[stindex]);
+       int status = mysql_stmt_execute(conn_.statements_[stindex]);
        if (status != 0) {
-               isc_throw(DbOperationError,
-                               "unable to execute <" << text_statements_[stindex] << "> - reason: " << mysql_error(mysql_));
+               isc_throw(DbOperationError, "unable to execute <"
+                       << conn_.text_statements_[stindex]
+                       << "> - reason: " << mysql_error(conn_.mysql_));
        }
 
        // Bind the output of the statement to the appropriate variables.
@@ -966,38 +952,24 @@ std::pair<uint32_t, uint32_t> MySqlHostDataSource::getVersion() const {
        bind[1].buffer = &minor;
        bind[1].buffer_length = sizeof(minor);
 
-       status = mysql_stmt_bind_result(statements_[stindex], bind);
+       status = mysql_stmt_bind_result(conn_.statements_[stindex], bind);
        if (status != 0) {
-               isc_throw(DbOperationError,
-                               "unable to bind result set: " << mysql_error(mysql_));
+               isc_throw(DbOperationError, "unable to bind result set: "
+                       << mysql_error(conn_.mysql_));
        }
 
        // Fetch the data and set up the "release" object to release associated
        // resources when this method exits then retrieve the data.
-       MySqlFreeResult fetch_release(statements_[stindex]);
-       status = mysql_stmt_fetch(statements_[stindex]);
+       MySqlFreeResult fetch_release(conn_.statements_[stindex]);
+       status = mysql_stmt_fetch(conn_.statements_[stindex]);
        if (status != 0) {
-               isc_throw(DbOperationError,
-                               "unable to obtain result set: " << mysql_error(mysql_));
+               isc_throw(DbOperationError, "unable to obtain result set: "
+                       << mysql_error(conn_.mysql_));
        }
 
        return (std::make_pair(major, minor));
 }
 
-void MySqlHostDataSource::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 MySqlHostDataSource::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
index f78d9bb3020c1b1d768ef4efb314eb9f4acd41bc..42f614d30a69e405e525074630cc81f949e45685 100644 (file)
 #include <boost/utility.hpp>
 #include <mysql.h>
 
-
 namespace isc {
 namespace dhcp {
 
-// Define the current database schema values
-
-const uint32_t CURRENT_VERSION_VERSION = 3;
-const uint32_t CURRENT_VERSION_MINOR = 0;
-
-
 // Forward declaration of the Host exchange objects.  These classes are defined
 // in the .cc file.
 class MySqlHostReservationExchange;
 
+/// @brief MySQL Host Data Source
+///
+/// This class provides the \ref isc::dhcp::BaseHostDataSource interface to the MySQL
+/// database.  Use of this backend presupposes that a MySQL database is
+/// available and that the Kea schema has been created within it.
 
-class MySqlHostDataSource : public BaseHostDataSource, public MySqlConnection {
+class MySqlHostDataSource: public BaseHostDataSource {
 public:
 
     /// @brief Constructor
@@ -63,7 +61,7 @@ public:
     /// @throw isc::dhcp::DbOpenError Error opening the database
     /// @throw isc::dhcp::DbOperationError An operation on the open database has
     ///        failed.
-       MySqlHostDataSource(const ParameterMap& parameters);
+    MySqlHostDataSource(const DatabaseConnection::ParameterMap& parameters);
 
     /// @brief Destructor (closes database)
     virtual ~MySqlHostDataSource();
@@ -93,221 +91,210 @@ public:
     getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid = DuidPtr()) const;
 
     /// @brief Returns a collection of hosts using the specified IPv4 address.
-       ///
-       /// This method may return multiple @c Host objects if they are connected
-       /// to different subnets.
-       ///
-       /// @param address IPv4 address for which the @c Host object is searched.
-       ///
-       /// @return Collection of const @c Host objects.
-       virtual ConstHostCollection
-       getAll4(const asiolink::IOAddress& address) const;
-
-       /// @brief Returns a host connected to the IPv4 subnet.
-       ///
-       /// Implementations of this method should guard against the case when
-       /// mutliple instances of the @c Host are present, e.g. when two
-       /// @c Host objects are found, one for the DUID, another one for the
-       /// HW address. In such case, an implementation of this method
-       /// should throw an exception.
-       ///
-       /// @param subnet_id Subnet identifier.
-       /// @param hwaddr HW address of the client or NULL if no HW address
-       /// available.
-       /// @param duid client id or NULL if not available.
-       ///
-       /// @return Const @c Host object using a specified HW address or DUID.
-       virtual ConstHostPtr
-       get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
-                       const DuidPtr& duid = DuidPtr()) const;
-
-       /// @brief Returns a host connected to the IPv4 subnet and having
-       /// a reservation for a specified IPv4 address.
-       ///
-       /// One of the use cases for this method is to detect collisions between
-       /// dynamically allocated addresses and reserved addresses. When the new
-       /// address is assigned to a client, the allocation mechanism should check
-       /// if this address is not reserved for some other host and do not allocate
-       /// this address if reservation is present.
-       ///
-       /// Implementations of this method should guard against invalid addresses,
-       /// such as IPv6 address.
-       ///
-       /// @param subnet_id Subnet identifier.
-       /// @param address reserved IPv4 address.
-       ///
-       /// @return Const @c Host object using a specified IPv4 address.
-       virtual ConstHostPtr
-       get4(const SubnetID& subnet_id, const asiolink::IOAddress& address) const;
-
-       /// @brief Returns a host connected to the IPv6 subnet.
-       ///
-       /// Implementations of this method should guard against the case when
-       /// mutliple instances of the @c Host are present, e.g. when two
-       /// @c Host objects are found, one for the DUID, another one for the
-       /// HW address. In such case, an implementation of this method
-       /// should throw an exception.
-       ///
-       /// @param subnet_id Subnet identifier.
-       /// @param hwaddr HW address of the client or NULL if no HW address
-       /// available.
-       /// @param duid DUID or NULL if not available.
-       ///
-       /// @return Const @c Host object using a specified HW address or DUID.
-       virtual ConstHostPtr
-       get6(const SubnetID& subnet_id, const DuidPtr& duid,
-                       const HWAddrPtr& hwaddr = HWAddrPtr()) const;
-
-       /// @brief Returns a host using the specified IPv6 prefix.
-       ///
-       /// @param prefix IPv6 prefix for which the @c Host object is searched.
-       /// @param prefix_len IPv6 prefix length.
-       ///
-       /// @return Const @c Host object using a specified HW address or DUID.
-       virtual ConstHostPtr
-       get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const;
-
-       /// @brief Returns a host from specific subnet and reserved address.
-       ///
-       /// @param subnet_id subnet identfier.
-       /// @param address specified address.
-       ///
-       /// @return Const @c host object that has a reservation for specified address.
-       virtual ConstHostPtr
-       get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const;
+    ///
+    /// This method may return multiple @c Host objects if they are connected
+    /// to different subnets.
+    ///
+    /// @param address IPv4 address for which the @c Host object is searched.
+    ///
+    /// @return Collection of const @c Host objects.
+    virtual ConstHostCollection
+    getAll4(const asiolink::IOAddress& address) const;
+
+    /// @brief Returns a host connected to the IPv4 subnet.
+    ///
+    /// Implementations of this method should guard against the case when
+    /// mutliple instances of the @c Host are present, e.g. when two
+    /// @c Host objects are found, one for the DUID, another one for the
+    /// HW address. In such case, an implementation of this method
+    /// should throw an MultipleRecords exception.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param hwaddr HW address of the client or NULL if no HW address
+    /// available.
+    /// @param duid client id or NULL if not available.
+    ///
+    /// @return Const @c Host object using a specified HW address or DUID.
+    virtual ConstHostPtr
+    get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
+            const DuidPtr& duid = DuidPtr()) const;
+
+    /// @brief Returns a host connected to the IPv4 subnet and having
+    /// a reservation for a specified IPv4 address.
+    ///
+    /// One of the use cases for this method is to detect collisions between
+    /// dynamically allocated addresses and reserved addresses. When the new
+    /// address is assigned to a client, the allocation mechanism should check
+    /// if this address is not reserved for some other host and do not allocate
+    /// this address if reservation is present.
+    ///
+    /// Implementations of this method should guard against invalid addresses,
+    /// such as IPv6 address.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param address reserved IPv4 address.
+    ///
+    /// @return Const @c Host object using a specified IPv4 address.
+    virtual ConstHostPtr
+    get4(const SubnetID& subnet_id, const asiolink::IOAddress& address) const;
+
+    /// @brief Returns a host connected to the IPv6 subnet.
+    ///
+    /// Implementations of this method should guard against the case when
+    /// mutliple instances of the @c Host are present, e.g. when two
+    /// @c Host objects are found, one for the DUID, another one for the
+    /// HW address. In such case, an implementation of this method
+    /// should throw an MultipleRecords exception.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param hwaddr HW address of the client or NULL if no HW address
+    /// available.
+    /// @param duid DUID or NULL if not available.
+    ///
+    /// @return Const @c Host object using a specified HW address or DUID.
+    virtual ConstHostPtr
+    get6(const SubnetID& subnet_id, const DuidPtr& duid,
+            const HWAddrPtr& hwaddr = HWAddrPtr()) const;
+
+    /// @brief Returns a host using the specified IPv6 prefix.
+    ///
+    /// @param prefix IPv6 prefix for which the @c Host object is searched.
+    /// @param prefix_len IPv6 prefix length.
+    ///
+    /// @return Const @c Host object using a specified HW address or DUID.
+    virtual ConstHostPtr
+    get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const;
+
+    /// @brief Returns a host from specific subnet and reserved address.
+    ///
+    /// @param subnet_id subnet identfier.
+    /// @param address specified address.
+    ///
+    /// @return Const @c host object that has a reservation for specified address.
+    virtual ConstHostPtr
+    get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const;
 
     /// @brief Adds a new host to the collection.
     ///
     /// The implementations of this method should guard against duplicate
     /// reservations for the same host, where possible. For example, when the
     /// reservation for the same HW address and subnet id is added twice, the
-    /// implementation should throw an exception. Note, that usually it is
-    /// impossible to guard against adding duplicated host, where one instance
-    /// is identified by HW address, another one by DUID.
+    /// addHost method should throw an DuplicateEntry exception. Note, that
+    /// usually it is impossible to guard against adding duplicated host, where
+    /// one instance is identified by HW address, another one by DUID.
     ///
     /// @param host Pointer to the new @c Host object being added.
     virtual void add(const HostPtr& host);
 
     /// @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 If 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();
+    ///
+    /// 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 stored in the database, 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;
+
+    MySqlConnection* getDatabaseConnection() {
+        return &conn_;
+    }
 
     /// @brief Statement Tags
     ///
     /// The contents of the enum are indexes into the list of SQL statements
-       enum StatementIndex {
-               INSERT_HOST,                            // Insert new host to collection
-               GET_HOST_HWADDR_DUID,           // Get hosts identified by DUID and/or HW address
-               GET_HOST_ADDR,                          // Get hosts with specified IPv4 address
-               GET_HOST_SUBID4_DHCPID,         // Get host with specified IPv4 SubnetID and HW address and/or DUID
-               GET_HOST_SUBID6_DHCPID,         // Get host with specified IPv6 SubnetID and HW address and/or DUID
-               GET_HOST_SUBID_ADDR,            // Get host with specified IPv4 SubnetID and IPv4 address
-               GET_HOST_PREFIX,                        // Get host with specified IPv6 prefix
-               GET_VERSION,                // Obtain version number
-               NUM_STATEMENTS              // Number of statements
-       };
+    enum StatementIndex {
+        INSERT_HOST,           // Insert new host to collection
+        GET_HOST_HWADDR_DUID,   // Gets hosts by DUID and/or HW address
+        GET_HOST_ADDR,         // Gets hosts by IPv4 address
+        GET_HOST_SUBID4_DHCPID,        // Gets host by IPv4 SubnetID, HW address/DUID
+        GET_HOST_SUBID6_DHCPID,        // Gets host by IPv6 SubnetID, HW address/DUID
+        GET_HOST_SUBID_ADDR,    // Gets host by IPv4 SubnetID and IPv4 address
+        GET_HOST_PREFIX,       // Gets host by IPv6 prefix
+        GET_VERSION,            // Obtain version number
+        NUM_STATEMENTS          // Number of statements
+    };
 
 private:
-       /// @brief Add Host Code
-       ///
-       /// This method performs adding a host operation.
-       ///     It binds the contents of the host object to
-       /// the prepared statement and adds it to the database.
-       ///
-       /// @param stindex Index of statemnent being executed
-       /// @param bind MYSQL_BIND array that has been created for the host
-       ///
-       /// @return true if the host was added, false if it was not.
-       bool addHost(StatementIndex stindex, std::vector<MYSQL_BIND>& bind);
-
-       /// @brief Get Host Collection Code
-       ///
-       /// This method obtains multiple hosts from the database.
-       ///
-       /// @param stindex Index of statement being executed
-       /// @param bind MYSQL_BIND array for input parameters
-       /// @param exchange Exchange object to use
-       /// @param result ConstHostCollection object returned.  Note that any hosts in
-       ///        the collection when this method is called are not erased: the
-       ///        new data is appended to the end.
-       /// @param single If true, only a single data item is to be retrieved.
-       ///        If more than one is present, a MultipleRecords exception will
-       ///        be thrown.
-       ///
-       /// @throw isc::dhcp::BadValue Data retrieved from the database was invalid.
-       /// @throw isc::dhcp::DbOperationError An operation on the open database has
-       ///        failed.
-       /// @throw isc::dhcp::MultipleRecords Multiple records were retrieved
-       ///        from the database where only one was expected.
-       void getHostCollection(StatementIndex stindex, MYSQL_BIND* bind,
-                       boost::shared_ptr<MySqlHostReservationExchange> exchange,
-                       ConstHostCollection& result, bool single = false) const;
-
-       /// @brief Check Error and Throw Exception
-       ///
-       /// Virtually all MySQL functions return a status which, if non-zero,
-       /// indicates an error.  This inline function conceals a lot of error
-       /// checking/exception-throwing code.
-       ///
-       /// @param status Status code: non-zero implies an error
-       /// @param index Index of statement that caused the error
-       /// @param what High-level description of the error
-       ///
-       /// @throw isc::dhcp::DbOperationError An operation on the open database has
-       ///        failed.
-       inline void checkError(int status, StatementIndex index,
-                       const char* what) const {
-               if (status != 0) {
-                       isc_throw(DbOperationError,
-                                       what << " for <" << text_statements_[index] << ">, reason: "
-                                       << mysql_error(mysql_) << " (error code " << mysql_errno(mysql_) << ")");
-               }
-       }
+    /// @brief Add Host Code
+    ///
+    /// This method performs adding a host operation.
+    ///        It binds the contents of the host object to
+    /// the prepared statement and adds it to the database.
+    ///
+    /// @param stindex Index of statemnent being executed
+    /// @param bind MYSQL_BIND array that has been created for the host
+    ///
+    /// @htrow isc::dhcp::DuplicateEntry Database throws duplicate entry error
+    void addHost(StatementIndex stindex, std::vector<MYSQL_BIND>& bind);
+
+    /// @brief Get Host Collection Code
+    ///
+    /// This method obtains multiple hosts from the database.
+    ///
+    /// @param stindex Index of statement being executed
+    /// @param bind MYSQL_BIND array for input parameters
+    /// @param exchange Exchange object to use
+    /// @param result ConstHostCollection object returned.  Note that any hosts
+    ///        in the collection when this method is called are not erased: the
+    ///        new data is appended to the end.
+    /// @param single If true, only a single data item is to be retrieved.
+    ///        If more than one is present, a MultipleRecords exception will
+    ///        be thrown.
+    ///
+    /// @throw isc::dhcp::BadValue Data retrieved from the database was invalid.
+    /// @throw isc::dhcp::DbOperationError An operation on the open database has
+    ///        failed.
+    /// @throw isc::dhcp::MultipleRecords Multiple records were retrieved
+    ///        from the database where only one was expected.
+    void getHostCollection(StatementIndex stindex, MYSQL_BIND* bind,
+            boost::shared_ptr<MySqlHostReservationExchange> exchange,
+            ConstHostCollection& result, bool single = false) const;
 
+    /// @brief Check Error and Throw Exception
+    ///
+    /// Virtually all MySQL functions return a status which, if non-zero,
+    /// indicates an error.  This inline function conceals a lot of error
+    /// checking/exception-throwing code.
+    ///
+    /// @param status Status code: non-zero implies an error
+    /// @param index Index of statement that caused the error
+    /// @param what High-level description of the error
+    ///
+    /// @throw isc::dhcp::DbOperationError An operation on the open database
+    ///        has failed.
+    inline void checkError(int status, StatementIndex index,
+            const char* what) const {
+        if (status != 0) {
+            isc_throw(DbOperationError, what << " for <"
+                    << conn_.text_statements_[index] << ">, reason: "
+                    << mysql_error(conn_.mysql_) << " (error code "
+                    << mysql_errno(conn_.mysql_) << ")");
+        }
+    }
 
     // Members
 
@@ -315,7 +302,12 @@ private:
     /// They are pointed-to objects as the contents may change in "const" calls,
     /// while the rest of this object does not.  (At alternative would be to
     /// declare them as "mutable".)
-    boost::shared_ptr<MySqlHostReservationExchange> hostExchange_; ///< Exchange object
+
+    /// @brief MySQL Host Reservation Exchange object
+    boost::shared_ptr<MySqlHostReservationExchange> hostExchange_;
+
+    /// @brief MySQL connection
+    MySqlConnection conn_;
 
 };
 
index 56e2a721778503f861ecc26001aec3f1dad5f552..cebeb4bfe29434c8327bc4a66c7c16b41b31eef4 100755 (executable)
 
 #include <boost/scoped_ptr.hpp>
 #include <boost/utility.hpp>
-#include <mysql.h>
+#include <mysql/mysql.h>
 
 #include <time.h>
 
 namespace isc {
 namespace dhcp {
 
-// Define the current database schema values
-
-const uint32_t CURRENT_VERSION_VERSION = 3;
-const uint32_t CURRENT_VERSION_MINOR = 0;
-
-
 // Forward declaration of the Lease exchange objects.  These classes are defined
 // in the .cc file.
 class MySqlLease4Exchange;
index 0ed10ae556025086f30aaf13f9829d35667b68b4..8cb2d84566d539011539d23c0a5b439004ec7c26 100644 (file)
@@ -320,7 +320,7 @@ public:
         // beginning of the epoch (around year 2038). The value is often
         // stored in the database but it is invalid when read back (overflow?).
         // Hence, the maximum timestamp value is restricted here.
-        if (expire_time_64 > DataSource::MAX_DB_TIME) {
+        if (expire_time_64 > DatabaseConnection::MAX_DB_TIME) {
             isc_throw(isc::BadValue, "Time value is too large: " << expire_time_64);
         }
 
index 8789f6b2d7cc5257e6d9ee99dff25d6700921125..e133406df530e7bd9c4baa1e38c205e46d83efcb 100644 (file)
@@ -23,6 +23,10 @@ namespace isc {
 namespace dhcp {
 namespace test {
 
+/// @brief Test Fixture class with utility functions for HostDataSource backends
+///
+/// It contains utility functions for test purposes.
+/// All concrete HostDataSource test classes should be derived from it.
 class GenericHostDataSourceTest : public ::testing::Test {
 public:
 
index 79680ac453fba9262c9d8bda2a55c1dae377031f..ece4422cf68dfe3ebda8fa7d16d69834e68a2b30 100644 (file)
@@ -58,6 +58,8 @@ const char* INVALID_USER = "user=invaliduser";
 const char* VALID_PASSWORD = "password=keatest";
 const char* INVALID_PASSWORD = "password=invalid";
 
+MySqlHostDataSource* myhdsptr_;
+
 // Given a combination of strings above, produce a connection string.
 string connectionString(const char* type, const char* name, const char* host,
                         const char* user, const char* password) {
@@ -166,15 +168,15 @@ public:
                          "*** accompanying exception output.\n";
             throw;
         }
-        hdsptr_ = &(HostDataSourceFactory::instance());
+        myhdsptr_ = (MySqlHostDataSource *) &(HostDataSourceFactory::instance());
     }
 
     /// @brief Destructor
     ///
-    /// Rolls back all pending transactions.  The deletion of hdsptr_ will close
+    /// Rolls back all pending transactions.  The deletion of myhdsptr_ will close
     /// the database.  Then reopen it and delete everything created by the test.
     virtual ~MySqlHostDataSourceTest() {
-        //hdsptr_->rollback();                         // need to decide where to implement rollback method (HostMgr or BaseHostDataSource maybe?)
+        myhdsptr_->getDatabaseConnection()->rollback();
         HostDataSourceFactory::destroy();
         destroySchema();
     }
@@ -189,7 +191,7 @@ public:
     void reopen(Universe) {
        HostDataSourceFactory::destroy();
        HostDataSourceFactory::create(validConnectionString());
-        hdsptr_ = &(HostDataSourceFactory::instance());
+       myhdsptr_ = (MySqlHostDataSource *) &(HostDataSourceFactory::instance());
     }
 
 };