Browse Source

[1899] Break up UNION SQL query into two and merge manually

Also drop unnecessary columns and ORDER BYs.
Mukund Sivaraman 12 years ago
parent
commit
66f45b3d67
1 changed files with 80 additions and 51 deletions
  1. 80 51
      src/lib/datasrc/sqlite3_accessor.cc

+ 80 - 51
src/lib/datasrc/sqlite3_accessor.cc

@@ -63,19 +63,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] = {
@@ -95,19 +96,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",
-    // 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. As there is
+    // only one RR per-owner per-zone, there's no need to order these
+    // for the sake of any post-processing.
+    "SELECT rdtype, ttl, \"NSEC3\", rdata, owner FROM nsec3 "
+        "WHERE zone_id = ?1",
     /*
      * 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
@@ -637,11 +638,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);
     }
 
@@ -660,6 +671,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
@@ -693,29 +707,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);
@@ -761,13 +781,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_;
 };