]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#93,!35] Moved common CB functions to a parent class.
authorMarcin Siodelski <marcin@isc.org>
Thu, 27 Sep 2018 10:28:17 +0000 (12:28 +0200)
committerMarcin Siodelski <marcin@isc.org>
Mon, 8 Oct 2018 14:39:22 +0000 (16:39 +0200)
src/hooks/dhcp/mysql_cb/Makefile.am
src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc
src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc [new file with mode: 0644]
src/hooks/dhcp/mysql_cb/mysql_cb_impl.h [new file with mode: 0644]

index 28da17d4f1cd791b379a67696353366b7f85d513..e6463eef9dbb32881f9dca700b1cf7dc1ef5873f 100644 (file)
@@ -27,6 +27,7 @@ noinst_LTLIBRARIES = libmysqlcb.la
 
 libmysqlcb_la_SOURCES  = mysql_cb_callouts.cc
 libmysqlcb_la_SOURCES += mysql_cb_dhcp4.cc mysql_cb_dhcp4.h
+libmysqlcb_la_SOURCES += mysql_cb_impl.cc mysql_cb_impl.h
 libmysqlcb_la_SOURCES += version.cc
 
 nodist_libmysqlcb_la_SOURCES = mysql_cb_messages.cc mysql_cb_messages.h
index 2e49b350b189f1df68cf55de0b57421cc55e569c..be011100ddf28c18d31c60c2d028baa336f1458f 100644 (file)
@@ -4,6 +4,8 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+#include <mysql_cb_dhcp4.h>
+#include <mysql_cb_impl.h>
 #include <cc/data.h>
 #include <database/db_exceptions.h>
 #include <dhcp/classify.h>
@@ -12,7 +14,6 @@
 #include <dhcpsrv/network.h>
 #include <dhcpsrv/pool.h>
 #include <dhcpsrv/lease.h>
-#include <mysql_cb_dhcp4.h>
 #include <mysql/mysql_connection.h>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/lexical_cast.hpp>
