diff --git a/src/lib/datasrc/sqlite3_accessor.cc b/src/lib/datasrc/sqlite3_accessor.cc index 11f364e9d7..0214762bfd 100644 --- a/src/lib/datasrc/sqlite3_accessor.cc +++ b/src/lib/datasrc/sqlite3_accessor.cc @@ -93,8 +93,19 @@ const char* const text_statements[NUM_STATEMENTS] = { "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", "DELETE FROM records WHERE zone_id=?1 AND name=?2 " // DEL_RECORD "AND rdtype=?3 AND rdata=?4", - "SELECT rdtype, ttl, sigtype, rdata, name FROM records " // ITERATE - "WHERE zone_id = ?1 ORDER BY rname, rdtype", + // The following iterates the whole zone. As the NSEC3 records + // (and corresponding RRSIGs) live in separate table, we need to + // take both of them. As the RRSIGs are for NSEC3s in the other + // table, we can easily hardcode the sigtype. + // + // The extra column is so we can order it by rname. This is to + // preserve the previous order, mostly for tests. + // TODO: Is it possible to get rid of the ordering? + "SELECT rdtype, ttl, sigtype, rdata, name, rname FROM records " // ITERATE + "WHERE zone_id = ?1 " + "UNION " + "SELECT rdtype, ttl, \"NSEC3\", rdata, owner, owner FROM nsec3 " + "WHERE zone_id = ?1 ORDER by rname, rdtype", /* * This one looks for previous name with NSEC record. It is done by * using the reversed name. The NSEC is checked because we need to diff --git a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc index c36c94bfa6..f3aea4e225 100644 --- a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc +++ b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc @@ -194,6 +194,49 @@ TEST_F(SQLite3AccessorTest, iterator) { EXPECT_FALSE(context->getNext(data)); } +// This tests the iterator through the whole zone returns NSEC3 records as +// well. We test this specifically, as it lives in separate table and needs +// extra handling. +TEST_F(SQLite3AccessorTest, nsec3Iterator) { + // Get the zone + const std::pair + zone_info(accessor->getZone("sql2.example.com.")); + ASSERT_TRUE(zone_info.first); + + // Iterate through it + DatabaseAccessor::IteratorContextPtr + context(accessor->getAllRecords(zone_info.second)); + + // We just pick a random NSEC3 to check, the check of complete iterator + // is in the above test. In addition, we count the number of NSEC3, RRSIG + // and all records, as some kind of check it returns all the data. + std::string data[DatabaseAccessor::COLUMN_COUNT]; + + size_t nsec3count(0), rrsigcount(0), recordcount(0); + bool nsec3match(false); + while (context->getNext(data)) { + if (data[DatabaseAccessor::TYPE_COLUMN] == "NSEC3") { + nsec3count ++; + if (data[DatabaseAccessor::NAME_COLUMN] == + "1BB7SO0452U1QHL98UISNDD9218GELR5.sql2.example.com.") { + nsec3match = true; + EXPECT_EQ("7200", data[DatabaseAccessor::TTL_COLUMN]); + EXPECT_EQ("1 0 10 FEEDABEE 4KLSVDE8KH8G95VU68R7AHBE1CPQN38J", + data[DatabaseAccessor::RDATA_COLUMN]); + } + } else if (data[DatabaseAccessor::TYPE_COLUMN] == "RRSIG") { + rrsigcount ++; + } + recordcount ++; + } + + // We counted everything now, so check there's nothing else to count + EXPECT_EQ(11, nsec3count); + EXPECT_EQ(22, rrsigcount); + EXPECT_EQ(46, recordcount); + EXPECT_TRUE(nsec3match) << "No NSEC3 found when iterating the zone"; +} + // This tests getting NSEC3 records TEST_F(SQLite3AccessorTest, nsec3) { const std::pair