mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 05:55:28 +00:00
[4277] Bare bones implementation of PgSqlHostDataSource
src/lib/dhcpsrv pgsql_host_data_source.c pgsql_host_data_source.h - new files, preliminary implementation src/lib/dhcpsrv/Makefile.am Added new files pgsql_host_data_source.cc, pgsql_host_data_source.h src/lib/dhcpsrv/dhcpsrv_messages.mes Added log messages DHCPSRV_PGSQL_HOST_DB_GET_VERSION, DHCPSRV_PGSQL_START_TRANSACTION src/lib/dhcpsrv/pgsql_connection.cc src/lib/dhcpsrv/pgsql_connection.h Added PgSqlTransaction Added PgSqlConnection::startTransaction() src/lib/dhcpsrv/pgsql_exchange.cc src/lib/dhcpsrv/pgsql_exchange.h PsqlBindArray - Added storage of conversion strings used for bound values - Added add() variants for uint8_t, IOAddress, uint8_t buffer - Added templated variant for miscellaneous types PgSqlExchange - Removed getColumnValue variants for various integers, replaced with templated version for miscellaneous types src/lib/dhcpsrv/pgsql_lease_mgr.cc Added todo comment to remember to account for hwaddr columns added to lease6 src/lib/dhcpsrv/tests/pgsql_exchange_unittest.cc TEST(PsqlBindArray, basicOperation) - new test to exercise bind functions
This commit is contained in:
@@ -136,6 +136,7 @@ libkea_dhcpsrv_la_SOURCES += ncr_generator.cc ncr_generator.h
|
||||
if HAVE_PGSQL
|
||||
libkea_dhcpsrv_la_SOURCES += pgsql_connection.cc pgsql_connection.h
|
||||
libkea_dhcpsrv_la_SOURCES += pgsql_exchange.cc pgsql_exchange.h
|
||||
libkea_dhcpsrv_la_SOURCES += pgsql_host_data_source.cc pgsql_host_data_source.h
|
||||
libkea_dhcpsrv_la_SOURCES += pgsql_lease_mgr.cc pgsql_lease_mgr.h
|
||||
endif
|
||||
libkea_dhcpsrv_la_SOURCES += pool.cc pool.h
|
||||
|
@@ -634,6 +634,10 @@ An error message indicating that communication with the MySQL database server
|
||||
has been lost. When this occurs the server exits immediately with a non-zero
|
||||
exit code. This is most likely due to a network issue.
|
||||
|
||||
% DHCPSRV_PGSQL_HOST_DB_GET_VERSION obtaining schema version information for the PostgreSQL hosts database
|
||||
A debug message issued when the server is about to obtain schema version
|
||||
information from the PostgreSQL hosts database.
|
||||
|
||||
% DHCPSRV_PGSQL_GET_ADDR4 obtaining IPv4 lease for address %1
|
||||
A debug message issued when the server is attempting to obtain an IPv4
|
||||
lease from the PostgreSQL database for the specified address.
|
||||
@@ -696,6 +700,15 @@ connection including database name and username needed to access it
|
||||
The code has issued a rollback call. All outstanding transaction will
|
||||
be rolled back and not committed to the database.
|
||||
|
||||
% DHCPSRV_PGSQL_START_TRANSACTION starting a new PostgreSQL transaction
|
||||
A debug message issued when a new PostgreSQL transaction is being started.
|
||||
This message is typically not issued when inserting data into a
|
||||
single table because the server doesn't explicitly start
|
||||
transactions in this case. This message is issued when data is
|
||||
inserted into multiple tables with multiple INSERT statements
|
||||
and there may be a need to rollback the whole transaction if
|
||||
any of these INSERT statements fail.
|
||||
|
||||
% DHCPSRV_PGSQL_UPDATE_ADDR4 updating IPv4 lease for address %1
|
||||
A debug message issued when the server is attempting to update IPv4
|
||||
lease from the PostgreSQL database for the specified address.
|
||||
|
@@ -35,6 +35,25 @@ const int PGSQL_DEFAULT_CONNECTION_TIMEOUT = 5; // seconds
|
||||
|
||||
const char PgSqlConnection::DUPLICATE_KEY[] = ERRCODE_UNIQUE_VIOLATION;
|
||||
|
||||
PgSqlTransaction::PgSqlTransaction(PgSqlConnection& conn)
|
||||
: conn_(conn), committed_(false) {
|
||||
conn_.startTransaction();
|
||||
}
|
||||
|
||||
PgSqlTransaction::~PgSqlTransaction() {
|
||||
// Rollback if the PgSqlTransaction::commit wasn't explicitly
|
||||
// called.
|
||||
if (!committed_) {
|
||||
conn_.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PgSqlTransaction::commit() {
|
||||
conn_.commit();
|
||||
committed_ = true;
|
||||
}
|
||||
|
||||
PgSqlConnection::~PgSqlConnection() {
|
||||
if (conn_) {
|
||||
// Deallocate the prepared queries.
|
||||
@@ -192,6 +211,18 @@ PgSqlConnection::checkStatementError(const PgSqlResult& r,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PgSqlConnection::startTransaction() {
|
||||
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
||||
DHCPSRV_PGSQL_START_TRANSACTION);
|
||||
PgSqlResult r(PQexec(conn_, "START TRANSACTION"));
|
||||
if (PQresultStatus(r) != PGRES_COMMAND_OK) {
|
||||
const char* error_message = PQerrorMessage(conn_);
|
||||
isc_throw(DbOperationError, "unable to start transaction"
|
||||
<< error_message);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PgSqlConnection::commit() {
|
||||
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_COMMIT);
|
||||
|
@@ -53,6 +53,7 @@ const size_t OID_NONE = 0; // PostgreSQL infers proper type
|
||||
const size_t OID_BOOL = 16;
|
||||
const size_t OID_BYTEA = 17;
|
||||
const size_t OID_INT8 = 20; // 8 byte int
|
||||
const size_t OID_INT4 = 23; // 4 byte int
|
||||
const size_t OID_INT2 = 21; // 2 byte int
|
||||
const size_t OID_TIMESTAMP = 1114;
|
||||
const size_t OID_VARCHAR = 1043;
|
||||
@@ -176,6 +177,62 @@ private:
|
||||
PGconn* pgconn_; ///< Postgresql connection
|
||||
};
|
||||
|
||||
/// @brief Forward declaration to @ref PgSqlConnection.
|
||||
class PgSqlConnection;
|
||||
|
||||
/// @brief RAII object representing PostgreSQL transaction.
|
||||
///
|
||||
/// An instance of this class should be created in a scope where multiple
|
||||
/// INSERT statements should be executed within a single transaction. The
|
||||
/// transaction is started when the constructor of this class is invoked.
|
||||
/// The transaction is ended when the @ref PgSqlTransaction::commit is
|
||||
/// explicitly called or when the instance of this class is destroyed.
|
||||
/// The @ref PgSqlTransaction::commit commits changes to the database
|
||||
/// and the changes remain in the database when the instance of the
|
||||
/// class is destroyed. If the class instance is destroyed before the
|
||||
/// @ref PgSqlTransaction::commit is called, the transaction is rolled
|
||||
/// back. The rollback on destruction guarantees that partial data is
|
||||
/// not stored in the database when there is an error during any
|
||||
/// of the operations belonging to a transaction.
|
||||
///
|
||||
/// The default PostgreSQL backend configuration enables 'autocommit'.
|
||||
/// Starting a transaction overrides 'autocommit' setting for this
|
||||
/// particular transaction only. It does not affect the global 'autocommit'
|
||||
/// setting for the database connection, i.e. all modifications to the
|
||||
/// database which don't use transactions will still be auto committed.
|
||||
class PgSqlTransaction : public boost::noncopyable {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// Starts transaction by making a "START TRANSACTION" query.
|
||||
///
|
||||
/// @param conn PostgreSQL connection to use for the transaction. This
|
||||
/// connection will be later used to commit or rollback changes.
|
||||
///
|
||||
/// @throw DbOperationError if "START TRANSACTION" query fails.
|
||||
PgSqlTransaction(PgSqlConnection& conn);
|
||||
|
||||
/// @brief Destructor.
|
||||
///
|
||||
/// Rolls back the transaction if changes haven't been committed.
|
||||
~PgSqlTransaction();
|
||||
|
||||
/// @brief Commits transaction.
|
||||
void commit();
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Holds reference to the PostgreSQL database connection.
|
||||
PgSqlConnection& conn_;
|
||||
|
||||
/// @brief Boolean flag indicating if the transaction has been committed.
|
||||
///
|
||||
/// This flag is used in the class destructor to assess if the
|
||||
/// transaction should be rolled back.
|
||||
bool committed_;
|
||||
};
|
||||
|
||||
/// @brief Common PgSql Connector Pool
|
||||
///
|
||||
/// This class provides common operations for PgSql database connection
|
||||
@@ -218,18 +275,23 @@ public:
|
||||
/// @throw DbOpenError Error opening the database
|
||||
void openDatabase();
|
||||
|
||||
/// @brief Start a transaction
|
||||
///
|
||||
/// Starts a transaction.
|
||||
///
|
||||
/// @throw DbOperationError If the transaction start failed.
|
||||
void startTransaction();
|
||||
|
||||
/// @brief Commit Transactions
|
||||
///
|
||||
/// Commits all pending database operations. On databases that don't
|
||||
/// support transactions, this is a no-op.
|
||||
/// Commits all pending database operations.
|
||||
///
|
||||
/// @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.
|
||||
/// Rolls back all pending database operations.
|
||||
///
|
||||
/// @throw DbOperationError If the rollback failed.
|
||||
void rollback();
|
||||
|
@@ -38,10 +38,38 @@ void PsqlBindArray::add(const std::vector<uint8_t>& data) {
|
||||
formats_.push_back(BINARY_FMT);
|
||||
}
|
||||
|
||||
void PsqlBindArray::add(const uint8_t* data, const size_t len) {
|
||||
values_.push_back(reinterpret_cast<const char*>(&(data[0])));
|
||||
lengths_.push_back(len);
|
||||
formats_.push_back(BINARY_FMT);
|
||||
}
|
||||
|
||||
void PsqlBindArray::add(const bool& value) {
|
||||
add(value ? TRUE_STR : FALSE_STR);
|
||||
}
|
||||
|
||||
void PsqlBindArray::add(const uint8_t& byte) {
|
||||
// We static_cast to an unsigned int, otherwise lexcial_cast may to
|
||||
// treat byte as a character, which yields "" for unprintable values
|
||||
bindString(boost::lexical_cast<std::string>
|
||||
(static_cast<unsigned int>(byte)));
|
||||
}
|
||||
|
||||
void PsqlBindArray::add(const isc::asiolink::IOAddress& addr) {
|
||||
if (addr.isV4()) {
|
||||
bindString(boost::lexical_cast<std::string>
|
||||
(static_cast<uint32_t>(addr)));
|
||||
} else {
|
||||
bindString(addr.toText());
|
||||
}
|
||||
}
|
||||
|
||||
// eventually this should replace add(std::string)
|
||||
void PsqlBindArray::bindString(const std::string& str) {
|
||||
bound_strs_.push_back(StringPtr(new std::string(str)));
|
||||
PsqlBindArray::add((bound_strs_.back())->c_str());
|
||||
}
|
||||
|
||||
std::string PsqlBindArray::toText() const {
|
||||
std::ostringstream stream;
|
||||
for (int i = 0; i < values_.size(); ++i) {
|
||||
@@ -135,32 +163,6 @@ PgSqlExchange::getColumnValue(const PgSqlResult& r, const int row,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PgSqlExchange::getColumnValue(const PgSqlResult& r, const int row,
|
||||
const size_t col, uint32_t &value) const {
|
||||
const char* data = getRawColumnValue(r, row, col);
|
||||
try {
|
||||
value = boost::lexical_cast<uint32_t>(data);
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(DbOperationError, "Invalid uint32_t data: " << data
|
||||
<< " for: " << getColumnLabel(col) << " row:" << row
|
||||
<< " : " << ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PgSqlExchange::getColumnValue(const PgSqlResult& r, const int row,
|
||||
const size_t col, int32_t &value) const {
|
||||
const char* data = getRawColumnValue(r, row, col);
|
||||
try {
|
||||
value = boost::lexical_cast<int32_t>(data);
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(DbOperationError, "Invalid int32_t data: " << data
|
||||
<< " for: " << getColumnLabel(col) << " row:" << row
|
||||
<< " : " << ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PgSqlExchange::getColumnValue(const PgSqlResult& r, const int row,
|
||||
const size_t col, uint8_t &value) const {
|
||||
|
@@ -7,10 +7,16 @@
|
||||
#ifndef PGSQL_EXCHANGE_H
|
||||
#define PGSQL_EXCHANGE_H
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcpsrv/pgsql_connection.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
@@ -24,6 +30,11 @@ namespace dhcp {
|
||||
/// be valid for the duration of the PostgreSQL statement execution. In other
|
||||
/// words populating them with pointers to values that go out of scope before
|
||||
/// statement is executed is a bad idea.
|
||||
|
||||
/// @brief smart pointer to strings used by PsqlBindArray to ensure scope
|
||||
/// of strings supplying exchange values
|
||||
typedef boost::shared_ptr<std::string> StringPtr;
|
||||
|
||||
struct PsqlBindArray {
|
||||
/// @brief Vector of pointers to the data values.
|
||||
std::vector<const char *> values_;
|
||||
@@ -74,14 +85,27 @@ struct PsqlBindArray {
|
||||
/// @param value std::string containing the value to add.
|
||||
void add(const std::string& value);
|
||||
|
||||
/// @brief Adds a binary value to the bind array.
|
||||
/// @brief Adds a vector of binary data to the bind array.
|
||||
///
|
||||
/// Adds a BINARY_FMT value to the end of the bind array using the
|
||||
/// given vector as the data source.
|
||||
/// given vector as the data source. NOTE this does not replicate
|
||||
/// the vector, so it must remain in scope until the bind array
|
||||
/// is destroyed.
|
||||
///
|
||||
/// @param data vector of binary bytes.
|
||||
void add(const std::vector<uint8_t>& data);
|
||||
|
||||
/// @brief Adds a buffer of binary data to the bind array.
|
||||
///
|
||||
/// Adds a BINARY_FMT value to the end of the bind array using the
|
||||
/// given vector as the data source. NOTE this does not replicate
|
||||
/// the buffer, so it must remain in scope until the bind array
|
||||
/// is destroyed.
|
||||
///
|
||||
/// @param data buffer of binary data.
|
||||
/// @param len number of bytes of data in buffer
|
||||
void add(const uint8_t* data, const size_t len);
|
||||
|
||||
/// @brief Adds a boolean value to the bind array.
|
||||
///
|
||||
/// Converts the given boolean value to its corresponding to PostgreSQL
|
||||
@@ -90,11 +114,62 @@ struct PsqlBindArray {
|
||||
/// @param value bool value to add.
|
||||
void add(const bool& value);
|
||||
|
||||
/// @brief Adds a uint8_t value to the bind array.
|
||||
///
|
||||
/// Converts the given uint8_t value to its corresponding numeric string
|
||||
/// literal and adds it as a TEXT_FMT value to the bind array.
|
||||
///
|
||||
/// @param value bool value to add.
|
||||
void add(const uint8_t& byte);
|
||||
|
||||
/// @brief Adds a the given IOAddress value to the bind array.
|
||||
///
|
||||
/// Converts the IOAddress, based on its protocol family, to the
|
||||
/// corresponding string literal and adds it as a TEXT_FMT value to
|
||||
/// the bind array.
|
||||
///
|
||||
/// @param value bool value to add.
|
||||
void add(const isc::asiolink::IOAddress& addr);
|
||||
|
||||
/// @brief Adds a the given value to the bind array.
|
||||
///
|
||||
/// Converts the given value its corresponding string literal
|
||||
/// boost::lexical_cast and adds it as a TEXT_FMT value to the bind array.
|
||||
///
|
||||
/// @param value bool value to add.
|
||||
template<typename T>
|
||||
void add(const T& numeric) {
|
||||
bindString(boost::lexical_cast<std::string>(numeric));
|
||||
}
|
||||
|
||||
/// @brief Binds a the given string to the bind array.
|
||||
///
|
||||
/// Prior to added the The given string the vector of exchange values,
|
||||
/// it duplicated as a StringPtr and saved internally. This garauntees
|
||||
/// the string remains in scope until the PsqlBindArray is destroyed,
|
||||
/// without the caller maintaining the string values.
|
||||
///
|
||||
/// @param value bool value to add.
|
||||
void bindString(const std::string& str);
|
||||
|
||||
//std::vector<const std::string> getBoundStrs() {
|
||||
std::vector<StringPtr> getBoundStrs() {
|
||||
return (bound_strs_);
|
||||
}
|
||||
|
||||
/// @brief Dumps the contents of the array to a string.
|
||||
/// @return std::string containing the dump
|
||||
std::string toText() const;
|
||||
|
||||
private:
|
||||
/// @brief vector of strings which supplied the values
|
||||
std::vector<StringPtr> bound_strs_;
|
||||
|
||||
};
|
||||
|
||||
/// @brief Defines a smart pointer to PsqlBindArray
|
||||
typedef boost::shared_ptr<PsqlBindArray> PsqlBindArrayPtr;
|
||||
|
||||
/// @brief Base class for marshalling data to and from PostgreSQL.
|
||||
///
|
||||
/// Provides the common functionality to set up binding information between
|
||||
@@ -179,30 +254,6 @@ public:
|
||||
void getColumnValue(const PgSqlResult& r, const int row, const size_t col,
|
||||
bool &value) const;
|
||||
|
||||
/// @brief Fetches an integer text column as a uint32_t.
|
||||
///
|
||||
/// @param r the result set containing the query results
|
||||
/// @param row the row number within the result set
|
||||
/// @param col the column number within the row
|
||||
/// @param[out] value parameter to receive the converted value
|
||||
///
|
||||
/// @throw DbOperationError if the value cannot be fetched or is
|
||||
/// invalid.
|
||||
void getColumnValue(const PgSqlResult& r, const int row, const size_t col,
|
||||
uint32_t &value) const;
|
||||
|
||||
/// @brief Fetches an integer text column as a int32_t.
|
||||
///
|
||||
/// @param r the result set containing the query results
|
||||
/// @param row the row number within the result set
|
||||
/// @param col the column number within the row
|
||||
/// @param[out] value parameter to receive the converted value
|
||||
///
|
||||
/// @throw DbOperationError if the value cannot be fetched or is
|
||||
/// invalid.
|
||||
void getColumnValue(const PgSqlResult& r, const int row, const size_t col,
|
||||
int32_t &value) const;
|
||||
|
||||
/// @brief Fetches an integer text column as a uint8_t.
|
||||
///
|
||||
/// @param r the result set containing the query results
|
||||
@@ -215,6 +266,31 @@ public:
|
||||
void getColumnValue(const PgSqlResult& r, const int row, const size_t col,
|
||||
uint8_t &value) const;
|
||||
|
||||
/// @brief Fetches a text column as the given value type
|
||||
///
|
||||
/// Uses boost::lexicalcast to convert the text column value into
|
||||
/// a value of type T.
|
||||
///
|
||||
/// @param r the result set containing the query results
|
||||
/// @param row the row number within the result set
|
||||
/// @param col the column number within the row
|
||||
/// @param[out] value parameter to receive the converted value
|
||||
///
|
||||
/// @throw DbOperationError if the value cannot be fetched or is
|
||||
/// invalid.
|
||||
template<typename T>
|
||||
void getColumnValue(const PgSqlResult& r, const int row, const size_t col,
|
||||
T& value) const {
|
||||
const char* data = getRawColumnValue(r, row, col);
|
||||
try {
|
||||
value = boost::lexical_cast<T>(data);
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(DbOperationError, "Invalid data: " << data
|
||||
<< " for: " << getColumnLabel(col) << " row:" << row
|
||||
<< " : " << ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Converts a column in a row in a result set to a binary bytes
|
||||
///
|
||||
/// Method is used to convert columns stored as BYTEA into a buffer of
|
||||
|
2220
src/lib/dhcpsrv/pgsql_host_data_source.cc
Normal file
2220
src/lib/dhcpsrv/pgsql_host_data_source.cc
Normal file
File diff suppressed because it is too large
Load Diff
255
src/lib/dhcpsrv/pgsql_host_data_source.h
Normal file
255
src/lib/dhcpsrv/pgsql_host_data_source.h
Normal file
@@ -0,0 +1,255 @@
|
||||
// Copyright (C) 2016 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 PGSQL_HOST_DATA_SOURCE_H
|
||||
#define PGSQL_HOST_DATA_SOURCE_H
|
||||
|
||||
#include <dhcpsrv/base_host_data_source.h>
|
||||
#include <dhcpsrv/pgsql_connection.h>
|
||||
#include <dhcpsrv/pgsql_exchange.h>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// Forward declaration to the implementation of the @ref PgSqlHostDataSource.
|
||||
class PgSqlHostDataSourceImpl;
|
||||
|
||||
/// @brief PostgreSQL Host Data Source
|
||||
///
|
||||
/// This class implements the @ref isc::dhcp::BaseHostDataSource interface to
|
||||
/// the PostgreSQL database. Use of this backend presupposes that a PostgreSQL
|
||||
/// database is available and that the Kea schema has been created within it.
|
||||
class PgSqlHostDataSource: public BaseHostDataSource {
|
||||
public:
|
||||
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// Uses the following keywords in the parameters passed to it to
|
||||
/// connect to the database:
|
||||
/// - name - Name of the database to which to connect (mandatory)
|
||||
/// - host - Host to which to connect (optional, defaults to "localhost")
|
||||
/// - user - Username under which to connect (optional)
|
||||
/// - password - Password for "user" on the database (optional)
|
||||
///
|
||||
/// If the database is successfully opened, the version number in the
|
||||
/// schema_version table will be checked against hard-coded value in
|
||||
/// the implementation file.
|
||||
///
|
||||
/// Finally, all the SQL commands are pre-compiled.
|
||||
///
|
||||
/// @param parameters A data structure relating keywords and values
|
||||
/// concerned with the database.
|
||||
///
|
||||
/// @throw isc::dhcp::NoDatabaseName Mandatory database name not given
|
||||
/// @throw isc::dhcp::DbOpenError Error opening the database
|
||||
/// @throw isc::dhcp::DbOperationError An operation on the open database has
|
||||
/// failed.
|
||||
PgSqlHostDataSource(const DatabaseConnection::ParameterMap& parameters);
|
||||
|
||||
/// @brief Virtual destructor.
|
||||
///
|
||||
/// Releases prepared MySQL statements used by the backend.
|
||||
virtual ~PgSqlHostDataSource();
|
||||
|
||||
/// @brief Return all hosts for the specified HW address or DUID.
|
||||
///
|
||||
/// This method returns all @c Host objects which represent reservations
|
||||
/// for the specified HW address or DUID. Note, that this method may
|
||||
/// return multiple reservations because a particular client may have
|
||||
/// reservations in multiple subnets and the same client may be identified
|
||||
/// by HW address or DUID. The server is unable to verify that the specific
|
||||
/// DUID and HW address belong to the same client, until the client sends
|
||||
/// a DHCP message.
|
||||
///
|
||||
/// Specifying both hardware address and DUID is allowed for this method
|
||||
/// and results in returning all objects that are associated with hardware
|
||||
/// address OR duid. For example: if one host is associated with the
|
||||
/// specified hardware address and another host is associated with the
|
||||
/// specified DUID, two hosts will be returned.
|
||||
///
|
||||
/// @param hwaddr HW address of the client or NULL if no HW address
|
||||
/// available.
|
||||
/// @param duid client id or NULL if not available, e.g. DHCPv4 client case.
|
||||
///
|
||||
/// @return Collection of const @c Host objects.
|
||||
virtual ConstHostCollection
|
||||
getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid = DuidPtr()) const;
|
||||
|
||||
/// @brief Return all hosts connected to any subnet for which reservations
|
||||
/// have been made using a specified identifier.
|
||||
///
|
||||
/// This method returns all @c Host objects which represent reservations
|
||||
/// for a specified identifier. This method may return multiple hosts
|
||||
/// because a particular client may have reservations in multiple subnets.
|
||||
///
|
||||
/// @param identifier_type Identifier type.
|
||||
/// @param identifier_begin Pointer to a begining of a buffer containing
|
||||
/// an identifier.
|
||||
/// @param identifier_len Identifier length.
|
||||
///
|
||||
/// @return Collection of const @c Host objects.
|
||||
virtual ConstHostCollection
|
||||
getAll(const Host::IdentifierType& identifier_type,
|
||||
const uint8_t* identifier_begin, const size_t identifier_len) 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 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.
|
||||
///
|
||||
/// @param subnet_id Subnet identifier.
|
||||
/// @param identifier_type Identifier type.
|
||||
/// @param identifier_begin Pointer to a begining of a buffer containing
|
||||
/// an identifier.
|
||||
/// @param identifier_len Identifier length.
|
||||
///
|
||||
/// @return Const @c Host object for which reservation has been made using
|
||||
/// the specified identifier.
|
||||
virtual ConstHostPtr
|
||||
get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
|
||||
const uint8_t* identifier_begin, const size_t identifier_len) 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 connected to the IPv6 subnet.
|
||||
///
|
||||
/// @param subnet_id Subnet identifier.
|
||||
/// @param identifier_type Identifier type.
|
||||
/// @param identifier_begin Pointer to a begining of a buffer containing
|
||||
/// an identifier.
|
||||
/// @param identifier_len Identifier length.
|
||||
///
|
||||
/// @return Const @c Host object for which reservation has been made using
|
||||
/// the specified identifier.
|
||||
virtual ConstHostPtr
|
||||
get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
|
||||
const uint8_t* identifier_begin, const size_t identifier_len) 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 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
|
||||
/// 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.
|
||||
///
|
||||
/// @return "mysql".
|
||||
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;
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Pointer to the implementation of the @ref PgSqlHostDataSource.
|
||||
PgSqlHostDataSourceImpl* impl_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PGSQL_HOST_DATA_SOURCE_H
|
@@ -26,6 +26,8 @@ using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
/// @todo TKM lease6 needs to accomodate hwaddr,hwtype, and hwaddr source columns
|
||||
|
||||
/// @brief Catalog of all the SQL statements currently supported. Note
|
||||
/// that the order columns appear in statement body must match the order they
|
||||
/// that the occur in the table. This does not apply to the where clause.
|
||||
|
@@ -69,5 +69,48 @@ TEST(PgSqlExchangeTest, convertTimeTest) {
|
||||
EXPECT_EQ(ref_time, from_time);
|
||||
}
|
||||
|
||||
TEST(PsqlBindArray, basicOperation) {
|
||||
|
||||
PsqlBindArray b;
|
||||
|
||||
uint8_t small_int = 25;
|
||||
b.add(small_int);
|
||||
|
||||
int reg_int = 376;
|
||||
b.add(reg_int);
|
||||
|
||||
uint64_t big_int = 86749032;
|
||||
b.add(big_int);
|
||||
|
||||
b.add((bool)(1));
|
||||
b.add((bool)(0));
|
||||
|
||||
b.add(isc::asiolink::IOAddress("192.2.15.34"));
|
||||
b.add(isc::asiolink::IOAddress("3001::1"));
|
||||
|
||||
std::string str("just a string");
|
||||
b.add(str);
|
||||
|
||||
std::vector<uint8_t> bytes;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
bytes.push_back(i+1);
|
||||
}
|
||||
|
||||
b.add(bytes);
|
||||
|
||||
std::string expected =
|
||||
"0 : \"25\"\n"
|
||||
"1 : \"376\"\n"
|
||||
"2 : \"86749032\"\n"
|
||||
"3 : \"TRUE\"\n"
|
||||
"4 : \"FALSE\"\n"
|
||||
"5 : \"3221360418\"\n"
|
||||
"6 : \"3001::1\"\n"
|
||||
"7 : \"just a string\"\n"
|
||||
"8 : 0x010203040506070809\n";
|
||||
|
||||
EXPECT_EQ(expected, b.toText());
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
|
Reference in New Issue
Block a user