@@ -32,7 +33,7 @@ namespace isc {
 namespace dhcp {
 
 /// @brief Implementation of the MySQL Configuration Backend.
-class MySqlConfigBackendDHCPv4Impl {
+class MySqlConfigBackendDHCPv4Impl : public MySqlConfigBackendImpl {
 public:
 
     /// @brief Statement tags.
@@ -74,10 +75,8 @@ public:
     ///
     /// @param parameters A data structure relating keywords and values
     /// concerned with the database.
-    MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& parameters);
-
-    /// @brief Destructor.
-    ~MySqlConfigBackendDHCPv4Impl();
+    explicit MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap&
+                                          parameters);
 
     /// @brief Sends query to the database to retrieve multiple subnets.
     ///
@@ -401,27 +400,6 @@ public:
         conn_.insertQuery(INSERT_POOL4, in_bindings);
     }
 
-    /// @brief Sends query to delete rows from a table.
-    ///
-    /// @param index Index of the statement to be executed.
-    void deleteFromTable(const StatementIndex& index) {
-        MySqlBindingCollection in_bindings;
-        conn_.updateDeleteQuery(index, in_bindings);
-    }
-
-    /// @brief Sends query to delete rows from a table.
-    ///
-    /// @param index Index of the statement to be executed.
-    /// @param key String value to be used as input binding to the delete
-    /// statement.
-    void deleteFromTable(const StatementIndex& index,
-                         const std::string& key) {
-        MySqlBindingCollection in_bindings = {
-            MySqlBinding::createString(key)
-        };
-        conn_.updateDeleteQuery(index, in_bindings);
-    }
-
     /// @brief Sends query to delete subnet by id.
     ///
     /// @param selector Server selector.
@@ -643,93 +621,6 @@ public:
     /// if the query contains no WHERE clause.
     /// @param [out] option_defs Reference to the container where fetched
     /// option definitions will be inserted.
-    void getOptionDefs4(const StatementIndex& index,
-                        const MySqlBindingCollection& in_bindings,
-                        OptionDefContainer& option_defs) {
-        // Create output bindings. The order must match that in the prepared
-        // statement.
-        MySqlBindingCollection out_bindings = {
-            MySqlBinding::createInteger<uint64_t>(), // id
-            MySqlBinding::createInteger<uint8_t>(), // code
-            MySqlBinding::createString(128), // name
-            MySqlBinding::createString(128), // space
-            MySqlBinding::createInteger<uint8_t>(), // type
-            MySqlBinding::createTimestamp(), // modification_ts
-            MySqlBinding::createInteger<uint8_t>(), // array
-            MySqlBinding::createString(128), // encapsulate
-            MySqlBinding::createString(512), // record_types
-            MySqlBinding::createString(65536) // user_context
-        };
-
-        uint64_t last_def_id = 0;
-
-        // Run select query.
-        conn_.selectQuery(index, in_bindings, out_bindings,
-                          [&option_defs, &last_def_id]
-                          (MySqlBindingCollection& out_bindings) {
-            // Get pointer to last fetched option definition.
-            OptionDefinitionPtr last_def;
-            if (!option_defs.empty()) {
-                last_def = *option_defs.rbegin();
-            }
-
-            // See if the last fetched definition is the one for which we now got
-            // the row of data. If not, it means that we need to create new option
-            // definition.
-            if ((last_def_id == 0) ||
-                (last_def_id != out_bindings[0]->getInteger<uint64_t>())) {
-
-                last_def_id = out_bindings[0]->getInteger<uint64_t>();
-
-                // Check array type, because depending on this value we have to use
-                // different constructor.
-                bool array_type = static_cast<bool>(out_bindings[6]->getInteger<uint8_t>());
-                if (array_type) {
-                    // Create array option.
-                    last_def.reset(new OptionDefinition(out_bindings[2]->getString(),
-                                                        out_bindings[1]->getInteger<uint8_t>(),
-                                                        static_cast<OptionDataType>
-                                                        (out_bindings[4]->getInteger<uint8_t>()),
-                                                        array_type));
-                } else {
-                    // Create non-array option.
-                    last_def.reset(new OptionDefinition(out_bindings[2]->getString(),
-                                                        out_bindings[1]->getInteger<uint8_t>(),
-                                                        static_cast<OptionDataType>
-                                                        (out_bindings[4]->getInteger<uint8_t>()),
-                                                        out_bindings[7]->getStringOrDefault("").c_str()));
-                }
-
-                // space
-                last_def->setOptionSpaceName(out_bindings[3]->getStringOrDefault(""));
-
-                // record_types
-                ElementPtr record_types_element = out_bindings[8]->getJSON();
-                if (record_types_element) {
-                    if (record_types_element->getType() != Element::list) {
-                        isc_throw(BadValue, "invalid record_types value "
-                                  << out_bindings[8]->getString());
-                    }
-                    // This element must contain a list of integers specifying
-                    // types of the record fields.
-                    for (auto i = 0; i < record_types_element->size(); ++i) {
-                        auto type_element = record_types_element->get(i);
-                        if (type_element->getType() != Element::integer) {
-                            isc_throw(BadValue, "record type values must be integers");
-                        }
-                        last_def->addRecordField(static_cast<OptionDataType>
-                                                 (type_element->intValue()));
-                    }
-                }
-
-                // Update modification time.
-                last_def->setModificationTime(out_bindings[5]->getTimestamp());
-
-                // Store created option definition.
-                option_defs.push_back(last_def);
-            }
-        });
-    }
 
     /// @brief Sends query to retrieve single option definition by code and
     /// option space.
@@ -748,10 +639,40 @@ public:
             MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(code)),
             MySqlBinding::createString(space)
         };
-        getOptionDefs4(GET_OPTION_DEF4_CODE_SPACE, in_bindings, option_defs);
+        getOptionDefs(GET_OPTION_DEF4_CODE_SPACE, in_bindings, option_defs);
         return (option_defs.empty() ? OptionDefinitionPtr() : *option_defs.begin());
     }
 
