sqlite3_accessor.cc 27 KB

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