#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
+#include <boost/array.hpp>
#include <boost/pointer_cast.hpp>
#include <boost/static_assert.hpp>
/// @brief Maximum length of option value.
/// The maximum size of the raw option data that may be read from the
-/// database.
+/// database.
const size_t OPTION_VALUE_MAX_LEN = 4096;
/// @brief Numeric value representing last supported identifier.
///
/// The contents of the enum are indexes into the list of SQL statements
enum StatementIndex {
- INSERT_HOST, // Insert new host to collection
- INSERT_V6_RESRV, // Insert v6 reservation
- INSERT_V4_HOST_OPTION, // Insert DHCPv4 option
- INSERT_V6_HOST_OPTION, // Insert DHCPv6 option
GET_HOST_DHCPID, // Gets hosts by host identifier
GET_HOST_ADDR, // Gets hosts by IPv4 address
GET_HOST_SUBID4_DHCPID, // Gets host by IPv4 SubnetID, HW address/DUID
GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address
GET_HOST_PREFIX, // Gets host by IPv6 prefix
GET_VERSION, // Obtain version number
+ INSERT_HOST, // Insert new host to collection
+ INSERT_V6_RESRV, // Insert v6 reservation
+ INSERT_V4_HOST_OPTION, // Insert DHCPv4 option
+ INSERT_V6_HOST_OPTION, // Insert DHCPv6 option
NUM_STATEMENTS // Number of statements
};
+ /// @brief Index of first statement performing write to the database.
+ ///
+ /// This value is used to mark border line between queries and other
+ /// statements and statements performing write operation on the database,
+ /// such as INSERT, DELETE, UPDATE.
+ static const StatementIndex WRITE_STMTS_BEGIN = INSERT_HOST;
+
/// @brief Constructor.
///
/// This constructor opens database connection and initializes prepared
/// @brief MySQL connection
PgSqlConnection conn_;
+ /// @brief Indicates if the database is opened in read only mode.
+ bool is_readonly_;
};
namespace {
+/// @brief Array of tagged statements.
+typedef boost::array<PgSqlTaggedStatement, PgSqlHostDataSourceImpl::NUM_STATEMENTS>
+TaggedStatementArray;
+
/// @brief Prepared PosgreSQL statements used by the backend to insert and
/// retrieve reservation data from the database.
-PgSqlTaggedStatement tagged_statements[] = {
- // PgSqlHostDataSourceImpl::INSERT_HOST
- // Inserts a host into the 'hosts' table. Returns the inserted host id.
- {8,
- { OID_BYTEA, OID_INT2,
- OID_INT4, OID_INT4, OID_INT8, OID_VARCHAR,
- OID_VARCHAR, OID_VARCHAR },
- "insert_host",
- "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
- " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
- " dhcp4_client_classes, dhcp6_client_classes) "
- "VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING host_id"
- },
-
- //PgSqlHostDataSourceImpl::INSERT_V6_RESRV
- // Inserts a single IPv6 reservation into 'reservations' table.
- {5,
- { OID_VARCHAR, OID_INT2, OID_INT4, OID_INT4, OID_INT4 },
- "insert_v6_resrv",
- "INSERT INTO ipv6_reservations(address, prefix_len, type, "
- " dhcp6_iaid, host_id) "
- "VALUES ($1, $2, $3, $4, $5)"
- },
-
- // PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION
- // Inserts a single DHCPv4 option into 'dhcp4_options' table.
- // Using fixed scope_id = 3, which associates an option with host.
- {6,
- { OID_INT2, OID_BYTEA, OID_TEXT,
- OID_VARCHAR, OID_BOOL, OID_INT8},
- "insert_v4_host_option",
- "INSERT INTO dhcp4_options(code, value, formatted_value, space, "
- " persistent, host_id, scope_id) "
- "VALUES ($1, $2, $3, $4, $5, $6, 3)"
- },
-
- // PgSqlHostDataSourceImpl::INSERT_V6_HOST_OPTION
- // Inserts a single DHCPv6 option into 'dhcp6_options' table.
- // Using fixed scope_id = 3, which associates an option with host.
- {6,
- { OID_INT2, OID_BYTEA, OID_TEXT,
- OID_VARCHAR, OID_BOOL, OID_INT8},
- "insert_v6_host_option",
- "INSERT INTO dhcp6_options(code, value, formatted_value, space, "
- " persistent, host_id, scope_id) "
- "VALUES ($1, $2, $3, $4, $5, $6, 3)"
- },
-
+TaggedStatementArray tagged_statements = { {
// PgSqlHostDataSourceImpl::GET_HOST_DHCPID
// Retrieves host information, IPv6 reservations and both DHCPv4 and
// DHCPv6 options associated with the host. The LEFT JOIN clause is used
// to retrieve information from 4 different tables using a single query.
// Hence, this query returns multiple rows for a single host.
- {2,
+ {2,
{ OID_BYTEA, OID_INT2 },
"get_host_dhcpid",
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
// are returned due to left joining IPv6 reservations and DHCPv6 options.
// The number of rows returned is multiplication of number of existing
// IPv6 reservations and DHCPv6 options.
- {2,
+ {2,
{ OID_VARCHAR, OID_INT2 },
"get_host_prefix",
"SELECT h.host_id, h.dhcp_identifier, "
//PgSqlHostDataSourceImpl::GET_VERSION
// Retrieves MySQL schema version.
- {0,
+ {0,
{ OID_NONE },
"get_version",
"SELECT version, minor FROM schema_version"
},
- // Marks the end of the statements table.
- {0, { 0 }, NULL, NULL}
+ // PgSqlHostDataSourceImpl::INSERT_HOST
+ // Inserts a host into the 'hosts' table. Returns the inserted host id.
+ {8,
+ { OID_BYTEA, OID_INT2,
+ OID_INT4, OID_INT4, OID_INT8, OID_VARCHAR,
+ OID_VARCHAR, OID_VARCHAR },
+ "insert_host",
+ "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
+ " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
+ " dhcp4_client_classes, dhcp6_client_classes) "
+ "VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING host_id"
+ },
+
+ //PgSqlHostDataSourceImpl::INSERT_V6_RESRV
+ // Inserts a single IPv6 reservation into 'reservations' table.
+ {5,
+ { OID_VARCHAR, OID_INT2, OID_INT4, OID_INT4, OID_INT4 },
+ "insert_v6_resrv",
+ "INSERT INTO ipv6_reservations(address, prefix_len, type, "
+ " dhcp6_iaid, host_id) "
+ "VALUES ($1, $2, $3, $4, $5)"
+ },
+
+ // PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION
+ // Inserts a single DHCPv4 option into 'dhcp4_options' table.
+ // Using fixed scope_id = 3, which associates an option with host.
+ {6,
+ { OID_INT2, OID_BYTEA, OID_TEXT,
+ OID_VARCHAR, OID_BOOL, OID_INT8},
+ "insert_v4_host_option",
+ "INSERT INTO dhcp4_options(code, value, formatted_value, space, "
+ " persistent, host_id, scope_id) "
+ "VALUES ($1, $2, $3, $4, $5, $6, 3)"
+ },
+
+ // PgSqlHostDataSourceImpl::INSERT_V6_HOST_OPTION
+ // Inserts a single DHCPv6 option into 'dhcp6_options' table.
+ // Using fixed scope_id = 3, which associates an option with host.
+ {6,
+ { OID_INT2, OID_BYTEA, OID_TEXT,
+ OID_VARCHAR, OID_BOOL, OID_INT8},
+ "insert_v6_host_option",
+ "INSERT INTO dhcp6_options(code, value, formatted_value, space, "
+ " persistent, host_id, scope_id) "
+ "VALUES ($1, $2, $3, $4, $5, $6, 3)"
+ }
+}
};
}; // end anonymous namespace
DHCP4_AND_DHCP6)),
host_ipv6_reservation_exchange_(new PgSqlIPv6ReservationExchange()),
host_option_exchange_(new PgSqlOptionExchange()),
- conn_(parameters) {
+ conn_(parameters),
+ is_readonly_(false) {
// Open the database.
conn_.openDatabase();
- int i = 0;
- for( ; tagged_statements[i].text != NULL ; ++i) {
- conn_.prepareStatement(tagged_statements[i]);
+ conn_.prepareStatements(tagged_statements.begin(),
+ tagged_statements.begin() + WRITE_STMTS_BEGIN);
+
+ std::string readonly_value = "false";
+ try {
+ readonly_value = conn_.getParameter("readonly");
+ boost::algorithm::to_lower(readonly_value);
+ } catch (...) {
+ // Parameter "readonly" hasn't been specified so we simply use
+ // the default value of "false".
+ }
+
+ if (readonly_value == "true") {
+ is_readonly_ = true;
+
+ } else if (readonly_value != "false") {
+ isc_throw(DbInvalidReadOnly, "invalid value '" << readonly_value
+ << "' specified for boolean parameter 'readonly'");
}
- // Just in case somebody foo-barred things
- if (i != NUM_STATEMENTS) {
- isc_throw(DbOpenError, "Number of statements prepared: " << i
- << " does not match expected count:" << NUM_STATEMENTS);
+ // If we are using read-write mode for the database we also prepare
+ // statements for INSERTS etc.
+ if (!is_readonly_) {
+ conn_.prepareStatements(tagged_statements.begin() + WRITE_STMTS_BEGIN,
+ tagged_statements.end());
}
}
PgSqlHostDataSource::
PgSqlHostDataSource(const PgSqlConnection::ParameterMap& parameters)
- : impl_(new PgSqlHostDataSourceImpl(parameters)) {
+ : impl_(new PgSqlHostDataSourceImpl(parameters),
+ "PostgreSQL host database backend is configured to"
+ " operate in read only mode") {
+ impl_.allowConstOnly(impl_->is_readonly_);
}
PgSqlHostDataSource::~PgSqlHostDataSource() {
- delete impl_;
+ delete impl_.getPtr();
}
void
return(impl_->getVersion());
}
+void
+PgSqlHostDataSource::commit() {
+ impl_->conn_.commit();
+}
+
+
+void
+PgSqlHostDataSource::rollback() {
+ impl_->conn_.rollback();
+}
+
}; // end of isc::dhcp namespace
}; // end of isc namespace