Commit 915be746 authored by Marcin Siodelski's avatar Marcin Siodelski

[#93,!35] Moved common CB functions to a parent class.

parent d8b406c7
...@@ -27,6 +27,7 @@ noinst_LTLIBRARIES = libmysqlcb.la ...@@ -27,6 +27,7 @@ noinst_LTLIBRARIES = libmysqlcb.la
libmysqlcb_la_SOURCES = mysql_cb_callouts.cc libmysqlcb_la_SOURCES = mysql_cb_callouts.cc
libmysqlcb_la_SOURCES += mysql_cb_dhcp4.cc mysql_cb_dhcp4.h 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 libmysqlcb_la_SOURCES += version.cc
nodist_libmysqlcb_la_SOURCES = mysql_cb_messages.cc mysql_cb_messages.h nodist_libmysqlcb_la_SOURCES = mysql_cb_messages.cc mysql_cb_messages.h
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // 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/. // 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 <cc/data.h>
#include <database/db_exceptions.h> #include <database/db_exceptions.h>
#include <dhcp/classify.h> #include <dhcp/classify.h>
...@@ -12,7 +14,6 @@ ...@@ -12,7 +14,6 @@
#include <dhcpsrv/network.h> #include <dhcpsrv/network.h>
#include <dhcpsrv/pool.h> #include <dhcpsrv/pool.h>
#include <dhcpsrv/lease.h> #include <dhcpsrv/lease.h>
#include <mysql_cb_dhcp4.h>
#include <mysql/mysql_connection.h> #include <mysql/mysql_connection.h>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
...@@ -32,7 +33,7 @@ namespace isc { ...@@ -32,7 +33,7 @@ namespace isc {
namespace dhcp { namespace dhcp {
/// @brief Implementation of the MySQL Configuration Backend. /// @brief Implementation of the MySQL Configuration Backend.
class MySqlConfigBackendDHCPv4Impl { class MySqlConfigBackendDHCPv4Impl : public MySqlConfigBackendImpl {
public: public:
/// @brief Statement tags. /// @brief Statement tags.
...@@ -74,10 +75,8 @@ public: ...@@ -74,10 +75,8 @@ public:
/// ///
/// @param parameters A data structure relating keywords and values /// @param parameters A data structure relating keywords and values
/// concerned with the database. /// concerned with the database.
MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& parameters); explicit MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap&
parameters);
/// @brief Destructor.
~MySqlConfigBackendDHCPv4Impl();
/// @brief Sends query to the database to retrieve multiple subnets. /// @brief Sends query to the database to retrieve multiple subnets.
/// ///
...@@ -401,27 +400,6 @@ public: ...@@ -401,27 +400,6 @@ public:
conn_.insertQuery(INSERT_POOL4, in_bindings); 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. /// @brief Sends query to delete subnet by id.
/// ///
/// @param selector Server selector. /// @param selector Server selector.
...@@ -643,93 +621,6 @@ public: ...@@ -643,93 +621,6 @@ public:
/// if the query contains no WHERE clause. /// if the query contains no WHERE clause.
/// @param [out] option_defs Reference to the container where fetched /// @param [out] option_defs Reference to the container where fetched
/// option definitions will be inserted. /// 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 /// @brief Sends query to retrieve single option definition by code and
/// option space. /// option space.
...@@ -748,10 +639,40 @@ public: ...@@ -748,10 +639,40 @@ public:
MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(code)), MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(code)),
MySqlBinding::createString(space) 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()); 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. /// @brief Sends query to insert or update option definition.
/// ///
/// @param selector Server selector. /// @param selector Server selector.
...@@ -812,63 +733,6 @@ public: ...@@ -812,63 +733,6 @@ public:
// Run DELETE. // Run DELETE.
conn_.updateDeleteQuery(DELETE_OPTION_DEF4_CODE_NAME, in_bindings); 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. /// @brief Array of tagged statements.
...@@ -1281,33 +1145,7 @@ TaggedStatementArray tagged_statements = { { ...@@ -1281,33 +1145,7 @@ TaggedStatementArray tagged_statements = { {
MySqlConfigBackendDHCPv4Impl:: MySqlConfigBackendDHCPv4Impl::
MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& parameters) MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& parameters)
: conn_(parameters) { : MySqlConfigBackendImpl(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_));
}
// Prepare query statements. Those are will be only used to retrieve // Prepare query statements. Those are will be only used to retrieve
// information from the database, so they can be used even if the // information from the database, so they can be used even if the
// database is read only for the current user. // database is read only for the current user.
...@@ -1316,18 +1154,6 @@ MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& parameters) ...@@ -1316,18 +1154,6 @@ MySqlConfigBackendDHCPv4Impl(const DatabaseConnection::ParameterMap& parameters)
// tagged_statements.begin() + WRITE_STMTS_BEGIN); // 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::
MySqlConfigBackendDHCPv4(const DatabaseConnection::ParameterMap& parameters) MySqlConfigBackendDHCPv4(const DatabaseConnection::ParameterMap& parameters)
: impl_(new MySqlConfigBackendDHCPv4Impl(parameters)) { : impl_(new MySqlConfigBackendDHCPv4Impl(parameters)) {
...@@ -1403,24 +1229,14 @@ MySqlConfigBackendDHCPv4::getOptionDef4(const ServerSelector& selector, ...@@ -1403,24 +1229,14 @@ MySqlConfigBackendDHCPv4::getOptionDef4(const ServerSelector& selector,
OptionDefContainer OptionDefContainer
MySqlConfigBackendDHCPv4::getAllOptionDefs4(const ServerSelector& selector) const { MySqlConfigBackendDHCPv4::getAllOptionDefs4(const ServerSelector& selector) const {
OptionDefContainer option_defs; return (impl_->getAllOptionDefs4(selector));
MySqlBindingCollection in_bindings;
impl_->getOptionDefs4(MySqlConfigBackendDHCPv4Impl::GET_ALL_OPTION_DEFS4,
in_bindings, option_defs);
return (option_defs);
} }
OptionDefContainer OptionDefContainer
MySqlConfigBackendDHCPv4:: MySqlConfigBackendDHCPv4::
getModifiedOptionDefs4(const ServerSelector& selector, getModifiedOptionDefs4(const ServerSelector& selector,
const boost::posix_time::ptime& modification_time) const { const boost::posix_time::ptime& modification_time) const {
OptionDefContainer option_defs; return (impl_->getModifiedOptionDefs4(selector, modification_time));
MySqlBindingCollection in_bindings = {
MySqlBinding::createTimestamp(modification_time)
};
impl_->getOptionDefs4(MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_OPTION_DEFS4,
in_bindings, option_defs);
return (option_defs);
} }
util::OptionalValue<std::string> util::OptionalValue<std::string>
......
// 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
// 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).</