Commit 3072c500 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[2575] define IF of deleteZone() and implement it for SQLite3.

parent 0c40d70c
......@@ -155,7 +155,7 @@ public:
///
/// It is empty, but needs a virtual one, since we will use the derived
/// classes in polymorphic way.
virtual ~DatabaseAccessor() { }
virtual ~DatabaseAccessor() {}
/// \brief Retrieve a zone identifier
///
......@@ -164,8 +164,8 @@ public:
/// apex), as the DatabaseClient will loop trough the labels itself and
/// find the most suitable zone.
///
/// It is not specified if and what implementation of this method may throw,
/// so code should expect anything.
/// It is not specified if and what implementation of this method may
/// throw, so code should expect anything.
///
/// \param name The (fully qualified) domain name of the zone's apex to be
/// looked up.
......@@ -195,6 +195,8 @@ public:
/// or was created by this call).
virtual int addZone(const std::string& name) = 0;
virtual void deleteZone(int zone_id) = 0;
/// \brief This holds the internal context of ZoneIterator for databases
///
/// While the ZoneIterator implementation from DatabaseClient does all the
......@@ -212,15 +214,15 @@ public:
/// \brief Destructor
///
/// Virtual destructor, so any descendand class is destroyed correctly.
virtual ~IteratorContext() { }
virtual ~IteratorContext() {}
/// \brief Function to provide next resource record
///
/// This function should provide data about the next resource record
/// from the data that is searched. The data is not converted yet.
///
/// Depending on how the iterator was constructed, there is a difference
/// in behaviour; for a 'full zone iterator', created with
/// Depending on how the iterator was constructed, there is a
/// difference in behaviour; for a 'full zone iterator', created with
/// getAllRecords(), all COLUMN_COUNT elements of the array are
/// overwritten.
/// For a 'name iterator', created with getRecords(), the column
......
......@@ -79,7 +79,8 @@ enum StatementID {
DEL_ZONE_NSEC3_RECORDS = 20,
DEL_NSEC3_RECORD = 21,
ADD_ZONE = 22,
NUM_STATEMENTS = 23
DELETE_ZONE = 23,
NUM_STATEMENTS = 24
};
const char* const text_statements[NUM_STATEMENTS] = {
......@@ -165,7 +166,9 @@ const char* const text_statements[NUM_STATEMENTS] = {
"AND rdtype=?3 AND rdata=?4",
// ADD_ZONE: add a zone to the zones table
"INSERT INTO zones (name, rdclass) VALUES (?1, ?2)" // ADD_ZONE
"INSERT INTO zones (name, rdclass) VALUES (?1, ?2)", // ADD_ZONE
// DELETE_ZONE: delete a zone from the zones table
"DELETE FROM zones WHERE id=?1" // DELETE_ZONE
};
struct SQLite3Parameters {
......@@ -643,6 +646,19 @@ SQLite3Accessor::addZone(const std::string& name) {
return (getzone_result.second);
}
void
SQLite3Accessor::deleteZone(int zone_id) {
// Transaction should have been started by the caller
if (!dbparameters_->in_transaction) {
isc_throw(InvalidOperation, "performing deleteZone on SQLite3 "
"data source without transaction");
}
StatementProcessor proc(*dbparameters_, DELETE_ZONE, "delete zone");
proc.bindInt(1, zone_id);
proc.exec();
}
namespace {
// Conversion to plain char
......
......@@ -139,6 +139,8 @@ public:
/// \return the id of the zone that has been added
virtual int addZone(const std::string& name);
virtual void deleteZone(int zone_id);
/// \brief Look up all resource records for a name
///
/// This implements the getRecords() method from DatabaseAccessor
......
......@@ -279,6 +279,11 @@ public:
"This database datasource can't add zones");
}
virtual void deleteZone(int) {
isc_throw(isc::NotImplemented,
"This database datasource can't delete zones");
}
virtual boost::shared_ptr<DatabaseAccessor> clone() {
// This accessor is stateless, so we can simply return a new instance.
return (boost::shared_ptr<DatabaseAccessor>(new NopAccessor));
......
......@@ -20,6 +20,8 @@
#include <dns/rrclass.h>
#include <exceptions/exceptions.h>
#include <sqlite3.h>
#include <gtest/gtest.h>
......@@ -1615,4 +1617,50 @@ TEST_F(SQLite3Update, addZoneWhileLocked) {
EXPECT_FALSE(accessor->getZone(new_zone).first);
}
//
// Tests for deleteZone() follow.
//
TEST_F(SQLite3Update, deleteZone) {
const std::pair<bool, int> zone_info(accessor->getZone("example.com."));
ASSERT_TRUE(zone_info.first);
zone_id = zone_info.second;
// Calling deleteZone without transaction should fail
EXPECT_THROW(accessor->deleteZone(zone_info.first), isc::InvalidOperation);
// Delete the zone. Then confirm it, both before and after commit.
accessor->startTransaction();
accessor->deleteZone(zone_info.second);
EXPECT_FALSE(accessor->getZone("example.com.").first);
accessor->commit();
EXPECT_FALSE(accessor->getZone("example.com.").first);
// Records are not deleted.
std::string data[DatabaseAccessor::COLUMN_COUNT];
EXPECT_TRUE(accessor->getRecords("example.com.", zone_id, false)
->getNext(data));
}
TEST_F(SQLite3Update, deleteZoneWhileLocked) {
const std::pair<bool, int> zone_info(accessor->getZone("example.com."));
ASSERT_TRUE(zone_info.first);
zone_id = zone_info.second;
// Adding another (not commit yet), it should lock the db
const std::string new_zone = "new.example.com.";
accessor->startTransaction();
zone_id = accessor->addZone(new_zone);
// deleteZone should throw an exception that it is locked
another_accessor->startTransaction();
EXPECT_THROW(another_accessor->deleteZone(zone_id), DataSourceError);
// Commit should do nothing, but not fail
another_accessor->commit();
accessor->rollback();
// The zone should still exist.
EXPECT_TRUE(accessor->getZone("example.com.").first);
}
} // end anonymous namespace
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment