From: Michal 'vorner' Vaner Date: Wed, 26 Sep 2012 12:02:04 +0000 (+0200) Subject: [2161] Remove the old sqlite3 data source X-Git-Tag: trac2351_base~37^2~2^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=25aae9d23312a6c808bbbbfcefbafe3dc31cba3f;p=thirdparty%2Fkea.git [2161] Remove the old sqlite3 data source And related other files. As well, no longer used. --- diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc index d1109bc8f1..b19f4c68a3 100644 --- a/src/bin/auth/auth_srv.cc +++ b/src/bin/auth/auth_srv.cc @@ -43,7 +43,6 @@ #include #include -#include #include #include diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am index 213b98cf83..425927cc36 100644 --- a/src/lib/datasrc/Makefile.am +++ b/src/lib/datasrc/Makefile.am @@ -22,7 +22,6 @@ CLEANFILES += static.zone lib_LTLIBRARIES = libb10-datasrc.la libb10_datasrc_la_SOURCES = data_source.h data_source.cc -libb10_datasrc_la_SOURCES += sqlite3_datasrc.h sqlite3_datasrc.cc libb10_datasrc_la_SOURCES += query.h query.cc libb10_datasrc_la_SOURCES += cache.h cache.cc libb10_datasrc_la_SOURCES += rbnode_rrset.h diff --git a/src/lib/datasrc/sqlite3_datasrc.cc b/src/lib/datasrc/sqlite3_datasrc.cc deleted file mode 100644 index bced1ae5b1..0000000000 --- a/src/lib/datasrc/sqlite3_datasrc.cc +++ /dev/null @@ -1,917 +0,0 @@ -// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") -// -// Permission to use, copy, modify, and/or distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH -// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, -// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -// PERFORMANCE OF THIS SOFTWARE. - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { -// Expected schema. The major version must match else there is an error. If -// the minor version of the database is less than this, a warning is output. -// -// It is assumed that a program written to run on m.n of the database will run -// with a database version m.p, where p is any number. However, if p < n, -// we assume that the database structure was upgraded for some reason, and that -// some advantage may result if the database is upgraded. Conversely, if p > n, -// The database is at a later version than the program was written for and the -// 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; -} - -using namespace std; -using namespace isc::dns; -using namespace isc::dns::rdata; - -namespace isc { -namespace datasrc { - -struct Sqlite3Parameters { - Sqlite3Parameters() : db_(NULL), major_version_(-1), minor_version_(-1), - q_zone_(NULL), q_record_(NULL), q_addrs_(NULL), q_referral_(NULL), - q_any_(NULL), q_count_(NULL), q_previous_(NULL), q_nsec3_(NULL), - q_prevnsec3_(NULL) - {} - sqlite3* db_; - int major_version_; - int minor_version_; - sqlite3_stmt* q_zone_; - sqlite3_stmt* q_record_; - sqlite3_stmt* q_addrs_; - sqlite3_stmt* q_referral_; - sqlite3_stmt* q_any_; - sqlite3_stmt* q_count_; - sqlite3_stmt* q_previous_; - sqlite3_stmt* q_nsec3_; - sqlite3_stmt* q_prevnsec3_; -}; - -namespace { -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)", - "CREATE TABLE zones (id INTEGER PRIMARY KEY, " - "name TEXT NOT NULL COLLATE NOCASE, " - "rdclass TEXT NOT NULL COLLATE NOCASE DEFAULT 'IN', " - "dnssec BOOLEAN NOT NULL DEFAULT 0)", - "CREATE INDEX zones_byname ON zones (name)", - "CREATE TABLE records (id INTEGER PRIMARY KEY, " - "zone_id INTEGER NOT NULL, name TEXT NOT NULL COLLATE NOCASE, " - "rname TEXT NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, " - "rdtype TEXT NOT NULL COLLATE NOCASE, sigtype TEXT COLLATE NOCASE, " - "rdata TEXT NOT NULL)", - "CREATE INDEX records_byname ON records (name)", - "CREATE INDEX records_byrname ON records (rname)", - "CREATE INDEX records_bytype_and_rname ON records (rdtype, rname)", - "CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, " - "hash TEXT NOT NULL COLLATE NOCASE, " - "owner TEXT NOT NULL COLLATE NOCASE, " - "ttl INTEGER NOT NULL, rdtype TEXT NOT NULL COLLATE NOCASE, " - "rdata TEXT NOT NULL)", - "CREATE INDEX nsec3_byhash ON nsec3 (hash)", - "CREATE TABLE diffs (id INTEGER PRIMARY KEY, " - "zone_id INTEGER NOT NULL, " - "version INTEGER NOT NULL, " - "operation INTEGER NOT NULL, " - "name TEXT NOT NULL COLLATE NOCASE, " - "rrtype TEXT NOT NULL COLLATE NOCASE, " - "ttl INTEGER NOT NULL, " - "rdata TEXT NOT NULL)", - NULL -}; - -const char* const q_version_str = "SELECT version FROM schema_version"; -const char* const q_minor_str = "SELECT minor FROM schema_version"; - -const char* const q_zone_str = "SELECT id FROM zones WHERE name=?1"; - -const char* const q_record_str = "SELECT rdtype, ttl, sigtype, rdata " - "FROM records WHERE zone_id=?1 AND name=?2 AND " - "((rdtype=?3 OR sigtype=?3) OR " - "(rdtype='CNAME' OR sigtype='CNAME') OR " - "(rdtype='NS' OR sigtype='NS'))"; - -const char* const q_addrs_str = "SELECT rdtype, ttl, sigtype, rdata " - "FROM records WHERE zone_id=?1 AND name=?2 AND " - "(rdtype='A' OR sigtype='A' OR rdtype='AAAA' OR sigtype='AAAA')"; - -const char* const q_referral_str = "SELECT rdtype, ttl, sigtype, rdata FROM " - "records WHERE zone_id=?1 AND name=?2 AND" - "(rdtype='NS' OR sigtype='NS' OR rdtype='DS' OR sigtype='DS' OR " - "rdtype='DNAME' OR sigtype='DNAME')"; - -const char* const q_any_str = "SELECT rdtype, ttl, sigtype, rdata " - "FROM records WHERE zone_id=?1 AND name=?2"; - -// Note: the wildcard symbol '%' is expected to be added to the text -// for the placeholder for LIKE given via sqlite3_bind_text(). We don't -// use the expression such as (?2 || '%') because it would disable the use -// of indices and could result in terrible performance. -const char* const q_count_str = "SELECT COUNT(*) FROM records " - "WHERE zone_id=?1 AND rname LIKE ?2;"; - -const char* const q_previous_str = "SELECT name FROM records " - "WHERE rname < ?2 AND zone_id=?1 AND rdtype = 'NSEC' " - "ORDER BY rname DESC LIMIT 1"; - -const char* const q_nsec3_str = "SELECT rdtype, ttl, rdata FROM nsec3 " - "WHERE zone_id = ?1 AND hash = $2"; - -const char* const q_prevnsec3_str = "SELECT hash FROM nsec3 " - "WHERE zone_id = ?1 AND hash <= $2 ORDER BY hash DESC LIMIT 1"; - -} - -// -// Find the exact zone match. Return -1 if not found, or the zone's -// ID if found. This will always be >= 0 if found. -// -int -Sqlite3DataSrc::hasExactZone(const char* const name) const { - int rc; - - sqlite3_reset(dbparameters->q_zone_); - rc = sqlite3_bind_text(dbparameters->q_zone_, 1, name, -1, SQLITE_STATIC); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind " << name << - " to SQL statement (zone)"); - } - - rc = sqlite3_step(dbparameters->q_zone_); - const int i = (rc == SQLITE_ROW) ? - sqlite3_column_int(dbparameters->q_zone_, 0) : -1; - sqlite3_reset(dbparameters->q_zone_); - return (i); -} - -namespace { -int -importSqlite3Rows(sqlite3_stmt* query, const Name& qname, const RRClass& qclass, - const RRType& qtype, const bool nsec3_tree, - RRsetList& result_sets, uint32_t& flags) -{ - int rows = 0; - int rc = sqlite3_step(query); - const bool qtype_is_any = (qtype == RRType::ANY()); - - while (rc == SQLITE_ROW) { - const char* type = (const char*)sqlite3_column_text(query, 0); - int ttl = sqlite3_column_int(query, 1); - const char* sigtype = NULL; - const char* rdata; - - if (nsec3_tree) { - rdata = (const char*)sqlite3_column_text(query, 2); - if (RRType(type) == RRType::RRSIG()) { - sigtype = "NSEC3"; - } - } else { - sigtype = (const char*)sqlite3_column_text(query, 2); - rdata = (const char*)sqlite3_column_text(query, 3); - } - - const RRType base_rrtype(sigtype != NULL ? sigtype : type); - - // found an NS; we need to inform the caller that this might be a - // referral, but we do not return the NS RRset to the caller - // unless asked for it. - if (base_rrtype == RRType::NS()) { - flags |= DataSrc::REFERRAL; - if (!qtype_is_any && qtype != RRType::NS()) { - rc = sqlite3_step(query); - continue; - } - } - - ++rows; - - // Looking for something else but found CNAME - if (base_rrtype == RRType::CNAME() && qtype != RRType::CNAME()) { - if (qtype == RRType::NSEC()) { - // NSEC query, just skip the CNAME - rc = sqlite3_step(query); - continue; - } else if (!qtype_is_any) { - // include the CNAME, but don't flag it for chasing if - // this is an ANY query - flags |= DataSrc::CNAME_FOUND; - } - } - - RRsetPtr rrset = result_sets.findRRset(base_rrtype, qclass); - if (rrset == NULL) { - rrset = RRsetPtr(new RRset(qname, qclass, base_rrtype, RRTTL(ttl))); - result_sets.addRRset(rrset); - } - - if (sigtype == NULL && base_rrtype == rrset->getType()) { - rrset->addRdata(createRdata(rrset->getType(), qclass, rdata)); - if (ttl > rrset->getTTL().getValue()) { - rrset->setTTL(RRTTL(ttl)); - } - } else if (sigtype != NULL && base_rrtype == rrset->getType()) { - RdataPtr rrsig = createRdata(RRType::RRSIG(), qclass, rdata); - if (rrset->getRRsig()) { - rrset->getRRsig()->addRdata(rrsig); - } else { - RRsetPtr sigs = RRsetPtr(new RRset(qname, qclass, - RRType::RRSIG(), - RRTTL(ttl))); - sigs->addRdata(rrsig); - rrset->addRRsig(sigs); - } - - if (ttl > rrset->getRRsig()->getTTL().getValue()) { - rrset->getRRsig()->setTTL(RRTTL(ttl)); - } - } - - rc = sqlite3_step(query); - } - - return (rows); -} -} - -int -Sqlite3DataSrc::findRecords(const Name& name, const RRType& rdtype, - RRsetList& target, const Name* zonename, - const Mode mode, uint32_t& flags) const -{ - LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_SQLITE_FINDREC).arg(name). - arg(rdtype); - flags = 0; - int zone_id = (zonename == NULL) ? findClosest(name, NULL) : - findClosest(*zonename, NULL); - if (zone_id < 0) { - flags = NO_SUCH_ZONE; - return (0); - } - - sqlite3_stmt* query; - switch (mode) { - case ADDRESS: - query = dbparameters->q_addrs_; - break; - case DELEGATION: - query = dbparameters->q_referral_; - break; - default: - if (rdtype == RRType::ANY()) { - query = dbparameters->q_any_; - } else { - query = dbparameters->q_record_; - } - break; - } - - sqlite3_reset(query); - sqlite3_clear_bindings(query); - - int rc; - rc = sqlite3_bind_int(query, 1, zone_id); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id << - " to SQL statement (query)"); - } - const string name_text = name.toText(); - rc = sqlite3_bind_text(query, 2, name_text.c_str(), -1, SQLITE_STATIC); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind name " << name_text << - " to SQL statement (query)"); - } - - const string rdtype_text = rdtype.toText(); - if (query == dbparameters->q_record_) { - rc = sqlite3_bind_text(query, 3, rdtype_text.c_str(), -1, - SQLITE_STATIC); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind RR type " << - rdtype.toText() << " to SQL statement (query)"); - } - } - - const int rows = importSqlite3Rows(query, name, getClass(), rdtype, false, - target, flags); - sqlite3_reset(query); - if (rows > 0) { - return (rows); - } - - // - // No rows were found. We need to find out whether there are - // any RRs with that name to determine whether this is NXDOMAIN or - // NXRRSET - // - sqlite3_reset(dbparameters->q_count_); - sqlite3_clear_bindings(dbparameters->q_count_); - - rc = sqlite3_bind_int(dbparameters->q_count_, 1, zone_id); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id << - " to SQL statement (qcount)"); - } - - const string revname_text = name.reverse().toText() + "%"; - rc = sqlite3_bind_text(dbparameters->q_count_, 2, - revname_text.c_str(), - -1, SQLITE_STATIC); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind name " << name.reverse() << - " to SQL statement (qcount)"); - } - - rc = sqlite3_step(dbparameters->q_count_); - if (rc == SQLITE_ROW) { - if (sqlite3_column_int(dbparameters->q_count_, 0) != 0) { - flags |= TYPE_NOT_FOUND; - sqlite3_reset(dbparameters->q_count_); - return (0); - } - } - - flags |= NAME_NOT_FOUND; - sqlite3_reset(dbparameters->q_count_); - return (0); -} - -// -// Search for the closest enclosing zone. Will return -1 if not found, -// >= 0 if found. If position is not NULL, it will be filled in with the -// longest match found. -// -int -Sqlite3DataSrc::findClosest(const Name& name, unsigned int* position) const { - const unsigned int nlabels = name.getLabelCount(); - for (unsigned int i = 0; i < nlabels; ++i) { - const Name matchname(name.split(i)); - const int rc = hasExactZone(matchname.toText().c_str()); - if (rc >= 0) { - if (position != NULL) { - *position = i; - } - return (rc); - } - } - - return (-1); -} - -void -Sqlite3DataSrc::findClosestEnclosure(DataSrcMatch& match) const { - LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE). - arg(match.getName()); - if (match.getClass() != getClass() && match.getClass() != RRClass::ANY()) { - return; - } - - unsigned int position; - if (findClosest(match.getName(), &position) == -1) { - LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE_NOT_FOUND) - .arg(match.getName()); - return; - } - - match.update(*this, match.getName().split(position)); -} - -DataSrc::Result -Sqlite3DataSrc::findPreviousName(const Name& qname, - Name& target, - const Name* zonename) const -{ - LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_PREVIOUS).arg(qname); - const int zone_id = (zonename == NULL) ? - findClosest(qname, NULL) : findClosest(*zonename, NULL); - if (zone_id < 0) { - LOG_ERROR(logger, DATASRC_SQLITE_PREVIOUS_NO_ZONE).arg(qname.toText()); - return (ERROR); - } - - sqlite3_reset(dbparameters->q_previous_); - sqlite3_clear_bindings(dbparameters->q_previous_); - - int rc = sqlite3_bind_int(dbparameters->q_previous_, 1, zone_id); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id << - " to SQL statement (qprevious)"); - } - const string revname_text = qname.reverse().toText(); - rc = sqlite3_bind_text(dbparameters->q_previous_, 2, - revname_text.c_str(), -1, SQLITE_STATIC); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind name " << qname << - " to SQL statement (qprevious)"); - } - - rc = sqlite3_step(dbparameters->q_previous_); - if (rc != SQLITE_ROW) { - sqlite3_reset(dbparameters->q_previous_); - return (ERROR); - } - - // XXX: bad cast. we should revisit this. - target = Name((const char*)sqlite3_column_text(dbparameters->q_previous_, - 0)); - sqlite3_reset(dbparameters->q_previous_); - return (SUCCESS); -} - -DataSrc::Result -Sqlite3DataSrc::findCoveringNSEC3(const Name& zonename, - string& hashstr, - RRsetList& target) const -{ - LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FIND_NSEC3). - arg(zonename).arg(hashstr); - const int zone_id = findClosest(zonename, NULL); - if (zone_id < 0) { - LOG_ERROR(logger, DATASRC_SQLITE_FIND_NSEC3_NO_ZONE).arg(zonename); - return (ERROR); - } - - sqlite3_reset(dbparameters->q_prevnsec3_); - sqlite3_clear_bindings(dbparameters->q_prevnsec3_); - - int rc = sqlite3_bind_int(dbparameters->q_prevnsec3_, 1, zone_id); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id << - " to SQL statement (previous NSEC3)"); - } - - rc = sqlite3_bind_text(dbparameters->q_prevnsec3_, 2, hashstr.c_str(), - -1, SQLITE_STATIC); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind hash " << hashstr << - " to SQL statement (previous NSEC3)"); - } - - rc = sqlite3_step(dbparameters->q_prevnsec3_); - const char* hash; - if (rc == SQLITE_ROW) { - hash = (const char*) sqlite3_column_text(dbparameters->q_prevnsec3_, 0); - } else { - // We need to find the final NSEC3 in the chain. - // A valid NSEC3 hash is in base32, which contains no - // letters higher than V, so a search for the previous - // NSEC3 from "w" will always find it. - sqlite3_reset(dbparameters->q_prevnsec3_); - rc = sqlite3_bind_text(dbparameters->q_prevnsec3_, 2, "w", -1, - SQLITE_STATIC); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind \"w\"" - " to SQL statement (previous NSEC3)"); - } - - rc = sqlite3_step(dbparameters->q_prevnsec3_); - if (rc != SQLITE_ROW) { - return (ERROR); - } - - hash = (const char*) sqlite3_column_text(dbparameters->q_prevnsec3_, 0); - } - - sqlite3_reset(dbparameters->q_nsec3_); - sqlite3_clear_bindings(dbparameters->q_nsec3_); - - rc = sqlite3_bind_int(dbparameters->q_nsec3_, 1, zone_id); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id << - " to SQL statement (NSEC3)"); - } - - rc = sqlite3_bind_text(dbparameters->q_nsec3_, 2, hash, -1, SQLITE_STATIC); - if (rc != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not bind hash " << hash << - " to SQL statement (NSEC3)"); - } - - DataSrc::Result result = SUCCESS; - uint32_t flags = 0; - if (importSqlite3Rows(dbparameters->q_nsec3_, - Name(hash).concatenate(zonename), - getClass(), RRType::NSEC3(), true, target, - flags) == 0 || flags != 0) { - result = ERROR; - } - hashstr = string(hash); - sqlite3_reset(dbparameters->q_nsec3_); - return (result); -} - -DataSrc::Result -Sqlite3DataSrc::findRRset(const Name& qname, - const RRClass& qclass, - const RRType& qtype, - RRsetList& target, - uint32_t& flags, - const Name* zonename) const -{ - LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FIND).arg(qname). - arg(qtype); - if (qclass != getClass() && qclass != RRClass::ANY()) { - LOG_ERROR(logger, DATASRC_SQLITE_FIND_BAD_CLASS).arg(getClass()). - arg(qclass); - return (ERROR); - } - findRecords(qname, qtype, target, zonename, NORMAL, flags); - return (SUCCESS); -} - -DataSrc::Result -Sqlite3DataSrc::findExactRRset(const Name& qname, - const RRClass& qclass, - const RRType& qtype, - RRsetList& target, - uint32_t& flags, - const Name* zonename) const -{ - LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDEXACT).arg(qname). - arg(qtype); - if (qclass != getClass() && qclass != RRClass::ANY()) { - LOG_ERROR(logger, DATASRC_SQLITE_FINDEXACT_BAD_CLASS).arg(getClass()). - arg(qclass); - return (ERROR); - } - findRecords(qname, qtype, target, zonename, NORMAL, flags); - - // Ignore referrals in this case - flags &= ~REFERRAL; - - // CNAMEs don't count in this case - if (flags & CNAME_FOUND) { - flags &= ~CNAME_FOUND; - flags |= TYPE_NOT_FOUND; - } - - return (SUCCESS); -} - -DataSrc::Result -Sqlite3DataSrc::findAddrs(const Name& qname, - const RRClass& qclass, - RRsetList& target, - uint32_t& flags, - const Name* zonename) const -{ - LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDADDRS).arg(qname); - if (qclass != getClass() && qclass != RRClass::ANY()) { - LOG_ERROR(logger, DATASRC_SQLITE_FINDADDRS_BAD_CLASS).arg(getClass()). - arg(qclass); - return (ERROR); - } - findRecords(qname, RRType::ANY(), target, zonename, ADDRESS, flags); - return (SUCCESS); -} - -DataSrc::Result -Sqlite3DataSrc::findReferral(const Name& qname, - const RRClass& qclass, - RRsetList& target, - uint32_t& flags, - const Name* zonename) const -{ - LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDREF).arg(qname); - if (qclass != getClass() && qclass != RRClass::ANY()) { - LOG_ERROR(logger, DATASRC_SQLITE_FINDREF_BAD_CLASS).arg(getClass()). - arg(qclass); - return (ERROR); - } - findRecords(qname, RRType::ANY(), target, zonename, DELEGATION, flags); - return (SUCCESS); -} - -Sqlite3DataSrc::Sqlite3DataSrc() : - dbparameters(new Sqlite3Parameters) -{ - LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CREATE); -} - -Sqlite3DataSrc::~Sqlite3DataSrc() { - LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_DESTROY); - if (dbparameters->db_ != NULL) { - close(); - } - delete dbparameters; -} - -DataSrc::Result -Sqlite3DataSrc::init(isc::data::ConstElementPtr config) { - if (config && config->contains("database_file")) { - open(config->get("database_file")->stringValue()); - } else { - isc_throw(DataSourceError, "No SQLite database file specified"); - } - return (SUCCESS); -} - -namespace { -// This is a helper class to initialize a Sqlite3 DB safely. An object of -// this class encapsulates all temporary resources that are necessary for -// the initialization, and release them in the destructor. Once everything -// is properly initialized, the move() method moves the allocated resources -// to the main object in an exception free manner. This way, the main code -// for the initialization can be exception safe, and can provide the strong -// exception guarantee. -class Sqlite3Initializer { -public: - ~Sqlite3Initializer() { - if (params_.q_zone_ != NULL) { - sqlite3_finalize(params_.q_zone_); - } - if (params_.q_record_ != NULL) { - sqlite3_finalize(params_.q_record_); - } - if (params_.q_addrs_ != NULL) { - sqlite3_finalize(params_.q_addrs_); - } - if (params_.q_referral_ != NULL) { - sqlite3_finalize(params_.q_referral_); - } - if (params_.q_any_ != NULL) { - sqlite3_finalize(params_.q_any_); - } - if (params_.q_count_ != NULL) { - sqlite3_finalize(params_.q_count_); - } - if (params_.q_previous_ != NULL) { - sqlite3_finalize(params_.q_previous_); - } - if (params_.q_nsec3_ != NULL) { - sqlite3_finalize(params_.q_nsec3_); - } - if (params_.q_prevnsec3_ != NULL) { - sqlite3_finalize(params_.q_prevnsec3_); - } - if (params_.db_ != NULL) { - sqlite3_close(params_.db_); - } - } - void move(Sqlite3Parameters* dst) { - *dst = params_; - params_ = Sqlite3Parameters(); // clear everything - } - Sqlite3Parameters params_; -}; - -sqlite3_stmt* -prepare(sqlite3* const db, const char* const statement) { - sqlite3_stmt* prepared = NULL; - if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) { - isc_throw(Sqlite3Error, "Could not prepare SQLite statement: " << - statement); - } - return (prepared); -} - -// small function to sleep for 0.1 seconds, needed when waiting for -// exclusive database locks (which should only occur on startup, and only -// when the database has not been created yet) -void do_sleep() { - struct timespec req; - req.tv_sec = 0; - req.tv_nsec = 100000000; - nanosleep(&req, NULL); -} - -// returns the schema version element if the schema version table exists -// returns -1 if it does not -int check_schema_version_element(sqlite3* db, const char* const version_query) { - sqlite3_stmt* prepared = NULL; - // At this point in time, the database might be exclusively locked, in - // which case even prepare() will return BUSY, so we may need to try a - // few times - for (size_t i = 0; i < 50; ++i) { - int rc = sqlite3_prepare_v2(db, version_query, -1, &prepared, NULL); - if (rc == SQLITE_ERROR) { - // this is the error that is returned when the table does not - // exist - return (-1); - } else if (rc == SQLITE_OK) { - break; - } else if (rc != SQLITE_BUSY || i == 50) { - isc_throw(Sqlite3Error, "Unable to prepare version query: " - << rc << " " << sqlite3_errmsg(db)); - } - do_sleep(); - } - if (sqlite3_step(prepared) != SQLITE_ROW) { - isc_throw(Sqlite3Error, - "Unable to query version: " << sqlite3_errmsg(db)); - } - int version = sqlite3_column_int(prepared, 0); - sqlite3_finalize(prepared); - return (version); -} - -// Returns the schema major and minor version numbers in a pair. -// Returns (-1, -1) if the table does not exist, (1, 0) for a V1 -// database, and (n, m) for any other. -pair check_schema_version(sqlite3* db) { - int major = check_schema_version_element(db, q_version_str); - if (major == -1) { - return (make_pair(-1, -1)); - } else if (major == 1) { - return (make_pair(1, 0)); - } else { - int minor = check_schema_version_element(db, q_minor_str); - return (make_pair(major, minor)); - } -} - -// A helper class used in create_database() below so we manage the one shot -// transaction safely. -class ScopedTransaction { -public: - ScopedTransaction(sqlite3* db) : db_(NULL) { - // try for 5 secs (50*0.1) - for (size_t i = 0; i < 50; ++i) { - const int rc = sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION", - NULL, NULL, NULL); - if (rc == SQLITE_OK) { - break; - } else if (rc != SQLITE_BUSY || i == 50) { - isc_throw(Sqlite3Error, "Unable to acquire exclusive lock " - "for database creation: " << sqlite3_errmsg(db)); - } - do_sleep(); - } - // Hold the DB pointer once we have successfully acquired the lock. - db_ = db; - } - ~ScopedTransaction() { - if (db_ != NULL) { - // Note: even rollback could fail in theory, but in that case - // we cannot do much for safe recovery anyway. We could at least - // log the event, but for now don't even bother to do that, with - // the expectation that we'll soon stop creating the schema in this - // module. - sqlite3_exec(db_, "ROLLBACK", NULL, NULL, NULL); - } - } - void commit() { - if (sqlite3_exec(db_, "COMMIT TRANSACTION", NULL, NULL, NULL) != - SQLITE_OK) { - isc_throw(Sqlite3Error, "Unable to commit newly created database " - "schema: " << sqlite3_errmsg(db_)); - } - db_ = NULL; - } - -private: - sqlite3* db_; -}; - -// return db version -pair create_database(sqlite3* db) { - logger.info(DATASRC_SQLITE_SETUP_OLD_API); - - // try to get an exclusive lock. Once that is obtained, do the version - // check *again*, just in case this process was racing another - ScopedTransaction transaction(db); - pair schema_version = check_schema_version(db); - if (schema_version.first == -1) { - for (int i = 0; SCHEMA_LIST[i] != NULL; ++i) { - if (sqlite3_exec(db, SCHEMA_LIST[i], NULL, NULL, NULL) != - SQLITE_OK) { - isc_throw(Sqlite3Error, - "Failed to set up schema " << SCHEMA_LIST[i]); - } - } - transaction.commit(); - - // Return the version. We query again to ensure that the only point - // in which the current schema version is defined is in the - // CREATE statements. - schema_version = check_schema_version(db); - } - return (schema_version); -} - -void -checkAndSetupSchema(Sqlite3Initializer* initializer) { - sqlite3* const db = initializer->params_.db_; - - // Note: we use the same SCHEMA_xxx_VERSION log IDs here and in - // sqlite3_accessor.cc, which is against our policy of ID uniqueness. - // The assumption is that this file will soon be deprecated, and we don't - // bother to define separate IDs for the short period. - pair schema_version = check_schema_version(db); - if (schema_version.first == -1) { - schema_version = create_database(db); - } else if (schema_version.first != SQLITE_SCHEMA_MAJOR_VERSION) { - LOG_ERROR(logger, DATASRC_SQLITE_INCOMPATIBLE_VERSION) - .arg(schema_version.first).arg(schema_version.second) - .arg(SQLITE_SCHEMA_MAJOR_VERSION).arg(SQLITE_SCHEMA_MINOR_VERSION); - isc_throw(IncompatibleDbVersion, "Incompatible database version"); - } else if (schema_version.second < SQLITE_SCHEMA_MINOR_VERSION) { - LOG_WARN(logger, DATASRC_SQLITE_COMPATIBLE_VERSION) - .arg(schema_version.first).arg(schema_version.second) - .arg(SQLITE_SCHEMA_MAJOR_VERSION).arg(SQLITE_SCHEMA_MINOR_VERSION); - } - - initializer->params_.major_version_ = schema_version.first; - initializer->params_.minor_version_ = schema_version.second; - initializer->params_.q_zone_ = prepare(db, q_zone_str); - initializer->params_.q_record_ = prepare(db, q_record_str); - initializer->params_.q_addrs_ = prepare(db, q_addrs_str); - initializer->params_.q_referral_ = prepare(db, q_referral_str); - initializer->params_.q_any_ = prepare(db, q_any_str); - initializer->params_.q_count_ = prepare(db, q_count_str); - initializer->params_.q_previous_ = prepare(db, q_previous_str); - initializer->params_.q_nsec3_ = prepare(db, q_nsec3_str); - initializer->params_.q_prevnsec3_ = prepare(db, q_prevnsec3_str); -} -} - -// -// Open the database. -// -void -Sqlite3DataSrc::open(const string& name) { - LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_OPEN).arg(name); - if (dbparameters->db_ != NULL) { - isc_throw(DataSourceError, "Duplicate SQLite open with " << name); - } - - Sqlite3Initializer initializer; - - if (sqlite3_open(name.c_str(), &initializer.params_.db_) != 0) { - isc_throw(Sqlite3Error, "Cannot open SQLite database file: " << name); - } - - checkAndSetupSchema(&initializer); - initializer.move(dbparameters); -} - -// -// Close the database. -// -DataSrc::Result -Sqlite3DataSrc::close(void) { - LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CLOSE); - if (dbparameters->db_ == NULL) { - isc_throw(DataSourceError, - "SQLite data source is being closed before open"); - } - - // XXX: sqlite3_finalize() could fail. What should we do in that case? - sqlite3_finalize(dbparameters->q_zone_); - dbparameters->q_zone_ = NULL; - - sqlite3_finalize(dbparameters->q_record_); - dbparameters->q_record_ = NULL; - - sqlite3_finalize(dbparameters->q_addrs_); - dbparameters->q_addrs_ = NULL; - - sqlite3_finalize(dbparameters->q_referral_); - dbparameters->q_referral_ = NULL; - - sqlite3_finalize(dbparameters->q_any_); - dbparameters->q_any_ = NULL; - - sqlite3_finalize(dbparameters->q_count_); - dbparameters->q_count_ = NULL; - - sqlite3_finalize(dbparameters->q_previous_); - dbparameters->q_previous_ = NULL; - - sqlite3_finalize(dbparameters->q_prevnsec3_); - dbparameters->q_prevnsec3_ = NULL; - - sqlite3_finalize(dbparameters->q_nsec3_); - dbparameters->q_nsec3_ = NULL; - - sqlite3_close(dbparameters->db_); - dbparameters->db_ = NULL; - - return (SUCCESS); -} - -} -} diff --git a/src/lib/datasrc/sqlite3_datasrc.h b/src/lib/datasrc/sqlite3_datasrc.h deleted file mode 100644 index 8ee042f5f5..0000000000 --- a/src/lib/datasrc/sqlite3_datasrc.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") -// -// Permission to use, copy, modify, and/or distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH -// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, -// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -// PERFORMANCE OF THIS SOFTWARE. - -#ifndef __DATA_SOURCE_SQLITE3_H -#define __DATA_SOURCE_SQLITE3_H - -#include - -#include - -#include - -namespace isc { - -namespace dns { -class Name; -class RRClass; -class RRType; -class RRsetList; -} - -namespace datasrc { - -class Query; -struct Sqlite3Parameters; - -class Sqlite3Error : public Exception { -public: - Sqlite3Error(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} -}; - -class IncompatibleDbVersion : public Exception { -public: - IncompatibleDbVersion(const char* file, size_t line, const char* what) : - isc::Exception(file, line, what) {} -}; - -class Sqlite3DataSrc : public DataSrc { - /// - /// \name Constructors, Assignment Operator and Destructor. - /// - /// Note: The copy constructor and the assignment operator are intentionally - /// defined as private. - //@{ -private: - Sqlite3DataSrc(const Sqlite3DataSrc& source); - Sqlite3DataSrc& operator=(const Sqlite3DataSrc& source); -public: - Sqlite3DataSrc(); - ~Sqlite3DataSrc(); - //@} - - void findClosestEnclosure(DataSrcMatch& match) const; - - Result findRRset(const isc::dns::Name& qname, - const isc::dns::RRClass& qclass, - const isc::dns::RRType& qtype, - isc::dns::RRsetList& target, - uint32_t& flags, - const isc::dns::Name* zonename) const; - - Result findExactRRset(const isc::dns::Name& qname, - const isc::dns::RRClass& qclass, - const isc::dns::RRType& qtype, - isc::dns::RRsetList& target, - uint32_t& flags, - const isc::dns::Name* zonename) const; - - Result findAddrs(const isc::dns::Name& qname, - const isc::dns::RRClass& qclass, - isc::dns::RRsetList& target, - uint32_t& flags, - const isc::dns::Name* zonename) const; - - Result findReferral(const isc::dns::Name& qname, - const isc::dns::RRClass& qclass, - isc::dns::RRsetList& target, - uint32_t& flags, - const isc::dns::Name* zonename) const; - - DataSrc::Result findPreviousName(const isc::dns::Name& qname, - isc::dns::Name& target, - const isc::dns::Name* zonename) const; - - Result findCoveringNSEC3(const isc::dns::Name& zonename, - std::string& hash, - isc::dns::RRsetList& target) const; - - Result init() { return (init(isc::data::ElementPtr())); } - Result init(const isc::data::ConstElementPtr config); - Result close(); - -private: - enum Mode { - NORMAL, - ADDRESS, - DELEGATION - }; - - void open(const std::string& name); - int hasExactZone(const char *name) const; - int findRecords(const isc::dns::Name& name, const isc::dns::RRType& rdtype, - isc::dns::RRsetList& target, const isc::dns::Name* zonename, - const Mode mode, uint32_t& flags) const; - int findClosest(const isc::dns::Name& name, unsigned int* position) const; - -private: - Sqlite3Parameters* dbparameters; -}; - -} -} - -#endif // __DATA_SOURCE_SQLITE3_H - -// Local Variables: -// mode: c++ -// End: diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am index 745c0d0fb6..f149eaeccc 100644 --- a/src/lib/datasrc/tests/Makefile.am +++ b/src/lib/datasrc/tests/Makefile.am @@ -52,7 +52,6 @@ run_unittests_SOURCES = $(common_sources) #run_unittests_SOURCES += datasrc_unittest.cc #run_unittests_SOURCES += query_unittest.cc #run_unittests_SOURCES += cache_unittest.cc -#run_unittests_SOURCES += sqlite3_unittest.cc #run_unittests_SOURCES += test_datasrc.h test_datasrc.cc run_unittests_SOURCES += test_client.h test_client.cc @@ -128,5 +127,4 @@ EXTRA_DIST += testdata/static.zone EXTRA_DIST += datasrc_unittest.cc EXTRA_DIST += query_unittest.cc EXTRA_DIST += cache_unittest.cc -EXTRA_DIST += sqlite3_unittest.cc EXTRA_DIST += test_datasrc.h test_datasrc.cc diff --git a/src/lib/datasrc/tests/sqlite3_unittest.cc b/src/lib/datasrc/tests/sqlite3_unittest.cc deleted file mode 100644 index ac1211bbdb..0000000000 --- a/src/lib/datasrc/tests/sqlite3_unittest.cc +++ /dev/null @@ -1,950 +0,0 @@ -// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") -// -// Permission to use, copy, modify, and/or distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH -// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, -// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -// PERFORMANCE OF THIS SOFTWARE. - -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -using namespace std; -using namespace isc::dns; -using namespace isc::dns::rdata; -using namespace isc::datasrc; -using namespace isc::data; - -namespace { -ConstElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON( - "{ \"database_file\": \"" TEST_DATA_DIR "/test.sqlite3\"}"); -ConstElementPtr SQLITE_DBFILE_EXAMPLE2 = Element::fromJSON( - "{ \"database_file\": \"" TEST_DATA_DIR "/example2.com.sqlite3\"}"); -ConstElementPtr SQLITE_DBFILE_EXAMPLE_ROOT = Element::fromJSON( - "{ \"database_file\": \"" TEST_DATA_DIR "/test-root.sqlite3\"}"); -ConstElementPtr SQLITE_DBFILE_BROKENDB = Element::fromJSON( - "{ \"database_file\": \"" TEST_DATA_DIR "/brokendb.sqlite3\"}"); -ConstElementPtr SQLITE_DBFILE_MEMORY = Element::fromJSON( - "{ \"database_file\": \":memory:\"}"); -ConstElementPtr SQLITE_DBFILE_NEWSCHEMA = Element::fromJSON( - "{ \"database_file\": \"" TEST_DATA_DIR "/newschema.sqlite3\"}"); -ConstElementPtr SQLITE_DBFILE_OLDSCHEMA = Element::fromJSON( - "{ \"database_file\": \"" TEST_DATA_DIR "/oldschema.sqlite3\"}"); - -// The following file must be non existent and must be non"creatable"; -// the sqlite3 library will try to create a new DB file if it doesn't exist, -// so to test a failure case the create operation should also fail. -// The "nodir", a non existent directory, is inserted for this purpose. -ConstElementPtr SQLITE_DBFILE_NOTEXIST = Element::fromJSON( - "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}"); - -const string sigdata_common(" 20100322084538 20100220084538 " - "33495 example.com. FAKEFAKEFAKEFAKE"); -const string dnskey1_data(" AwEAAcOUBllYc1hf7ND9uDy+Yz1BF3sI0m4q" - "NGV7WcTD0WEiuV7IjXgHE36fCmS9QsUxSSOV" - "o1I/FMxI2PJVqTYHkXFBS7AzLGsQYMU7UjBZ" - "SotBJ6Imt5pXMu+lEDNy8TOUzG3xm7g0qcbW" - "YF6qCEfvZoBtAqi5Rk7Mlrqs8agxYyMx"); -const string dnskey2_data(" AwEAAe5WFbxdCPq2jZrZhlMj7oJdff3W7syJ" - "tbvzg62tRx0gkoCDoBI9DPjlOQG0UAbj+xUV" - "4HQZJStJaZ+fHU5AwVNT+bBZdtV+NujSikhd" - "THb4FYLg2b3Cx9NyJvAVukHp/91HnWuG4T36" - "CzAFrfPwsHIrBz9BsaIQ21VRkcmj7DswfI/i" - "DGd8j6bqiODyNZYQ+ZrLmF0KIJ2yPN3iO6Zq" - "23TaOrVTjB7d1a/h31ODfiHAxFHrkY3t3D5J" - "R9Nsl/7fdRmSznwtcSDgLXBoFEYmw6p86Acv" - "RyoYNcL1SXjaKVLG5jyU3UR+LcGZT5t/0xGf" - "oIK/aKwENrsjcKZZj660b1M="); -const string nsec3_signature("gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK" - "mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L" - "is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02" - "xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o" - "8gHSY5vYTtothcZQa4BMKhmGQEk="); - -const Name zone_name("example.com"); -const Name nomatch_name("example.org"); -const Name child_name("sql1.example.com"); -const Name www_name("www.example.com"); -const Name www_upper_name("WWW.EXAMPLE.COM"); - -typedef enum { - NORMAL, - EXACT, - ADDRESS, - REFERRAL -} FindMode; - -class Sqlite3DataSourceTest : public ::testing::Test { -protected: - Sqlite3DataSourceTest() : rrclass(RRClass::IN()), - rrclass_notmatch(RRClass::CH()), - rrtype(RRType::A()), rrttl(RRTTL(3600)), - find_flags(0), rrset_matched(0), rrset_count(0) - { - data_source.init(SQLITE_DBFILE_EXAMPLE); - - common_a_data.push_back("192.0.2.1"); - common_sig_data.push_back("A 5 3 3600" + sigdata_common); - common_aaaa_data.push_back("2001:db8::1234"); - common_aaaa_sig_data.push_back("AAAA 5 3 3600" + sigdata_common); - - www_nsec_data.push_back("example.com. A RRSIG NSEC"); - www_nsec_sig_data.push_back("NSEC 5 3 7200" + sigdata_common); - - mix_a_data.push_back("192.0.2.1"); - mix_a_data.push_back("192.0.2.2"); - mix_aaaa_data.push_back("2001:db8::1"); - mix_aaaa_data.push_back("2001:db8::2"); - - apex_soa_data.push_back("master.example.com. admin.example.com. " - "1234 3600 1800 2419200 7200"); - apex_soa_sig_data.push_back("SOA 5 2 3600" + sigdata_common); - apex_ns_data.push_back("dns01.example.com."); - apex_ns_data.push_back("dns02.example.com."); - apex_ns_data.push_back("dns03.example.com."); - apex_ns_sig_data.push_back("NS 5 2 3600" + sigdata_common); - apex_mx_data.push_back("10 mail.example.com."); - apex_mx_data.push_back("20 mail.subzone.example.com."); - apex_mx_sig_data.push_back("MX 5 2 3600" + sigdata_common); - apex_nsec_data.push_back("cname-ext.example.com. " - "NS SOA MX RRSIG NSEC DNSKEY"); - apex_nsec_sig_data.push_back("NSEC 5 2 7200" + sigdata_common); - apex_dnskey_data.push_back("256 3 5" + dnskey1_data); - apex_dnskey_data.push_back("257 3 5" + dnskey2_data); - // this one is special (using different key): - apex_dnskey_sig_data.push_back("DNSKEY 5 2 3600 20100322084538 " - "20100220084538 4456 example.com. " - "FAKEFAKEFAKEFAKE"); - apex_dnskey_sig_data.push_back("DNSKEY 5 2 3600" + sigdata_common); - - wild_a_data.push_back("192.0.2.255"); - dname_data.push_back("sql1.example.com."); - dname_sig_data.push_back("DNAME 5 3 3600" + sigdata_common); - cname_data.push_back("cnametest.example.org."); - cname_sig_data.push_back("CNAME 5 3 3600" + sigdata_common); - cname_nsec_data.push_back("mail.example.com. CNAME RRSIG NSEC"); - cname_nsec_sig_data.push_back("NSEC 5 3 7200" + sigdata_common); - delegation_ns_data.push_back("ns1.subzone.example.com."); - delegation_ns_data.push_back("ns2.subzone.example.com."); - delegation_ds_data.push_back("40633 5 1 " - "3E56C0EA92CF529E005A4B62979533350492 " - "F105"); - delegation_ds_data.push_back("40633 5 2 " - "AA8D4BD330C68BFB4D785894DDCF6B689CE9" - "873C4A3801F57A5AA3FE17925B8C"); - delegation_ds_sig_data.push_back("DS 5 3 3600" + sigdata_common); - child_ds_data.push_back("33313 5 1 " - "FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8DE"); - child_ds_data.push_back("33313 5 2 " - "0B99B7006F496D135B01AB17EDB469B4BE9E" - "1973884DEA757BC4E3015A8C3AB3"); - child_ds_sig_data.push_back("DS 5 3 3600" + sigdata_common); - delegation_nsec_data.push_back("*.wild.example.com. NS DS RRSIG NSEC"); - delegation_nsec_sig_data.push_back("NSEC 5 3 7200" + sigdata_common); - child_a_data.push_back("192.0.2.100"); - child_sig_data.push_back("A 5 4 3600 20100322084536 " - "20100220084536 12447 sql1.example.com. " - "FAKEFAKEFAKEFAKE"); - nsec3_data.push_back("1 0 10 FEEDABEE 4KLSVDE8KH8G95VU68R7AHBE1CPQN38J"); - nsec3_sig_data.push_back("NSEC3 5 4 7200 20100410172647 " - "20100311172647 63192 sql2.example.com. " - + nsec3_signature); - } - Sqlite3DataSrc data_source; - // we allow these to be modified in the test - RRClass rrclass; - RRClass rrclass_notmatch; - RRType rrtype; - RRTTL rrttl; - RRsetList result_sets; - uint32_t find_flags; - unsigned rrset_matched; - unsigned rrset_count; - - vector types; - vector ttls; - vector* > answers; - vector* > signatures; - - vector expected_types; - vector common_a_data; - vector common_sig_data; - vector common_aaaa_data; - vector common_aaaa_sig_data; - vector www_nsec_data; - vector www_nsec_sig_data; - vector mix_a_data; - vector mix_aaaa_data; - vector apex_soa_data; - vector apex_soa_sig_data; - vector apex_ns_data; - vector apex_ns_sig_data; - vector apex_mx_data; - vector apex_mx_sig_data; - vector apex_nsec_data; - vector apex_nsec_sig_data; - vector apex_dnskey_data; - vector apex_dnskey_sig_data; - vector wild_a_data; - vector dname_data; - vector dname_sig_data; - vector cname_data; - vector cname_sig_data; - vector cname_nsec_data; - vector cname_nsec_sig_data; - vector delegation_ns_data; - vector delegation_ns_sig_data; - vector delegation_ds_data; - vector delegation_ds_sig_data; - vector child_ds_data; - vector child_ds_sig_data; - vector delegation_nsec_data; - vector delegation_nsec_sig_data; - vector child_a_data; - vector child_sig_data; - vector nsec3_data; - vector nsec3_sig_data; - - void findReferralRRsetCommon(const Name& qname, const RRClass& qclass); - void findAddressRRsetCommon(const RRClass& qclass); -}; - -void -checkRRset(RRsetPtr rrset, const Name& expected_name, - const RRClass& expected_class, const RRType& expected_type, - const RRTTL& expected_rrttl, const vector& expected_data, - const vector* expected_sig_data) -{ - EXPECT_EQ(expected_name, rrset->getName()); - EXPECT_EQ(expected_class, rrset->getClass()); - EXPECT_EQ(expected_type, rrset->getType()); - EXPECT_EQ(expected_rrttl, rrset->getTTL()); - - RdataIteratorPtr rdata_iterator = rrset->getRdataIterator(); - vector::const_iterator data_it = expected_data.begin(); - for (; data_it != expected_data.end(); ++data_it) { - EXPECT_FALSE(rdata_iterator->isLast()); - if (rdata_iterator->isLast()) { - // buggy case, should stop here - break; - } - - // We use text-based comparison so that we can easily identify which - // data causes the error. RDATA::compare() is the most strict - // comparison method, but in this case text-based comparison should - // be okay because we generate the text data from Rdata objects - // rather than hand-write the expected text. - EXPECT_EQ(createRdata(expected_type, expected_class, - *data_it)->toText(), - rdata_iterator->getCurrent().toText()); - rdata_iterator->next(); - } - - if (expected_sig_data != NULL) { - RRsetPtr sig_rrset = rrset->getRRsig(); - EXPECT_FALSE(sig_rrset == NULL); - if (sig_rrset != NULL) { // check this to avoid possible bug. - // Note: we assume the TTL for RRSIG is the same as that of the - // RRSIG target. - checkRRset(sig_rrset, expected_name, expected_class, - RRType::RRSIG(), expected_rrttl, *expected_sig_data, - NULL); - } - } else { - EXPECT_TRUE(NULL == rrset->getRRsig()); - } - - EXPECT_TRUE(rdata_iterator->isLast()); -} - -void -checkFind(FindMode mode, const Sqlite3DataSrc& data_source, - const Name& expected_name, const Name* zone_name, - const RRClass& qclass, const RRClass& expected_class, - const RRType& expected_type, const vector& expected_ttls, - const uint32_t expected_flags, const vector& expected_types, - const vector* >& expected_answers, - const vector* >& expected_signatures) -{ - RRsetList result_sets; - uint32_t find_flags; - unsigned int rrset_matched = 0; - unsigned int rrset_count = 0; - - switch (mode) { - case NORMAL: - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(expected_name, qclass, - expected_type, result_sets, find_flags, - zone_name)); - break; - case EXACT: - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findExactRRset(expected_name, qclass, - expected_type, result_sets, - find_flags, zone_name)); - break; - case ADDRESS: - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findAddrs(expected_name, qclass, result_sets, - find_flags, zone_name)); - break; - case REFERRAL: - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findReferral(expected_name, qclass, result_sets, - find_flags, zone_name)); - break; - } - EXPECT_EQ(expected_flags, find_flags); - RRsetList::iterator it = result_sets.begin(); - for (; it != result_sets.end(); ++it) { - vector::const_iterator found_type = - find(expected_types.begin(), expected_types.end(), - (*it)->getType()); - // there should be a match - EXPECT_TRUE(found_type != expected_types.end()); - if (found_type != expected_types.end()) { - unsigned int index = distance(expected_types.begin(), found_type); - checkRRset(*it, expected_name, expected_class, (*it)->getType(), - expected_ttls[index], *expected_answers[index], - expected_signatures[index]); - ++rrset_matched; - } - ++rrset_count; - } - EXPECT_EQ(expected_types.size(), rrset_count); - EXPECT_EQ(expected_types.size(), rrset_matched); -} - -void -checkFind(FindMode mode, const Sqlite3DataSrc& data_source, - const Name& expected_name, const Name* zone_name, - const RRClass& qclass, const RRClass& expected_class, - const RRType& expected_type, const RRTTL& expected_rrttl, - const uint32_t expected_flags, - const vector& expected_data, - const vector* expected_sig_data) -{ - vector types; - vector ttls; - vector* > answers; - vector* > signatures; - - types.push_back(expected_type); - ttls.push_back(expected_rrttl); - answers.push_back(&expected_data); - signatures.push_back(expected_sig_data); - - checkFind(mode, data_source, expected_name, zone_name, qclass, - expected_class, expected_type, ttls, expected_flags, types, - answers, signatures); -} - -TEST_F(Sqlite3DataSourceTest, close) { - EXPECT_EQ(DataSrc::SUCCESS, data_source.close()); -} - -TEST_F(Sqlite3DataSourceTest, reOpen) { - // Replace the data with a totally different zone. This should succeed, - // and shouldn't match any names in the previously managed domains. - EXPECT_EQ(DataSrc::SUCCESS, data_source.close()); - EXPECT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_EXAMPLE2)); - - DataSrcMatch match(www_name, rrclass); - data_source.findClosestEnclosure(match); - EXPECT_EQ(static_cast(NULL), match.getEnclosingZone()); - EXPECT_EQ(static_cast(NULL), match.getDataSource()); -} - -TEST_F(Sqlite3DataSourceTest, openFail) { - EXPECT_EQ(DataSrc::SUCCESS, data_source.close()); - EXPECT_THROW(data_source.init(SQLITE_DBFILE_NOTEXIST), Sqlite3Error); -} - -TEST_F(Sqlite3DataSourceTest, doubleOpen) { - // An attempt of duplicate open should trigger an exception. - EXPECT_THROW(data_source.init(SQLITE_DBFILE_EXAMPLE), DataSourceError); -} - -TEST_F(Sqlite3DataSourceTest, doubleClose) { - // An attempt of duplicate close should trigger an exception. - EXPECT_EQ(DataSrc::SUCCESS, data_source.close()); - EXPECT_THROW(data_source.close(), DataSourceError); -} - -TEST_F(Sqlite3DataSourceTest, openBrokenDB) { - EXPECT_EQ(DataSrc::SUCCESS, data_source.close()); - // The database exists but is broken. An exception will be thrown - // in the middle of the initialization. - EXPECT_THROW(data_source.init(SQLITE_DBFILE_BROKENDB), Sqlite3Error); - // Confirming the strong exception guarantee: the data source must be - // in the closed state. - EXPECT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_EXAMPLE)); -} - -// Different schema versions, see sqlite3_accessor_unittest. -TEST_F(Sqlite3DataSourceTest, differentSchemaVersions) { - EXPECT_EQ(DataSrc::SUCCESS, data_source.close()); - EXPECT_THROW(data_source.init(SQLITE_DBFILE_NEWSCHEMA), - IncompatibleDbVersion); - EXPECT_THROW(data_source.init(SQLITE_DBFILE_OLDSCHEMA), - IncompatibleDbVersion); - // Don't bother to test the new_minor case; we should retire this stuff - // before it really happens. -} - -// This test only confirms that on-the-fly schema creation works. -TEST_F(Sqlite3DataSourceTest, memoryDB) { - EXPECT_EQ(DataSrc::SUCCESS, data_source.close()); - EXPECT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_MEMORY)); -} - -TEST_F(Sqlite3DataSourceTest, findClosestEnclosure) { - DataSrcMatch match(www_name, rrclass); - data_source.findClosestEnclosure(match); - EXPECT_EQ(zone_name, *match.getEnclosingZone()); - EXPECT_EQ(&data_source, match.getDataSource()); -} - -TEST_F(Sqlite3DataSourceTest, findClosestEnclosureMatchRoot) { - EXPECT_EQ(DataSrc::SUCCESS, data_source.close()); - EXPECT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_EXAMPLE_ROOT)); - - DataSrcMatch match(Name("org."), rrclass); - data_source.findClosestEnclosure(match); - EXPECT_EQ(Name("."), *match.getEnclosingZone()); - EXPECT_EQ(&data_source, match.getDataSource()); -} - -TEST_F(Sqlite3DataSourceTest, findClosestEnclosureAtDelegation) { - // The search name exists both in the parent and child zones, but - // child has a better match. - DataSrcMatch match(child_name, rrclass); - data_source.findClosestEnclosure(match); - EXPECT_EQ(child_name, *match.getEnclosingZone()); - EXPECT_EQ(&data_source, match.getDataSource()); -} - -TEST_F(Sqlite3DataSourceTest, findClosestEnclosureNoMatch) { - DataSrcMatch match(nomatch_name, rrclass); - data_source.findClosestEnclosure(match); - EXPECT_EQ(static_cast(NULL), match.getEnclosingZone()); - EXPECT_EQ(static_cast(NULL), match.getDataSource()); -} - -TEST_F(Sqlite3DataSourceTest, findClosestClassMismatch) { - DataSrcMatch match(nomatch_name, rrclass); - data_source.findClosestEnclosure(match); - EXPECT_EQ(static_cast(NULL), match.getEnclosingZone()); - EXPECT_EQ(static_cast(NULL), match.getDataSource()); -} - -// If the query class is ANY, the result should be the same as the case where -// the class exactly matches. -TEST_F(Sqlite3DataSourceTest, findClosestClassAny) { - DataSrcMatch match(www_name, RRClass::ANY()); - data_source.findClosestEnclosure(match); - EXPECT_EQ(zone_name, *match.getEnclosingZone()); - EXPECT_EQ(&data_source, match.getDataSource()); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetNormal) { - // Without specifying the zone name, and then with the zone name - checkFind(NORMAL, data_source, www_name, NULL, rrclass, rrclass, rrtype, - rrttl, 0, common_a_data, &common_sig_data); - - checkFind(NORMAL, data_source, www_name, &zone_name, rrclass, rrclass, - rrtype, rrttl, 0, common_a_data, &common_sig_data); - - // With a zone name that doesn't match - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(www_name, rrclass, rrtype, - result_sets, find_flags, &nomatch_name)); - EXPECT_EQ(DataSrc::NO_SUCH_ZONE, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); // should be empty -} - -TEST_F(Sqlite3DataSourceTest, findRRsetClassMismatch) { - EXPECT_EQ(DataSrc::ERROR, - data_source.findRRset(www_name, rrclass_notmatch, rrtype, - result_sets, find_flags, NULL)); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetClassAny) { - checkFind(NORMAL, data_source, www_name, NULL, RRClass::ANY(), rrclass, - rrtype, rrttl, 0, common_a_data, &common_sig_data); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetClassClassAny) { - checkFind(NORMAL, data_source, www_name, NULL, RRClass::ANY(), rrclass, - rrtype, rrttl, 0, common_a_data, &common_sig_data); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetNormalANY) { - types.push_back(RRType::A()); - types.push_back(RRType::NSEC()); - ttls.push_back(RRTTL(3600)); - ttls.push_back(RRTTL(7200)); - answers.push_back(&common_a_data); - answers.push_back(&www_nsec_data); - signatures.push_back(&common_sig_data); - signatures.push_back(&www_nsec_sig_data); - - rrtype = RRType::ANY(); - checkFind(NORMAL, data_source, www_name, NULL, rrclass, rrclass, rrtype, - ttls, 0, types, answers, signatures); - - checkFind(NORMAL, data_source, www_name, &zone_name, rrclass, rrclass, - rrtype, ttls, 0, types, answers, signatures); -} - -// Case insensitive lookup -TEST_F(Sqlite3DataSourceTest, findRRsetNormalCase) { - checkFind(NORMAL, data_source, www_upper_name, NULL, rrclass, rrclass, - rrtype, rrttl, 0, common_a_data, &common_sig_data); - - checkFind(NORMAL, data_source, www_upper_name, &zone_name, rrclass, rrclass, - rrtype, rrttl, 0, common_a_data, &common_sig_data); - - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(www_upper_name, rrclass, rrtype, - result_sets, find_flags, &nomatch_name)); - EXPECT_EQ(DataSrc::NO_SUCH_ZONE, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); // should be empty -} - -TEST_F(Sqlite3DataSourceTest, findRRsetApexNS) { - rrtype = RRType::NS(); - checkFind(NORMAL, data_source, zone_name, NULL, rrclass, rrclass, rrtype, - rrttl, DataSrc::REFERRAL, apex_ns_data, &apex_ns_sig_data); - - checkFind(NORMAL, data_source, zone_name, &zone_name, rrclass, rrclass, - rrtype, rrttl, DataSrc::REFERRAL, apex_ns_data, - &apex_ns_sig_data); - - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(zone_name, rrclass, rrtype, - result_sets, find_flags, &nomatch_name)); - EXPECT_EQ(DataSrc::NO_SUCH_ZONE, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); // should be empty -} - -TEST_F(Sqlite3DataSourceTest, findRRsetApexANY) { - types.push_back(RRType::SOA()); - types.push_back(RRType::NS()); - types.push_back(RRType::MX()); - types.push_back(RRType::NSEC()); - types.push_back(RRType::DNSKEY()); - ttls.push_back(rrttl); // SOA TTL - ttls.push_back(rrttl); // NS TTL - ttls.push_back(rrttl); // MX TTL - ttls.push_back(RRTTL(7200)); // NSEC TTL - ttls.push_back(rrttl); // DNSKEY TTL - answers.push_back(&apex_soa_data); - answers.push_back(&apex_ns_data); - answers.push_back(&apex_mx_data); - answers.push_back(&apex_nsec_data); - answers.push_back(&apex_dnskey_data); - signatures.push_back(&apex_soa_sig_data); - signatures.push_back(&apex_ns_sig_data); - signatures.push_back(&apex_mx_sig_data); - signatures.push_back(&apex_nsec_sig_data); - signatures.push_back(&apex_dnskey_sig_data); - - rrtype = RRType::ANY(); - - // there is an NS at the zone apex, so the REFERRAL flag should - // be set, but will ordinarily be ignored by the caller - checkFind(NORMAL, data_source, zone_name, NULL, rrclass, rrclass, rrtype, - ttls, DataSrc::REFERRAL, types, answers, signatures); - - checkFind(NORMAL, data_source, zone_name, &zone_name, rrclass, rrclass, - rrtype, ttls, DataSrc::REFERRAL, types, answers, signatures); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetMixedANY) { - // ANY query for mixed order RRs - const Name qname("mix.example.com"); - - types.push_back(RRType::A()); - types.push_back(RRType::AAAA()); - ttls.push_back(rrttl); - ttls.push_back(rrttl); - answers.push_back(&mix_a_data); - answers.push_back(&mix_aaaa_data); - signatures.push_back(NULL); - signatures.push_back(NULL); - - rrtype = RRType::ANY(); - checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass, - rrtype, ttls, 0, types, answers, signatures); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetApexNXRRSET) { - rrtype = RRType::AAAA(); - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(zone_name, rrclass, rrtype, - result_sets, find_flags, &zone_name)); - // there's an NS RRset at the apex name, so the REFERRAL flag should be - // set, too. - EXPECT_EQ(DataSrc::TYPE_NOT_FOUND | DataSrc::REFERRAL, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); - - // Same test, without specifying the zone name - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(zone_name, rrclass, rrtype, - result_sets, find_flags, NULL)); - // there's an NS RRset at the apex name, so the REFERRAL flag should be - // set, too. - EXPECT_EQ(DataSrc::TYPE_NOT_FOUND | DataSrc::REFERRAL, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); -} - -// Matching a wildcard node. There's nothing special for the data source API -// point of view, but perform minimal tests anyway. -TEST_F(Sqlite3DataSourceTest, findRRsetWildcard) { - const Name qname("*.wild.example.com"); - checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass, - rrtype, rrttl, 0, wild_a_data, &common_sig_data); - checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass, - rrtype, rrttl, 0, wild_a_data, &common_sig_data); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetEmptyNode) { - // foo.bar.example.com exists, but bar.example.com doesn't have any data. - const Name qname("bar.example.com"); - - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(qname, rrclass, rrtype, - result_sets, find_flags, NULL)); - EXPECT_EQ(DataSrc::TYPE_NOT_FOUND, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); - - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(qname, rrclass, rrtype, - result_sets, find_flags, &zone_name)); - EXPECT_EQ(DataSrc::TYPE_NOT_FOUND, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); -} - -// There's nothing special about DNAME lookup for the data source API -// point of view, but perform minimal tests anyway. -TEST_F(Sqlite3DataSourceTest, findRRsetDNAME) { - const Name qname("dname.example.com"); - - rrtype = RRType::DNAME(); - checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass, - rrtype, rrttl, 0, dname_data, &dname_sig_data); - checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass, - rrtype, rrttl, 0, dname_data, &dname_sig_data); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetCNAME) { - const Name qname("foo.example.com"); - - // This qname only has the CNAME (+ sigs). CNAME query is not different - // from ordinary queries. - rrtype = RRType::CNAME(); - checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass, - rrtype, rrttl, 0, cname_data, &cname_sig_data); - checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass, - rrtype, rrttl, 0, cname_data, &cname_sig_data); - - // queries for (ordinary) different RR types that match the CNAME. - // CNAME_FOUND flag is set, and the CNAME RR is returned instead of A - rrtype = RRType::A(); - types.push_back(RRType::CNAME()); - ttls.push_back(rrttl); - answers.push_back(&cname_data); - signatures.push_back(&cname_sig_data); - checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass, - rrtype, ttls, DataSrc::CNAME_FOUND, types, answers, signatures); - checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass, - rrtype, ttls, DataSrc::CNAME_FOUND, types, answers, signatures); - - // NSEC query that match the CNAME. - // CNAME_FOUND flag is NOT set, and the NSEC RR is returned instead of - // CNAME. - rrtype = RRType::NSEC(); - checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass, - rrtype, RRTTL(7200), 0, cname_nsec_data, &cname_nsec_sig_data); - checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass, - rrtype, RRTTL(7200), 0, cname_nsec_data, &cname_nsec_sig_data); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetDelegation) { - const Name qname("www.subzone.example.com"); - - // query for a name under a zone cut. From the data source API point - // of view this is no different than "NXDOMAIN". - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(qname, rrclass, rrtype, - result_sets, find_flags, NULL)); - EXPECT_EQ(DataSrc::NAME_NOT_FOUND, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetDelegationAtZoneCut) { - const Name qname("subzone.example.com"); - - // query for a name *at* a zone cut. It matches the NS RRset for the - // delegation. - - // For non-NS ordinary queries, "no type" should be set too, and no RRset is - // returned. - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(qname, rrclass, rrtype, - result_sets, find_flags, NULL)); - EXPECT_EQ(DataSrc::TYPE_NOT_FOUND | DataSrc::REFERRAL, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); - - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(qname, rrclass, rrtype, - result_sets, find_flags, &zone_name)); - EXPECT_EQ(DataSrc::TYPE_NOT_FOUND | DataSrc::REFERRAL, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); - - // For NS query, RRset is returned with the REFERRAL flag. No RRSIG should - // be provided. - rrtype = RRType::NS(); - checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass, - rrtype, rrttl, DataSrc::REFERRAL, delegation_ns_data, NULL); - checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass, - rrtype, rrttl, DataSrc::REFERRAL, delegation_ns_data, NULL); - - // For ANY query. At the backend data source level, it returns all - // existent records with their RRSIGs, setting the referral flag. - rrtype = RRType::ANY(); - types.push_back(RRType::NS()); - types.push_back(RRType::NSEC()); - types.push_back(RRType::DS()); - ttls.push_back(rrttl); - ttls.push_back(RRTTL(7200)); - ttls.push_back(rrttl); - answers.push_back(&delegation_ns_data); - answers.push_back(&delegation_nsec_data); - answers.push_back(&delegation_ds_data); - signatures.push_back(NULL); - signatures.push_back(&delegation_nsec_sig_data); - signatures.push_back(&delegation_ds_sig_data); - - checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass, - rrtype, ttls, DataSrc::REFERRAL, types, answers, - signatures); - checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass, - rrtype, ttls, DataSrc::REFERRAL, types, answers, - signatures); - - // For NSEC query. At the backend data source level, it returns NSEC+ - // RRSIG with the referral flag. - rrtype = RRType::NSEC(); - checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass, - rrtype, RRTTL(7200), DataSrc::REFERRAL, delegation_nsec_data, - &delegation_nsec_sig_data); - checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass, - rrtype, RRTTL(7200), DataSrc::REFERRAL, delegation_nsec_data, - &delegation_nsec_sig_data); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetInChildZone) { - const Name qname("www.sql1.example.com"); - const Name child_zone_name("sql1.example.com"); - - // If we don't specify the zone, the data source should identify the - // best matching zone. - checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass, - rrtype, rrttl, 0, child_a_data, &child_sig_data); - - // If we specify the parent zone, it's treated as NXDOMAIN because it's - // under a zone cut. - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findRRset(qname, rrclass, rrtype, - result_sets, find_flags, &zone_name)); - EXPECT_EQ(DataSrc::NAME_NOT_FOUND, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); - - // If we specify the child zone, it should be the same as the first case. - checkFind(NORMAL, data_source, qname, &child_zone_name, rrclass, rrclass, - rrtype, rrttl, 0, child_a_data, &child_sig_data); -} - -TEST_F(Sqlite3DataSourceTest, findExactRRset) { - // Normal case. No different than findRRset. - checkFind(EXACT, data_source, www_name, &zone_name, rrclass, rrclass, - rrtype, rrttl, 0, common_a_data, &common_sig_data); -} - -TEST_F(Sqlite3DataSourceTest, findExactRRsetClassMismatch) { - EXPECT_EQ(DataSrc::ERROR, - data_source.findExactRRset(www_name, rrclass_notmatch, rrtype, - result_sets, find_flags, NULL)); -} - -TEST_F(Sqlite3DataSourceTest, findExactRRsetClassAny) { - checkFind(EXACT, data_source, www_name, &zone_name, RRClass::ANY(), rrclass, - rrtype, rrttl, 0, common_a_data, &common_sig_data); -} - -TEST_F(Sqlite3DataSourceTest, findRRsetNSEC3) { - // Simple NSEC3 tests (more should be added) - string hashstr("1BB7SO0452U1QHL98UISNDD9218GELR5"); - - const Name nsec3_zonename("sql2.example.com"); - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findCoveringNSEC3(nsec3_zonename, - hashstr, result_sets)); - RRsetList::iterator it = result_sets.begin(); - checkRRset(*it, Name(hashstr).concatenate(nsec3_zonename), rrclass, - RRType::NSEC3(), RRTTL(7200), nsec3_data, &nsec3_sig_data); - ++it; - EXPECT_TRUE(it == result_sets.end()); - -} - -TEST_F(Sqlite3DataSourceTest, findExactRRsetCNAME) { - const Name qname("foo.example.com"); - - // This qname only has the CNAME (+ sigs). In this case it should be - // no different than findRRset for CNAME query. - rrtype = RRType::CNAME(); - checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass, - rrtype, rrttl, 0, cname_data, &cname_sig_data); - - // queries for (ordinary) different RR types that match the CNAME. - // "type not found" set, but CNAME and its sig are returned (awkward, - // but that's how it currently works). - rrtype = RRType::A(); - types.push_back(RRType::CNAME()); - ttls.push_back(rrttl); - answers.push_back(&cname_data); - signatures.push_back(&cname_sig_data); - checkFind(EXACT, data_source, qname, &zone_name, rrclass, rrclass, - rrtype, ttls, DataSrc::TYPE_NOT_FOUND, types, answers, - signatures); -} - -void -Sqlite3DataSourceTest::findReferralRRsetCommon(const Name& qname, - const RRClass& qclass) -{ - types.push_back(RRType::NS()); - types.push_back(RRType::DS()); - ttls.push_back(rrttl); - ttls.push_back(rrttl); - answers.push_back(&apex_ns_data); - answers.push_back(&child_ds_data); - signatures.push_back(NULL); - signatures.push_back(&child_ds_sig_data); - // Note: zone_name matters here because we need to perform the search - // in the parent zone. - checkFind(REFERRAL, data_source, qname, &zone_name, qclass, rrclass, - rrtype, ttls, DataSrc::REFERRAL, types, answers, signatures); -} - - -TEST_F(Sqlite3DataSourceTest, findReferralRRset) { - // A referral lookup searches for NS, DS, or DNAME, or their sigs. - const Name qname("sql1.example.com"); - findReferralRRsetCommon(qname, rrclass); -} - -TEST_F(Sqlite3DataSourceTest, findReferralRRsetClassMismatch) { - EXPECT_EQ(DataSrc::ERROR, - data_source.findReferral(www_name, rrclass_notmatch, result_sets, - find_flags, NULL)); -} - -TEST_F(Sqlite3DataSourceTest, findReferralRRsetClassAny) { - const Name qname("sql1.example.com"); - findReferralRRsetCommon(qname, RRClass::ANY()); -} - -TEST_F(Sqlite3DataSourceTest, findReferralRRsetDNAME) { - // same as above. the DNAME case. - const Name qname("dname.example.com"); - checkFind(REFERRAL, data_source, qname, &zone_name, rrclass, rrclass, - RRType::DNAME(), rrttl, 0, dname_data, &dname_sig_data); -} - -TEST_F(Sqlite3DataSourceTest, findReferralRRsetFail) { - // qname has not "referral" records. the result should be "empty". - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findReferral(www_name, rrclass, - result_sets, find_flags, &zone_name)); - EXPECT_EQ(DataSrc::TYPE_NOT_FOUND, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); -} - -void -Sqlite3DataSourceTest::findAddressRRsetCommon(const RRClass& qclass) { - // A referral lookup searches for A or AAAA, or their sigs. - - // A-only case - checkFind(ADDRESS, data_source, www_name, &zone_name, qclass, rrclass, - rrtype, rrttl, 0, common_a_data, &common_sig_data); - - // AAAA-only case - checkFind(ADDRESS, data_source, Name("ip6.example.com"), &zone_name, - qclass, rrclass, RRType::AAAA(), rrttl, 0, common_aaaa_data, - &common_aaaa_sig_data); - - // Dual-stack - types.push_back(RRType::A()); - ttls.push_back(rrttl); - answers.push_back(&common_a_data); - signatures.push_back(&common_sig_data); - types.push_back(RRType::AAAA()); - ttls.push_back(rrttl); - answers.push_back(&common_aaaa_data); - signatures.push_back(&common_aaaa_sig_data); - checkFind(ADDRESS, data_source, Name("ip46.example.com"), &zone_name, - rrclass, rrclass, rrtype, ttls, 0, types, answers, signatures); - - // The qname doesn't have no address records. - EXPECT_EQ(DataSrc::SUCCESS, - data_source.findAddrs(Name("text.example.com"), qclass, - result_sets, find_flags, &zone_name)); - EXPECT_EQ(DataSrc::TYPE_NOT_FOUND, find_flags); - EXPECT_TRUE(result_sets.begin() == result_sets.end()); -} - -TEST_F(Sqlite3DataSourceTest, findAddressRRset) { - findAddressRRsetCommon(rrclass); -} - -TEST_F(Sqlite3DataSourceTest, findAddressRRsetClassMismatch) { - EXPECT_EQ(DataSrc::ERROR, data_source.findAddrs(www_name, rrclass_notmatch, - result_sets, find_flags, - NULL)); -} - -TEST_F(Sqlite3DataSourceTest, findAddressRRsetClassAny) { - findAddressRRsetCommon(RRClass::ANY()); -} - -}