Browse Source

[1891] implemented addNSEC3RecordToZone, 1st step.

defined a new statement for updating the nsec3 table, and used it from
addNSEC3RecordToZone.  some validation checks are still missing.
also made simple cleanup of removing unnecessary namespace qualifiers.
JINMEI Tatuya 13 years ago
parent
commit
7aac25a59b

+ 14 - 8
src/lib/datasrc/sqlite3_accessor.cc

@@ -73,7 +73,8 @@ enum StatementID {
     NSEC3 = 16,
     NSEC3_PREVIOUS = 17,
     NSEC3_LAST = 18,
-    NUM_STATEMENTS = 19
+    ADD_NSEC3_RECORD = 19,
+    NUM_STATEMENTS = 20
 };
 
 const char* const text_statements[NUM_STATEMENTS] = {
@@ -135,19 +136,22 @@ const char* const text_statements[NUM_STATEMENTS] = {
         "WHERE zone_id=?1 AND id>=?2 and id<=?3 "
         "ORDER BY id ASC",
 
-    // Query to get the NSEC3 records
+    // NSEC3: Query to get the NSEC3 records
     //
     // The "1" in SELECT is for positioning the rdata column to the
     // expected position, so we can reuse the same code as for other
     // lookups.
     "SELECT rdtype, ttl, 1, rdata FROM nsec3 WHERE zone_id=?1 AND "
         "hash=?2",
-    // For getting the previous NSEC3 hash
+    // NSEC3_PREVIOUS: For getting the previous NSEC3 hash
     "SELECT DISTINCT hash FROM nsec3 WHERE zone_id=?1 AND hash < ?2 "
         "ORDER BY hash DESC LIMIT 1",
-    // And for wrap-around
+    // NSEC3_LAST: And for wrap-around
     "SELECT DISTINCT hash FROM nsec3 WHERE zone_id=?1 "
         "ORDER BY hash DESC LIMIT 1",
+    // ADD_NSEC3_RECORD: Add NSEC3-related (NSEC3 or NSEC3-covering RRSIG) RR
+    "INSERT INTO nsec3 (zone_id, hash, owner, ttl, rdtype, rdata) "
+    "VALUES (?1, ?2, '', ?3, ?4, ?5)"
 };
 
 struct SQLite3Parameters {
@@ -1128,15 +1132,17 @@ SQLite3Accessor::addRecordToZone(const string (&columns)[ADD_COLUMN_COUNT]) {
         isc_throw(DataSourceError, "adding record to SQLite3 "
                   "data source without transaction");
     }
-    doUpdate<const string (&)[DatabaseAccessor::ADD_COLUMN_COUNT]>(
+    doUpdate<const string (&)[ADD_COLUMN_COUNT]>(
         *dbparameters_, ADD_RECORD, columns, "add record to zone");
 }
 
 void
 SQLite3Accessor::addNSEC3RecordToZone(
-    const string (&/*columns*/)[ADD_NSEC3_COLUMN_COUNT])
+    const string (&columns)[ADD_NSEC3_COLUMN_COUNT])
 {
-    isc_throw(NotImplemented, "not yet implemented");
+    // TODO: no transaction case
+    doUpdate<const string (&)[ADD_NSEC3_COLUMN_COUNT]>(
+        *dbparameters_, ADD_NSEC3_RECORD, columns, "add NSEC3 record to zone");
 }
 
 void
@@ -1145,7 +1151,7 @@ SQLite3Accessor::deleteRecordInZone(const string (&params)[DEL_PARAM_COUNT]) {
         isc_throw(DataSourceError, "deleting record in SQLite3 "
                   "data source without transaction");
     }
-    doUpdate<const string (&)[DatabaseAccessor::DEL_PARAM_COUNT]>(
+    doUpdate<const string (&)[DEL_PARAM_COUNT]>(
         *dbparameters_, DEL_RECORD, params, "delete record from zone");
 }
 

+ 80 - 8
src/lib/datasrc/tests/sqlite3_accessor_unittest.cc

@@ -12,8 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <algorithm>
-#include <vector>
+#include "faked_nsec3.h"
 
 #include <datasrc/sqlite3_accessor.h>
 
@@ -21,14 +20,20 @@
 
 #include <dns/rrclass.h>
 
+#include <sqlite3.h>
+
 #include <gtest/gtest.h>
+
 #include <boost/lexical_cast.hpp>
 #include <boost/scoped_ptr.hpp>
+
+#include <algorithm>
+#include <vector>
 #include <fstream>
-#include <sqlite3.h>
 
 using namespace std;
 using namespace isc::datasrc;
+using namespace isc::datasrc::test;
 using boost::lexical_cast;
 using isc::data::ConstElementPtr;
 using isc::data::Element;
@@ -463,11 +468,11 @@ TEST(SQLite3Open, getDBNameExampleROOT) {
 // Simple function to match records
 void
 checkRecordRow(const std::string columns[],
-               const std::string& field0,
-               const std::string& field1,
-               const std::string& field2,
-               const std::string& field3,
-               const std::string& field4)
+               const std::string& field0, // for type
+               const std::string& field1, // for TTL
+               const std::string& field2, // for "sigtype"
+               const std::string& field3, // for rdata
+               const std::string& field4) // for name
 {
     EXPECT_EQ(field0, columns[DatabaseAccessor::TYPE_COLUMN]);
     EXPECT_EQ(field1, columns[DatabaseAccessor::TTL_COLUMN]);
@@ -736,6 +741,18 @@ const char* const deleted_data[] = {
     // Existing data to be removed commonly used by some of the tests below
     "foo.bar.example.com.", "A", "192.0.2.1"
 };
+const char* const nsec3_data[DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT] = {
+    // example NSEC parameters.  Using "apex_hash" just as a convenient
+    // shortcut; otherwise it has nothing to do with the zone apex for the
+    // purpose of this test.
+    apex_hash, "3600", "NSEC3",
+    "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR NS SOA"
+};
+const char* const nsec3_sig_data[DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT] = {
+    ns1_hash, "3600", "RRSIG",
+    "NSEC3 5 3 3600 20000101000000 20000201000000 12345 "
+    "example.com. FAKEFAKEFAKE"
+};
 
 class SQLite3Update : public SQLite3AccessorTest {
 protected:
@@ -762,6 +779,7 @@ protected:
     int zone_id;
     std::string get_columns[DatabaseAccessor::COLUMN_COUNT];
     std::string add_columns[DatabaseAccessor::ADD_COLUMN_COUNT];
+    std::string add_nsec3_columns[DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT];
     std::string del_params[DatabaseAccessor::DEL_PARAM_COUNT];
     std::string diff_params[DatabaseAccessor::DIFF_PARAM_COUNT];
 
@@ -789,6 +807,28 @@ checkRecords(SQLite3Accessor& accessor, int zone_id, const std::string& name,
     EXPECT_TRUE(it == expected_rows.end());
 }
 
+// Similar to the previous one, but checking transactions on the nsec3 table.
+void
+checkNSEC3Records(SQLite3Accessor& accessor, int zone_id,
+                  const std::string& hash,
+                  vector<const char* const*> expected_rows)
+{
+    DatabaseAccessor::IteratorContextPtr iterator =
+        accessor.getNSEC3Records(hash, zone_id);
+    std::string columns[DatabaseAccessor::COLUMN_COUNT];
+    vector<const char* const*>::const_iterator it = expected_rows.begin();
+    while (iterator->getNext(columns)) {
+        ASSERT_TRUE(it != expected_rows.end());
+        checkRecordRow(columns, (*it)[DatabaseAccessor::ADD_NSEC3_TYPE],
+                       (*it)[DatabaseAccessor::ADD_NSEC3_TTL],
+                       "",      // sigtype, should always be empty
+                       (*it)[DatabaseAccessor::ADD_NSEC3_RDATA],
+                       "");     // name, always empty
+        ++it;
+    }
+    EXPECT_TRUE(it == expected_rows.end());
+}
+
 TEST_F(SQLite3Update, emptyUpdate) {
     // If we do nothing between start and commit, the zone content
     // should be intact.
@@ -924,6 +964,38 @@ TEST_F(SQLite3Update, addRecord) {
     checkRecords(*accessor, zone_id, "newdata.example.com.", expected_stored);
 }
 
+TEST_F(SQLite3Update, addNSEC3Record) {
+    // Similar to the previous test, but for NSEC3-related records
+    checkRecords(*accessor, zone_id, apex_hash, empty_stored);
+    checkRecords(*accessor, zone_id, ns1_hash, empty_stored);
+
+    zone_id = accessor->startUpdateZone("example.com.", false).second;
+    // Add an NSEC3
+    copy(nsec3_data, nsec3_data + DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT,
+         add_nsec3_columns);
+    accessor->addNSEC3RecordToZone(add_nsec3_columns);
+    // Add an RRSIG for NSEC3
+    copy(nsec3_sig_data,
+         nsec3_sig_data + DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT,
+         add_nsec3_columns);
+    accessor->addNSEC3RecordToZone(add_nsec3_columns);
+
+    // Check the stored data, before and after commit().
+    for (size_t i = 0; i < 2; ++i) {
+        expected_stored.clear();
+        expected_stored.push_back(nsec3_data);
+        checkNSEC3Records(*accessor, zone_id, apex_hash, expected_stored);
+
+        expected_stored.clear();
+        expected_stored.push_back(nsec3_sig_data);
+        checkNSEC3Records(*accessor, zone_id, ns1_hash, expected_stored);
+
+        if (i == 0) {          // make sure commit() happens only once
+            accessor->commit();
+        }
+    }
+}
+
 TEST_F(SQLite3Update, addThenRollback) {
     zone_id = accessor->startUpdateZone("example.com.", false).second;
     copy(new_data, new_data + DatabaseAccessor::ADD_COLUMN_COUNT,