/// @param host Pointer to the new @c Host object being added.
virtual void add(const HostPtr& host) = 0;
- /// @brief Attempts to delete a host by (subnet-id, address)
+ /// @brief Attempts to delete hosts by (subnet-id, address)
///
/// This method supports both v4 and v6.
///
/// has already been added to the IPv4 or IPv6 subnet.
virtual void add(const HostPtr& host);
- /// @brief Attempts to delete a host by address.
+ /// @brief Attempts to delete a hosts by address.
///
/// This method supports both v4 and v6.
/// @todo: Not implemented.
/// @param host pointer to the new @ref Host being added.
virtual void add(const HostPtr& host) override;
- /// @brief Attempts to delete a host by (subnet-id, address)
+ /// @brief Attempts to delete hosts by (subnet-id, address)
///
/// This method supports both v4 and v6.
///
/// @param host Pointer to the new @c Host object being added.
virtual void add(const HostPtr& host);
- /// @brief Attempts to delete a host by address.
+ /// @brief Attempts to delete hosts by address.
///
/// This method supports both v4 and v6.
///
INSERT_V4_HOST_OPTION, // Insert DHCPv4 option
INSERT_V6_HOST_OPTION, // Insert DHCPv6 option
DEL_HOST_ADDR4, // Delete v4 host (subnet-id, addr4)
+ DEL_HOST_ADDR6, // Delete v6 host (subnet-id, addr6)
DEL_HOST_SUBID4_ID, // Delete v4 host (subnet-id, ident.type, identifier)
DEL_HOST_SUBID6_ID, // Delete v6 host (subnet-id, ident.type, identifier)
NUM_STATEMENTS // Number of statements
"persistent, user_context, dhcp_client_class, dhcp6_subnet_id, host_id, scope_id) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"},
- // Delete a single IPv4 reservation by subnet id and reserved address.
+ // Delete IPv4 reservations by subnet id and reserved address.
{MySqlHostDataSourceImpl::DEL_HOST_ADDR4,
"DELETE FROM hosts WHERE dhcp4_subnet_id = ? AND ipv4_address = ?"},
+ // Delete IPv6 reservations by subnet id and reserved address/prefix.
+ {MySqlHostDataSourceImpl::DEL_HOST_ADDR6,
+ "DELETE h FROM hosts AS h "
+ "INNER JOIN ipv6_reservations AS r "
+ "ON h.host_id = r.host_id "
+ "WHERE h.dhcp6_subnet_id = ? AND r.address = ?"},
+
// Delete a single IPv4 reservation by subnet id and identifier.
{MySqlHostDataSourceImpl::DEL_HOST_SUBID4_ID,
"DELETE FROM hosts WHERE dhcp4_subnet_id = ? AND dhcp_identifier_type=? "
// If operating in read-only mode, throw exception.
impl_->checkReadOnly(ctx);
- if (addr.isV4()) {
- // Set up the WHERE clause value
- MYSQL_BIND inbind[2];
+ // Set up the WHERE clause value
+ MYSQL_BIND inbind[2];
- uint32_t subnet = subnet_id;
- memset(inbind, 0, sizeof(inbind));
- inbind[0].buffer_type = MYSQL_TYPE_LONG;
- inbind[0].buffer = reinterpret_cast<char*>(&subnet);
- inbind[0].is_unsigned = MLM_TRUE;
+ uint32_t subnet = subnet_id;
+ memset(inbind, 0, sizeof(inbind));
+ inbind[0].buffer_type = MYSQL_TYPE_LONG;
+ inbind[0].buffer = reinterpret_cast<char*>(&subnet);
+ inbind[0].is_unsigned = MLM_TRUE;
+ // v4
+ if (addr.isV4()) {
uint32_t addr4 = addr.toUint32();
inbind[1].buffer_type = MYSQL_TYPE_LONG;
inbind[1].buffer = reinterpret_cast<char*>(&addr4);
inbind[1].is_unsigned = MLM_TRUE;
- ConstHostCollection collection;
return (impl_->delStatement(ctx, MySqlHostDataSourceImpl::DEL_HOST_ADDR4, inbind));
}
// v6
- ConstHostPtr host = get6(subnet_id, addr);
- if (!host) {
- return (false);
- }
+ std::string addr_str = addr.toText();
+ unsigned long addr_len = addr_str.size();
+ inbind[1].buffer_type = MYSQL_TYPE_BLOB;
+ inbind[1].buffer = reinterpret_cast<char*>
+ (const_cast<char*>(addr_str.c_str()));
+ inbind[1].length = &addr_len;
+ inbind[1].buffer_length = addr_len;
- // Ok, there is a host. Let's delete it.
- return del6(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0],
- host->getIdentifier().size());
+ return (impl_->delStatement(ctx, MySqlHostDataSourceImpl::DEL_HOST_ADDR6, inbind));
}
bool
/// @param host Pointer to the new @c Host object being added.
virtual void add(const HostPtr& host);
- /// @brief Attempts to delete a host by (subnet-id, address)
+ /// @brief Attempts to delete hosts by (subnet-id, address)
///
/// This method supports both v4 and v6.
///
INSERT_V4_HOST_OPTION, // Insert DHCPv4 option
INSERT_V6_HOST_OPTION, // Insert DHCPv6 option
DEL_HOST_ADDR4, // Delete v4 host (subnet-id, addr4)
+ DEL_HOST_ADDR6, // Delete v6 host (subnet-id, addr6)
DEL_HOST_SUBID4_ID, // Delete v4 host (subnet-id, ident.type, identifier)
DEL_HOST_SUBID6_ID, // Delete v6 host (subnet-id, ident.type, identifier)
NUM_STATEMENTS // Number of statements
"DELETE FROM hosts WHERE dhcp4_subnet_id = $1 AND ipv4_address = $2"
},
+ // PgSqlHostDataSourceImpl::DEL_HOST_ADDR6
+ // Deletes a v6 host that matches (subnet-id, addr6)
+ {2,
+ { OID_INT8, OID_VARCHAR },
+ "del_host_addr6",
+ "DELETE FROM hosts USING ipv6_reservations "
+ " WHERE dhcp6_subnet_id = $1 AND ipv6_reservations.address = $2"
+ },
+
// PgSqlHostDataSourceImpl::DEL_HOST_SUBID4_ID
// Deletes a v4 host that matches (subnet4-id, identifier-type, identifier)
{3,
// If operating in read-only mode, throw exception.
impl_->checkReadOnly(ctx);
+ PsqlBindArrayPtr bind_array(new PsqlBindArray());
+ bind_array->add(subnet_id);
+
+ // v4
if (addr.isV4()) {
- PsqlBindArrayPtr bind_array(new PsqlBindArray());
- bind_array->add(subnet_id);
bind_array->add(addr);
return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_ADDR4,
bind_array));
}
- ConstHostPtr host = get6(subnet_id, addr);
- if (!host) {
- return (false);
- }
+ // v6
+ bind_array->add(addr.toText());
- return del6(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0],
- host->getIdentifier().size());
+ return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_ADDR6,
+ bind_array));
}
bool
/// violation
virtual void add(const HostPtr& host);
- /// @brief Attempts to delete a host by (subnet-id, address)
+ /// @brief Attempts to delete hosts by (subnet-id, address)
///
/// This method supports both v4 and v6.
///
ASSERT_NO_THROW(returned = hdsptr_->getAll6(host->getIPv6SubnetID(), IOAddress("2001:db8::1")));
EXPECT_EQ(2, returned.size());
EXPECT_NE(returned[0]->getIdentifierAsText(), returned[1]->getIdentifierAsText());
+
+ // Let's now try to delete the hosts by subnet_id and address.
+ bool deleted = false;
+ ASSERT_NO_THROW(deleted = hdsptr_->del(subnet_id, IOAddress("2001:db8::1")));
+ ASSERT_TRUE(deleted);
+ ASSERT_NO_THROW(returned = hdsptr_->getAll6(host->getIPv6SubnetID(), IOAddress("2001:db8::1")));
+ EXPECT_TRUE(returned.empty());
}
void
ASSERT_NO_THROW(returned = hdsptr_->getAll4(host->getIPv4SubnetID(), IOAddress("192.0.2.1")));
EXPECT_EQ(2, returned.size());
EXPECT_NE(returned[0]->getIdentifierAsText(), returned[1]->getIdentifierAsText());
+
+ // Let's now try to delete the hosts by subnet_id and address.
+ bool deleted = false;
+ ASSERT_NO_THROW(deleted = hdsptr_->del(subnet_id, IOAddress("192.0.2.1")));
+ ASSERT_TRUE(deleted);
+ ASSERT_NO_THROW(returned = hdsptr_->getAll4(host->getIPv4SubnetID(), IOAddress("192.0.2.1")));
+ EXPECT_TRUE(returned.empty());
}
void
CREATE INDEX key_dhcp6_address_prefix_len
ON ipv6_reservations (address ASC, prefix_len ASC);
+# Stop using a trigger to delete entries dependent on hosts table.
+# Use cascade action instead. This works better with complex delete
+# statements.
+DROP TRIGGER IF EXISTS host_BDEL;
+
+# Replace existing constraint to set cascade actions.
+ALTER TABLE ipv6_reservations DROP FOREIGN KEY fk_ipv6_reservations_Host;
+ALTER TABLE ipv6_reservations ADD CONSTRAINT fk_ipv6_reservations_Host
+ FOREIGN KEY (host_id)
+ REFERENCES hosts(host_id)
+ ON DELETE CASCADE ON UPDATE CASCADE;
+
+ALTER TABLE dhcp4_options ADD CONSTRAINT fk_dhcp4_options_Host
+ FOREIGN KEY (host_id)
+ REFERENCES hosts(host_id)
+ ON DELETE CASCADE ON UPDATE CASCADE;
+
+ALTER TABLE dhcp6_options ADD CONSTRAINT fk_dhcp6_options_Host
+ FOREIGN KEY (host_id)
+ REFERENCES hosts(host_id)
+ ON DELETE CASCADE ON UPDATE CASCADE;
+
# Update the schema version number
UPDATE schema_version
SET version = '9', minor = '4';
CREATE INDEX key_dhcp6_address_prefix_len
ON ipv6_reservations (address ASC, prefix_len ASC);
+# Stop using a trigger to delete entries dependent on hosts table.
+# Use cascade action instead. This works better with complex delete
+# statements.
+DROP TRIGGER IF EXISTS host_BDEL;
+
+# Replace existing constraint to set cascade actions.
+ALTER TABLE ipv6_reservations DROP FOREIGN KEY fk_ipv6_reservations_Host;
+ALTER TABLE ipv6_reservations ADD CONSTRAINT fk_ipv6_reservations_Host
+ FOREIGN KEY (host_id)
+ REFERENCES hosts(host_id)
+ ON DELETE CASCADE ON UPDATE CASCADE;
+
+ALTER TABLE dhcp4_options ADD CONSTRAINT fk_dhcp4_options_Host
+ FOREIGN KEY (host_id)
+ REFERENCES hosts(host_id)
+ ON DELETE CASCADE ON UPDATE CASCADE;
+
+ALTER TABLE dhcp6_options ADD CONSTRAINT fk_dhcp6_options_Host
+ FOREIGN KEY (host_id)
+ REFERENCES hosts(host_id)
+ ON DELETE CASCADE ON UPDATE CASCADE;
+
# Update the schema version number
UPDATE schema_version
SET version = '9', minor = '4';