BIND 10 trac2342, updated. d141c47a59c217c07e377a988ed92fa1cb9a3314 [2342] Add programmer documentation
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Nov 6 13:46:54 UTC 2012
The branch, trac2342 has been updated
via d141c47a59c217c07e377a988ed92fa1cb9a3314 (commit)
via 3dc78f0e8380b2d5e21c8e07f392a8dde4c3d456 (commit)
via 2d399aa7d71950c6424ed6deddb6c74f5e102525 (commit)
from 1ed8ce0cc009b89158583d462e96b42e160dbe3e (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit d141c47a59c217c07e377a988ed92fa1cb9a3314
Author: Stephen Morris <stephen at isc.org>
Date: Tue Nov 6 13:44:17 2012 +0000
[2342] Add programmer documentation
Also add missing library into the makefile - this showed its
absence on OS/X.
commit 3dc78f0e8380b2d5e21c8e07f392a8dde4c3d456
Author: Stephen Morris <stephen at isc.org>
Date: Tue Nov 6 12:58:10 2012 +0000
[2342] Abstracted common MySQL binding code into a separate method.
commit 2d399aa7d71950c6424ed6deddb6c74f5e102525
Author: Stephen Morris <stephen at isc.org>
Date: Mon Nov 5 19:29:39 2012 +0000
[2342] Have unit tests create database schema on the fly
The unit tests now create the schema before each test and destroy
it afterwards. This will be more flexible than needing to update
the schema on test machines each time. The drawback is the need
to keep the database creation script in step with the hardcoded
set of SQL statements in the test program.
-----------------------------------------------------------------------
Summary of changes:
doc/devel/mainpage.dox | 1 +
src/lib/dhcp/Makefile.am | 5 +-
src/lib/dhcp/database_backends.dox | 47 ++++++
src/lib/dhcp/mysql_lease_mgr.cc | 186 ++++++++++++------------
src/lib/dhcp/mysql_lease_mgr.h | 32 ++++
src/lib/dhcp/tests/Makefile.am | 1 +
src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc | 90 ++++++++----
src/lib/dhcp/tests/schema_copy.h | 85 +++++++++++
8 files changed, 329 insertions(+), 118 deletions(-)
create mode 100644 src/lib/dhcp/database_backends.dox
create mode 100644 src/lib/dhcp/tests/schema_copy.h
-----------------------------------------------------------------------
diff --git a/doc/devel/mainpage.dox b/doc/devel/mainpage.dox
index 0da5287..a36d227 100644
--- a/doc/devel/mainpage.dox
+++ b/doc/devel/mainpage.dox
@@ -29,6 +29,7 @@
* - @subpage libdhcp
* - @subpage libdhcpIntro
* - @subpage libdhcpIfaceMgr
+ * - @subpage dhcp-database-backends
* - @subpage perfdhcpInternals
*
* @section misc Miscellaneous topics
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index ff3b937..4761b24 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -52,14 +52,15 @@ libb10_dhcpsrv_la_SOURCES += triplet.h
libb10_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
libb10_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
-libb10_dhcpsrv_la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+libb10_dhcpsrv_la_LIBADD = $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/util/libb10-util.la
libb10_dhcpsrv_la_LDFLAGS = -no-undefined -version-info 2:0:0
if HAVE_MYSQL
libb10_dhcpsrv_la_LDFLAGS += $(MYSQL_LIBS)
endif
-EXTRA_DIST = README
+EXTRA_DIST = README database_backends.dox
if USE_CLANGPP
# Disable unused parameter warning caused by some of the
diff --git a/src/lib/dhcp/database_backends.dox b/src/lib/dhcp/database_backends.dox
new file mode 100644
index 0000000..27b4c24
--- /dev/null
+++ b/src/lib/dhcp/database_backends.dox
@@ -0,0 +1,47 @@
+/**
+ @page dhcp-database-backends DHCP Database Back-Ends
+
+ All DHCP lease data is stored in some form of database, the interface
+ to this being through the Lease Manager.
+
+ All backend classes such as isc::dhcp::MySqlLeaseMgr are derived from
+ the abstract isc::dhcp::LeaseMgr class. This provides methods to
+ create, retrieve, modify and delete leases in the database.
+
+ @section dhcpdb-instantiation Instantiation of Lease Managers
+
+ A lease manager is instantiated through a the LeaseMgrFactory class. This
+ has three methods:
+
+ - isc::dhcp::LeaseMgrFactory::create - Creates a singleton Lease
+ Manager of the appropriate type.
+ - isc::dhcp::LeaseMgrFactory::instance - Returns a reference to the
+ the instance of the Lease Manager.
+ - isc::dhcp::LeaseMgrFactory::destroy - Destroys the singleton lease manager.
+
+ The selection of the Lease Manager (and thus the backend database) is
+ is controlled by the argument passed to isc::dhcp::LeaseMgrfactory::create.
+ This is a string containing a set of "keyword=value" pairs (no embedded
+ spaces), each pair separated by a space from the others, e.g.
+
+ \code
+ type=mysql user=keatest password=keatest name=keatest host=localhost
+ \endcode
+
+ The following keywords are used for all backends:
+
+ - type - specifies the type of database backend. The following types are
+ supported:
+ - mysql - Use MySQL as the database
+
+ The following keywords apply to the MySQL backend:
+
+ - host - host on which the selected database is running. If not supplied,
+ "localhost" is assumed.
+ - name - name of the MySQL database to access. There is no default - this
+ must be supplied.
+ - password - password for the selected user ID (see below). If not specified,
+ no password is used.
+ - user - database user ID under which the database is accessed. If not
+ specified, no user ID is used - the database is assumed to be open.
+ */
diff --git a/src/lib/dhcp/mysql_lease_mgr.cc b/src/lib/dhcp/mysql_lease_mgr.cc
index d3523e9..6e3e308 100644
--- a/src/lib/dhcp/mysql_lease_mgr.cc
+++ b/src/lib/dhcp/mysql_lease_mgr.cc
@@ -95,21 +95,23 @@ TaggedStatement tagged_statements[] = {
namespace isc {
namespace dhcp {
+
+
/// @brief Exchange MySQL and Lease6 Data
///
/// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
/// describe the parameters in the prepared statements. Where information is
/// inserted or retrieved - INSERT, UPDATE, SELECT - a large amount of that
/// structure is identical - it defines data values in the Lease6 structure.
-///
-/// This class handles the creation of that array. For maximum flexibility,
-/// the data is appended to an array of MYSQL_BIND elemements, so allowing
-/// additional elements to be prepended/appended to it.
+/// This class handles the creation of that array.
///
/// Owing to the MySQL API, the process requires some intermediate variables
/// to hold things like length etc. This object holds the intermediate
/// variables as well.
+// Note - there are no unit tests for this class. It is tested indirectly
+// in all MySqlLeaseMgr::xxx6() calls where it is used.
+
class MySqlLease6Exchange {
public:
/// @brief Constructor
@@ -117,7 +119,8 @@ public:
/// Apart from the initialization of false_ and true_, the other
/// initializations are to satisfy cppcheck: none are really needed, as all
/// variables are initialized/set in the methods.
- MySqlLease6Exchange() : addr6_length_(0), duid_length_(0), false_(0), true_(1) {
+ MySqlLease6Exchange() : addr6_length_(0), duid_length_(0),
+ false_(0), true_(1) {
memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
memset(duid_buffer_, 0, sizeof(duid_buffer_));
}
@@ -126,12 +129,10 @@ public:
///
/// Fills in the MYSQL_BIND objects for the Lease6 passed to it.
///
- /// @param lease Lease object to be added to the database
- /// @param bindvec Vector of MySQL BIND objects: the elements describing the
- /// lease are appended to this vector. The data added to the vector
- /// only remain valid while both the lease and this object are valid.
- void
- createBindForSend(const Lease6Ptr& lease, std::vector<MYSQL_BIND>& bindvec) {
+ /// @param lease Lease object to be added to the database.
+ ///
+ /// @return Vector of MySQL BIND objects representing the data to be added.
+ std::vector<MYSQL_BIND> createBindForSend(const Lease6Ptr& lease) {
// Store lease object to ensure it remains valid.
lease_ = lease;
@@ -209,7 +210,7 @@ public:
// Add the data to the vector. Note the end element is one after the
// end of the array.
- bindvec.insert(bindvec.end(), &bind_[0], &bind_[9]);
+ return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[9]));
}
/// @brief Create BIND array to receive data
@@ -218,11 +219,8 @@ public:
/// After data is successfully received, getLeaseData() is used to copy
/// it to a Lease6 object.
///
- /// @param bindvec Vector of MySQL BIND objects: the elements describing the
- /// lease are appended to this vector. The data added to the vector
- /// only remain valid while both the lease and this object are valid.
-
- void createBindForReceive(std::vector<MYSQL_BIND>& bindvec) {
+ /// @return Vector of MySQL BIND objects.
+ std::vector<MYSQL_BIND> createBindForReceive() {
// Ensure both the array of MYSQL_BIND structures and the error array
// are clear.
@@ -283,7 +281,7 @@ public:
bind_[7].buffer = reinterpret_cast<char*>(&iaid_);
bind_[7].is_unsigned = true_;
bind_[7].error = &error_[7];
-
+
// prefix_len: unsigned tinyint
bind_[8].buffer_type = MYSQL_TYPE_TINY;
bind_[8].buffer = reinterpret_cast<char*>(&prefixlen_);
@@ -292,7 +290,7 @@ public:
// Add the data to the vector. Note the end element is one after the
// end of the array.
- bindvec.insert(bindvec.end(), &bind_[0], &bind_[9]);
+ return(std::vector<MYSQL_BIND>(&bind_[0], &bind_[9]));
}
/// @brief Copy Received Data into Lease6 Object
@@ -353,7 +351,7 @@ public:
}
private:
- // Note: All array legths are equal to the corresponding variable in the
+ // Note: All array lengths are equal to the corresponding variable in the
// schema.
std::string addr6_; ///< String form of address
char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN]; ///< Character
@@ -377,6 +375,8 @@ private:
};
+// MySqlLeaseMgr Methods
+
MySqlLeaseMgr::MySqlLeaseMgr(const LeaseMgr::ParameterMap& parameters)
: LeaseMgr(parameters), mysql_(NULL) {
@@ -397,8 +397,13 @@ MySqlLeaseMgr::MySqlLeaseMgr(const LeaseMgr::ParameterMap& parameters)
// Prepare all statements likely to be used.
prepareStatements();
+
+ // Create the exchange object for use in exchanging data between the
+ // program and the database.
+ exchange6_.reset(new MySqlLease6Exchange());
}
+
MySqlLeaseMgr::~MySqlLeaseMgr() {
// Free up the prepared statements, ignoring errors. (What would we do
// about them - we're destroying this object and are not really concerned
@@ -470,6 +475,7 @@ MySqlLeaseMgr::convertFromDatabaseTime(const MYSQL_TIME& expire,
cltt = mktime(&expire_tm) - valid_lifetime;
}
+
void
MySqlLeaseMgr::openDatabase() {
@@ -539,6 +545,7 @@ MySqlLeaseMgr::openDatabase() {
}
}
+
void
MySqlLeaseMgr::prepareStatement(StatementIndex index, const char* text) {
// Validate that there is space for the statement in the statements array
@@ -565,6 +572,7 @@ MySqlLeaseMgr::prepareStatement(StatementIndex index, const char* text) {
}
}
+
void
MySqlLeaseMgr::prepareStatements() {
// Allocate space for all statements
@@ -581,6 +589,7 @@ MySqlLeaseMgr::prepareStatements() {
}
}
+
bool
MySqlLeaseMgr::addLease(const Lease4Ptr& /* lease */) {
isc_throw(NotImplemented, "MySqlLeaseMgr::addLease(const Lease4Ptr&) "
@@ -588,14 +597,13 @@ MySqlLeaseMgr::addLease(const Lease4Ptr& /* lease */) {
return (false);
}
+
bool
MySqlLeaseMgr::addLease(const Lease6Ptr& lease) {
const StatementIndex stindex = INSERT_LEASE6;
// Create the MYSQL_BIND array for the lease
- MySqlLease6Exchange exchange;
- std::vector<MYSQL_BIND> bind;
- exchange.createBindForSend(lease, bind);
+ std::vector<MYSQL_BIND> bind = exchange6_->createBindForSend(lease);
// Bind the parameters to the statement
int status = mysql_stmt_bind_param(statements_[stindex], &bind[0]);
@@ -618,6 +626,7 @@ MySqlLeaseMgr::addLease(const Lease6Ptr& lease) {
return (true);
}
+
Lease4Ptr
MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */,
SubnetID /* subnet_id */) const {
@@ -626,6 +635,7 @@ MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */,
return (Lease4Ptr());
}
+
Lease4Ptr
MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */) const {
isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const IOAddress&) "
@@ -633,6 +643,7 @@ MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */) const {
return (Lease4Ptr());
}
+
Lease4Collection
MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */) const {
isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const HWAddr&) "
@@ -640,6 +651,7 @@ MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */) const {
return (Lease4Collection());
}
+
Lease4Ptr
MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */,
SubnetID /* subnet_id */) const {
@@ -648,6 +660,7 @@ MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */,
return (Lease4Ptr());
}
+
Lease4Collection
MySqlLeaseMgr::getLease4(const ClientId& /* clientid */) const {
isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const ClientID&) "
@@ -655,6 +668,7 @@ MySqlLeaseMgr::getLease4(const ClientId& /* clientid */) const {
return (Lease4Collection());
}
+
Lease4Ptr
MySqlLeaseMgr::getLease4(const ClientId& /* clientid */,
SubnetID /* subnet_id */) const {
@@ -663,6 +677,32 @@ MySqlLeaseMgr::getLease4(const ClientId& /* clientid */,
return (Lease4Ptr());
}
+
+// A convenience function used in the various getLease6() methods. It binds
+// the selection parameters to the prepared statement, and binds the variables
+// that will receive the data. These are stored in the MySqlLease6Exchange
+// object associated with the lease manager and converted to a Lease6 object
+// when retrieved.
+void
+MySqlLeaseMgr::bind6AndExecute(StatementIndex stindex, MYSQL_BIND* inbind) const {
+
+ // Bind the input parameters to the statement
+ int status = mysql_stmt_bind_param(statements_[stindex], inbind);
+ checkError(status, stindex, "unable to bind WHERE clause parameter");
+
+ // Set up the SELECT clause
+ std::vector<MYSQL_BIND> outbind = exchange6_->createBindForReceive();
+
+ // Bind the output parameters to the statement
+ status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]);
+ checkError(status, stindex, "unable to bind SELECT caluse parameters");
+
+ // Execute the statement
+ status = mysql_stmt_execute(statements_[stindex]);
+ checkError(status, stindex, "unable to execute");
+}
+
+
Lease6Ptr
MySqlLeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
const StatementIndex stindex = GET_LEASE6_ADDR;
@@ -679,30 +719,17 @@ MySqlLeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
inbind[0].buffer_length = addr6_length;
inbind[0].length = &addr6_length;
- // Bind the input parameters to the statement
- int status = mysql_stmt_bind_param(statements_[stindex], inbind);
- checkError(status, stindex, "unable to bind WHERE clause parameter");
-
- // Set up the SELECT clause
- MySqlLease6Exchange exchange;
- std::vector<MYSQL_BIND> outbind;
- exchange.createBindForReceive(outbind);
-
- // Bind the output parameters to the statement
- status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]);
- checkError(status, stindex, "unable to bind SELECT caluse parameters");
-
- // Execute the statement
- status = mysql_stmt_execute(statements_[stindex]);
- checkError(status, stindex, "unable to execute");
+ // Bind the input parameters to the statement and bind the output
+ // to fields in the exchange object, then execute the prepared statement.
+ bind6AndExecute(stindex, inbind);
// Fetch the data.
- status = mysql_stmt_fetch(statements_[stindex]);
+ int status = mysql_stmt_fetch(statements_[stindex]);
Lease6Ptr result;
if (status == 0) {
try {
- result = exchange.getLeaseData();
+ result = exchange6_->getLeaseData();
} catch (const isc::BadValue& ex) {
// Free up result set.
@@ -724,7 +751,7 @@ MySqlLeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
// @TODO Handle truncation
// We are ignoring truncation for now, so the only other result is
// no data was found. In that case, we return a null Lease6 structure.
- // This has already been set, so the action is a no-op.
+ // This has already been set, so no action is needed.
}
// Free data structures associated with information returned.
@@ -732,6 +759,7 @@ MySqlLeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
return (result);
}
+
Lease6Collection
MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid) const {
const StatementIndex stindex = GET_LEASE6_DUID_IAID;
@@ -742,7 +770,7 @@ MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid) const {
// DUID. The complex casting is needed to obtain the "const" vector of
// uint8_t from the DUID, point to the start of it (discarding the
- // "const"ness) and finally casing it to "char*" for the MySQL buffer
+ // "const"ness) and finally casting it to "char*" for the MySQL buffer
// element.
const vector<uint8_t>& duid_vector = duid.getDuid();
unsigned long duid_length = duid_vector.size();
@@ -757,26 +785,13 @@ MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid) const {
inbind[1].buffer = reinterpret_cast<char*>(&iaid);
inbind[1].is_unsigned = static_cast<my_bool>(1);
- // Bind the input parameters to the statement
- int status = mysql_stmt_bind_param(statements_[stindex], inbind);
- checkError(status, stindex, "unable to bind WHERE clause parameter");
-
- // Set up the SELECT clause
- MySqlLease6Exchange exchange;
- std::vector<MYSQL_BIND> outbind;
- exchange.createBindForReceive(outbind);
+ // Bind the input parameters to the statement and bind the output
+ // to fields in the exchange object, then execute the prepared statement.
+ bind6AndExecute(stindex, inbind);
- // Bind the output parameters to the statement
- status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]);
- checkError(status, stindex, "unable to bind SELECT clause parameters");
-
- // Execute the query.
- status = mysql_stmt_execute(statements_[stindex]);
- checkError(status, stindex, "unable to execute");
-
- // Ensure that all the lease information is retrieved in one go to avoid overhead
- // of going back and forth between client and server.
- status = mysql_stmt_store_result(statements_[stindex]);
+ // Ensure that all the lease information is retrieved in one go to avoid
+ // overhead of going back and forth between client and server.
+ int status = mysql_stmt_store_result(statements_[stindex]);
checkError(status, stindex, "unable to set up for storing all results");
// Fetch the data. There could be multiple rows, so we need to iterate
@@ -784,7 +799,7 @@ MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid) const {
Lease6Collection result;
while ((status = mysql_stmt_fetch(statements_[stindex])) == 0) {
try {
- Lease6Ptr lease = exchange.getLeaseData();
+ Lease6Ptr lease = exchange6_->getLeaseData();
result.push_back(lease);
} catch (const isc::BadValue& ex) {
@@ -811,6 +826,7 @@ MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid) const {
return (result);
}
+
Lease6Ptr
MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
SubnetID subnet_id) const {
@@ -842,31 +858,18 @@ MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
inbind[2].buffer = reinterpret_cast<char*>(&subnet_id);
inbind[2].is_unsigned = static_cast<my_bool>(1);
- // Bind the input parameters to the statement
- int status = mysql_stmt_bind_param(statements_[stindex], inbind);
- checkError(status, stindex, "unable to bind WHERE clause parameter");
-
- // Set up the SELECT clause
- MySqlLease6Exchange exchange;
- std::vector<MYSQL_BIND> outbind;
- exchange.createBindForReceive(outbind);
-
- // Bind the output parameters to the statement
- status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]);
- checkError(status, stindex, "unable to bind SELECT clause parameters");
-
- // Execute the query.
- status = mysql_stmt_execute(statements_[stindex]);
- checkError(status, stindex, "unable to execute");
+ // Bind the input parameters to the statement and bind the output
+ // to fields in the exchange object, then execute the prepared statement.
+ bind6AndExecute(stindex, inbind);
Lease6Ptr result;
- status = mysql_stmt_fetch(statements_[stindex]);
+ int status = mysql_stmt_fetch(statements_[stindex]);
if (status == 0) {
try {
- result = exchange.getLeaseData();
+ result = exchange6_->getLeaseData();
- // TODO: check for more than one row returned. At present, just ignore
- // the excess and take the first.
+ // TODO: check for more than one row returned. At present, just
+ // ignore the excess and take the first.
} catch (const isc::BadValue& ex) {
// Free up result set.
@@ -897,20 +900,20 @@ MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
return (result);
}
+
void
MySqlLeaseMgr::updateLease4(const Lease4Ptr& /* lease4 */) {
isc_throw(NotImplemented, "MySqlLeaseMgr::updateLease4(const Lease4Ptr&) "
"not implemented yet");
}
+
void
MySqlLeaseMgr::updateLease6(const Lease6Ptr& lease) {
const StatementIndex stindex = UPDATE_LEASE6;
// Create the MYSQL_BIND array for the data being updated
- MySqlLease6Exchange exchange;
- std::vector<MYSQL_BIND> bind;
- exchange.createBindForSend(lease, bind);
+ std::vector<MYSQL_BIND> bind = exchange6_->createBindForSend(lease);
// Set up the WHERE clause value
MYSQL_BIND where;
@@ -947,6 +950,7 @@ MySqlLeaseMgr::updateLease6(const Lease6Ptr& lease) {
}
}
+
bool
MySqlLeaseMgr::deleteLease4(const isc::asiolink::IOAddress& /* addr */) {
isc_throw(NotImplemented, "MySqlLeaseMgr::deleteLease4(const IOAddress&) "
@@ -954,6 +958,7 @@ MySqlLeaseMgr::deleteLease4(const isc::asiolink::IOAddress& /* addr */) {
return (false);
}
+
bool
MySqlLeaseMgr::deleteLease6(const isc::asiolink::IOAddress& addr) {
const StatementIndex stindex = DELETE_LEASE6;
@@ -981,10 +986,9 @@ MySqlLeaseMgr::deleteLease6(const isc::asiolink::IOAddress& addr) {
// See how many rows were affected. Note that the statement may delete
// multiple rows.
return (mysql_stmt_affected_rows(statements_[stindex]) > 0);
-
- return false;
}
+
std::string
MySqlLeaseMgr::getName() const {
std::string name = "";
@@ -996,11 +1000,13 @@ MySqlLeaseMgr::getName() const {
return (name);
}
+
std::string
MySqlLeaseMgr::getDescription() const {
- return (std::string(""));
+ return (std::string("MySQL Database"));
}
+
std::pair<uint32_t, uint32_t>
MySqlLeaseMgr::getVersion() const {
const StatementIndex stindex = GET_VERSION;
@@ -1048,6 +1054,7 @@ MySqlLeaseMgr::getVersion() const {
return (std::make_pair(major, minor));
}
+
void
MySqlLeaseMgr::commit() {
if (mysql_commit(mysql_) != 0) {
@@ -1055,6 +1062,7 @@ MySqlLeaseMgr::commit() {
}
}
+
void
MySqlLeaseMgr::rollback() {
if (mysql_rollback(mysql_) != 0) {
diff --git a/src/lib/dhcp/mysql_lease_mgr.h b/src/lib/dhcp/mysql_lease_mgr.h
index 6a542f6..6b5773b 100644
--- a/src/lib/dhcp/mysql_lease_mgr.h
+++ b/src/lib/dhcp/mysql_lease_mgr.h
@@ -16,6 +16,7 @@
#define MYSQL_LEASE_MGR_H
#include <time.h>
+#include <boost/scoped_ptr.hpp>
#include <mysql.h>
#include <dhcp/lease_mgr.h>
@@ -27,6 +28,12 @@ namespace dhcp {
const uint32_t CURRENT_VERSION_VERSION = 0;
const uint32_t CURRENT_VERSION_MINOR = 1;
+
+// Forward declaration of the Lease6 exchange object. This class is defined
+// in the .cc file.
+class MySqlLease6Exchange;
+
+
/// @brief MySQL Lease Manager
///
/// This is a concrete API for the backend for the MySQL database.
@@ -374,6 +381,25 @@ private:
/// @exception DbOpenError Error opening the database
void openDatabase();
+ /// @brief Binds Parameters and Executes
+ ///
+ /// This method abstracts a lot of common processing from the getXxxx()
+ /// methods. It binds the parameters passed to it to the appropriate
+ /// prepared statement, and binds the variables in the exchange6 object to
+ /// the output parameters of the statement. It then executes the prepared
+ /// statement.
+ ///
+ /// The data can be retrieved using mysql_stmt_fetch and the getLeaseData()
+ /// method on the exchange6 object.
+ ///
+ /// @param stindex Index of prepared statement to be executed
+ /// @param inbind Array of MYSQL_BIND objects representing the parameters.
+ /// (Note that the number is determined by the number of parameters
+ /// in the statement.)
+ ///
+ /// @exception DbOperationError Error doing a database operation.
+ void bind6AndExecute(StatementIndex stindex, MYSQL_BIND* inbind) const;
+
/// @brief Check Error and Throw Exception
///
/// Virtually all MySQL functions return a status which, if non-zero,
@@ -396,6 +422,12 @@ private:
}
// Members
+
+ /// Used for transfer of data to/from the database. This is a pointed-to
+ /// object as its contents may change in "const" calls, while the rest
+ /// of this object does not. (At alternative would be to declare it as
+ /// "mutable".)
+ boost::scoped_ptr<MySqlLease6Exchange> exchange6_;
MYSQL* mysql_; ///< MySQL context object
std::vector<std::string> text_statements_; ///< Raw text of statements
std::vector<MYSQL_STMT*> statements_; ///< Prepared statements
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index 05f02b8..4b9beb6 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -39,6 +39,7 @@ libdhcp___unittests_SOURCES += option6_ia_unittest.cc
libdhcp___unittests_SOURCES += option_unittest.cc
libdhcp___unittests_SOURCES += pkt4_unittest.cc
libdhcp___unittests_SOURCES += pkt6_unittest.cc
+libdhcp___unittests_SOURCES += schema_copy.h
libdhcp___unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
libdhcp___unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc
index 87afe78..6c473bc 100644
--- a/src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc
+++ b/src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc
@@ -30,6 +30,9 @@ using namespace std;
namespace {
+// Creation of the schema
+#include "schema_copy.h"
+
// IPv6 addresseses
const char* ADDRESS_0 = "2001:db8::0";
const char* ADDRESS_1 = "2001:db8::1";
@@ -103,6 +106,52 @@ validConnectionString() {
VALID_USER, VALID_PASSWORD));
}
+// @brief Clear everything from the database
+//
+// There is no error checking in this code: if something fails, one of the
+// tests will fall over.
+void destroySchema() {
+ // Initialise
+ MYSQL handle;
+ (void) mysql_init(&handle);
+
+ // Open database
+ (void) mysql_real_connect(&handle, "localhost", "keatest",
+ "keatest", "keatest", 0, NULL, 0);
+
+ // Get rid of everything in it.
+ for (int i = 0; destroy_statement[i] != NULL; ++i) {
+ (void) mysql_query(&handle, destroy_statement[i]);
+ }
+
+ // ... and close
+ (void) mysql_close(&handle);
+}
+
+// @brief Create the Schema
+//
+// Creates all the tables in what is assumed to be an empty database.
+//
+// There is no error checking in this code: if it fails, one of the tests
+// will fall over.
+void createSchema() {
+ // Initialise
+ MYSQL handle;
+ (void) mysql_init(&handle);
+
+ // Open database
+ (void) mysql_real_connect(&handle, "localhost", "keatest",
+ "keatest", "keatest", 0, NULL, 0);
+
+ // Get rid of everything in it.
+ for (int i = 0; create_statement[i] != NULL; ++i) {
+ (void) mysql_query(&handle, create_statement[i]);
+ }
+
+ // ... and close
+ (void) mysql_close(&handle);
+}
+
// Note: Doxygen "///" not used - even though Doxygen is used to
// document class and methods - to avoid the comments appearing
// in the programming manual.
@@ -127,7 +176,8 @@ public:
L6_ADDRESS(ADDRESS_6), L6_IOADDRESS(L6_ADDRESS),
L7_ADDRESS(ADDRESS_7), L7_IOADDRESS(L7_ADDRESS)
{
- clearAll();
+ destroySchema();
+ createSchema();
LeaseMgrFactory::create(validConnectionString());
lmptr_ = &(LeaseMgrFactory::instance());
}
@@ -140,7 +190,7 @@ public:
virtual ~MySqlLeaseMgrTest() {
lmptr_->rollback();
LeaseMgrFactory::destroy();
- clearAll();
+ destroySchema();
}
// @brief Reopen the database
@@ -153,28 +203,6 @@ public:
lmptr_ = &(LeaseMgrFactory::instance());
}
- // @brief Clear everything from the database tables
- //
- // There is no error checking in this code, as this is just
- // extra checking that the database is clear before the text.
- void clearAll() {
- // Initialise
- MYSQL handle;
- (void) mysql_init(&handle);
-
- // Open database
- (void) mysql_real_connect(&handle, "localhost", "keatest",
- "keatest", "keatest", 0, NULL,
- 0);
-
- // Clear the database
- (void) mysql_query(&handle, "DELETE FROM lease4");
- (void) mysql_query(&handle, "DELETE FROM lease6");
-
- // ... and close
- (void) mysql_close(&handle);
- }
-
// @brief Initialize Lease6 Fields
//
// Returns a pointer to a Lease6 structure. Different values are put
@@ -378,8 +406,13 @@ public:
// opened: the fixtures assume that and check basic operations.
TEST(MySqlOpenTest, OpenDatabase) {
- // Check that database opens correctly and tidy up. If it fails, print
- // the error message.
+
+ // Schema needs to be created for the test to work.
+ destroySchema();
+ createSchema();
+
+ // Check that lease manager open the database opens correctly and tidy up.
+ // If it fails, print the error message.
try {
LeaseMgrFactory::create(validConnectionString());
EXPECT_NO_THROW((void) LeaseMgrFactory::instance());
@@ -423,6 +456,9 @@ TEST(MySqlOpenTest, OpenDatabase) {
EXPECT_THROW(LeaseMgrFactory::create(connectionString(
VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
NoDatabaseName);
+
+ // Tidy up after the test
+ destroySchema();
}
// @brief Check conversion functions
@@ -684,4 +720,4 @@ TEST_F(MySqlLeaseMgrTest, UpdateLease6) {
EXPECT_THROW(lmptr_->updateLease6(leases[2]), isc::dhcp::NoSuchLease);
}
-}; // end of anonymous namespace
+}; // Of anonymous namespace
diff --git a/src/lib/dhcp/tests/schema_copy.h b/src/lib/dhcp/tests/schema_copy.h
new file mode 100644
index 0000000..1dd796d
--- /dev/null
+++ b/src/lib/dhcp/tests/schema_copy.h
@@ -0,0 +1,85 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef SCHEMA_COPY_H
+#define SCHEMA_COPY_H
+
+namespace {
+
+// What follows is a set of statements that creates a copy of the schema
+// in the test database. It is used by the MySQL unit test prior to each
+// test.
+//
+// Each SQL statement is a single string. The statements are not terminated
+// by semicolons, and the strings must end with a comma. The final line
+// statement must be NULL (not in quotes)
+
+// THIS MUST BE KEPT UP TO DATE AND UPDATED IF THE SCHEMA CHANGES
+
+// Deletion of existing tables.
+
+const char* destroy_statement[] = {
+ "DROP TABLE lease4",
+ "DROP TABLE lease6",
+ "DROP TABLE lease6_types",
+ "DROP TABLE schema_version",
+ NULL
+};
+
+// Creation of the new tables.
+
+const char* create_statement[] = {
+ "CREATE TABLE lease4 ("
+ "address INT UNSIGNED PRIMARY KEY NOT NULL,"
+ "hwaddr VARBINARY(20),"
+ "client_id VARBINARY(128),"
+ "lease_time INT UNSIGNED,"
+ "expire TIMESTAMP,"
+ "subnet_id INT UNSIGNED"
+ ") ENGINE = INNODB",
+
+ "CREATE TABLE lease6 ("
+ "address VARCHAR(40) PRIMARY KEY NOT NULL,"
+ "duid VARBINARY(128),"
+ "valid_lifetime INT UNSIGNED,"
+ "expire TIMESTAMP,"
+ "subnet_id INT UNSIGNED,"
+ "pref_lifetime INT UNSIGNED,"
+ "lease_type TINYINT,"
+ "iaid INT UNSIGNED,"
+ "prefix_len TINYINT UNSIGNED"
+ ") ENGINE = INNODB",
+
+ "CREATE TABLE lease6_types ("
+ "lease_type TINYINT PRIMARY KEY NOT NULL,"
+ "name VARCHAR(5)"
+ ")",
+
+ "INSERT INTO lease6_types VALUES (0, \"IA_NA\")",
+ "INSERT INTO lease6_types VALUES (1, \"IA_TA\")",
+ "INSERT INTO lease6_types VALUES (2, \"IA_PD\")",
+
+ "CREATE TABLE schema_version ("
+ "version INT PRIMARY KEY NOT NULL,"
+ "minor INT"
+ ")",
+
+ "INSERT INTO schema_version VALUES (0, 1)",
+
+ NULL
+};
+
+}; // Anonymous namespace
+
+#endif // SCHEMA_COPY_H
More information about the bind10-changes
mailing list