Commit ef364ccb authored by Stephen Morris's avatar Stephen Morris
Browse files

[2404] First set of changes as a result of review

* Corrections of miscellaneous typos in comments
* Update database version to 1.0
* Handling of truncation while fetching data from the database
parent 46cfa077
......@@ -8,6 +8,17 @@
the abstract isc::dhcp::LeaseMgr class. This provides methods to
create, retrieve, modify and delete leases in the database.
There are currently two available Lease Managers, MySQL and Memfile:
- The MySQL lease manager uses the freely available MySQL as its backend
database. This is not included in BIND 10 DHCP by default:
the --with-dhcp-mysql switch must be supplied to "configure" for support
to be compiled into the software.
- Memfile is an in-memory lease database, with (currently) nothing being
written to persistent storage. The long-term plans for the backend do
include the ability to store this on disk, but it is currently a
low-priority item.
@section dhcpdb-instantiation Instantiation of Lease Managers
A lease manager is instantiated through the LeaseMgrFactory class. This
......
......@@ -43,7 +43,7 @@ CREATE TABLE lease4 (
# N.B. The use of a VARCHAR for the address is temporary for development:
# it will eventually be replaced by BINARY(16).
CREATE TABLE lease6 (
address VARCHAR(40) PRIMARY KEY NOT NULL, # IPv6 address
address VARCHAR(39) PRIMARY KEY NOT NULL, # IPv6 address
duid VARBINARY(128), # DUID
valid_lifetime INT UNSIGNED, # Length of the lease (seconds)
expire TIMESTAMP, # Expiration time of the lease
......@@ -77,7 +77,7 @@ CREATE TABLE schema_version (
minor INT # Minor version number
);
START TRANSACTION;
INSERT INTO schema_version VALUES (0, 2);
INSERT INTO schema_version VALUES (1, 0);
COMMIT;
# Notes:
......
......@@ -101,6 +101,13 @@ public:
isc::Exception(file, line, what) {}
};
/// @brief Data is truncated
class DataTruncated : public Exception {
public:
DataTruncated(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief Structure that holds a lease for IPv4 address
///
/// For performance reasons it is a simple structure, not a class. If we chose
......@@ -173,7 +180,7 @@ struct Lease4 {
/// IA container and not the address itself, since our data model does not
/// define a separate IA entity, we are keeping it in the lease. In the
/// case of multiple addresses/prefixes for the same IA, each must have
/// consistent T1 and T2 values. This is pecified in seconds since cltt.
/// consistent T1 and T2 values. This is specified in seconds since cltt.
uint32_t t2_;
/// @brief Ralid lifetime
......@@ -234,6 +241,7 @@ typedef std::vector<Lease4Ptr> Lease4Collection;
/// For performance reasons it is a simple structure, not a class. If we chose
/// make it a class, all fields would have to made private and getters/setters
/// would be required. As this is a critical part of the code that will be used
/// extensively, direct access is warranted.
struct Lease6 {
/// @brief Type of lease contents
......@@ -249,6 +257,8 @@ struct Lease6 {
uint32_t t2, SubnetID subnet_id, uint8_t prefixlen_ = 0);
/// @brief IPv6 address
///
/// IPv6 address or, in the case of a prefix delegation, the prefix.
isc::asiolink::IOAddress addr_;
/// @brief Lease type
......@@ -264,7 +274,7 @@ struct Lease6 {
/// @brief Identity Association Identifier (IAID)
///
/// DHCPv6 stores all addresses and prefixes in IA containers (IA_NA,
/// IA_TA, IA_PD). Most containers may appear more than once in a message.
/// IA_TA, IA_PD). All containers may appear more than once in a message.
/// To differentiate between them, the IAID field is present
uint32_t iaid_;
......
......@@ -17,8 +17,10 @@
#include <asiolink/io_address.h>
#include <dhcpsrv/mysql_lease_mgr.h>
#include <boost/static_assert.hpp>
#include <mysql/mysqld_error.h>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <string>
......@@ -79,21 +81,39 @@ namespace {
/// fields. The values should be greater than or equal to the length set in
/// the schema definition.
///
/// The exception is the length of any VARCHAR fields: these should be set
/// greater than or equal to the length of the field plus 2: this allows for
/// the insertion of a trailing null regardless of whether the data returned
/// contains a trailing null (the documentation is not clear on this point).
/// The exception is the length of any VARCHAR fields: buffers for these should
/// be set greater than or equal to the length of the field plus 1: this allows
/// for the insertion of a trailing null whatever data is returned.
const size_t ADDRESS6_TEXT_MAX_LEN = 42; ///< Max size of a IPv6 text buffer
const size_t DUID_MAX_LEN = 128; ///< Max size of a DUID
const size_t HWADDR_MAX_LEN = 128; ///< Max size of a hardware address
const size_t CLIENT_ID_MAX_LEN = 128; ///< Max size of a client ID
/// @brief Maximum size of an IPv6 address represented as a text string.
///
/// This is 32 hexadecimal characters written in 8 groups of four, plus seven
/// colon separators.
const size_t ADDRESS6_TEXT_MAX_LEN = 39;
/// @brief Maximum size of a DUID.
const size_t DUID_MAX_LEN = 128;
/// @brief Maximum size of a hardware address.
const size_t HWADDR_MAX_LEN = 20;
/// @brief Maximum size of a client identification.
///
/// Note that the value is arbitrarily chosen: RFC 2131 does not specify an
/// upper limit, but this seems long enough.
const size_t CLIENT_ID_MAX_LEN = 128;
/// @brief Number of columns in Lease4 table
const size_t LEASE4_COLUMNS = 6;
/// @brief Number of columns in Lease6 table
const size_t LEASE6_COLUMNS = 9;
/// @brief MySQL True/False constants
///
/// Declare typed values so as to avoid problems of data conversion. These
/// are local to the file but are given the prefix MLM (MySql Lease Manager) to
/// avoid any likely conflicts with variables n header files named TRUE or
/// avoid any likely conflicts with variables in header files named TRUE or
/// FALSE.
const my_bool MLM_FALSE = 0; ///< False value
......@@ -136,6 +156,7 @@ TaggedStatement tagged_statements[] = {
"valid_lifetime, expire, subnet_id "
"FROM lease4 "
"WHERE hwaddr = ?"},
{MySqlLeaseMgr::GET_LEASE4_HWADDR_SUBID,
"SELECT address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id "
......@@ -190,6 +211,69 @@ TaggedStatement tagged_statements[] = {
namespace isc {
namespace dhcp {
/// @brief Common MySQL and Lease Data Methods
///
/// The MySqlLease4Exchange and MySqlLease6Exchange classes provide the
/// functionaility to set up binding information between variables in the
/// program and data extracted from the database. This class is the common
/// base to both of them, containing some common methods.
class MySqlLeaseExchange {
public:
/// @brief Set error indicators
///
/// Sets the error indicator for each of the MYSQL_BIND elements. It points
/// the "error" field within an element of the input array to the
/// corresponding element of the passed error array.
///
/// @param bind Array of BIND elements
/// @param error Array of error elements. If there is an error in getting
/// data associated with one of the "bind" elements, the
/// corresponding element in the error array is set to MLM_TRUE.
/// @param count Size of each of the arrays.
void setErrorIndicators(MYSQL_BIND* bind, my_bool* error, size_t count) {
for (size_t i = 0; i < count; ++i) {
error[i] = MLM_FALSE;
bind[i].error = reinterpret_cast<char*>(&error[i]);
}
}
/// @brief Return columns in error
///
/// If an error is returned from a fetch (in particular, a truncated
/// status), this method can be called to get the names of the fields in
/// error. It returns a string comprising the names of the fields
/// separated by commas. In the case of there being no error indicators
/// set, it returns the string "(None)".
///
/// @param error Array of error elements. An element is set to MLM_TRUE
/// if the corresponding column in the database is the source of
/// the error.
/// @param names Array of column names, the same size as the error array.
/// @param count Size of each of the arrays.
std::string getColumnsInError(my_bool* error, std::string* names,
size_t count) {
std::string result = "";
// Accumulate list of column names
for (size_t i = 0; i < count; ++i) {
if (error[i] == MLM_TRUE) {
if (!result.empty()) {
result += ", ";
}
result += names[i];
}
}
if (result.empty()) {
result = "(None)";
}
return (result);
}
};
/// @brief Exchange MySQL and Lease4 Data
///
/// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
......@@ -203,15 +287,28 @@ namespace dhcp {
/// @note There are no unit tests for this class. It is tested indirectly
/// in all MySqlLeaseMgr::xxx4() calls where it is used.
class MySqlLease4Exchange {
class MySqlLease4Exchange : public MySqlLeaseExchange {
public:
/// @brief Set number of columns in this lease structure
static const size_t LEASE_COLUMNS = LEASE4_COLUMNS;
/// @brief Constructor
///
/// The initialization of the variables here is nonly to satisfy cppcheck -
/// The initialization of the variables here is only to satisfy cppcheck -
/// all variables are initialized/set in the methods before they are used.
MySqlLease4Exchange() : addr4_(0), hwaddr_length_(0), client_id_length_(0) {
memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
// Set the column names (for error messages)
columns_[0] = "address";
columns_[1] = "hwaddr";
columns_[2] = "client_id";
columns_[3] = "valid_lifetime";
columns_[4] = "expire";
columns_[5] = "subnet_id";
BOOST_STATIC_ASSERT(5 < LEASE_COLUMNS);
}
/// @brief Create MYSQL_BIND objects for Lease4 Pointer
......@@ -235,14 +332,14 @@ public:
// structure.
// Address: uint32_t
// The address in the Lease structre is an IOAddress object. Convert
// The address in the Lease structure is an IOAddress object. Convert
// this to an integer for storage.
addr4_ = static_cast<uint32_t>(lease_->addr_);
bind_[0].buffer_type = MYSQL_TYPE_LONG;
bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
bind_[0].is_unsigned = MLM_TRUE;
// hwaddr: varbinary
// hwaddr: varbinary(128)
// For speed, we avoid copying the data into temporary storage and
// instead extract it from the lease structure directly.
hwaddr_length_ = lease_->hwaddr_.size();
......@@ -251,7 +348,7 @@ public:
bind_[1].buffer_length = hwaddr_length_;
bind_[1].length = &hwaddr_length_;
// client_id: varbinary
// client_id: varbinary(128)
client_id_ = lease_->client_id_->getClientId();
client_id_length_ = client_id_.size();
bind_[2].buffer_type = MYSQL_TYPE_BLOB;
......@@ -285,9 +382,15 @@ public:
bind_[5].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
bind_[5].is_unsigned = MLM_TRUE;
// Add the error flags
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
// .. and check that we have the numbers correct at compile time.
BOOST_STATIC_ASSERT(5 < LEASE_COLUMNS);
// Add the data to the vector. Note the end element is one after the
// end of the array.
return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[6]));
return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
}
/// @brief Create BIND array to receive data
......@@ -335,9 +438,15 @@ public:
bind_[5].buffer = reinterpret_cast<char*>(&subnet_id_);
bind_[5].is_unsigned = MLM_TRUE;
// Add the error flags
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
// .. and check that we have the numbers correct at compile time.
BOOST_STATIC_ASSERT(5 < LEASE_COLUMNS);
// Add the data to the vector. Note the end element is one after the
// end of the array.
return(std::vector<MYSQL_BIND>(&bind_[0], &bind_[6]));
return(std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
}
/// @brief Copy Received Data into Lease6 Object
......@@ -359,12 +468,29 @@ public:
valid_lifetime_, cltt, subnet_id_)));
}
/// @brief Return columns in error
///
/// If an error is returned from a fetch (in particular, a truncated
/// status), this method can be called to get the names of the fields in
/// error. It returns a string comprising the names of the fields
/// separated by commas. In the case of there being no error indicators
/// set, it returns the string "(None)".
///
/// @return Comma-separated list of columns in error, or the string
/// "(None)".
std::string getErrorColumns() {
return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
}
private:
// Note: All array lengths are equal to the corresponding variable in the
// schema.
// Note: Arrays are declared fixed length for speed of creation
uint32_t addr4_; ///< IPv4 address
MYSQL_BIND bind_[6]; ///< Bind array
MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array
std::string columns_[LEASE_COLUMNS];///< Column names
my_bool error_[LEASE_COLUMNS]; ///< Error array
std::vector<uint8_t> hwaddr_; ///< Hardware address
uint8_t hwaddr_buffer_[HWADDR_MAX_LEN];
///< Hardware address buffer
......@@ -394,7 +520,10 @@ private:
/// @note There are no unit tests for this class. It is tested indirectly
/// in all MySqlLeaseMgr::xxx6() calls where it is used.
class MySqlLease6Exchange {
class MySqlLease6Exchange : public MySqlLeaseExchange {
/// @brief Set number of columns in this lease structure
static const size_t LEASE_COLUMNS = LEASE6_COLUMNS;
public:
/// @brief Constructor
///
......@@ -403,6 +532,19 @@ public:
MySqlLease6Exchange() : addr6_length_(0), duid_length_(0) {
memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
memset(duid_buffer_, 0, sizeof(duid_buffer_));
std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
// Set the column names (for error messages)
columns_[0] = "address";
columns_[1] = "duid";
columns_[2] = "valid_lifetime";
columns_[3] = "expire";
columns_[4] = "subnet_id";
columns_[5] = "pref_lifetime";
columns_[6] = "lease_type";
columns_[7] = "iaid";
columns_[8] = "prefix_len";
BOOST_STATIC_ASSERT(5 < LEASE_COLUMNS);
}
/// @brief Create MYSQL_BIND objects for Lease6 Pointer
......@@ -421,7 +563,7 @@ public:
// for this lease.
memset(bind_, 0, sizeof(bind_));
// address: varchar(40)
// address: varchar(39)
addr6_ = lease_->addr_.toText();
addr6_length_ = addr6_.size();
......@@ -435,7 +577,7 @@ public:
// The const_cast could be avoided by copying the string to a writeable
// buffer and storing the address of that in the "buffer" element.
// However, this introduces a copy operation (with additional overhead)
// purely to get round the strictures introduced by design of the
// purely to get round the structures introduced by design of the
// MySQL interface (which uses the area pointed to by "buffer" as input
// when specifying query parameters and as output when retrieving data).
// For that reason, "const_cast" has been used.
......@@ -465,7 +607,7 @@ public:
//
// expire = cltt_ + valid_lft_
//
// @TODO Handle overflows
// @todo Handle overflows
MySqlLeaseMgr::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_,
expire_);
bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
......@@ -503,9 +645,15 @@ public:
bind_[8].buffer = reinterpret_cast<char*>(&lease_->prefixlen_);
bind_[8].is_unsigned = MLM_TRUE;
// Add the error flags
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
// .. and check that we have the numbers correct at compile time.
BOOST_STATIC_ASSERT(8 < LEASE_COLUMNS);
// Add the data to the vector. Note the end element is one after the
// end of the array.
return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[9]));
return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
}
/// @brief Create BIND array to receive data
......@@ -521,10 +669,10 @@ public:
// Initialize MYSQL_BIND array.
memset(bind_, 0, sizeof(bind_));
// address: varchar
// address: varchar(39)
// A Lease6_ address has a maximum of 39 characters. The array is
// a few bytes longer than this to guarantee that we can always null
// terminate it.
// one byte longer than this to guarantee that we can always null
// terminate it whatever is returned.
addr6_length_ = sizeof(addr6_buffer_) - 1;
bind_[0].buffer_type = MYSQL_TYPE_STRING;
bind_[0].buffer = addr6_buffer_;
......@@ -573,9 +721,15 @@ public:
bind_[8].buffer = reinterpret_cast<char*>(&prefixlen_);
bind_[8].is_unsigned = MLM_TRUE;
// Add the error flags
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
// .. and check that we have the numbers correct at compile time.
BOOST_STATIC_ASSERT(8 < LEASE_COLUMNS);
// Add the data to the vector. Note the end element is one after the
// end of the array.
return(std::vector<MYSQL_BIND>(&bind_[0], &bind_[9]));
return(std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
}
/// @brief Copy Received Data into Lease6 Object
......@@ -633,18 +787,34 @@ public:
return (result);
}
/// @brief Return columns in error
///
/// If an error is returned from a fetch (in particular, a truncated
/// status), this method can be called to get the names of the fields in
/// error. It returns a string comprising the names of the fields
/// separated by commas. In the case of there being no error indicators
/// set, it returns the string "(None)".
///
/// @return Comma-separated list of columns in error, or the string
/// "(None)".
std::string getErrorColumns() {
return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
}
private:
// Note: All array lengths are equal to the corresponding variable in the
// schema.
// Note: arrays are declared fixed length for speed of creation
std::string addr6_; ///< String form of address
char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN]; ///< Character
char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character
///< array form of V6 address
unsigned long addr6_length_; ///< Length of the address
MYSQL_BIND bind_[9]; ///< Bind array
MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array
std::string columns_[LEASE_COLUMNS];///< Column names
std::vector<uint8_t> duid_; ///< Client identification
uint8_t duid_buffer_[DUID_MAX_LEN]; ///< Buffer form of DUID
unsigned long duid_length_; ///< Length of the DUID
my_bool error_[LEASE_COLUMNS]; ///< Error indicators
MYSQL_TIME expire_; ///< Lease expiry time
uint32_t iaid_; ///< Identity association ID
Lease6Ptr lease_; ///< Pointer to lease object
......@@ -1055,8 +1225,9 @@ void MySqlLeaseMgr::getLeaseCollection(StatementIndex stindex,
// Error - unable to fetch results
checkError(status, stindex, "unable to fetch results");
} else if (status == MYSQL_DATA_TRUNCATED) {
// @TODO Handle truncation
;
// Data truncated - throw an exception indicating what was at fault
isc_throw(DataTruncated, "returned data truncated column affected: "
<< exchange->getErrorColumns());
}
}
......@@ -1281,7 +1452,7 @@ MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid) const {
// Note that the const_cast could be avoided by copying the DUID to
// a writeable buffer and storing the address of that in the "buffer"
// element. However, this introduces a copy operation (with additional
// overhead) purely to get round the strictures introduced by design of
// overhead) purely to get round the structures introduced by design of
// the MySQL interface (which uses the area pointed to by "buffer" as
// input when specifying query parameters and as output when retrieving
// data). For that reason, "const_cast" has been used.
......
......@@ -27,8 +27,8 @@ namespace dhcp {
// Define the current database schema values
const uint32_t CURRENT_VERSION_VERSION = 0;
const uint32_t CURRENT_VERSION_MINOR = 2;
const uint32_t CURRENT_VERSION_VERSION = 1;
const uint32_t CURRENT_VERSION_MINOR = 0;
// Forward declaration of the Lease exchange objects. This class is defined
......@@ -119,6 +119,12 @@ public:
/// @param addr address of the searched lease
///
/// @return smart pointer to the lease (or NULL if a lease is not found)
///
/// @throw isc::dhcp::DataTruncation Data was truncated on retrieval to
/// fit into the space allocated for the result. This indicates a
/// programming error.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const;
......@@ -132,6 +138,12 @@ public:
/// @param hwaddr hardware address of the client
///
/// @return lease collection
///
/// @throw isc::dhcp::DataTruncation Data was truncated on retrieval to
/// fit into the space allocated for the result. This indicates a
/// programming error.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
virtual Lease4Collection getLease4(const HWAddr& hwaddr) const;
/// @brief Returns existing IPv4 leases for specified hardware address
......@@ -144,6 +156,12 @@ public:
/// @param subnet_id identifier of the subnet that lease must belong to
///
/// @return a pointer to the lease (or NULL if a lease is not found)
///
/// @throw isc::dhcp::DataTruncation Data was truncated on retrieval to
/// fit into the space allocated for the result. This indicates a
/// programming error.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
virtual Lease4Ptr getLease4(const HWAddr& hwaddr,
SubnetID subnet_id) const;
......@@ -157,6 +175,12 @@ public:
/// @param clientid client identifier
///
/// @return lease collection
///
/// @throw isc::dhcp::DataTruncation Data was truncated on retrieval to
/// fit into the space allocated for the result. This indicates a
/// programming error.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
virtual Lease4Collection getLease4(const ClientId& clientid) const;
/// @brief Returns existing IPv4 lease for specified client-id
......@@ -168,6 +192,12 @@ public:
/// @param subnet_id identifier of the subnet that lease must belong to
///
/// @return a pointer to the lease (or NULL if a lease is not found)
///
/// @throw isc::dhcp::DataTruncation Data was truncated on retrieval to
/// fit into the space allocated for the result. This indicates a
/// programming error.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
virtual Lease4Ptr getLease4(const ClientId& clientid,
SubnetID subnet_id) const;
......@@ -183,6 +213,9 @@ public:
///
/// @throw isc::BadValue record retrieved from database had an invalid
/// lease type field.
/// @throw isc::dhcp::DataTruncation Data was truncated on retrieval to
/// fit into the space allocated for the result. This indicates a
/// programming error.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
virtual Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const;
......@@ -198,6 +231,14 @@ public:
/// @param iaid IA identifier
///
/// @return smart pointer to the lease (or NULL if a lease is not found)
///
/// @throw isc::BadValue record retrieved from database had an invalid
/// lease type field.
/// @throw isc::dhcp::DataTruncation Data was truncated on retrieval to
/// fit into the space allocated for the result. This indicates a
/// programming error.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
virtual Lease6Collection getLease6(const DUID& duid,
uint32_t iaid) const;
......@@ -208,6 +249,14 @@ public:
/// @param subnet_id subnet id of the subnet the lease belongs to
///
/// @return smart pointer to the lease (or NULL if a lease is not found)
///
/// @throw isc::BadValue record retrieved from database had an invalid
/// lease type field.
/// @throw isc::dhcp::DataTruncation Data was truncated on retrieval to
/// fit into the space allocated for the result. This indicates a
/// programming error.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
virtual Lease6Ptr getLease6(const DUID& duid, uint32_t iaid,
SubnetID subnet_id) const;
......
......@@ -50,7 +50,7 @@ const char* create_statement[] = {
") ENGINE = INNODB",
"CREATE TABLE lease6 ("
"address VARCHAR(40) PRIMARY KEY NOT NULL,"
"address VARCHAR(39) PRIMARY KEY NOT NULL,"
"duid VARBINARY(128),"
"valid_lifetime INT UNSIGNED,"
"expire TIMESTAMP,"
......@@ -75,7 +75,7 @@ const char* create_statement[] = {
"minor INT"
")",
"INSERT INTO schema_version VALUES (0, 2)",
"INSERT INTO schema_version VALUES (1, 0)",
NULL
};
......