|
@@ -14,38 +14,109 @@
|
|
|
|
|
|
#include <sqlite3.h>
|
|
|
|
|
|
+#include <string>
|
|
|
+#include <vector>
|
|
|
+
|
|
|
+#include <boost/foreach.hpp>
|
|
|
+
|
|
|
#include <datasrc/sqlite3_accessor.h>
|
|
|
#include <datasrc/logger.h>
|
|
|
#include <datasrc/data_source.h>
|
|
|
#include <util/filename.h>
|
|
|
|
|
|
-#include <boost/lexical_cast.hpp>
|
|
|
+using namespace std;
|
|
|
|
|
|
namespace isc {
|
|
|
namespace datasrc {
|
|
|
|
|
|
+// The following enum and char* array define the SQL statements commonly
|
|
|
+// used in this implementation. Corresponding prepared statements (of
|
|
|
+// type sqlite3_stmt*) are maintained in the statements_ array of the
|
|
|
+// SQLite3Parameters structure.
|
|
|
+
|
|
|
+enum StatementID {
|
|
|
+ ZONE = 0,
|
|
|
+ ANY = 1,
|
|
|
+ BEGIN = 2,
|
|
|
+ COMMIT = 3,
|
|
|
+ ROLLBACK = 4,
|
|
|
+ DEL_ZONE_RECORDS = 5,
|
|
|
+ ADD_RECORD = 6,
|
|
|
+ DEL_RECORD = 7,
|
|
|
+ ITERATE = 8,
|
|
|
+ NUM_STATEMENTS = 9
|
|
|
+};
|
|
|
+
|
|
|
+const char* const text_statements[NUM_STATEMENTS] = {
|
|
|
+ // note for ANY and ITERATE: the order of the SELECT values is
|
|
|
+ // specifically chosen to match the enum values in RecordColumns
|
|
|
+ "SELECT id FROM zones WHERE name=?1 AND rdclass = ?2", // ZONE
|
|
|
+ "SELECT rdtype, ttl, sigtype, rdata FROM records " // ANY
|
|
|
+ "WHERE zone_id=?1 AND name=?2",
|
|
|
+ "BEGIN", // BEGIN
|
|
|
+ "COMMIT", // COMMIT
|
|
|
+ "ROLLBACK", // ROLLBACK
|
|
|
+ "DELETE FROM records WHERE zone_id=?1", // DEL_ZONE_RECORDS
|
|
|
+ "INSERT INTO records " // ADD_RECORD
|
|
|
+ "(zone_id, name, rname, ttl, rdtype, sigtype, rdata) "
|
|
|
+ "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
|
|
|
+ "DELETE FROM records WHERE zone_id=?1 AND name=?2 " // DEL_RECORD
|
|
|
+ "AND rdtype=?3 AND rdata=?4",
|
|
|
+ "SELECT rdtype, ttl, sigtype, rdata, name FROM records " // ITERATE
|
|
|
+ "WHERE zone_id = ?1 ORDER BY name, rdtype"
|
|
|
+};
|
|
|
+
|
|
|
struct SQLite3Parameters {
|
|
|
SQLite3Parameters() :
|
|
|
- db_(NULL), version_(-1),
|
|
|
- q_zone_(NULL), q_any_(NULL)
|
|
|
- /*q_record_(NULL), q_addrs_(NULL), q_referral_(NULL),
|
|
|
- q_count_(NULL), q_previous_(NULL), q_nsec3_(NULL),
|
|
|
- q_prevnsec3_(NULL) */
|
|
|
- {}
|
|
|
+ db_(NULL), version_(-1), updating_zone(false), updated_zone_id(-1)
|
|
|
+ {
|
|
|
+ for (int i = 0; i < NUM_STATEMENTS; ++i) {
|
|
|
+ statements_[i] = NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
sqlite3* db_;
|
|
|
int version_;
|
|
|
- sqlite3_stmt* q_zone_;
|
|
|
- sqlite3_stmt* q_any_;
|
|
|
- /*
|
|
|
- TODO: Yet unneeded statements
|
|
|
- sqlite3_stmt* q_record_;
|
|
|
- sqlite3_stmt* q_addrs_;
|
|
|
- sqlite3_stmt* q_referral_;
|
|
|
- sqlite3_stmt* q_count_;
|
|
|
- sqlite3_stmt* q_previous_;
|
|
|
- sqlite3_stmt* q_nsec3_;
|
|
|
- sqlite3_stmt* q_prevnsec3_;
|
|
|
- */
|
|
|
+ sqlite3_stmt* statements_[NUM_STATEMENTS];
|
|
|
+ bool updating_zone; // whether or not updating the zone
|
|
|
+ int updated_zone_id; // valid only when updating_zone is true
|
|
|
+};
|
|
|
+
|
|
|
+// This is a helper class to encapsulate the code logic of executing
|
|
|
+// a specific SQLite3 statement, ensuring the corresponding prepared
|
|
|
+// statement is always reset whether the execution is completed successfully
|
|
|
+// or it results in an exception.
|
|
|
+// Note that an object of this class is intended to be used for "ephemeral"
|
|
|
+// statement, which is completed with a single "step" (normally within a
|
|
|
+// single call to an SQLite3Database method). In particular, it cannot be
|
|
|
+// used for "SELECT" variants, which generally expect multiple matching rows.
|
|
|
+class StatementExecuter {
|
|
|
+public:
|
|
|
+ // desc will be used on failure in the what() message of the resulting
|
|
|
+ // DataSourceError exception.
|
|
|
+ StatementExecuter(SQLite3Parameters& dbparameters, StatementID stmt_id,
|
|
|
+ const char* desc) :
|
|
|
+ dbparameters_(dbparameters), stmt_id_(stmt_id), desc_(desc)
|
|
|
+ {
|
|
|
+ sqlite3_clear_bindings(dbparameters_.statements_[stmt_id_]);
|
|
|
+ }
|
|
|
+
|
|
|
+ ~StatementExecuter() {
|
|
|
+ sqlite3_reset(dbparameters_.statements_[stmt_id_]);
|
|
|
+ }
|
|
|
+
|
|
|
+ void exec() {
|
|
|
+ if (sqlite3_step(dbparameters_.statements_[stmt_id_]) !=
|
|
|
+ SQLITE_DONE) {
|
|
|
+ sqlite3_reset(dbparameters_.statements_[stmt_id_]);
|
|
|
+ isc_throw(DataSourceError, "failed to " << desc_ << ": " <<
|
|
|
+ sqlite3_errmsg(dbparameters_.db_));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ SQLite3Parameters& dbparameters_;
|
|
|
+ const StatementID stmt_id_;
|
|
|
+ const char* const desc_;
|
|
|
};
|
|
|
|
|
|
SQLite3Database::SQLite3Database(const std::string& filename,
|
|
@@ -72,35 +143,10 @@ namespace {
|
|
|
class Initializer {
|
|
|
public:
|
|
|
~Initializer() {
|
|
|
- if (params_.q_zone_ != NULL) {
|
|
|
- sqlite3_finalize(params_.q_zone_);
|
|
|
- }
|
|
|
- if (params_.q_any_ != NULL) {
|
|
|
- sqlite3_finalize(params_.q_any_);
|
|
|
- }
|
|
|
- /*
|
|
|
- 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_);
|
|
|
+ for (int i = 0; i < NUM_STATEMENTS; ++i) {
|
|
|
+ sqlite3_finalize(params_.statements_[i]);
|
|
|
}
|
|
|
- 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_);
|
|
|
}
|
|
@@ -136,49 +182,6 @@ const char* const SCHEMA_LIST[] = {
|
|
|
NULL
|
|
|
};
|
|
|
|
|
|
-const char* const q_zone_str = "SELECT id FROM zones WHERE name=?1 AND rdclass = ?2";
|
|
|
-
|
|
|
-// note that the order of the SELECT values is specifically chosen to match
|
|
|
-// the enum values in RecordColumns
|
|
|
-const char* const q_any_str = "SELECT rdtype, ttl, sigtype, rdata "
|
|
|
- "FROM records WHERE zone_id=?1 AND name=?2";
|
|
|
-
|
|
|
-// note that the order of the SELECT values is specifically chosen to match
|
|
|
-// the enum values in RecordColumns
|
|
|
-const char* const q_iterate_str = "SELECT rdtype, ttl, sigtype, rdata, name FROM records "
|
|
|
- "WHERE zone_id = ?1 "
|
|
|
- "ORDER BY name, rdtype";
|
|
|
-
|
|
|
-/* TODO: Prune the statements, not everything will be needed maybe?
|
|
|
-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_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";
|
|
|
- */
|
|
|
-
|
|
|
sqlite3_stmt*
|
|
|
prepare(sqlite3* const db, const char* const statement) {
|
|
|
sqlite3_stmt* prepared = NULL;
|
|
@@ -213,17 +216,9 @@ checkAndSetupSchema(Initializer* initializer) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- initializer->params_.q_zone_ = prepare(db, q_zone_str);
|
|
|
- initializer->params_.q_any_ = prepare(db, q_any_str);
|
|
|
- /* TODO: Yet unneeded statements
|
|
|
- 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_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);
|
|
|
- */
|
|
|
+ for (int i = 0; i < NUM_STATEMENTS; ++i) {
|
|
|
+ initializer->params_.statements_[i] = prepare(db, text_statements[i]);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
}
|
|
@@ -262,34 +257,10 @@ SQLite3Database::close(void) {
|
|
|
}
|
|
|
|
|
|
// 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_any_);
|
|
|
- dbparameters_->q_any_ = NULL;
|
|
|
-
|
|
|
- /* TODO: Once they are needed or not, uncomment or drop
|
|
|
- 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_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;
|
|
|
- */
|
|
|
+ for (int i = 0; i < NUM_STATEMENTS; ++i) {
|
|
|
+ sqlite3_finalize(dbparameters_->statements_[i]);
|
|
|
+ dbparameters_->statements_[i] = NULL;
|
|
|
+ }
|
|
|
|
|
|
sqlite3_close(dbparameters_->db_);
|
|
|
dbparameters_->db_ = NULL;
|
|
@@ -297,41 +268,43 @@ SQLite3Database::close(void) {
|
|
|
|
|
|
std::pair<bool, int>
|
|
|
SQLite3Database::getZone(const isc::dns::Name& name) const {
|
|
|
+ return (getZone(name.toText()));
|
|
|
+}
|
|
|
+
|
|
|
+std::pair<bool, int>
|
|
|
+SQLite3Database::getZone(const string& name) const {
|
|
|
int rc;
|
|
|
+ sqlite3_stmt* const stmt = dbparameters_->statements_[ZONE];
|
|
|
|
|
|
// Take the statement (simple SELECT id FROM zones WHERE...)
|
|
|
// and prepare it (bind the parameters to it)
|
|
|
- sqlite3_reset(dbparameters_->q_zone_);
|
|
|
- rc = sqlite3_bind_text(dbparameters_->q_zone_, 1, name.toText().c_str(),
|
|
|
- -1, SQLITE_TRANSIENT);
|
|
|
+ sqlite3_reset(stmt);
|
|
|
+ rc = sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_STATIC);
|
|
|
if (rc != SQLITE_OK) {
|
|
|
isc_throw(SQLite3Error, "Could not bind " << name <<
|
|
|
" to SQL statement (zone)");
|
|
|
}
|
|
|
- rc = sqlite3_bind_text(dbparameters_->q_zone_, 2, class_.c_str(), -1,
|
|
|
- SQLITE_STATIC);
|
|
|
+ rc = sqlite3_bind_text(stmt, 2, class_.c_str(), -1, SQLITE_STATIC);
|
|
|
if (rc != SQLITE_OK) {
|
|
|
isc_throw(SQLite3Error, "Could not bind " << class_ <<
|
|
|
" to SQL statement (zone)");
|
|
|
}
|
|
|
|
|
|
// Get the data there and see if it found anything
|
|
|
- rc = sqlite3_step(dbparameters_->q_zone_);
|
|
|
- std::pair<bool, int> result;
|
|
|
+ rc = sqlite3_step(stmt);
|
|
|
if (rc == SQLITE_ROW) {
|
|
|
- result = std::pair<bool, int>(true,
|
|
|
- sqlite3_column_int(dbparameters_->
|
|
|
- q_zone_, 0));
|
|
|
- return (result);
|
|
|
+ const int zone_id = sqlite3_column_int(stmt, 0);
|
|
|
+ sqlite3_reset(stmt);
|
|
|
+ return (pair<bool, int>(true, zone_id));
|
|
|
} else if (rc == SQLITE_DONE) {
|
|
|
- result = std::pair<bool, int>(false, 0);
|
|
|
// Free resources
|
|
|
- sqlite3_reset(dbparameters_->q_zone_);
|
|
|
- return (result);
|
|
|
+ sqlite3_reset(stmt);
|
|
|
+ return (pair<bool, int>(false, 0));
|
|
|
}
|
|
|
|
|
|
+ sqlite3_reset(stmt);
|
|
|
isc_throw(DataSourceError, "Unexpected failure in sqlite3_step: " <<
|
|
|
- sqlite3_errmsg(dbparameters_->db_));
|
|
|
+ sqlite3_errmsg(dbparameters_->db_));
|
|
|
// Compilers might not realize isc_throw always throws
|
|
|
return (std::pair<bool, int>(false, 0));
|
|
|
}
|
|
@@ -375,7 +348,8 @@ public:
|
|
|
statement_(NULL)
|
|
|
{
|
|
|
// We create the statement now and then just keep getting data from it
|
|
|
- statement_ = prepare(database->dbparameters_->db_, q_iterate_str);
|
|
|
+ statement_ = prepare(database->dbparameters_->db_,
|
|
|
+ text_statements[ITERATE]);
|
|
|
bindZoneId(id);
|
|
|
}
|
|
|
|
|
@@ -388,7 +362,8 @@ public:
|
|
|
statement_(NULL)
|
|
|
{
|
|
|
// We create the statement now and then just keep getting data from it
|
|
|
- statement_ = prepare(database->dbparameters_->db_, q_any_str);
|
|
|
+ statement_ = prepare(database->dbparameters_->db_,
|
|
|
+ text_statements[ANY]);
|
|
|
bindZoneId(id);
|
|
|
bindName(name);
|
|
|
}
|
|
@@ -467,5 +442,121 @@ SQLite3Database::getAllRecords(int id) const {
|
|
|
return (IteratorContextPtr(new Context(shared_from_this(), id)));
|
|
|
}
|
|
|
|
|
|
+pair<bool, int>
|
|
|
+SQLite3Database::startUpdateZone(const string& zone_name, const bool replace) {
|
|
|
+ if (dbparameters_->updating_zone) {
|
|
|
+ isc_throw(DataSourceError,
|
|
|
+ "duplicate zone update on SQLite3 data source");
|
|
|
+ }
|
|
|
+
|
|
|
+ const pair<bool, int> zone_info(getZone(zone_name));
|
|
|
+ if (!zone_info.first) {
|
|
|
+ return (zone_info);
|
|
|
+ }
|
|
|
+
|
|
|
+ dbparameters_->updating_zone = true;
|
|
|
+ dbparameters_->updated_zone_id = zone_info.second;
|
|
|
+
|
|
|
+ StatementExecuter(*dbparameters_, BEGIN,
|
|
|
+ "start an SQLite3 transaction").exec();
|
|
|
+
|
|
|
+ if (replace) {
|
|
|
+ StatementExecuter delzone_exec(*dbparameters_, DEL_ZONE_RECORDS,
|
|
|
+ "delete zone records");
|
|
|
+
|
|
|
+ sqlite3_clear_bindings(dbparameters_->statements_[DEL_ZONE_RECORDS]);
|
|
|
+ if (sqlite3_bind_int(dbparameters_->statements_[DEL_ZONE_RECORDS],
|
|
|
+ 1, zone_info.second) != SQLITE_OK) {
|
|
|
+ isc_throw(DataSourceError,
|
|
|
+ "failed to bind SQLite3 parameter: " <<
|
|
|
+ sqlite3_errmsg(dbparameters_->db_));
|
|
|
+ }
|
|
|
+
|
|
|
+ delzone_exec.exec();
|
|
|
+ }
|
|
|
+
|
|
|
+ return (zone_info);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+SQLite3Database::commitUpdateZone() {
|
|
|
+ if (!dbparameters_->updating_zone) {
|
|
|
+ isc_throw(DataSourceError, "committing zone update on SQLite3 "
|
|
|
+ "data source without transaction");
|
|
|
+ }
|
|
|
+
|
|
|
+ StatementExecuter(*dbparameters_, COMMIT,
|
|
|
+ "commit an SQLite3 transaction").exec();
|
|
|
+ dbparameters_->updating_zone = false;
|
|
|
+ dbparameters_->updated_zone_id = -1;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+SQLite3Database::rollbackUpdateZone() {
|
|
|
+ if (!dbparameters_->updating_zone) {
|
|
|
+ isc_throw(DataSourceError, "rolling back zone update on SQLite3 "
|
|
|
+ "data source without transaction");
|
|
|
+ }
|
|
|
+
|
|
|
+ StatementExecuter(*dbparameters_, ROLLBACK,
|
|
|
+ "rollback an SQLite3 transaction").exec();
|
|
|
+ dbparameters_->updating_zone = false;
|
|
|
+ dbparameters_->updated_zone_id = -1;
|
|
|
+}
|
|
|
+
|
|
|
+namespace {
|
|
|
+// Commonly used code sequence for adding/deleting record
|
|
|
+void
|
|
|
+doUpdate(SQLite3Parameters& dbparams, StatementID stmt_id,
|
|
|
+ const vector<string>& update_params, const char* exec_desc)
|
|
|
+{
|
|
|
+ sqlite3_stmt* const stmt = dbparams.statements_[stmt_id];
|
|
|
+ StatementExecuter executer(dbparams, stmt_id, exec_desc);
|
|
|
+
|
|
|
+ int param_id = 0;
|
|
|
+ if (sqlite3_bind_int(stmt, ++param_id, dbparams.updated_zone_id)
|
|
|
+ != SQLITE_OK) {
|
|
|
+ isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
|
|
|
+ sqlite3_errmsg(dbparams.db_));
|
|
|
+ }
|
|
|
+ BOOST_FOREACH(const string& column, update_params) {
|
|
|
+ if (sqlite3_bind_text(stmt, ++param_id, column.c_str(), -1,
|
|
|
+ SQLITE_TRANSIENT) != SQLITE_OK) {
|
|
|
+ isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
|
|
|
+ sqlite3_errmsg(dbparams.db_));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ executer.exec();
|
|
|
+}
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+SQLite3Database::addRecordToZone(const vector<string>& columns) {
|
|
|
+ if (!dbparameters_->updating_zone) {
|
|
|
+ isc_throw(DataSourceError, "adding record to SQLite3 "
|
|
|
+ "data source without transaction");
|
|
|
+ }
|
|
|
+ if (columns.size() != ADD_COLUMN_COUNT) {
|
|
|
+ isc_throw(DataSourceError, "adding incompatible number of columns "
|
|
|
+ "to SQLite3 data source: " << columns.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ doUpdate(*dbparameters_, ADD_RECORD, columns, "add record to zone");
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+SQLite3Database::deleteRecordInZone(const vector<string>& params) {
|
|
|
+ if (!dbparameters_->updating_zone) {
|
|
|
+ isc_throw(DataSourceError, "deleting record in SQLite3 "
|
|
|
+ "data source without transaction");
|
|
|
+ }
|
|
|
+ if (params.size() != DEL_PARAM_COUNT) {
|
|
|
+ isc_throw(DataSourceError, "incompatible # of parameters for "
|
|
|
+ "deleting in SQLite3 data source: " << params.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ doUpdate(*dbparameters_, DEL_RECORD, params, "delete record from zone");
|
|
|
+}
|
|
|
+
|
|
|
}
|
|
|
}
|