+    /// @brief Sends query to retrieve all option definitions.
+    ///
+    /// @param selector Server selector.
+    /// @return Container holding returned option definitions.
+    OptionDefContainer getAllOptionDefs4(const ServerSelector& selector) {
+        OptionDefContainer option_defs;
+        MySqlBindingCollection in_bindings;
+        getOptionDefs(MySqlConfigBackendDHCPv4Impl::GET_ALL_OPTION_DEFS4,
+                      in_bindings, option_defs);
+        return (option_defs);
+    }
+
+    /// @brief Sends query to retrieve option definitions with modification
+    /// time later than specified timestamp.
+    ///
+    /// @param selector Server selector.
+    /// @param modification_time Lower bound subnet modification time.
+    /// @return Container holding returned option definitions.
+    OptionDefContainer
+    getModifiedOptionDefs4(const ServerSelector& selector,
+                           const boost::posix_time::ptime& modification_time) {
+        OptionDefContainer option_defs;
+        MySqlBindingCollection in_bindings = {
+            MySqlBinding::createTimestamp(modification_time)
+        };
+        getOptionDefs(MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTION_DEFS4,
+                      in_bindings, option_defs);
+        return (option_defs);
+    }
+
     /// @brief Sends query to insert or update option definition.
     ///
     /// @param selector Server selector.
@@ -812,63 +733,6 @@ public:
         // Run DELETE.
         conn_.updateDeleteQuery(DELETE_OPTION_DEF4_CODE_NAME, in_bindings);
     }
-
-    /// @brief Creates input binding for relay addresses.
-    ///
-    /// @param network Pointer to a shared network or subnet for which binding
-    /// should be created.
-    /// @return Pointer to the binding (possibly null binding if there are no
-    /// relay addresses specified).
-    MySqlBindingPtr createInputRelayBinding(const NetworkPtr& network) {
-        ElementPtr relay_element = Element::createList();
-        const auto& addresses = network->getRelayAddresses();
-        if (!addresses.empty()) {
-            for (const auto& address : addresses) {
-                relay_element->add(Element::create(address.toText()));
-            }
-        }
-
-        return (relay_element->empty() ? MySqlBinding::createNull() :
-                MySqlBinding::condCreateString(relay_element->str()));
-    }
-
-    /// @brief Creates input binding for 'require_client_classes' parameter.
-    ///
-    /// @param network Pointer to a shared network or subnet for which binding
-    /// should be created.
-    /// @return Pointer to the binding (possibly null binding if there are no
-    /// required classes specified).
-    MySqlBindingPtr createInputRequiredClassesBinding(const NetworkPtr& network) {
-        // Create JSON list of required classes.
-        ElementPtr required_classes_element = Element::createList();
-        const auto& required_classes = network->getRequiredClasses();
-        for (auto required_class = required_classes.cbegin();
-             required_class != required_classes.cend();
-             ++required_class) {
-            required_classes_element->add(Element::create(*required_class));
-        }
-
-        return (required_classes_element ?
-                MySqlBinding::createString(required_classes_element->str()) :
-                MySqlBinding::createNull());
-    }
-
-    /// @brief Creates input binding for user context parameter.
-    ///
-    /// @param network Pointer to a shared network, subnet or other configuration
-    /// element for which binding should be created.
-    /// @return Pointer to the binding (possibly null binding if context is
-    /// null).
-    template<typename T>
-    MySqlBindingPtr createInputContextBinding(const T& config_element) {
-        // Create user context binding if user context exists.
-        auto context_element = config_element->getContext();
-        return (context_element ? MySqlBinding::createString(context_element->str()) :
-                MySqlBinding::createNull());
-    }
-
-    /// @brief Represents connection to the MySQL database.
-    MySqlConnection conn_;
 };
 
 /// @brief Array of tagged statements.
