[svn] commit: r1388 - in /trunk/src/lib/auth: sqlite3_datasrc.cc sqlite3_datasrc.h tests/sqlite3_unittest.cc
BIND 10 source code commits
bind10-changes at lists.isc.org
Sat Mar 13 03:23:54 UTC 2010
Author: jinmei
Date: Sat Mar 13 03:23:54 2010
New Revision: 1388
Log:
provided the strong exception guarantee in DB initialization.
Modified:
trunk/src/lib/auth/sqlite3_datasrc.cc
trunk/src/lib/auth/sqlite3_datasrc.h
trunk/src/lib/auth/tests/sqlite3_unittest.cc
Modified: trunk/src/lib/auth/sqlite3_datasrc.cc
==============================================================================
--- trunk/src/lib/auth/sqlite3_datasrc.cc (original)
+++ trunk/src/lib/auth/sqlite3_datasrc.cc Sat Mar 13 03:23:54 2010
@@ -17,6 +17,8 @@
#include <string>
#include <sstream>
+#include <sqlite3.h>
+
#include "sqlite3_datasrc.h"
#include <dns/rrttl.h>
@@ -25,34 +27,85 @@
#include <dns/rrset.h>
#include <dns/rrsetlist.h>
-#include <iostream>
-
using namespace std;
using namespace isc::dns;
using namespace isc::dns::rdata;
namespace isc {
namespace auth {
+
+struct Sqlite3Parameters {
+ Sqlite3Parameters() : db_(NULL), 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 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 {
// Note: this cannot be std::string to avoid
// "static initialization order fiasco".
const char* DEFAULT_DB_FILE = "/tmp/zone.sqlite3";
-}
-
-//
-// Prepare a statement. Can call release() or sqlite3_finalize()
-// directly.
-//
-sqlite3_stmt*
-Sqlite3DataSrc::prepare(const char* statement) {
- sqlite3_stmt* prepared = NULL;
-
- if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) {
- isc_throw(Sqlite3Error, "could not prepare sqlite3 statement: " <<
- statement);
- }
- return (prepared);
+
+const char* const SCHEMA_LIST[] = {
+ "CREATE TABLE schema_version (version INTEGER NOT NULL)",
+ "INSERT INTO schema_version VALUES (1)",
+ "CREATE TABLE zones (id INTEGER PRIMARY KEY, "
+ "name STRING NOT NULL COLLATE NOCASE, "
+ "rdclass STRING 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 STRING NOT NULL COLLATE NOCASE, "
+ "rname STRING NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
+ "rdtype STRING NOT NULL COLLATE NOCASE, sigtype STRING COLLATE NOCASE, "
+ "rdata STRING NOT NULL)",
+ "CREATE INDEX records_byname ON records (name)",
+ "CREATE INDEX records_byrname ON records (rname)",
+ "CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
+ "hash STRING NOT NULL COLLATE NOCASE, owner STRING NOT NULL COLLATE NOCASE, "
+ "ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
+ "rdata STRING NOT NULL)",
+ "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
+ NULL
+};
+
+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";
+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 zone_id=?1 AND rdtype = 'NSEC' AND "
+ "rname < $2 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";
+
}
//
@@ -64,17 +117,6 @@
}
//
-// Get the database schema version.
-//
-int
-Sqlite3DataSrc::getVersion(void) {
- if (database_version == -1) {
- loadVersion();
- }
- return (database_version);
-}
-
-//
// Find the exact zone match. Return -1 if not found, or the zone's
// ID if found. This will always be >= 0 if found.
//
@@ -82,16 +124,17 @@
Sqlite3DataSrc::hasExactZone(const char* name) const {
int rc;
- sqlite3_reset(q_zone);
- rc = sqlite3_bind_text(q_zone, 1, name, -1, SQLITE_STATIC);
+ 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(q_zone);
- const int i = (rc == SQLITE_ROW) ? sqlite3_column_int(q_zone, 0) : -1;
- sqlite3_reset(q_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);
}
@@ -200,16 +243,16 @@
sqlite3_stmt* query;
switch (mode) {
case ADDRESS:
- query = q_addrs;
+ query = dbparameters->q_addrs_;
break;
case DELEGATION:
- query = q_referral;
+ query = dbparameters->q_referral_;
break;
default:
if (rdtype == RRType::ANY()) {
- query = q_any;
+ query = dbparameters->q_any_;
} else {
- query = q_record;
+ query = dbparameters->q_record_;
}
break;
}
@@ -230,7 +273,7 @@
" to SQL statement (query)");
}
- if (query == q_record) {
+ if (query == dbparameters->q_record_) {
rc = sqlite3_bind_text(query, 3, rdtype.toText().c_str(), -1,
SQLITE_STATIC);
if (rc != SQLITE_OK) {
@@ -251,33 +294,33 @@
// any RRs with that name to determine whether this is NXDOMAIN or
// NXRRSET
//
- sqlite3_reset(q_count);
- sqlite3_clear_bindings(q_count);
-
- rc = sqlite3_bind_int(q_count, 1, zone_id);
+ 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)");
}
- rc = sqlite3_bind_text(q_count, 2, name.reverse().toText().c_str(), -1,
- SQLITE_STATIC);
+ rc = sqlite3_bind_text(dbparameters->q_count_, 2,
+ name.reverse().toText().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(q_count);
+ rc = sqlite3_step(dbparameters->q_count_);
if (rc == SQLITE_ROW) {
- if (sqlite3_column_int(q_count, 0) != 0) {
+ if (sqlite3_column_int(dbparameters->q_count_, 0) != 0) {
flags |= TYPE_NOT_FOUND;
- sqlite3_reset(q_count);
+ sqlite3_reset(dbparameters->q_count_);
return (0);
}
}
flags |= NAME_NOT_FOUND;
- sqlite3_reset(q_count);
+ sqlite3_reset(dbparameters->q_count_);
return (0);
}
@@ -303,200 +346,6 @@
return (-1);
}
-
-void
-Sqlite3DataSrc::loadVersion(void) {
- sqlite3_stmt* prepared = prepare("SELECT version FROM schema_version");
- if (sqlite3_step(prepared) != SQLITE_ROW) {
- isc_throw(Sqlite3Error, "Failed to find a row in schema_version table");
- }
- database_version = sqlite3_column_int(prepared, 0);
- release(prepared);
-}
-
-void
-Sqlite3DataSrc::setupPreparedStatements(void) {
-
- const char* const q_zone_str = "SELECT id FROM zones WHERE name=?1";
- try {
- q_zone = prepare(q_zone_str);
- } catch (const char* e) {
- cout << e << endl << q_zone_str << endl;
- cout << sqlite3_errmsg(db) << endl;
- throw(e);
- }
-
- const char* 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'))";
- try {
- q_record = prepare(q_record_str);
- } catch (const char* e) {
- cout << e << endl << q_record_str << endl;
- cout << sqlite3_errmsg(db) << endl;
- throw(e);
- }
-
- const char* 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')";
- try {
- q_addrs = prepare(q_addrs_str);
- } catch (const char* e) {
- cout << e << endl << q_addrs_str << endl;
- cout << sqlite3_errmsg(db) << endl;
- throw(e);
- }
- const char* 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')";
- try {
- q_referral = prepare(q_referral_str);
- } catch (const char* e) {
- cout << e << endl << q_referral_str << endl;
- cout << sqlite3_errmsg(db) << endl;
- throw(e);
- }
- const char* q_any_str = "SELECT rdtype, ttl, sigtype, rdata "
- "FROM records WHERE zone_id=?1 AND name=?2";
- try {
- q_any = prepare(q_any_str);
- } catch (const char* e) {
- cout << e << endl << q_any_str << endl;
- cout << sqlite3_errmsg(db) << endl;
- throw(e);
- }
-
- const char* q_count_str = "SELECT COUNT(*) FROM records "
- "WHERE zone_id=?1 AND "
- "rname LIKE (?2 || '%');";
- try {
- q_count = prepare(q_count_str);
- } catch (const char* e) {
- cout << e << endl << q_count_str << endl;
- cout << sqlite3_errmsg(db) << endl;
- throw(e);
- }
-
- const char* q_previous_str = "SELECT name FROM records "
- "WHERE zone_id=?1 AND rdtype = 'NSEC' AND "
- "rname < $2 ORDER BY rname DESC LIMIT 1";
- try {
- q_previous = prepare(q_previous_str);
- } catch (const char* e) {
- cout << e << endl << q_previous_str << endl;
- cout << sqlite3_errmsg(db) << endl;
- throw(e);
- }
-
- const char* q_nsec3_str = "SELECT rdtype, ttl, rdata FROM nsec3 "
- "WHERE zone_id = ?1 AND hash = $2";
- try {
- q_nsec3 = prepare(q_nsec3_str);
- } catch (const char* e) {
- cout << e << endl << q_nsec3_str << endl;
- cout << sqlite3_errmsg(db) << endl;
- throw(e);
- }
-
- const char* q_prevnsec3_str = "SELECT hash FROM nsec3 "
- "WHERE zone_id = ?1 AND hash <= $2 "
- "ORDER BY hash DESC LIMIT 1";
- try {
- q_prevnsec3 = prepare(q_prevnsec3_str);
- } catch (const char* e) {
- cout << e << endl << q_prevnsec3_str << endl;
- cout << sqlite3_errmsg(db) << endl;
- throw(e);
- }
-}
-
-void
-Sqlite3DataSrc::execSetupQuery(const char* const query) {
- if (sqlite3_exec(db, query, NULL, NULL, NULL) != SQLITE_OK) {
- isc_throw(Sqlite3Error, "Failed to find a row in schema_version table: "
- << query);
- }
-}
-
-void
-Sqlite3DataSrc::checkAndSetupSchema(void) {
- try {
- loadVersion();
- setupPreparedStatements();
- // cout << "Loaded existing schema" << endl;
- } catch(...) {
- execSetupQuery("CREATE TABLE schema_version ("
- "version INTEGER NOT NULL)");
- execSetupQuery("INSERT INTO schema_version VALUES (1)");
- execSetupQuery("CREATE TABLE zones ("
- "id INTEGER PRIMARY KEY, "
- "name STRING NOT NULL COLLATE NOCASE, "
- "rdclass STRING NOT NULL COLLATE NOCASE DEFAULT 'IN', "
- "dnssec BOOLEAN NOT NULL DEFAULT 0)");
- execSetupQuery("CREATE INDEX zones_byname ON zones (name)");
- execSetupQuery("CREATE TABLE records ("
- "id INTEGER PRIMARY KEY, "
- "zone_id INTEGER NOT NULL, "
- "name STRING NOT NULL COLLATE NOCASE, "
- "rname STRING NOT NULL COLLATE NOCASE, "
- "ttl INTEGER NOT NULL, "
- "rdtype STRING NOT NULL COLLATE NOCASE, "
- "sigtype STRING COLLATE NOCASE, "
- "rdata STRING NOT NULL)");
- execSetupQuery("CREATE INDEX records_byname ON records (name)");
- execSetupQuery("CREATE INDEX records_byrname ON records (rname)");
- execSetupQuery("CREATE TABLE nsec3 ("
- "id INTEGER PRIMARY KEY, "
- "zone_id INTEGER NOT NULL, "
- "hash STRING NOT NULL COLLATE NOCASE, "
- "owner STRING NOT NULL COLLATE NOCASE, "
- "ttl INTEGER NOT NULL, "
- "rdtype STRING NOT NULL COLLATE NOCASE, "
- "rdata STRING NOT NULL)");
- execSetupQuery("CREATE INDEX nsec3_byhash ON nsec3 (hash)");
-
- setupPreparedStatements();
- // cout << "Created new file and schema" << endl;
- }
-}
-
-Sqlite3DataSrc::Sqlite3DataSrc() :
- db(NULL)
-{
- database_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;
-}
-
-Sqlite3DataSrc::~Sqlite3DataSrc() {
- if (db != NULL) {
- close();
- }
-}
-
-DataSrc::Result
-Sqlite3DataSrc::init(const isc::data::ElementPtr config) {
- if (config && config->contains("database_file")) {
- open(config->get("database_file")->stringValue());
- } else {
- open(DEFAULT_DB_FILE);
- }
- return (SUCCESS);
-}
-
void
Sqlite3DataSrc::findClosestEnclosure(NameMatch& match,
const RRClass& qclass) const
@@ -526,30 +375,31 @@
return (ERROR);
}
- sqlite3_reset(q_previous);
- sqlite3_clear_bindings(q_previous);
-
- int rc = sqlite3_bind_int(q_previous, 1, zone_id);
+ 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)");
}
- rc = sqlite3_bind_text(q_previous, 2, qname.reverse().toText().c_str(),
- -1, SQLITE_STATIC);
+ rc = sqlite3_bind_text(dbparameters->q_previous_, 2,
+ qname.reverse().toText().c_str(), -1, SQLITE_STATIC);
if (rc != SQLITE_OK) {
isc_throw(Sqlite3Error, "Could not bind name " << qname <<
" to SQL statement (qprevious)");
}
- rc = sqlite3_step(q_previous);
+ rc = sqlite3_step(dbparameters->q_previous_);
if (rc != SQLITE_ROW) {
- sqlite3_reset(q_previous);
+ sqlite3_reset(dbparameters->q_previous_);
return (ERROR);
}
// XXX: bad cast. we should revisit this.
- target = Name((const char*)sqlite3_column_text(q_previous, 0));
- sqlite3_reset(q_previous);
+ target = Name((const char*)sqlite3_column_text(dbparameters->q_previous_,
+ 0));
+ sqlite3_reset(dbparameters->q_previous_);
return (SUCCESS);
}
@@ -563,55 +413,57 @@
return (ERROR);
}
- sqlite3_reset(q_prevnsec3);
- sqlite3_clear_bindings(q_prevnsec3);
-
- int rc = sqlite3_bind_int(q_prevnsec3, 1, zone_id);
+ 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(q_prevnsec3, 2, hashstr.c_str(), -1, SQLITE_STATIC);
+ 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(q_prevnsec3);
+ rc = sqlite3_step(dbparameters->q_prevnsec3_);
const char* hash;
if (rc == SQLITE_ROW) {
- hash = (const char*) sqlite3_column_text(q_prevnsec3, 0);
+ 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(q_prevnsec3);
- rc = sqlite3_bind_text(q_prevnsec3, 2, "w", -1, SQLITE_STATIC);
+ 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(q_prevnsec3);
+ rc = sqlite3_step(dbparameters->q_prevnsec3_);
if (rc != SQLITE_ROW) {
return (ERROR);
}
- hash = (const char*) sqlite3_column_text(q_prevnsec3, 0);
- }
-
- sqlite3_reset(q_nsec3);
- sqlite3_clear_bindings(q_nsec3);
-
- rc = sqlite3_bind_int(q_nsec3, 1, zone_id);
+ 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(q_nsec3, 2, hash, -1, SQLITE_STATIC);
+ 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)");
@@ -619,13 +471,14 @@
DataSrc::Result result = SUCCESS;
uint32_t flags = 0;
- if (importSqlite3Rows(q_nsec3, Name(hash).concatenate(zonename),
+ 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(q_nsec3);
+ sqlite3_reset(dbparameters->q_nsec3_);
return (result);
}
@@ -684,78 +537,182 @@
findRecords(qname, RRType::ANY(), target, zonename, DELEGATION, flags);
return (SUCCESS);
}
+
+Sqlite3DataSrc::Sqlite3DataSrc() :
+ dbparameters(new Sqlite3Parameters)
+{}
+
+Sqlite3DataSrc::~Sqlite3DataSrc() {
+ if (dbparameters->db_ != NULL) {
+ close();
+ }
+ delete dbparameters;
+}
+
+DataSrc::Result
+Sqlite3DataSrc::init(const isc::data::ElementPtr config) {
+ if (config && config->contains("database_file")) {
+ open(config->get("database_file")->stringValue());
+ } else {
+ open(DEFAULT_DB_FILE);
+ }
+ 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 sqlite3 statement: " <<
+ statement);
+ }
+ return (prepared);
+}
+
+void
+checkAndSetupSchema(Sqlite3Initializer* initializer) {
+ sqlite3* const db = initializer->params_.db_;
+
+ sqlite3_stmt* prepared = NULL;
+ if (sqlite3_prepare_v2(db, "SELECT version FROM schema_version", -1,
+ &prepared, NULL) == SQLITE_OK &&
+ sqlite3_step(prepared) == SQLITE_ROW) {
+ initializer->params_.version_ = sqlite3_column_int(prepared, 0);
+ sqlite3_finalize(prepared);
+ } else {
+ if (prepared != NULL) {
+ sqlite3_finalize(prepared);
+ }
+ 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]);
+ }
+ }
+ }
+
+ 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) {
- if (db != NULL) {
+ if (dbparameters->db_ != NULL) {
isc_throw(DataSourceError, "Duplicate Sqlite3 open with " << name);
}
- if (sqlite3_open(name.c_str(), &db) != 0) {
- // sqlite3_close() must be called even when open fails.
- sqlite3_close(db);
+
+ Sqlite3Initializer initializer;
+
+ if (sqlite3_open(name.c_str(), &initializer.params_.db_) != 0) {
isc_throw(Sqlite3Error, "Cannot open Sqlite3 database file: " << name);
}
- checkAndSetupSchema();
-}
-
+ checkAndSetupSchema(&initializer);
+ initializer.move(dbparameters);
+}
+
+//
+// Close the database.
+//
DataSrc::Result
Sqlite3DataSrc::close(void) {
- if (db == NULL) {
+ if (dbparameters->db_ == NULL) {
isc_throw(DataSourceError,
"Sqlite3 data source is being closed before open");
}
- if (q_zone != NULL) {
- release(q_zone);
- q_zone = NULL;
- }
-
- if (q_record) {
- release(q_record);
- q_record = NULL;
- }
-
- if (q_addrs) {
- release(q_addrs);
- q_addrs = NULL;
- }
-
- if (q_referral) {
- release(q_referral);
- q_referral = NULL;
- }
-
- if (q_any) {
- release(q_any);
- q_any = NULL;
- }
-
- if (q_count) {
- release(q_count);
- q_count = NULL;
- }
-
- if (q_previous) {
- release(q_previous);
- q_previous = NULL;
- }
-
- if (q_prevnsec3) {
- release(q_prevnsec3);
- q_prevnsec3 = NULL;
- }
-
- if (q_nsec3) {
- release(q_nsec3);
- q_nsec3 = NULL;
- }
-
- sqlite3_close(db);
-
- db = NULL;
+ // 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);
}
Modified: trunk/src/lib/auth/sqlite3_datasrc.h
==============================================================================
--- trunk/src/lib/auth/sqlite3_datasrc.h (original)
+++ trunk/src/lib/auth/sqlite3_datasrc.h Sat Mar 13 03:23:54 2010
@@ -21,8 +21,6 @@
#include <exceptions/exceptions.h>
-#include <sqlite3.h>
-
#include "data_source.h"
namespace isc {
@@ -37,6 +35,7 @@
namespace auth {
class Query;
+struct Sqlite3Parameters;
class Sqlite3Error : public Exception {
public:
@@ -108,34 +107,15 @@
};
void open(const std::string& name);
- sqlite3_stmt* prepare(const char *statement);
void release(sqlite3_stmt* prepared);
- int getVersion(void);
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;
- void loadVersion(void);
- void setupPreparedStatements(void);
- void execSetupQuery(const char *query);
- void checkAndSetupSchema(void);
- sqlite3 *db;
- int database_version;
-
- //
- // Prepared statements
- //
- 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;
+private:
+ Sqlite3Parameters* dbparameters;
};
}
Modified: trunk/src/lib/auth/tests/sqlite3_unittest.cc
==============================================================================
--- trunk/src/lib/auth/tests/sqlite3_unittest.cc (original)
+++ trunk/src/lib/auth/tests/sqlite3_unittest.cc Sat Mar 13 03:23:54 2010
@@ -382,7 +382,6 @@
EXPECT_THROW(data_source.close(), DataSourceError);
}
-#if 0 // currently fails
TEST_F(Sqlite3DataSourceTest, openBrokenDB) {
EXPECT_EQ(DataSrc::SUCCESS, data_source.close());
// The database exists but is broken. An exception will be thrown
@@ -392,7 +391,6 @@
// in the closed state.
EXPECT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_EXAMPLE));
}
-#endif
// This test only confirms that on-the-fly schema creation works.
TEST_F(Sqlite3DataSourceTest, memoryDB) {
More information about the bind10-changes
mailing list