Commit 765c0d79 authored by Andrei Pavel's avatar Andrei Pavel

boost::any for CHDS

parent 4cd773d5
......@@ -89,10 +89,6 @@ struct StatementTagHash {
}
};
/// Define CQL schema version: 2.0
const uint32_t CQL_SCHEMA_VERSION_MAJOR = 2;
const uint32_t CQL_SCHEMA_VERSION_MINOR = 0;
/// @brief Equality function for StatementMap keys
struct StatementTagEqual {
bool operator()(StatementTag const& lhs, StatementTag const& rhs) const {
......
// Copyright (C) 2016 Deutsche Telekom AG.
// Copyright (C) 2016-2017 Deutsche Telekom AG.
//
// Author: Andrei Pavel <andrei.pavel@qualitance.com>
//
......@@ -16,29 +16,31 @@
#include <config.h>
#include <dhcpsrv/cql_host_data_source.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option.h>
#include <dhcp/option_definition.h>
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/cql_host_data_source.h>
#include <dhcpsrv/cql_lease_mgr.h>
#include <dhcpsrv/cql_exchange.h>
#include <dhcpsrv/db_exceptions.h>
#include <dhcpsrv/dhcpsrv_log.h>
#include <util/buffer.h>
#include <util/optional_value.h>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/unordered_map.hpp>
#include <openssl/md5.h> // for MD5_DIGEST_LENGTH
#include <stdint.h> // for uint64_t
#include <openssl/md5.h>
#include <boost/algorithm/string/classification.hpp> // for boost::is_any_of
#include <boost/algorithm/string/split.hpp> // for split
#include <boost/assert.hpp> // for BOOST_ASSERT
#include <boost/unordered_map.hpp> // for std::unordered_map
#include <list>
#include <vector>
#include <iosfwd> // for size_t, std::stringstream
#include <memory> // for std::unique_ptr
#include <string> // for std::string
using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::util;
......@@ -48,72 +50,85 @@ namespace {
/// @brief Host identifier consisting of DUID or hardware address
typedef std::vector<uint8_t> HostIdentifier;
/// @brief Host identifier converted to Cassandra data type
typedef std::vector<cass_byte_t> CassHostIdentifier;
/// @brief Host identifier converted to Cassandra data type
typedef std::vector<cass_byte_t> CassOptionBuffer;
/// @brief key for HostMap containing objects which uniquely identify a
/// host: host identifier, host identifier type, subnets for IPv4 and IPv6
typedef boost::tuple<HostIdentifier,
Host::IdentifierType,
SubnetID,
SubnetID,
asiolink::IOAddress>
HostKey;
/// and the IPv4 reservation
typedef std::
tuple<HostIdentifier, Host::IdentifierType, SubnetID, SubnetID, IOAddress>
HostKey;
enum HostKeyComponent {
HOST_IDENTIFIER,
HOST_IDENTIFIER_TYPE,
IPv4_SUBNET_ID,
IPv6_SUBNET_ID,
IPv4_RESERVATION
};
/// @brief Map used to merge reservations and options into a single host on
/// retrieve from database
typedef boost::unordered_map<HostKey, HostPtr, boost::hash<HostKey> > HostMap;
typedef std::unordered_map<HostKey, HostPtr, boost::hash<HostKey>> HostMap;
typedef std::pair<HostKey, HostPtr> HostPair;
/// @brief Wrapper used to specify option space alongside option descriptor
struct OptionWrapper {
OptionWrapper(OptionDescriptorPtr option_descriptor,
std::string option_space)
: option_descriptor_(option_descriptor), option_space_(option_space) {
}
OptionDescriptorPtr option_descriptor_;
std::string option_space_;
};
/// @brief Maximum size of an IPv4 address represented as a text string. 12
/// digits plus 3 full stops (dots).
static const size_t ADDRESS4_TEXT_MAX_LENGTH = 15U;
static constexpr size_t ADDRESS4_TEXT_MAX_LENGTH = 15u;
/// @brief Maximum size of an IPv6 address represented as a text string. 32
/// hexadecimal characters written in 8 groups of four, plus 7 colon
/// separators.
static const size_t ADDRESS6_TEXT_MAX_LENGTH = 39U;
static constexpr size_t ADDRESS6_TEXT_MAX_LENGTH = 39u;
/// @brief Maximum length of classes stored in a host_ipv4/6_client_classes
/// column.
static const size_t CLIENT_CLASSES_MAX_LENGTH = 255U;
static constexpr size_t CLIENT_CLASSES_MAX_LENGTH = 255u;
/// @brief Maximum length of the hostname stored in DNS. This length is
/// restricted by the length of the domain-name carried in the Client FQDN
/// Option (see RFC4702 and RFC4704).
static const size_t HOSTNAME_MAX_LENGTH = 255U;
static constexpr size_t HOSTNAME_MAX_LENGTH = 255u;
/// @brief Maximum length of option value
static const size_t OPTION_VALUE_MAX_LENGTH = 4096U;
static constexpr size_t OPTION_VALUE_MAX_LENGTH = 4096u;
/// @brief Maximum length of option value specified in textual format
static const size_t OPTION_FORMATTED_VALUE_MAX_LENGTH = 8192U;
static constexpr size_t OPTION_FORMATTED_VALUE_MAX_LENGTH = 8192u;
/// @brief Maximum length of option space name
static const size_t OPTION_SPACE_MAX_LENGTH = 128U;
static constexpr size_t OPTION_SPACE_MAX_LENGTH = 128u;
/// @brief Numeric value representing the last supported identifier. This value
/// is used to validate whether the identifier type stored in a database is
/// within bounds of supported identifiers.
static const cass_int8_t MAX_IDENTIFIER_TYPE =
static_cast<cass_int8_t>(Host::IDENT_CIRCUIT_ID);
static constexpr cass_int32_t MAX_IDENTIFIER_TYPE =
static_cast<cass_int32_t>(Host::IDENT_CIRCUIT_ID);
/// @{
/// @brief Invalid values in the Cassandra database
static const char NULL_RESERVED_IPV6_PREFIX_ADDRESS[] = "";
static const cass_int32_t NULL_RESERVED_IPV6_PREFIX_LENGTH = 0;
static const cass_int32_t NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE = -1;
static const cass_int32_t NULL_IAID = -1;
static const cass_int32_t NULL_OPTION_UNIVERSE = -1;
static const cass_int32_t NULL_OPTION_CODE = -1;
static const CassOptionBuffer NULL_OPTION_VALUE = CassOptionBuffer();
static const char NULL_OPTION_FORMATTED_VALUE[] = "";
static const char NULL_OPTION_SPACE[] = "";
static const cass_bool_t NULL_OPTION_IS_PERSISTENT = cass_false;
static const char NULL_OPTION_CLIENT_CLASS[] = "";
static const cass_int32_t NULL_OPTION_SUBNET_ID = -1;
static constexpr char NULL_RESERVED_IPV6_PREFIX_ADDRESS[] = "::";
static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_LENGTH = 0;
static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE = -1;
static constexpr cass_int32_t NULL_IAID = -1;
static constexpr cass_int32_t NULL_OPTION_UNIVERSE = -1;
static constexpr cass_int32_t NULL_OPTION_CODE = -1;
static const CassBlob NULL_OPTION_VALUE = CassBlob();
static constexpr char NULL_OPTION_FORMATTED_VALUE[] = "";
static constexpr char NULL_OPTION_SPACE[] = "";
static constexpr cass_bool_t NULL_OPTION_IS_PERSISTENT = cass_false;
static constexpr char NULL_OPTION_CLIENT_CLASS[] = "";
static constexpr cass_int32_t NULL_OPTION_SUBNET_ID = -1;
// static constexpr CassCollection* NULL_COLLECTION = NULL;
/// @}
/// @brief Invalid reservation used to check for an invalid IPv6Resrv formed
......@@ -121,377 +136,19 @@ static const cass_int32_t NULL_OPTION_SUBNET_ID = -1;
static const IPv6Resrv NULL_IPV6_RESERVATION =
IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("::"), 128);
} // anonymous namespace
} // namespace
namespace isc {
namespace dhcp {
/// @{
/// @brief Statement parameters
// INSERT_HOST
static const char* INSERT_HOST_PARAMS[] = {
static_cast<const char*>("id"),
static_cast<const char*>("host_identifier"),
static_cast<const char*>("host_identifier_type"),
static_cast<const char*>("host_ipv4_subnet_id"),
static_cast<const char*>("host_ipv6_subnet_id"),
static_cast<const char*>("host_ipv4_address"),
static_cast<const char*>("hostname"),
static_cast<const char*>("host_ipv4_client_classes"),
static_cast<const char*>("host_ipv6_client_classes"),
static_cast<const char*>("reserved_ipv6_prefix_address"),
static_cast<const char*>("reserved_ipv6_prefix_length"),
static_cast<const char*>("reserved_ipv6_prefix_address_type"),
static_cast<const char*>("iaid"),
static_cast<const char*>("option_universe"),
static_cast<const char*>("option_code"),
static_cast<const char*>("option_value"),
static_cast<const char*>("option_formatted_value"),
static_cast<const char*>("option_space"),
static_cast<const char*>("option_is_persistent"),
static_cast<const char*>("option_client_class"),
static_cast<const char*>("option_subnet_id"),
NULL};
// GET_HOST_BY_HOST_ID
static const char* GET_HOST_BY_HOST_ID_PARAMS[] = {
static_cast<const char*>("host_identifier"),
static_cast<const char*>("host_identifier_type"),
NULL};
// GET_HOST_BY_IPV4_ADDRESS
static const char* GET_HOST_BY_IPV4_ADDRESS_PARAMS[] = {
static_cast<const char*>("host_ipv4_address"),
NULL};
// GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID
static const char* GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID_PARAMS[] = {
static_cast<const char*>("host_ipv4_subnet_id"),
static_cast<const char*>("host_identifier"),
static_cast<const char*>("host_identifier_type"),
NULL};
// GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID,
static const char* GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID_PARAMS[] = {
static_cast<const char*>("host_ipv6_subnet_id"),
static_cast<const char*>("host_identifier"),
static_cast<const char*>("host_identifier_type"),
NULL};
// GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS,
static const char* GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS_PARAMS[] = {
static_cast<const char*>("host_ipv4_subnet_id"),
static_cast<const char*>("host_ipv4_address"),
NULL};
// GET_HOST_BY_IPV6_PREFIX
static const char* GET_HOST_BY_IPV6_PREFIX_PARAMS[] = {
static_cast<const char*>("reserved_ipv6_prefix_address"),
static_cast<const char*>("reserved_ipv6_prefix_length"),
NULL};
// GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS
static const char* GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS_PARAMS[] = {
static_cast<const char*>("host_ipv6_subnet_id"),
static_cast<const char*>("reserved_ipv6_prefix_address"),
NULL};
// GET_VERSION
static const char* GET_VERSION_PARAMS[] = {NULL};
/// @}
/// @brief Prepared CQL statements used by the backend to insert and retrieve
/// hosts from the database.
static CqlTaggedStatement tagged_statements[] = {
// INSERT_HOST
{INSERT_HOST_PARAMS, "INSERT_HOST",
"INSERT INTO host_reservations ( "
"id, "
"host_identifier, "
"host_identifier_type, "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
"hostname, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"reserved_ipv6_prefix_length, "
"reserved_ipv6_prefix_address_type, "
"iaid, "
"option_universe, "
"option_code, "
"option_value, "
"option_formatted_value, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
"option_subnet_id "
") "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "
"IF NOT EXISTS "
},
// GET_HOST_BY_HOST_ID
{GET_HOST_BY_HOST_ID_PARAMS, "GET_HOST_BY_HOST_ID",
"SELECT "
"id, "
"host_identifier, "
"host_identifier_type, "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
"hostname, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"reserved_ipv6_prefix_length, "
"reserved_ipv6_prefix_address_type, "
"iaid, "
"option_universe, "
"option_code, "
"option_value, "
"option_formatted_value, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
"option_subnet_id "
"FROM host_reservations "
"WHERE host_identifier = ? "
"AND host_identifier_type = ? "
"ALLOW FILTERING "
},
// GET_HOST_BY_IPV4_ADDRESS
{GET_HOST_BY_IPV4_ADDRESS_PARAMS, "GET_HOST_BY_IPV4_ADDRESS",
"SELECT "
"id, "
"host_identifier, "
"host_identifier_type, "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
"hostname, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"reserved_ipv6_prefix_length, "
"reserved_ipv6_prefix_address_type, "
"iaid, "
"option_universe, "
"option_code, "
"option_value, "
"option_formatted_value, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
"option_subnet_id "
"FROM host_reservations "
"WHERE host_ipv4_address = ? "
"ALLOW FILTERING "
},
// GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID
{GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID_PARAMS,
"GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID",
"SELECT "
"id, "
"host_identifier, "
"host_identifier_type, "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
"hostname, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"reserved_ipv6_prefix_length, "
"reserved_ipv6_prefix_address_type, "
"iaid, "
"option_universe, "
"option_code, "
"option_value, "
"option_formatted_value, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
"option_subnet_id "
"FROM host_reservations "
"WHERE host_ipv4_subnet_id = ? "
"AND host_identifier = ? "
"AND host_identifier_type = ? "
"ALLOW FILTERING "
},
// GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID
{GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID_PARAMS,
"GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID",
"SELECT "
"id, "
"host_identifier, "
"host_identifier_type, "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
"hostname, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"reserved_ipv6_prefix_length, "
"reserved_ipv6_prefix_address_type, "
"iaid, "
"option_universe, "
"option_code, "
"option_value, "
"option_formatted_value, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
"option_subnet_id "
"FROM host_reservations "
"WHERE host_ipv6_subnet_id = ? "
"AND host_identifier = ? "
"AND host_identifier_type = ? "
"ALLOW FILTERING "
},
// GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS
{GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS_PARAMS,
"GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS",
"SELECT "
"id, "
"host_identifier, "
"host_identifier_type, "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
"hostname, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"reserved_ipv6_prefix_length, "
"reserved_ipv6_prefix_address_type, "
"iaid, "
"option_universe, "
"option_code, "
"option_value, "
"option_formatted_value, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
"option_subnet_id "
"FROM host_reservations "
"WHERE host_ipv4_subnet_id = ? "
"AND host_ipv4_address = ? "
"ALLOW FILTERING "
},
// GET_HOST_BY_IPV6_PREFIX
{GET_HOST_BY_IPV6_PREFIX_PARAMS, "GET_HOST_BY_IPV6_PREFIX",
"SELECT "
"id, "
"host_identifier, "
"host_identifier_type, "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
"hostname, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"reserved_ipv6_prefix_length, "
"reserved_ipv6_prefix_address_type, "
"iaid, "
"option_universe, "
"option_code, "
"option_value, "
"option_formatted_value, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
"option_subnet_id "
"FROM host_reservations "
"WHERE reserved_ipv6_prefix_address = ? "
"AND reserved_ipv6_prefix_length = ? "
"ALLOW FILTERING "
},
// GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS
{GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS_PARAMS,
"GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS",
"SELECT "
"id, "
"host_identifier, "
"host_identifier_type, "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
"hostname, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"reserved_ipv6_prefix_length, "
"reserved_ipv6_prefix_address_type, "
"iaid, "
"option_universe, "
"option_code, "
"option_value, "
"option_formatted_value, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
"option_subnet_id "
"FROM host_reservations "
"WHERE host_ipv6_subnet_id = ? "
"AND reserved_ipv6_prefix_address = ? "
"ALLOW FILTERING "
},
// GET_VERSION
{GET_VERSION_PARAMS, "GET_VERSION",
"SELECT version, minor FROM schema_version"},
// End of list sentinel
{NULL, NULL, NULL}}; // tagged_statements
/// @brief Provides mechanisms for sending and retrieving data from the
/// host_reservations table.
class CqlHostExchange : public virtual CqlExchange {
public:
/// @brief Statement Tags
///
/// The contents of the enum are indexes into the list of CQL statements
enum StatementIndex {
// Inserts all options belonging to any reservation from a single host.
INSERT_HOST,
// Retrieves host information, IPv6 reservations and both IPv4 and IPv6
// options associated with the host.
GET_HOST_BY_HOST_ID,
// Retrieves host information along with the IPv4 options associated
// with it.
GET_HOST_BY_IPV4_ADDRESS,
// Retrieves host information and IPv4 options using subnet identifier
// and client's identifier (i.e. hardware address or DUID).
GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID,
// Retrieves host information, IPv6 reservations and IPv6 options
// associated with a host using subnet identifier and client's
// identifier (i.e. hardware address or DUID).
GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID,
// Retrieves host information and IPv4 options for the host using subnet
// identifier and IPv4 reservation.
GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS,
// Retrieves host information, IPv6 reservations and IPv6 options
// associated with a host using prefix and prefix length. This query
// returns host information for a single host. However, multiple rows
// are returned due to left joining IPv6 reservations and IPv6 options.
// The number of rows returned is multiplication of number of existing
// IPv6 reservations and IPv6 options.
GET_HOST_BY_IPV6_PREFIX,
// Retrieves host information and IPv6 options for the host using subnet
// identifier and IPv6 reservation.
GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS,
// Get CQL schema version.
GET_VERSION,
// Number of statements
NUM_STATEMENTS
};
/// @brief Constructor
///
/// Specifies table columns.
CqlHostExchange();
CqlHostExchange(CqlConnection& connection);
/// @brief Virtual destructor.
virtual ~CqlHostExchange();
......@@ -501,13 +158,14 @@ public:
/// Creates a bind array to receive @ref Host data from the Cassandra
/// database. After data is successfully received, @ref retrieve() can be
/// called to retrieve the @ref Host object. Called in @ref
/// CqlExchange::executeRead().
/// CqlExchange::executeSelect().
///
/// @param data array of objects representing data being retrieved
/// @param statement_index prepared statement being executed; defaults to an
/// @param statement_tag prepared statement being executed; defaults to an
/// invalid statement
virtual void createBindForReceive(CqlDataArray& data,
const int statement_index = -1);
virtual void
createBindForSelect(AnyArray& data,
StatementTag statement_tag = NULL) override;
/// @brief Binds @ref Host to data array to send data to the Cassandra
/// database.
......@@ -521,12 +179,14 @@ public:
/// @param option_space option space
/// @param option_descriptor structure used to hold option information
/// @param data array being filled with data from to the Host object
void createBindForSend(const HostPtr& host,
const OptionalValue<SubnetID>& subnet_id,
const IPv6Resrv* const reservation,
const std::string& option_space,
const OptionDescriptor& option_descriptor,
CqlDataArray& data);
/// @param statement_tag tag of the statement being executed
void createBindForMutation(const HostPtr& host,
const OptionalValue<SubnetID>& subnet_id,
const IPv6Resrv* const reservation,
const std::string& option_space,
const OptionDescriptor& option_descriptor,
StatementTag statement_tag,
AnyArray& data);
/// @brief Create unique hash for storage in table id.
///
......@@ -542,34 +202,85 @@ public:
/// @brief Copy received data into Host object
///
/// Copies information about the host into a newly created @ref Host object
/// Called in @ref executeRead after @ref createBindForReceive().
/// Called in @ref executeSelect after @ref createBindForSelect().
///
/// @return Host Pointer to a @ref HostPtr object holding a pointer to the
/// @ref Host object returned.
virtual void* retrieve();
virtual boost::any retrieve() override;
/// @brief Creates IPv6 reservation from the data contained in the
/// currently processed row.
/// currently processed row.
///
/// Called after createBindForReceive().
/// Called after createBindForSelect().
///
/// @return IPv6Resrv object (containing IPv6 address or prefix reservation)
const IPv6Resrv retrieveReservation() const;
/// @brief Retrieves option from members.
OptionDescriptorPtr retrieveOption() const;
///
/// Called after createBindForSelect().
///
/// @return OptionDescriptorPtr object (containing the option from the
/// database)
const OptionWrapper retrieveOption() const;
/// @brief Statement tags definitions
/// @{
// Inserts all options belonging to any reservation from a single host.
static constexpr StatementTag INSERT_HOST = "INSERT_HOST";
// Retrieves host information, IPv6 reservations and both IPv4 and IPv6
// options associated with the host.
static constexpr StatementTag GET_HOST_BY_HOST_ID = "GET_HOST_BY_HOST_ID";
// Retrieves host information along with the IPv4 options associated
// with it.
static constexpr StatementTag GET_HOST_BY_IPV4_ADDRESS =
"GET_HOST_BY_IPV4_ADDRESS";
// Retrieves host information and IPv4 options using subnet identifier
// and client's identifier (i.e. hardware address or DUID).
static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID =
"GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID";