Browse Source

Merge branch 'trac1899_2'

Mukund Sivaraman 12 years ago
parent
commit
daedcaea54

+ 8 - 1
src/bin/dbutil/dbutil.py.in

@@ -193,10 +193,17 @@ UPGRADES = [
             "ALTER TABLE schema_version " +
                 "ADD COLUMN minor INTEGER NOT NULL DEFAULT 0"
         ]
+     },
+
+    {'from': (2, 0), 'to': (2, 1),
+     'statements': [
+            "CREATE INDEX nsec3_byhash_and_rdtype ON nsec3 " +
+                "(hash, rdtype)"
+        ]
     }
 
 # To extend this, leave the above statements in place and add another
-# dictionary to the list.  The "from" version should be (2, 0), the "to"
+# dictionary to the list.  The "from" version should be (2, 1), the "to"
 # version whatever the version the update is to, and the SQL statements are
 # the statements required to perform the upgrade.  This way, the upgrade
 # program will be able to upgrade both a V1.0 and a V2.0 database.

+ 3 - 3
src/bin/dbutil/tests/dbutil_test.sh.in

@@ -165,7 +165,7 @@ upgrade_ok_test() {
     if [ $? -eq 0 ]
     then
         # Compare schema with the reference
-        get_schema $testdata/v2_0.sqlite3
+        get_schema $testdata/v2_1.sqlite3
         expected_schema=$db_schema
         get_schema $tempfile
         actual_schema=$db_schema
@@ -177,7 +177,7 @@ upgrade_ok_test() {
         fi
 
         # Check the version is set correctly
-        check_version $tempfile "V2.0"
+        check_version $tempfile "V2.1"
 
         # Check that a backup was made
         check_backup $1 $2
@@ -449,7 +449,7 @@ copy_file $testdata/old_v1.sqlite3 $tempfile
 Yes
 .
 passzero $?
-check_version $tempfile "V2.0"
+check_version $tempfile "V2.1"
 rm -f $tempfile $backupfile
 
 echo "13.4 Interactive prompt - no"

+ 1 - 0
src/bin/dbutil/tests/testdata/Makefile.am

@@ -10,3 +10,4 @@ EXTRA_DIST += old_v1.sqlite3
 EXTRA_DIST += README
 EXTRA_DIST += too_many_version.sqlite3
 EXTRA_DIST += v2_0.sqlite3
+EXTRA_DIST += v2_1.sqlite3

BIN
src/bin/dbutil/tests/testdata/v2_1.sqlite3


+ 81 - 53
src/lib/datasrc/sqlite3_accessor.cc

@@ -44,7 +44,7 @@ namespace {
 // program may not be taking advantage of features (possibly performance
 // improvements) added to the database.
 const int SQLITE_SCHEMA_MAJOR_VERSION = 2;
-const int SQLITE_SCHEMA_MINOR_VERSION = 0;
+const int SQLITE_SCHEMA_MINOR_VERSION = 1;
 }
 
 namespace isc {
@@ -65,19 +65,20 @@ enum StatementID {
     DEL_ZONE_RECORDS = 6,
     ADD_RECORD = 7,
     DEL_RECORD = 8,
-    ITERATE = 9,
-    FIND_PREVIOUS = 10,
-    ADD_RECORD_DIFF = 11,
-    LOW_DIFF_ID = 12,
-    HIGH_DIFF_ID = 13,
-    DIFF_RECS = 14,
-    NSEC3 = 15,
-    NSEC3_PREVIOUS = 16,
-    NSEC3_LAST = 17,
-    ADD_NSEC3_RECORD = 18,
-    DEL_ZONE_NSEC3_RECORDS = 19,
-    DEL_NSEC3_RECORD = 20,
-    NUM_STATEMENTS = 21
+    ITERATE_RECORDS = 9,
+    ITERATE_NSEC3 = 10,
+    FIND_PREVIOUS = 11,
+    ADD_RECORD_DIFF = 12,
+    LOW_DIFF_ID = 13,
+    HIGH_DIFF_ID = 14,
+    DIFF_RECS = 15,
+    NSEC3 = 16,
+    NSEC3_PREVIOUS = 17,
+    NSEC3_LAST = 18,
+    ADD_NSEC3_RECORD = 19,
+    DEL_ZONE_NSEC3_RECORDS = 20,
+    DEL_NSEC3_RECORD = 21,
+    NUM_STATEMENTS = 22
 };
 
 const char* const text_statements[NUM_STATEMENTS] = {
@@ -102,19 +103,17 @@ 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",
-    // 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",
+
+    // ITERATE_RECORDS:
+    // The following iterates the whole zone in the records table.
+    "SELECT rdtype, ttl, sigtype, rdata, name FROM records "
+        "WHERE zone_id = ?1 ORDER BY rname, rdtype",
+
+    // ITERATE_NSEC3:
+    // The following iterates the whole zone in the nsec3 table. As the
+    // RRSIGs are for NSEC3s, we can hardcode the sigtype.
+    "SELECT rdtype, ttl, \"NSEC3\", rdata, owner FROM nsec3 "
+        "WHERE zone_id = ?1 ORDER BY hash, 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
@@ -332,7 +331,7 @@ public:
 const char* const SCHEMA_LIST[] = {
     "CREATE TABLE schema_version (version INTEGER NOT NULL, "
         "minor INTEGER NOT NULL DEFAULT 0)",
-    "INSERT INTO schema_version VALUES (2, 0)",
+    "INSERT INTO schema_version VALUES (2, 1)",
     "CREATE TABLE zones (id INTEGER PRIMARY KEY, "
     "name TEXT NOT NULL COLLATE NOCASE, "
     "rdclass TEXT NOT NULL COLLATE NOCASE DEFAULT 'IN', "
@@ -358,6 +357,7 @@ const char* const SCHEMA_LIST[] = {
         "ttl INTEGER NOT NULL, rdtype TEXT NOT NULL COLLATE NOCASE, "
         "rdata TEXT NOT NULL)",
     "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
+    "CREATE INDEX nsec3_byhash_and_rdtype ON nsec3 (hash, rdtype)",
     "CREATE TABLE diffs (id INTEGER PRIMARY KEY, "
         "zone_id INTEGER NOT NULL, "
         "version INTEGER NOT NULL, "
@@ -642,11 +642,21 @@ public:
         iterator_type_(ITT_ALL),
         accessor_(accessor),
         statement_(NULL),
+        statement2_(NULL),
+        rc_(SQLITE_OK),
+        rc2_(SQLITE_OK),
         name_("")
     {
-        // We create the statement now and then just keep getting data from it
+        // We create the statements now and then just keep getting data
+        // from them.
         statement_ = prepare(accessor->dbparameters_->db_,
-                             text_statements[ITERATE]);
+                             text_statements[ITERATE_NSEC3]);
+        bindZoneId(id);
+
+        std::swap(statement_, statement2_);
+
+        statement_ = prepare(accessor->dbparameters_->db_,
+                             text_statements[ITERATE_RECORDS]);
         bindZoneId(id);
     }
 
@@ -665,6 +675,9 @@ public:
         iterator_type_(qtype == QT_NSEC3 ? ITT_NSEC3 : ITT_NAME),
         accessor_(accessor),
         statement_(NULL),
+        statement2_(NULL),
+        rc_(SQLITE_OK),
+        rc2_(SQLITE_OK),
         name_(name)
     {
         // Choose the statement text depending on the query type, and
@@ -703,29 +716,35 @@ public:
         // If there's another row, get it
         // If finalize has been called (e.g. when previous getNext() got
         // SQLITE_DONE), directly return false
-        if (statement_ == NULL) {
-            return false;
-        }
-        const int rc(sqlite3_step(statement_));
-        if (rc == SQLITE_ROW) {
-            // For both types, we copy the first four columns
-            copyColumn(data, TYPE_COLUMN);
-            copyColumn(data, TTL_COLUMN);
-            // The NSEC3 lookup does not provide the SIGTYPE, it is not
-            // necessary and not contained in the table.
-            if (iterator_type_ != ITT_NSEC3) {
-                copyColumn(data, SIGTYPE_COLUMN);
+        while (statement_ != NULL) {
+            rc_ = sqlite3_step(statement_);
+            if (rc_ == SQLITE_ROW) {
+                // For both types, we copy the first four columns
+                copyColumn(data, TYPE_COLUMN);
+                copyColumn(data, TTL_COLUMN);
+                // The NSEC3 lookup does not provide the SIGTYPE, it is not
+                // necessary and not contained in the table.
+                if (iterator_type_ != ITT_NSEC3) {
+                    copyColumn(data, SIGTYPE_COLUMN);
+                }
+                copyColumn(data, RDATA_COLUMN);
+                // Only copy Name if we are iterating over every record
+                if (iterator_type_ == ITT_ALL) {
+                    copyColumn(data, NAME_COLUMN);
+                }
+                return (true);
+            } else if (rc_ != SQLITE_DONE) {
+                isc_throw(DataSourceError,
+                          "Unexpected failure in sqlite3_step: " <<
+                          sqlite3_errmsg(accessor_->dbparameters_->db_));
             }
-            copyColumn(data, RDATA_COLUMN);
-            // Only copy Name if we are iterating over every record
-            if (iterator_type_ == ITT_ALL) {
-                copyColumn(data, NAME_COLUMN);
+            // We are done with statement_. If statement2_ has not been
+            // used yet, try that one now.
+            if ((statement2_ == NULL) || (rc2_ != SQLITE_OK)) {
+                break;
             }
-            return (true);
-        } else if (rc != SQLITE_DONE) {
-            isc_throw(DataSourceError,
-                      "Unexpected failure in sqlite3_step: " <<
-                      sqlite3_errmsg(accessor_->dbparameters_->db_));
+            std::swap(statement_, statement2_);
+            std::swap(rc_, rc2_);
         }
         finalize();
         return (false);
@@ -771,13 +790,22 @@ private:
     }
 
     void finalize() {
-        sqlite3_finalize(statement_);
-        statement_ = NULL;
+        if (statement_ != NULL) {
+             sqlite3_finalize(statement_);
+             statement_ = NULL;
+        }
+        if (statement2_ != NULL) {
+             sqlite3_finalize(statement2_);
+             statement2_ = NULL;
+        }
     }
 
     const IteratorType iterator_type_;
     boost::shared_ptr<const SQLite3Accessor> accessor_;
     sqlite3_stmt* statement_;
+    sqlite3_stmt* statement2_;
+    int rc_;
+    int rc2_;
     const std::string name_;
 };
 

+ 5 - 0
src/lib/datasrc/tests/sqlite3_accessor_unittest.cc

@@ -191,6 +191,11 @@ TEST_F(SQLite3AccessorTest, iterator) {
     checkRR(context, "sub.example.org.", "3600", "NS", "ns.sub.example.org.");
     checkRR(context, "ns.sub.example.org.", "3600", "A", "192.0.2.101");
     checkRR(context, "www.example.org.", "3600", "A", "192.0.2.1");
+    checkRR(context, "ns3.example.org.", "3600", "NSEC3",
+            "1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG");
+    checkRR(context, "ns3.example.org.", "3600", "RRSIG",
+            "NSEC3 5 3 3600 20000101000000 20000201000000 "
+            "12345 ns3.example.org. FAKEFAKEFAKE");
 
     // Check there's no other
     EXPECT_FALSE(context->getNext(data));

BIN
src/lib/datasrc/tests/testdata/example.org.sqlite3


+ 2 - 1
src/lib/python/isc/datasrc/sqlite3_ds.py

@@ -25,7 +25,7 @@ RR_RDATA_INDEX = 7
 
 # Current major and minor versions of schema
 SCHEMA_MAJOR_VERSION = 2
-SCHEMA_MINOR_VERSION = 0
+SCHEMA_MINOR_VERSION = 1
 
 class Sqlite3DSError(Exception):
     """ Define exceptions."""
@@ -81,6 +81,7 @@ def create(cur):
                     rdtype TEXT NOT NULL COLLATE NOCASE,
                     rdata TEXT NOT NULL)""")
         cur.execute("CREATE INDEX nsec3_byhash ON nsec3 (hash)")
+        cur.execute("CREATE INDEX nsec3_byhash_and_rdtype ON nsec3 (hash, rdtype)")
         cur.execute("""CREATE TABLE diffs (id INTEGER PRIMARY KEY,
                     zone_id INTEGER NOT NULL,
                     version INTEGER NOT NULL,