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
/// 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_));
}
///
/// 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;
// 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
/// 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.
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_);
// 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
}
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
};
+// MySqlLeaseMgr Methods
+
MySqlLeaseMgr::MySqlLeaseMgr(const LeaseMgr::ParameterMap& parameters)
: LeaseMgr(parameters), mysql_(NULL) {
// 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
cltt = mktime(&expire_tm) - valid_lifetime;
}
+
void
MySqlLeaseMgr::openDatabase() {
}
}
+
void
MySqlLeaseMgr::prepareStatement(StatementIndex index, const char* text) {
// Validate that there is space for the statement in the statements array
}
}
+
void
MySqlLeaseMgr::prepareStatements() {
// Allocate space for all statements
}
}
+
bool
MySqlLeaseMgr::addLease(const Lease4Ptr& /* lease */) {
isc_throw(NotImplemented, "MySqlLeaseMgr::addLease(const Lease4Ptr&) "
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]);
return (true);
}
+
Lease4Ptr
MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */,
SubnetID /* subnet_id */) const {
return (Lease4Ptr());
}
+
Lease4Ptr
MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */) const {
isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const IOAddress&) "
return (Lease4Ptr());
}
+
Lease4Collection
MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */) const {
isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const HWAddr&) "
return (Lease4Collection());
}
+
Lease4Ptr
MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */,
SubnetID /* subnet_id */) const {
return (Lease4Ptr());
}
+
Lease4Collection
MySqlLeaseMgr::getLease4(const ClientId& /* clientid */) const {
isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const ClientID&) "
return (Lease4Collection());
}
+
Lease4Ptr
MySqlLeaseMgr::getLease4(const ClientId& /* clientid */,
SubnetID /* subnet_id */) const {
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;
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.
// @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.
return (result);
}
+
Lease6Collection
MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid) const {
const StatementIndex stindex = GET_LEASE6_DUID_IAID;
// 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();
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
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) {
return (result);
}
+
Lease6Ptr
MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
SubnetID subnet_id) const {
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.
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;
}
}
+
bool
MySqlLeaseMgr::deleteLease4(const isc::asiolink::IOAddress& /* addr */) {
isc_throw(NotImplemented, "MySqlLeaseMgr::deleteLease4(const IOAddress&) "
return (false);
}
+
bool
MySqlLeaseMgr::deleteLease6(const isc::asiolink::IOAddress& addr) {
const StatementIndex stindex = DELETE_LEASE6;
// 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 = "";
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;
return (std::make_pair(major, minor));
}
+
void
MySqlLeaseMgr::commit() {
if (mysql_commit(mysql_) != 0) {
}
}
+
void
MySqlLeaseMgr::rollback() {
if (mysql_rollback(mysql_) != 0) {