diff --git a/src/lib/datasrc/sqlite3_accessor.cc b/src/lib/datasrc/sqlite3_accessor.cc index 7a0ac9cc1f..1b2ec8e499 100644 --- a/src/lib/datasrc/sqlite3_accessor.cc +++ b/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 accessor_; sqlite3_stmt* statement_; + sqlite3_stmt* statement2_; + int rc_; + int rc2_; const std::string name_; };