@@ -1281,33 +1145,7 @@ TaggedStatementArray tagged_statements = { {
 
 MySqlConfigBackendDHCPv4Impl::
 MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& parameters)
-    : conn_(parameters) {
-    // Open the database.
-    conn_.openDatabase();
-
-    // Test schema version before we try to prepare statements.
-    std::pair<uint32_t, uint32_t> code_version(MYSQL_SCHEMA_VERSION_MAJOR,
-                                               MYSQL_SCHEMA_VERSION_MINOR);
-/*    std::pair<uint32_t, uint32_t> db_version = getVersion();
-    if (code_version != db_version) {
-        isc_throw(DbOpenError, "MySQL schema version mismatch: need version: "
-                  << code_version.first << "." << code_version.second
-                  << " found version:  " << db_version.first << "."
-                  << db_version.second);
-    } */
-
-    // Enable autocommit. In case transaction is explicitly used, this
-    // setting will be overwritten for the transaction. However, there are
-    // cases when lack of autocommit could cause transactions to hang
-    // until commit or rollback is explicitly called. This already
-    // caused issues for some unit tests which were unable to cleanup
-    // the database after the test because of pending transactions.
-    // Use of autocommit will eliminate this problem.
-    my_bool result = mysql_autocommit(conn_.mysql_, 1);
-    if (result != 0) {
-        isc_throw(DbOperationError, mysql_error(conn_.mysql_));
-    }
-
+    : MySqlConfigBackendImpl(parameters) {
     // Prepare query statements. Those are will be only used to retrieve
     // information from the database, so they can be used even if the
     // database is read only for the current user.
@@ -1316,18 +1154,6 @@ MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& parameters)
 //                            tagged_statements.begin() + WRITE_STMTS_BEGIN);
 }
 
-MySqlConfigBackendDHCPv4Impl::~MySqlConfigBackendDHCPv4Impl() {
-    // 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;
-        }
-    }
-}
-
 MySqlConfigBackendDHCPv4::
 MySqlConfigBackendDHCPv4(const DatabaseConnection::ParameterMap& parameters)
     : impl_(new MySqlConfigBackendDHCPv4Impl(parameters)) {
@@ -1403,24 +1229,14 @@ MySqlConfigBackendDHCPv4::getOptionDef4(const ServerSelector& selector,
 
 OptionDefContainer
 MySqlConfigBackendDHCPv4::getAllOptionDefs4(const ServerSelector& selector) const {
-    OptionDefContainer option_defs;
-    MySqlBindingCollection in_bindings;
-    impl_->getOptionDefs4(MySqlConfigBackendDHCPv4Impl::GET_ALL_OPTION_DEFS4,
-                          in_bindings, option_defs);
-    return (option_defs);
+    return (impl_->getAllOptionDefs4(selector));
 }
 
 OptionDefContainer
 MySqlConfigBackendDHCPv4::
 getModifiedOptionDefs4(const ServerSelector& selector,
                        const boost::posix_time::ptime& modification_time) const {
-    OptionDefContainer option_defs;
-    MySqlBindingCollection in_bindings = {
-        MySqlBinding::createTimestamp(modification_time)
-    };
-    impl_->getOptionDefs4(MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTION_DEFS4,
-                          in_bindings, option_defs);
-    return (option_defs);
+    return (impl_->getModifiedOptionDefs4(selector, modification_time));
 }
 
 util::OptionalValue<std::string>
diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc
new file mode 100644 (file)
index 0000000..e978bb2
--- /dev/null
@@ -0,0 +1,196 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <mysql_cb_impl.h>
+#include <asiolink/io_address.h>
+#include <mysql.h>
+#include <mysqld_error.h>
+#include <cstdint>
+#include <utility>
+
+using namespace isc::data;
+using namespace isc::db;
+
+namespace isc {
+namespace dhcp {
+
+MySqlConfigBackendImpl::
+MySqlConfigBackendImpl(const DatabaseConnection::ParameterMap& parameters)
+    : conn_(parameters) {
+    // Open the database.
+    conn_.openDatabase();
+
+    // Test schema version before we try to prepare statements.
+    std::pair<uint32_t, uint32_t> code_version(MYSQL_SCHEMA_VERSION_MAJOR,
+                                               MYSQL_SCHEMA_VERSION_MINOR);
+/*    std::pair<uint32_t, uint32_t> db_version = getVersion();
+    if (code_version != db_version) {
+        isc_throw(DbOpenError, "MySQL schema version mismatch: need version: "
+                  << code_version.first << "." << code_version.second
+                  << " found version:  " << db_version.first << "."
+                  << db_version.second);
+    } */
+
+    // Enable autocommit. In case transaction is explicitly used, this
+    // setting will be overwritten for the transaction. However, there are
+    // cases when lack of autocommit could cause transactions to hang
+    // until commit or rollback is explicitly called. This already
+    // caused issues for some unit tests which were unable to cleanup
+    // the database after the test because of pending transactions.
+    // Use of autocommit will eliminate this problem.
+    my_bool result = mysql_autocommit(conn_.mysql_, 1);
+    if (result != 0) {
+        isc_throw(DbOperationError, mysql_error(conn_.mysql_));
+    }
+}
+
+MySqlConfigBackendImpl::~MySqlConfigBackendImpl() {
+    // 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;
+        }
+    }
+}
+
+void
+MySqlConfigBackendImpl::deleteFromTable(const int index) {
+    MySqlBindingCollection in_bindings;
+    conn_.updateDeleteQuery(index, in_bindings);
+}
+
+void
+MySqlConfigBackendImpl::deleteFromTable(const int index, const std::string& key) {
+    MySqlBindingCollection in_bindings = {
+            MySqlBinding::createString(key)
+    };
+    conn_.updateDeleteQuery(index, in_bindings);
+}
+
+void
+MySqlConfigBackendImpl::getOptionDefs(const int index,
+                                      const MySqlBindingCollection& in_bindings,
+                                      OptionDefContainer& option_defs) {
+    // Create output bindings. The order must match that in the prepared
+    // statement.
+    MySqlBindingCollection out_bindings = {
+        MySqlBinding::createInteger<uint64_t>(), // id
+        MySqlBinding::createInteger<uint8_t>(), // code
+        MySqlBinding::createString(128), // name
+        MySqlBinding::createString(128), // space
+        MySqlBinding::createInteger<uint8_t>(), // type
+        MySqlBinding::createTimestamp(), // modification_ts
+        MySqlBinding::createInteger<uint8_t>(), // array
+        MySqlBinding::createString(128), // encapsulate
+        MySqlBinding::createString(512), // record_types
+        MySqlBinding::createString(65536) // user_context
+    };
+
+    uint64_t last_def_id = 0;
+
+    // Run select query.
+    conn_.selectQuery(index, in_bindings, out_bindings,
+                      [&option_defs, &last_def_id]
+                      (MySqlBindingCollection& out_bindings) {
+        // Get pointer to last fetched option definition.
+        OptionDefinitionPtr last_def;
+        if (!option_defs.empty()) {
+            last_def = *option_defs.rbegin();
+        }
+
+        // See if the last fetched definition is the one for which we now got
+        // the row of data. If not, it means that we need to create new option
+        // definition.
+        if ((last_def_id == 0) ||
+            (last_def_id != out_bindings[0]->getInteger<uint64_t>())) {
+
+            last_def_id = out_bindings[0]->getInteger<uint64_t>();
+
+            // Check array type, because depending on this value we have to use
+            // different constructor.
+            bool array_type = static_cast<bool>(out_bindings[6]->getInteger<uint8_t>());
+            if (array_type) {
+                // Create array option.
+                last_def.reset(new OptionDefinition(out_bindings[2]->getString(),
+                                                    out_bindings[1]->getInteger<uint8_t>(),
+                                                    static_cast<OptionDataType>
+                                                    (out_bindings[4]->getInteger<uint8_t>()),
+                                                    array_type));
+            } else {
+                // Create non-array option.
+                last_def.reset(new OptionDefinition(out_bindings[2]->getString(),
+                                                    out_bindings[1]->getInteger<uint8_t>(),
+                                                    static_cast<OptionDataType>
+                                                    (out_bindings[4]->getInteger<uint8_t>()),
+                                                    out_bindings[7]->getStringOrDefault("").c_str()));
+            }
+
+            // space
+            last_def->setOptionSpaceName(out_bindings[3]->getStringOrDefault(""));
+
+            // record_types
+            ElementPtr record_types_element = out_bindings[8]->getJSON();
+            if (record_types_element) {
+                if (record_types_element->getType() != Element::list) {
+                    isc_throw(BadValue, "invalid record_types value "
+                              << out_bindings[8]->getString());
+                }
+                // This element must contain a list of integers specifying
+                // types of the record fields.
+                for (auto i = 0; i < record_types_element->size(); ++i) {
+                    auto type_element = record_types_element->get(i);
+                    if (type_element->getType() != Element::integer) {
+                        isc_throw(BadValue, "record type values must be integers");
+                    }
+                    last_def->addRecordField(static_cast<OptionDataType>
+                                             (type_element->intValue()));
+                }
+            }
+
+            // Update modification time.
+            last_def->setModificationTime(out_bindings[5]->getTimestamp());
+
+            // Store created option definition.
+            option_defs.push_back(last_def);
+        }
+    });
+}
+
+MySqlBindingPtr
+MySqlConfigBackendImpl::createInputRelayBinding(const NetworkPtr& network) {
+    ElementPtr relay_element = Element::createList();
+    const auto& addresses = network->getRelayAddresses();
+    if (!addresses.empty()) {
+        for (const auto& address : addresses) {
+            relay_element->add(Element::create(address.toText()));
+        }
+    }
+
+    return (relay_element->empty() ? MySqlBinding::createNull() :
+            MySqlBinding::condCreateString(relay_element->str()));
+}
+
+MySqlBindingPtr
+MySqlConfigBackendImpl::createInputRequiredClassesBinding(const NetworkPtr& network) {
+    // Create JSON list of required classes.
+    ElementPtr required_classes_element = Element::createList();
+    const auto& required_classes = network->getRequiredClasses();
+    for (auto required_class = required_classes.cbegin();
+         required_class != required_classes.cend();
+         ++required_class) {
+        required_classes_element->add(Element::create(*required_class));
+    }
+
+    return (required_classes_element ?
+            MySqlBinding::createString(required_classes_element->str()) :
+            MySqlBinding::createNull());
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h
new file mode 100644 (file)
index 0000000..c3f81f3
--- /dev/null
@@ -0,0 +1,104 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef MYSQL_CONFIG_BACKEND_IMPL_H
+#define MYSQL_CONFIG_BACKEND_IMPL_H
+
+#include <database/database_connection.h>
+#include <dhcp/option_definition.h>
+#include <dhcpsrv/network.h>
+#include <mysql/mysql_binding.h>
+#include <mysql/mysql_connection.h>
+#include <string>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Base class for MySQL Config Backend implementations.
+///
+/// This class contains common methods for manipulating data in the
+/// MySQL database, used by all servers.
+class MySqlConfigBackendImpl {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// @param parameters A data structure relating keywords and values
+    /// concerned with the database.
+    explicit MySqlConfigBackendImpl(const db::DatabaseConnection::ParameterMap& parameters);
+
+    /// @brief Destructor.
+    ~MySqlConfigBackendImpl();
+
+    /// @brief Sends query to delete rows from a table.
+    ///
+    /// @param index Index of the statement to be executed.
+    void deleteFromTable(const int index);
+
+    /// @brief Sends query to delete rows from a table.
+    ///
+    /// @param index Index of the statement to be executed.
+    /// @param key String value to be used as input binding to the delete
+    /// statement
+    void deleteFromTable(const int index,
+                         const std::string& key);
+
+    /// @brief Sends query to the database to retrieve multiple option
+    /// definitions.
+    ///
+    /// Query should order option definitions by id.
+    ///
+    /// @param index Index of the query to be used.
+    /// @param in_bindings Input bindings specifying selection criteria. The
+    /// size of the bindings collection must match the number of placeholders
+    /// in the prepared statement. The input bindings collection must be empty
+    /// if the query contains no WHERE clause.
+    /// @param [out] option_defs Reference to the container where fetched
+    /// option definitions will be inserted.
+    void getOptionDefs(const int index,
+                       const db::MySqlBindingCollection& in_bindings,
+                       OptionDefContainer& option_defs);
+
+    /// @brief Creates input binding for relay addresses.
+    ///
+    /// @param network Pointer to a shared network or subnet for which binding
+    /// should be created.
+    /// @return Pointer to the binding (possibly null binding if there are no
+    /// relay addresses specified).
+    db::MySqlBindingPtr createInputRelayBinding(const NetworkPtr& network);
+
+    /// @brief Creates input binding for 'require_client_classes' parameter.
+    ///
+    /// @param network Pointer to a shared network or subnet for which binding
+    /// should be created.
+    /// @return Pointer to the binding (possibly null binding if there are no
+    /// required classes specified).
+    db::MySqlBindingPtr createInputRequiredClassesBinding(const NetworkPtr& network);
+
+    /// @brief Creates input binding for user context parameter.
+    ///
+    /// @param T Type of the configuration element to which context belongs.
+    /// @param network Pointer to a shared network, subnet or other configuration
+    /// element for which binding should be created.
+    /// @return Pointer to the binding (possibly null binding if context is
+    /// null).
+    template<typename T>
+    db::MySqlBindingPtr createInputContextBinding(const T& config_element) {
+        // Create user context binding if user context exists.
+        auto context_element = config_element->getContext();
+        return (context_element ? db::MySqlBinding::createString(context_element->str()) :
+                db::MySqlBinding::createNull());
+    }
+
+
+    /// @brief Represents connection to the MySQL database.
+    db::MySqlConnection conn_;
+};
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
+
+#endif