sqlite3_accessor.cc 26 KB

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