sqlite3_accessor.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <sqlite3.h>
  15. #include <string>
  16. #include <vector>
  17. #include <boost/foreach.hpp>
  18. #include <datasrc/sqlite3_accessor.h>
  19. #include <datasrc/logger.h>
  20. #include <datasrc/data_source.h>
  21. #include <util/filename.h>
  22. using namespace std;
  23. #define SQLITE_SCHEMA_VERSION 1
  24. namespace isc {
  25. namespace datasrc {
  26. // The following enum and char* array define the SQL statements commonly
  27. // used in this implementation. Corresponding prepared statements (of
  28. // type sqlite3_stmt*) are maintained in the statements_ array of the
  29. // SQLite3Parameters structure.
  30. enum StatementID {
  31. ZONE = 0,
  32. ANY = 1,
  33. ANY_SUB = 2,
  34. BEGIN = 3,
  35. COMMIT = 4,
  36. ROLLBACK = 5,
  37. DEL_ZONE_RECORDS = 6,
  38. ADD_RECORD = 7,
  39. DEL_RECORD = 8,
  40. ITERATE = 9,
  41. FIND_PREVIOUS = 10,
  42. NUM_STATEMENTS = 11
  43. };
  44. const char* const text_statements[NUM_STATEMENTS] = {
  45. // note for ANY and ITERATE: the order of the SELECT values is
  46. // specifically chosen to match the enum values in RecordColumns
  47. "SELECT id FROM zones WHERE name=?1 AND rdclass = ?2", // ZONE
  48. "SELECT rdtype, ttl, sigtype, rdata FROM records " // ANY
  49. "WHERE zone_id=?1 AND name=?2",
  50. "SELECT rdtype, ttl, sigtype, rdata " // ANY_SUB
  51. "FROM records WHERE zone_id=?1 AND name LIKE (\"%.\" || ?2)",
  52. "BEGIN", // BEGIN
  53. "COMMIT", // COMMIT
  54. "ROLLBACK", // ROLLBACK
  55. "DELETE FROM records WHERE zone_id=?1", // DEL_ZONE_RECORDS
  56. "INSERT INTO records " // ADD_RECORD
  57. "(zone_id, name, rname, ttl, rdtype, sigtype, rdata) "
  58. "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
  59. "DELETE FROM records WHERE zone_id=?1 AND name=?2 " // DEL_RECORD
  60. "AND rdtype=?3 AND rdata=?4",
  61. "SELECT rdtype, ttl, sigtype, rdata, name FROM records " // ITERATE
  62. "WHERE zone_id = ?1 ORDER BY name, rdtype",
  63. /*
  64. * This one looks for previous name with NSEC record. It is done by
  65. * using the reversed name. The NSEC is checked because we need to
  66. * skip glue data, which don't have the NSEC.
  67. */
  68. "SELECT name FROM records " // FIND_PREVIOUS
  69. "WHERE zone_id=?1 AND rdtype = 'NSEC' AND "
  70. "rname < $2 ORDER BY rname DESC LIMIT 1"
  71. };
  72. struct SQLite3Parameters {
  73. SQLite3Parameters() :
  74. db_(NULL), version_(-1), updating_zone(false), updated_zone_id(-1)
  75. {
  76. for (int i = 0; i < NUM_STATEMENTS; ++i) {
  77. statements_[i] = NULL;
  78. }
  79. }
  80. sqlite3* db_;
  81. int version_;
  82. sqlite3_stmt* statements_[NUM_STATEMENTS];
  83. bool updating_zone; // whether or not updating the zone
  84. int updated_zone_id; // valid only when updating_zone is true
  85. };
  86. // This is a helper class to encapsulate the code logic of executing
  87. // a specific SQLite3 statement, ensuring the corresponding prepared
  88. // statement is always reset whether the execution is completed successfully
  89. // or it results in an exception.
  90. // Note that an object of this class is intended to be used for "ephemeral"
  91. // statement, which is completed with a single "step" (normally within a
  92. // single call to an SQLite3Database method). In particular, it cannot be
  93. // used for "SELECT" variants, which generally expect multiple matching rows.
  94. class StatementProcessor {
  95. public:
  96. // desc will be used on failure in the what() message of the resulting
  97. // DataSourceError exception.
  98. StatementProcessor(SQLite3Parameters& dbparameters, StatementID stmt_id,
  99. const char* desc) :
  100. dbparameters_(dbparameters), stmt_id_(stmt_id), desc_(desc)
  101. {
  102. sqlite3_clear_bindings(dbparameters_.statements_[stmt_id_]);
  103. }
  104. ~StatementProcessor() {
  105. sqlite3_reset(dbparameters_.statements_[stmt_id_]);
  106. }
  107. void exec() {
  108. if (sqlite3_step(dbparameters_.statements_[stmt_id_]) != SQLITE_DONE) {
  109. sqlite3_reset(dbparameters_.statements_[stmt_id_]);
  110. isc_throw(DataSourceError, "failed to " << desc_ << ": " <<
  111. sqlite3_errmsg(dbparameters_.db_));
  112. }
  113. }
  114. private:
  115. SQLite3Parameters& dbparameters_;
  116. const StatementID stmt_id_;
  117. const char* const desc_;
  118. };
  119. SQLite3Accessor::SQLite3Accessor(const std::string& filename,
  120. const isc::dns::RRClass& rrclass) :
  121. dbparameters_(new SQLite3Parameters),
  122. filename_(filename),
  123. class_(rrclass.toText()),
  124. database_name_("sqlite3_" +
  125. isc::util::Filename(filename).nameAndExtension())
  126. {
  127. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_NEWCONN);
  128. open(filename);
  129. }
  130. SQLite3Accessor::SQLite3Accessor(const std::string& filename,
  131. const string& rrclass) :
  132. dbparameters_(new SQLite3Parameters),
  133. filename_(filename),
  134. class_(rrclass),
  135. database_name_("sqlite3_" +
  136. isc::util::Filename(filename).nameAndExtension())
  137. {
  138. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_NEWCONN);
  139. open(filename);
  140. }
  141. boost::shared_ptr<DatabaseAccessor>
  142. SQLite3Accessor::clone() {
  143. return (boost::shared_ptr<DatabaseAccessor>(new SQLite3Accessor(filename_,
  144. class_)));
  145. }
  146. namespace {
  147. // This is a helper class to initialize a Sqlite3 DB safely. An object of
  148. // this class encapsulates all temporary resources that are necessary for
  149. // the initialization, and release them in the destructor. Once everything
  150. // is properly initialized, the move() method moves the allocated resources
  151. // to the main object in an exception free manner. This way, the main code
  152. // for the initialization can be exception safe, and can provide the strong
  153. // exception guarantee.
  154. class Initializer {
  155. public:
  156. ~Initializer() {
  157. for (int i = 0; i < NUM_STATEMENTS; ++i) {
  158. sqlite3_finalize(params_.statements_[i]);
  159. }
  160. if (params_.db_ != NULL) {
  161. sqlite3_close(params_.db_);
  162. }
  163. }
  164. void move(SQLite3Parameters* dst) {
  165. *dst = params_;
  166. params_ = SQLite3Parameters(); // clear everything
  167. }
  168. SQLite3Parameters params_;
  169. };
  170. const char* const SCHEMA_LIST[] = {
  171. "CREATE TABLE schema_version (version INTEGER NOT NULL)",
  172. "INSERT INTO schema_version VALUES (1)",
  173. "CREATE TABLE zones (id INTEGER PRIMARY KEY, "
  174. "name STRING NOT NULL COLLATE NOCASE, "
  175. "rdclass STRING NOT NULL COLLATE NOCASE DEFAULT 'IN', "
  176. "dnssec BOOLEAN NOT NULL DEFAULT 0)",
  177. "CREATE INDEX zones_byname ON zones (name)",
  178. "CREATE TABLE records (id INTEGER PRIMARY KEY, "
  179. "zone_id INTEGER NOT NULL, name STRING NOT NULL COLLATE NOCASE, "
  180. "rname STRING NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
  181. "rdtype STRING NOT NULL COLLATE NOCASE, sigtype STRING COLLATE NOCASE, "
  182. "rdata STRING NOT NULL)",
  183. "CREATE INDEX records_byname ON records (name)",
  184. "CREATE INDEX records_byrname ON records (rname)",
  185. "CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
  186. "hash STRING NOT NULL COLLATE NOCASE, "
  187. "owner STRING NOT NULL COLLATE NOCASE, "
  188. "ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
  189. "rdata STRING NOT NULL)",
  190. "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
  191. NULL
  192. };
  193. sqlite3_stmt*
  194. prepare(sqlite3* const db, const char* const statement) {
  195. sqlite3_stmt* prepared = NULL;
  196. if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) {
  197. isc_throw(SQLite3Error, "Could not prepare SQLite statement: " <<
  198. statement);
  199. }
  200. return (prepared);
  201. }
  202. // small function to sleep for 0.1 seconds, needed when waiting for
  203. // exclusive database locks (which should only occur on startup, and only
  204. // when the database has not been created yet)
  205. void doSleep() {
  206. struct timespec req;
  207. req.tv_sec = 0;
  208. req.tv_nsec = 100000000;
  209. nanosleep(&req, NULL);
  210. }
  211. // returns the schema version if the schema version table exists
  212. // returns -1 if it does not
  213. int checkSchemaVersion(sqlite3* db) {
  214. sqlite3_stmt* prepared = NULL;
  215. // At this point in time, the database might be exclusively locked, in
  216. // which case even prepare() will return BUSY, so we may need to try a
  217. // few times
  218. for (size_t i = 0; i < 50; ++i) {
  219. int rc = sqlite3_prepare_v2(db, "SELECT version FROM schema_version",
  220. -1, &prepared, NULL);
  221. if (rc == SQLITE_ERROR) {
  222. // this is the error that is returned when the table does not
  223. // exist
  224. return (-1);
  225. } else if (rc == SQLITE_OK) {
  226. break;
  227. } else if (rc != SQLITE_BUSY || i == 50) {
  228. isc_throw(SQLite3Error, "Unable to prepare version query: "
  229. << rc << " " << sqlite3_errmsg(db));
  230. }
  231. doSleep();
  232. }
  233. if (sqlite3_step(prepared) != SQLITE_ROW) {
  234. isc_throw(SQLite3Error,
  235. "Unable to query version: " << sqlite3_errmsg(db));
  236. }
  237. int version = sqlite3_column_int(prepared, 0);
  238. sqlite3_finalize(prepared);
  239. return (version);
  240. }
  241. // return db version
  242. int create_database(sqlite3* db) {
  243. // try to get an exclusive lock. Once that is obtained, do the version
  244. // check *again*, just in case this process was racing another
  245. //
  246. // try for 5 secs (50*0.1)
  247. int rc;
  248. logger.info(DATASRC_SQLITE_SETUP);
  249. for (size_t i = 0; i < 50; ++i) {
  250. rc = sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL,
  251. NULL);
  252. if (rc == SQLITE_OK) {
  253. break;
  254. } else if (rc != SQLITE_BUSY || i == 50) {
  255. isc_throw(SQLite3Error, "Unable to acquire exclusive lock "
  256. "for database creation: " << sqlite3_errmsg(db));
  257. }
  258. doSleep();
  259. }
  260. int schema_version = checkSchemaVersion(db);
  261. if (schema_version == -1) {
  262. for (int i = 0; SCHEMA_LIST[i] != NULL; ++i) {
  263. if (sqlite3_exec(db, SCHEMA_LIST[i], NULL, NULL, NULL) !=
  264. SQLITE_OK) {
  265. isc_throw(SQLite3Error,
  266. "Failed to set up schema " << SCHEMA_LIST[i]);
  267. }
  268. }
  269. sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, NULL);
  270. return (SQLITE_SCHEMA_VERSION);
  271. } else {
  272. return (schema_version);
  273. }
  274. }
  275. void
  276. checkAndSetupSchema(Initializer* initializer) {
  277. sqlite3* const db = initializer->params_.db_;
  278. int schema_version = checkSchemaVersion(db);
  279. if (schema_version != SQLITE_SCHEMA_VERSION) {
  280. schema_version = create_database(db);
  281. }
  282. initializer->params_.version_ = schema_version;
  283. for (int i = 0; i < NUM_STATEMENTS; ++i) {
  284. initializer->params_.statements_[i] = prepare(db, text_statements[i]);
  285. }
  286. }
  287. }
  288. void
  289. SQLite3Accessor::open(const std::string& name) {
  290. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CONNOPEN).arg(name);
  291. if (dbparameters_->db_ != NULL) {
  292. // There shouldn't be a way to trigger this anyway
  293. isc_throw(DataSourceError, "Duplicate SQLite open with " << name);
  294. }
  295. Initializer initializer;
  296. if (sqlite3_open(name.c_str(), &initializer.params_.db_) != 0) {
  297. isc_throw(SQLite3Error, "Cannot open SQLite database file: " << name);
  298. }
  299. checkAndSetupSchema(&initializer);
  300. initializer.move(dbparameters_.get());
  301. }
  302. SQLite3Accessor::~SQLite3Accessor() {
  303. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_DROPCONN);
  304. if (dbparameters_->db_ != NULL) {
  305. close();
  306. }
  307. }
  308. void
  309. SQLite3Accessor::close(void) {
  310. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CONNCLOSE);
  311. if (dbparameters_->db_ == NULL) {
  312. isc_throw(DataSourceError,
  313. "SQLite data source is being closed before open");
  314. }
  315. // XXX: sqlite3_finalize() could fail. What should we do in that case?
  316. for (int i = 0; i < NUM_STATEMENTS; ++i) {
  317. sqlite3_finalize(dbparameters_->statements_[i]);
  318. dbparameters_->statements_[i] = NULL;
  319. }
  320. sqlite3_close(dbparameters_->db_);
  321. dbparameters_->db_ = NULL;
  322. }
  323. std::pair<bool, int>
  324. SQLite3Accessor::getZone(const std::string& name) const {
  325. int rc;
  326. sqlite3_stmt* const stmt = dbparameters_->statements_[ZONE];
  327. // Take the statement (simple SELECT id FROM zones WHERE...)
  328. // and prepare it (bind the parameters to it)
  329. sqlite3_reset(stmt);
  330. rc = sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_STATIC);
  331. if (rc != SQLITE_OK) {
  332. isc_throw(SQLite3Error, "Could not bind " << name <<
  333. " to SQL statement (zone)");
  334. }
  335. rc = sqlite3_bind_text(stmt, 2, class_.c_str(), -1, SQLITE_STATIC);
  336. if (rc != SQLITE_OK) {
  337. isc_throw(SQLite3Error, "Could not bind " << class_ <<
  338. " to SQL statement (zone)");
  339. }
  340. // Get the data there and see if it found anything
  341. rc = sqlite3_step(stmt);
  342. if (rc == SQLITE_ROW) {
  343. const int zone_id = sqlite3_column_int(stmt, 0);
  344. sqlite3_reset(stmt);
  345. return (pair<bool, int>(true, zone_id));
  346. } else if (rc == SQLITE_DONE) {
  347. // Free resources
  348. sqlite3_reset(stmt);
  349. return (pair<bool, int>(false, 0));
  350. }
  351. sqlite3_reset(stmt);
  352. isc_throw(DataSourceError, "Unexpected failure in sqlite3_step: " <<
  353. sqlite3_errmsg(dbparameters_->db_));
  354. // Compilers might not realize isc_throw always throws
  355. return (std::pair<bool, int>(false, 0));
  356. }
  357. namespace {
  358. // Conversion to plain char
  359. const char*
  360. convertToPlainChar(const unsigned char* ucp, sqlite3 *db) {
  361. if (ucp == NULL) {
  362. // The field can really be NULL, in which case we return an
  363. // empty string, or sqlite may have run out of memory, in
  364. // which case we raise an error
  365. if (sqlite3_errcode(db) == SQLITE_NOMEM) {
  366. isc_throw(DataSourceError,
  367. "Sqlite3 backend encountered a memory allocation "
  368. "error in sqlite3_column_text()");
  369. } else {
  370. return ("");
  371. }
  372. }
  373. const void* p = ucp;
  374. return (static_cast<const char*>(p));
  375. }
  376. }
  377. class SQLite3Accessor::Context : public DatabaseAccessor::IteratorContext {
  378. public:
  379. // Construct an iterator for all records. When constructed this
  380. // way, the getNext() call will copy all fields
  381. Context(const boost::shared_ptr<const SQLite3Accessor>& accessor, int id) :
  382. iterator_type_(ITT_ALL),
  383. accessor_(accessor),
  384. statement_(NULL),
  385. name_("")
  386. {
  387. // We create the statement now and then just keep getting data from it
  388. statement_ = prepare(accessor->dbparameters_->db_,
  389. text_statements[ITERATE]);
  390. bindZoneId(id);
  391. }
  392. // Construct an iterator for records with a specific name. When constructed
  393. // this way, the getNext() call will copy all fields except name
  394. Context(const boost::shared_ptr<const SQLite3Accessor>& accessor, int id,
  395. const std::string& name, bool subdomains) :
  396. iterator_type_(ITT_NAME),
  397. accessor_(accessor),
  398. statement_(NULL),
  399. name_(name)
  400. {
  401. // We create the statement now and then just keep getting data from it
  402. statement_ = prepare(accessor->dbparameters_->db_,
  403. subdomains ? text_statements[ANY_SUB] :
  404. text_statements[ANY]);
  405. bindZoneId(id);
  406. bindName(name_);
  407. }
  408. bool getNext(std::string (&data)[COLUMN_COUNT]) {
  409. // If there's another row, get it
  410. // If finalize has been called (e.g. when previous getNext() got
  411. // SQLITE_DONE), directly return false
  412. if (statement_ == NULL) {
  413. return false;
  414. }
  415. const int rc(sqlite3_step(statement_));
  416. if (rc == SQLITE_ROW) {
  417. // For both types, we copy the first four columns
  418. copyColumn(data, TYPE_COLUMN);
  419. copyColumn(data, TTL_COLUMN);
  420. copyColumn(data, SIGTYPE_COLUMN);
  421. copyColumn(data, RDATA_COLUMN);
  422. // Only copy Name if we are iterating over every record
  423. if (iterator_type_ == ITT_ALL) {
  424. copyColumn(data, NAME_COLUMN);
  425. }
  426. return (true);
  427. } else if (rc != SQLITE_DONE) {
  428. isc_throw(DataSourceError,
  429. "Unexpected failure in sqlite3_step: " <<
  430. sqlite3_errmsg(accessor_->dbparameters_->db_));
  431. }
  432. finalize();
  433. return (false);
  434. }
  435. virtual ~Context() {
  436. finalize();
  437. }
  438. private:
  439. // Depending on which constructor is called, behaviour is slightly
  440. // different. We keep track of what to do with the iterator type
  441. // See description of getNext() and the constructors
  442. enum IteratorType {
  443. ITT_ALL,
  444. ITT_NAME
  445. };
  446. void copyColumn(std::string (&data)[COLUMN_COUNT], int column) {
  447. data[column] = convertToPlainChar(sqlite3_column_text(statement_,
  448. column),
  449. accessor_->dbparameters_->db_);
  450. }
  451. void bindZoneId(const int zone_id) {
  452. if (sqlite3_bind_int(statement_, 1, zone_id) != SQLITE_OK) {
  453. finalize();
  454. isc_throw(SQLite3Error, "Could not bind int " << zone_id <<
  455. " to SQL statement: " <<
  456. sqlite3_errmsg(accessor_->dbparameters_->db_));
  457. }
  458. }
  459. void bindName(const std::string& name) {
  460. if (sqlite3_bind_text(statement_, 2, name.c_str(), -1,
  461. SQLITE_TRANSIENT) != SQLITE_OK) {
  462. const char* errmsg = sqlite3_errmsg(accessor_->dbparameters_->db_);
  463. finalize();
  464. isc_throw(SQLite3Error, "Could not bind text '" << name <<
  465. "' to SQL statement: " << errmsg);
  466. }
  467. }
  468. void finalize() {
  469. sqlite3_finalize(statement_);
  470. statement_ = NULL;
  471. }
  472. const IteratorType iterator_type_;
  473. boost::shared_ptr<const SQLite3Accessor> accessor_;
  474. sqlite3_stmt *statement_;
  475. const std::string name_;
  476. };
  477. DatabaseAccessor::IteratorContextPtr
  478. SQLite3Accessor::getRecords(const std::string& name, int id,
  479. bool subdomains) const
  480. {
  481. return (IteratorContextPtr(new Context(shared_from_this(), id, name,
  482. subdomains)));
  483. }
  484. DatabaseAccessor::IteratorContextPtr
  485. SQLite3Accessor::getAllRecords(int id) const {
  486. return (IteratorContextPtr(new Context(shared_from_this(), id)));
  487. }
  488. pair<bool, int>
  489. SQLite3Accessor::startUpdateZone(const string& zone_name, const bool replace) {
  490. if (dbparameters_->updating_zone) {
  491. isc_throw(DataSourceError,
  492. "duplicate zone update on SQLite3 data source");
  493. }
  494. const pair<bool, int> zone_info(getZone(zone_name));
  495. if (!zone_info.first) {
  496. return (zone_info);
  497. }
  498. StatementProcessor(*dbparameters_, BEGIN,
  499. "start an SQLite3 transaction").exec();
  500. if (replace) {
  501. try {
  502. StatementProcessor delzone_exec(*dbparameters_, DEL_ZONE_RECORDS,
  503. "delete zone records");
  504. sqlite3_clear_bindings(
  505. dbparameters_->statements_[DEL_ZONE_RECORDS]);
  506. if (sqlite3_bind_int(dbparameters_->statements_[DEL_ZONE_RECORDS],
  507. 1, zone_info.second) != SQLITE_OK) {
  508. isc_throw(DataSourceError,
  509. "failed to bind SQLite3 parameter: " <<
  510. sqlite3_errmsg(dbparameters_->db_));
  511. }
  512. delzone_exec.exec();
  513. } catch (const DataSourceError&) {
  514. // Once we start a transaction, if something unexpected happens
  515. // we need to rollback the transaction so that a subsequent update
  516. // is still possible with this accessor.
  517. StatementProcessor(*dbparameters_, ROLLBACK,
  518. "rollback an SQLite3 transaction").exec();
  519. throw;
  520. }
  521. }
  522. dbparameters_->updating_zone = true;
  523. dbparameters_->updated_zone_id = zone_info.second;
  524. return (zone_info);
  525. }
  526. void
  527. SQLite3Accessor::commitUpdateZone() {
  528. if (!dbparameters_->updating_zone) {
  529. isc_throw(DataSourceError, "committing zone update on SQLite3 "
  530. "data source without transaction");
  531. }
  532. StatementProcessor(*dbparameters_, COMMIT,
  533. "commit an SQLite3 transaction").exec();
  534. dbparameters_->updating_zone = false;
  535. dbparameters_->updated_zone_id = -1;
  536. }
  537. void
  538. SQLite3Accessor::rollbackUpdateZone() {
  539. if (!dbparameters_->updating_zone) {
  540. isc_throw(DataSourceError, "rolling back zone update on SQLite3 "
  541. "data source without transaction");
  542. }
  543. StatementProcessor(*dbparameters_, ROLLBACK,
  544. "rollback an SQLite3 transaction").exec();
  545. dbparameters_->updating_zone = false;
  546. dbparameters_->updated_zone_id = -1;
  547. }
  548. namespace {
  549. // Commonly used code sequence for adding/deleting record
  550. template <typename COLUMNS_TYPE>
  551. void
  552. doUpdate(SQLite3Parameters& dbparams, StatementID stmt_id,
  553. COLUMNS_TYPE update_params, const char* exec_desc)
  554. {
  555. sqlite3_stmt* const stmt = dbparams.statements_[stmt_id];
  556. StatementProcessor executer(dbparams, stmt_id, exec_desc);
  557. int param_id = 0;
  558. if (sqlite3_bind_int(stmt, ++param_id, dbparams.updated_zone_id)
  559. != SQLITE_OK) {
  560. isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
  561. sqlite3_errmsg(dbparams.db_));
  562. }
  563. const size_t column_count =
  564. sizeof(update_params) / sizeof(update_params[0]);
  565. for (int i = 0; i < column_count; ++i) {
  566. if (sqlite3_bind_text(stmt, ++param_id, update_params[i].c_str(), -1,
  567. SQLITE_TRANSIENT) != SQLITE_OK) {
  568. isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
  569. sqlite3_errmsg(dbparams.db_));
  570. }
  571. }
  572. executer.exec();
  573. }
  574. }
  575. void
  576. SQLite3Accessor::addRecordToZone(const string (&columns)[ADD_COLUMN_COUNT]) {
  577. if (!dbparameters_->updating_zone) {
  578. isc_throw(DataSourceError, "adding record to SQLite3 "
  579. "data source without transaction");
  580. }
  581. doUpdate<const string (&)[DatabaseAccessor::ADD_COLUMN_COUNT]>(
  582. *dbparameters_, ADD_RECORD, columns, "add record to zone");
  583. }
  584. void
  585. SQLite3Accessor::deleteRecordInZone(const string (&params)[DEL_PARAM_COUNT]) {
  586. if (!dbparameters_->updating_zone) {
  587. isc_throw(DataSourceError, "deleting record in SQLite3 "
  588. "data source without transaction");
  589. }
  590. doUpdate<const string (&)[DatabaseAccessor::DEL_PARAM_COUNT]>(
  591. *dbparameters_, DEL_RECORD, params, "delete record from zone");
  592. }
  593. std::string
  594. SQLite3Accessor::findPreviousName(int zone_id, const std::string& rname)
  595. const
  596. {
  597. sqlite3_reset(dbparameters_->statements_[FIND_PREVIOUS]);
  598. sqlite3_clear_bindings(dbparameters_->statements_[FIND_PREVIOUS]);
  599. if (sqlite3_bind_int(dbparameters_->statements_[FIND_PREVIOUS], 1,
  600. zone_id) != SQLITE_OK) {
  601. isc_throw(SQLite3Error, "Could not bind zone ID " << zone_id <<
  602. " to SQL statement (find previous): " <<
  603. sqlite3_errmsg(dbparameters_->db_));
  604. }
  605. if (sqlite3_bind_text(dbparameters_->statements_[FIND_PREVIOUS], 2,
  606. rname.c_str(), -1, SQLITE_STATIC) != SQLITE_OK) {
  607. isc_throw(SQLite3Error, "Could not bind name " << rname <<
  608. " to SQL statement (find previous): " <<
  609. sqlite3_errmsg(dbparameters_->db_));
  610. }
  611. std::string result;
  612. const int rc = sqlite3_step(dbparameters_->statements_[FIND_PREVIOUS]);
  613. if (rc == SQLITE_ROW) {
  614. // We found it
  615. result = convertToPlainChar(sqlite3_column_text(dbparameters_->
  616. statements_[FIND_PREVIOUS], 0), dbparameters_->db_);
  617. }
  618. sqlite3_reset(dbparameters_->statements_[FIND_PREVIOUS]);
  619. if (rc == SQLITE_DONE) {
  620. // No NSEC records here, this DB doesn't support DNSSEC or
  621. // we asked before the apex
  622. isc_throw(isc::NotImplemented, "The zone doesn't support DNSSEC or "
  623. "query before apex");
  624. }
  625. if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
  626. // Some kind of error
  627. isc_throw(SQLite3Error, "Could not get data for previous name");
  628. }
  629. return (result);
  630. }
  631. }
  632. }