sqlite3_accessor.cc 26 KB

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