From: JINMEI Tatuya Date: Thu, 10 Jan 2013 05:06:46 +0000 (-0800) Subject: [2575] define IF of deleteZone() and implement it for SQLite3. X-Git-Tag: bind10-1.0.0-rc-release~95^2~12^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3072c500b4c563cb22b7cdae805cdb6c1e99a408;p=thirdparty%2Fkea.git [2575] define IF of deleteZone() and implement it for SQLite3. --- diff --git a/src/lib/datasrc/database.h b/src/lib/datasrc/database.h index 9db8a8fa66..b50d25a78c 100644 --- a/src/lib/datasrc/database.h +++ b/src/lib/datasrc/database.h @@ -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 diff --git a/src/lib/datasrc/sqlite3_accessor.cc b/src/lib/datasrc/sqlite3_accessor.cc index 4ef49d054b..bd71544d0f 100644 --- a/src/lib/datasrc/sqlite3_accessor.cc +++ b/src/lib/datasrc/sqlite3_accessor.cc @@ -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 diff --git a/src/lib/datasrc/sqlite3_accessor.h b/src/lib/datasrc/sqlite3_accessor.h index c5773d019d..fc47c73fd9 100644 --- a/src/lib/datasrc/sqlite3_accessor.h +++ b/src/lib/datasrc/sqlite3_accessor.h @@ -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 diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc index 174da0442c..c71f200eb7 100644 --- a/src/lib/datasrc/tests/database_unittest.cc +++ b/src/lib/datasrc/tests/database_unittest.cc @@ -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 clone() { // This accessor is stateless, so we can simply return a new instance. return (boost::shared_ptr(new NopAccessor)); diff --git a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc index 8dff6d5a21..c263304f28 100644 --- a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc +++ b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc @@ -20,6 +20,8 @@ #include +#include + #include #include @@ -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 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 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