MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // option: user_context
MySqlBinding::createString(SHARED_NETWORK_NAME_BUF_LENGTH), // option: shared_network_name
MySqlBinding::createInteger<uint64_t>(), // option: pool_id
- MySqlBinding::createTimestamp() //option: modification_ts
+ MySqlBinding::createTimestamp(), //option: modification_ts
+ MySqlBinding::createInteger<uint8_t>(), // calculate_tee_times
+ MySqlBinding::createInteger<float>(), // t1_percent
+ MySqlBinding::createInteger<float>() // t2_percent
};
uint64_t last_pool_id = 0;
// match_client_id
if (!out_bindings[8]->amNull()) {
- last_subnet->setMatchClientId(static_cast<bool>
- (out_bindings[8]->getInteger<uint8_t>()));
+ last_subnet->setMatchClientId(out_bindings[8]->getBool());
}
// modification_ts
last_subnet->setContext(user_context);
}
+ // calculate_tee_times
+ if (!out_bindings[49]->amNull()) {
+ last_subnet->setCalculateTeeTimes(out_bindings[49]->getBool());
+ }
+
+ // t1_percent
+ if (!out_bindings[50]->amNull()) {
+ last_subnet->setT1Percent(out_bindings[50]->getFloat());
+ }
+
+ // t2_percent
+ if (!out_bindings[51]->amNull()) {
+ last_subnet->setT2Percent(out_bindings[51]->getFloat());
+ }
+
// Subnet ready. Add it to the list.
subnets.push_back(last_subnet);
}
MySqlBinding::condCreateString(subnet->getSname()),
shared_network_binding,
createInputContextBinding(subnet),
- createBinding(subnet->getValid())
+ createBinding(subnet->getValid()),
+ MySqlBinding::condCreateBool(subnet->getCalculateTeeTimes()),
+ MySqlBinding::condCreateFloat(subnet->getT1Percent()),
+ MySqlBinding::condCreateFloat(subnet->getT2Percent())
};
MySqlTransaction transaction(conn_);
// match_client_id
if (!out_bindings[4]->amNull()) {
- last_network->setMatchClientId(static_cast<bool>
- (out_bindings[4]->getInteger<uint8_t>()));
+ last_network->setMatchClientId(out_bindings[4]->getBool());
}
// modification_ts
createOptionValueBinding(option),
MySqlBinding::condCreateString(option->formatted_value_),
MySqlBinding::condCreateString(option->space_name_),
- MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(option->persistent_)),
+ MySqlBinding::createBool(option->persistent_),
MySqlBinding::createNull(),
MySqlBinding::createNull(),
MySqlBinding::createInteger<uint8_t>(0),
createOptionValueBinding(option),
MySqlBinding::condCreateString(option->formatted_value_),
MySqlBinding::condCreateString(option->space_name_),
- MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(option->persistent_)),
+ MySqlBinding::createBool(option->persistent_),
MySqlBinding::createNull(),
MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)),
MySqlBinding::createInteger<uint8_t>(1),
createOptionValueBinding(option),
MySqlBinding::condCreateString(option->formatted_value_),
MySqlBinding::condCreateString(option->space_name_),
- MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(option->persistent_)),
+ MySqlBinding::createBool(option->persistent_),
MySqlBinding::createNull(),
MySqlBinding::createNull(),
MySqlBinding::createInteger<uint8_t>(5),
createOptionValueBinding(option),
MySqlBinding::condCreateString(option->formatted_value_),
MySqlBinding::condCreateString(option->space_name_),
- MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(option->persistent_)),
+ MySqlBinding::createBool(option->persistent_),
MySqlBinding::createNull(),
MySqlBinding::createNull(),
MySqlBinding::createInteger<uint8_t>(4),
"dhcp4" : option_def->getOptionSpaceName()),
MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(option_def->getType())),
MySqlBinding::createTimestamp(option_def->getModificationTime()),
- MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(option_def->getArrayType())),
+ MySqlBinding::createBool(option_def->getArrayType()),
MySqlBinding::createString(option_def->getEncapsulatedSpace()),
record_types_binding,
createInputContextBinding(option_def)
" server_hostname,"
" shared_network_name,"
" user_context,"
- " valid_lifetime"
+ " valid_lifetime,"
+ " calculate_tee_times,"
+ " t1_percent,"
+ " t2_percent"
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,"
- "?, ?, ?, ?, ?, ?, ?, ?)" },
+ "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" },
// Insert association of the subnet with a server.
{ MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4_SERVER,
" server_hostname = ?,"
" shared_network_name = ?,"
" user_context = ?,"
- " valid_lifetime = ? "
+ " valid_lifetime = ?,"
+ " calculate_tee_times = ?,"
+ " t1_percent = ?,"
+ " t2_percent = ? "
"WHERE subnet_id = ?" },
// Update existing shared network.
" o.user_context," \
" o.shared_network_name," \
" o.pool_id," \
- " o.modification_ts " \
+ " o.modification_ts," \
+ " s.calculate_tee_times," \
+ " s.t1_percent," \
+ " s.t2_percent " \
"FROM dhcp4_subnet AS s " \
"INNER JOIN dhcp4_subnet_server AS a " \
" ON s.subnet_id = a.subnet_id " \
subnet->setSname("server-hostname");
subnet->setContext(user_context);
subnet->setValid(555555);
+ subnet->setCalculateTeeTimes(true);
+ subnet->setT1Percent(0.345);
+ subnet->setT2Percent(0.444);
Pool4Ptr pool1(new Pool4(IOAddress("192.0.2.10"), IOAddress("192.0.2.20")));
subnet->addPool(pool1);
return (getBlob());
}
+float
+MySqlBinding::getFloat() const {
+ // It may seem a bit weird that we use getInteger template method
+ // for getting a floating point value. However, the getInteger method
+ // seems to be generic enough to support it. If we were to redo the
+ // API of this class we would probably introduce a getNumericValue
+ // method instead of getInteger. However, we already have getInteger
+ // used in many places so we should stick to it.
+ return (getInteger<float>());
+}
+
ptime
MySqlBinding::getTimestamp() const {
// Make sure the binding type is timestamp.
return (binding);
}
+MySqlBindingPtr
+MySqlBinding::createFloat(const float value) {
+ // It may seem a bit weird that we use createInteger template method
+ // for setting a floating point value. However, the setInteger method
+ // seems to be generic enough to support it. If we were to redo the
+ // API of this class we would probably introduce a createNumericValue
+ // method instead of createInteger. However, we already have createInteger
+ // used in many places so we should stick to it.
+ return (createInteger<float>(value));
+}
+
+MySqlBindingPtr
+MySqlBinding::createBool(const bool value) {
+ return (createInteger<uint8_t>(static_cast<uint8_t>(value)));
+}
+
MySqlBindingPtr
MySqlBinding::condCreateBool(const util::Optional<bool>& value) {
if (value.unspecified()) {
static const bool am_unsigned = true;
};
+template<>
+struct MySqlBindingTraits<float> {
+ static const enum_field_types column_type = MYSQL_TYPE_FLOAT;
+ static const size_t length = 4;
+ static const bool am_unsigned = false;
+};
+
/// @brief Forward declaration of @c MySqlBinding class.
class MySqlBinding;
return (getInteger<T>());
}
+ /// @brief Returns float value held in the binding.
+ ///
+ /// Call @c MySqlBinding::amNull to verify that the value is not
+ /// null prior to calling this method.
+ ///
+ /// @throw InvalidOperation if the value is NULL or the binding
+ /// type does not match the template parameter.
+ ///
+ /// @return Float value.
+ float getFloat() const;
+
+ /// @brief Returns boolean value held in the binding.
+ ///
+ /// Call @c MySqlBinding::amNull to verify that the value is not
+ /// null prior to calling this method.
+ ///
+ /// @throw InvalidOperation if the value is NULL or the binding
+ /// type is not uint8_t.
+ ///
+ /// @return Boolean value.
+ bool getBool() const {
+ return (static_cast<bool>(getInteger<uint8_t>()));
+ }
+
/// @brief Returns timestamp value held in the binding.
///
/// Call @c MySqlBinding::amNull to verify that the value is not
return (value.unspecified() ? createNull() : createInteger<T>(value.get()));
}
+ /// @brief Creates binding having a float type for sending data.
+ ///
+ /// @param value Float value to be sent to the database.
+ ///
+ /// @return Pointer to the created binding.
+ static MySqlBindingPtr createFloat(const float value);
+
+ /// @Conditionally creates binding of float type for sending data if
+ /// provided value is specified.
+ ///
+ /// @tparam T Floating point type to be converted to float.
+ ///
+ /// @param value Value to be stored in the database as float.
+ ///
+ /// @return Pointer to the created binding.
+ template<typename T>
+ static MySqlBindingPtr condCreateFloat(const util::Optional<T>& value) {
+ return (value.unspecified() ? createNull() :
+ createInteger<float> (static_cast<float>(value.get())));
+ }
+
+ /// @brief Creates binding having a bool type for sending data.
+ ///
+ /// @param value Boolean value to be sent to the database.
+ ///
+ /// @return Pointer to the created binding holding an @c uint8_t
+ /// value representing the boolean value.
+ static MySqlBindingPtr createBool(const bool value);
+
/// @brief Conditionally creates binding of @c uint8_t type representing
/// a boolean value if provided value is specified.
///
#include <boost/date_time/posix_time/posix_time.hpp>
#include <gtest/gtest.h>
+using namespace isc;
using namespace isc::asiolink;
using namespace isc::data;
using namespace isc::db;
EXPECT_EQ("bar", binding->getStringOrDefault("foo"));
}
-// This test verifies that null binding is created for unspecified string.
+// This test verifies that null binding is created for unspecified string
+// and the string binding is created for a specified string.
TEST(MySqlBindingTest, conditionalString) {
auto binding = MySqlBinding::condCreateString(Optional<std::string>());
EXPECT_TRUE(binding->amNull());
EXPECT_EQ("foo", binding->getString());
}
+// This test verifies that an error is thrown upon an attempt to use
+// invalid accessor for a string binding.
+TEST(MySqlBindingTest, stringTypeMismatch) {
+ auto binding = MySqlBinding::createString("foo");
+ EXPECT_NO_THROW(static_cast<void>(binding->getString()));
+
+ EXPECT_THROW(static_cast<void>(binding->getBlob()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getInteger<uint16_t>()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getFloat()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getBool()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getTimestamp()), InvalidOperation);
+}
+
// This test verifies that null JSON is returned if the string binding
// is null, JSON value is returned when string value is valid JSON and
// that exception is thrown if the string is not a valid JSON.
EXPECT_EQ(blob, binding->getBlobOrDefault(default_blob));
}
+// This test verifies that an error is thrown upon an attempt to use
+// invalid accessor for a blob binding.
+TEST(MySqlBindingTest, blobTypeMismatch) {
+ std::vector<uint8_t> blob(10, 1);
+ auto binding = MySqlBinding::createBlob(blob.begin(), blob.end());
+ EXPECT_NO_THROW(static_cast<void>(binding->getBlob()));
+
+ EXPECT_THROW(static_cast<void>(binding->getString()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getInteger<uint16_t>()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getFloat()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getBool()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getTimestamp()), InvalidOperation);
+}
+
// This test verifies that default number is returned if binding is null.
TEST(MySqlBindingTest, defaultInteger) {
auto binding = MySqlBinding::createNull();
EXPECT_EQ(1024, binding->getIntegerOrDefault<uint32_t>(123));
}
-// This test verifies that null binding is created for unspecified number.
+// This test verifies that null binding is created for unspecified number
+// and the integer binding is created for a specified number.
TEST(MySqlBindingTest, conditionalInteger) {
auto binding = MySqlBinding::condCreateInteger<uint16_t>(Optional<uint16_t>());
EXPECT_TRUE(binding->amNull());
EXPECT_EQ(1, binding->getInteger<uint16_t>());
}
+// This test verifies that an error is thrown upon an attempt to use
+// invalid accessor for an integer binding.
+TEST(MySqlBindingTest, integerTypeMismatch) {
+ auto binding = MySqlBinding::createInteger<uint32_t>(123);
+ EXPECT_NO_THROW(static_cast<void>(binding->getInteger<uint32_t>()));
+
+ EXPECT_THROW(static_cast<void>(binding->getString()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getBlob()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getInteger<uint8_t>()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getInteger<uint16_t>()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getFloat()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getBool()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getTimestamp()), InvalidOperation);
+}
+
+// This test verifies that null binding is created for unspecified floating
+// point value and the float binding is created for the specified value.
+TEST(MySqlBindingTest, conditionalFloat) {
+ auto binding = MySqlBinding::condCreateFloat(Optional<float>());
+ EXPECT_TRUE(binding->amNull());
+
+ binding = MySqlBinding::condCreateFloat<float>(1.567f);
+ ASSERT_FALSE(binding->amNull());
+ EXPECT_EQ(1.567f, binding->getFloat());
+}
+
+// This test verifies that an error is thrown upon an attempt to use
+// invalid accessor for a float binding.
+TEST(MySqlBindingTest, floatTypeMismatch) {
+ auto binding = MySqlBinding::createFloat(123.123f);
+ EXPECT_NO_THROW(static_cast<void>(binding->getFloat()));
+
+ EXPECT_THROW(static_cast<void>(binding->getString()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getBlob()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getInteger<uint8_t>()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getInteger<uint16_t>()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getInteger<uint32_t>()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getBool()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getTimestamp()), InvalidOperation);
+}
+
// This test verifies that null binding is created for unspecified boolean
+// value and the uint8_t binding is created for a specified boolean
// value.
TEST(MySqlBindingTest, conditionalBoolean) {
auto binding = MySqlBinding::condCreateBool(Optional<bool>());
binding = MySqlBinding::condCreateBool(false);
ASSERT_FALSE(binding->amNull());
- EXPECT_EQ(0, binding->getInteger<uint8_t>());
+ EXPECT_FALSE(binding->getBool());
binding = MySqlBinding::condCreateBool(true);
ASSERT_FALSE(binding->amNull());
- EXPECT_NE(binding->getInteger<uint8_t>(), 0);
+ EXPECT_TRUE(binding->getBool());
+}
+
+// This test verifies that an error is thrown upon an attempt to use
+// invalid accessor for a float binding.
+TEST(MySqlBindingTest, booleanTypeMismatch) {
+ auto binding = MySqlBinding::createBool(false);
+ EXPECT_NO_THROW(static_cast<void>(binding->getBool()));
+ EXPECT_NO_THROW(static_cast<void>(binding->getInteger<uint8_t>()));
+
+ EXPECT_THROW(static_cast<void>(binding->getString()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getBlob()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getInteger<uint16_t>()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getInteger<uint32_t>()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getFloat()), InvalidOperation);
+ EXPECT_THROW(static_cast<void>(binding->getTimestamp()), InvalidOperation);
}
-// This test verifies that null binding is created for unspecified address.
+// This test verifies that null binding is created for unspecified address
+// and the uint32_t binding is created for the specified address.
TEST(MySqlBindingTest, conditionalIPv4Address) {
auto binding = MySqlBinding::condCreateIPv4Address(Optional<IOAddress>());
EXPECT_TRUE(binding->amNull());
MODIFY COLUMN modification_ts TIMESTAMP NOT NULL
DEFAULT CURRENT_TIMESTAMP;
+ALTER TABLE dhcp4_subnet
+ ADD COLUMN calculate_tee_times TINYINT(1) DEFAULT NULL,
+ ADD COLUMN t1_percent FLOAT DEFAULT NULL,
+ ADD COLUMN t2_percent FLOAT DEFAULT NULL;
+
ALTER TABLE dhcp4_subnet
MODIFY COLUMN reservation_mode TINYINT(3) DEFAULT NULL;
ALTER TABLE dhcp4_subnet
MODIFY COLUMN match_client_id TINYINT(1) DEFAULT NULL;
+ALTER TABLE dhcp4_shared_network
+ ADD COLUMN calculate_tee_times TINYINT(1) DEFAULT NULL,
+ ADD COLUMN t1_percent FLOAT DEFAULT NULL,
+ ADD COLUMN t2_percent FLOAT DEFAULT NULL;
+
ALTER TABLE dhcp4_shared_network
MODIFY COLUMN reservation_mode TINYINT(3) DEFAULT NULL;
ALTER TABLE dhcp4_shared_network
MODIFY COLUMN match_client_id TINYINT(1) DEFAULT NULL;
+ALTER TABLE dhcp6_subnet
+ ADD COLUMN calculate_tee_times TINYINT(1) DEFAULT NULL,
+ ADD COLUMN t1_percent FLOAT DEFAULT NULL,
+ ADD COLUMN t2_percent FLOAT DEFAULT NULL;
+
ALTER TABLE dhcp6_subnet
MODIFY COLUMN reservation_mode TINYINT(3) DEFAULT NULL;
+ALTER TABLE dhcp6_shared_network
+ ADD COLUMN calculate_tee_times TINYINT(1) DEFAULT NULL,
+ ADD COLUMN t1_percent FLOAT DEFAULT NULL,
+ ADD COLUMN t2_percent FLOAT DEFAULT NULL;
+
ALTER TABLE dhcp6_shared_network
MODIFY COLUMN reservation_mode TINYINT(3) DEFAULT NULL;
+
-- -----------------------------------------------------
-- Make sure that constraints on the 7.0 schema tables
-- have appropriate referential actions. All tables
MODIFY COLUMN modification_ts TIMESTAMP NOT NULL
DEFAULT CURRENT_TIMESTAMP;
+ALTER TABLE dhcp4_subnet
+ ADD COLUMN calculate_tee_times TINYINT(1) DEFAULT NULL,
+ ADD COLUMN t1_percent FLOAT DEFAULT NULL,
+ ADD COLUMN t2_percent FLOAT DEFAULT NULL;
+
ALTER TABLE dhcp4_subnet
MODIFY COLUMN reservation_mode TINYINT(3) DEFAULT NULL;
ALTER TABLE dhcp4_subnet
MODIFY COLUMN match_client_id TINYINT(1) DEFAULT NULL;
+ALTER TABLE dhcp4_shared_network
+ ADD COLUMN calculate_tee_times TINYINT(1) DEFAULT NULL,
+ ADD COLUMN t1_percent FLOAT DEFAULT NULL,
+ ADD COLUMN t2_percent FLOAT DEFAULT NULL;
+
ALTER TABLE dhcp4_shared_network
MODIFY COLUMN reservation_mode TINYINT(3) DEFAULT NULL;
ALTER TABLE dhcp4_shared_network
MODIFY COLUMN match_client_id TINYINT(1) DEFAULT NULL;
+ALTER TABLE dhcp6_subnet
+ ADD COLUMN calculate_tee_times TINYINT(1) DEFAULT NULL,
+ ADD COLUMN t1_percent FLOAT DEFAULT NULL,
+ ADD COLUMN t2_percent FLOAT DEFAULT NULL;
+
ALTER TABLE dhcp6_subnet
MODIFY COLUMN reservation_mode TINYINT(3) DEFAULT NULL;
+ALTER TABLE dhcp6_shared_network
+ ADD COLUMN calculate_tee_times TINYINT(1) DEFAULT NULL,
+ ADD COLUMN t1_percent FLOAT DEFAULT NULL,
+ ADD COLUMN t2_percent FLOAT DEFAULT NULL;
+
ALTER TABLE dhcp6_shared_network
MODIFY COLUMN reservation_mode TINYINT(3) DEFAULT NULL;