sqlite3_accessor.cc 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  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 <datasrc/sqlite3_accessor.h>
  18. #include <datasrc/logger.h>
  19. #include <datasrc/data_source.h>
  20. #include <datasrc/factory.h>
  21. #include <datasrc/database.h>
  22. #include <util/filename.h>
  23. using namespace std;
  24. using namespace isc::data;
  25. #define SQLITE_SCHEMA_VERSION 1
  26. namespace isc {
  27. namespace datasrc {
  28. // The following enum and char* array define the SQL statements commonly
  29. // used in this implementation. Corresponding prepared statements (of
  30. // type sqlite3_stmt*) are maintained in the statements_ array of the
  31. // SQLite3Parameters structure.
  32. enum StatementID {
  33. ZONE = 0,
  34. ANY = 1,
  35. ANY_SUB = 2,
  36. BEGIN = 3,
  37. COMMIT = 4,
  38. ROLLBACK = 5,
  39. DEL_ZONE_RECORDS = 6,
  40. ADD_RECORD = 7,
  41. DEL_RECORD = 8,
  42. ITERATE = 9,
  43. FIND_PREVIOUS = 10,
  44. ADD_RECORD_DIFF = 11,
  45. GET_RECORD_DIFF = 12, // This is temporary for testing "add diff"
  46. LOW_DIFF_ID = 13,
  47. HIGH_DIFF_ID = 14,
  48. DIFF_RECS = 15,
  49. NSEC3 = 16,
  50. NSEC3_PREVIOUS = 17,
  51. NSEC3_LAST = 18,
  52. NUM_STATEMENTS = 19
  53. };
  54. const char* const text_statements[NUM_STATEMENTS] = {
  55. // note for ANY and ITERATE: the order of the SELECT values is
  56. // specifically chosen to match the enum values in RecordColumns
  57. "SELECT id FROM zones WHERE name=?1 AND rdclass = ?2", // ZONE
  58. "SELECT rdtype, ttl, sigtype, rdata FROM records " // ANY
  59. "WHERE zone_id=?1 AND name=?2",
  60. "SELECT rdtype, ttl, sigtype, rdata " // ANY_SUB
  61. "FROM records WHERE zone_id=?1 AND name LIKE (\"%.\" || ?2)",
  62. "BEGIN", // BEGIN
  63. "COMMIT", // COMMIT
  64. "ROLLBACK", // ROLLBACK
  65. "DELETE FROM records WHERE zone_id=?1", // DEL_ZONE_RECORDS
  66. "INSERT INTO records " // ADD_RECORD
  67. "(zone_id, name, rname, ttl, rdtype, sigtype, rdata) "
  68. "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
  69. "DELETE FROM records WHERE zone_id=?1 AND name=?2 " // DEL_RECORD
  70. "AND rdtype=?3 AND rdata=?4",
  71. "SELECT rdtype, ttl, sigtype, rdata, name FROM records " // ITERATE
  72. "WHERE zone_id = ?1 ORDER BY rname, rdtype",
  73. /*
  74. * This one looks for previous name with NSEC record. It is done by
  75. * using the reversed name. The NSEC is checked because we need to
  76. * skip glue data, which don't have the NSEC.
  77. */
  78. "SELECT name FROM records " // FIND_PREVIOUS
  79. "WHERE zone_id=?1 AND rdtype = 'NSEC' AND "
  80. "rname < ?2 ORDER BY rname DESC LIMIT 1",
  81. "INSERT INTO diffs " // ADD_RECORD_DIFF
  82. "(zone_id, version, operation, name, rrtype, ttl, rdata) "
  83. "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
  84. "SELECT name, rrtype, ttl, rdata, version, operation " // GET_RECORD_DIFF
  85. "FROM diffs WHERE zone_id = ?1 ORDER BY id, operation",
  86. // Two statements to select the lowest ID and highest ID in a set of
  87. // differences.
  88. "SELECT id FROM diffs " // LOW_DIFF_ID
  89. "WHERE zone_id=?1 AND version=?2 and OPERATION=?3 "
  90. "ORDER BY id ASC LIMIT 1",
  91. "SELECT id FROM diffs " // HIGH_DIFF_ID
  92. "WHERE zone_id=?1 AND version=?2 and OPERATION=?3 "
  93. "ORDER BY id DESC LIMIT 1",
  94. // In the next statement, note the redundant ID. This is to ensure
  95. // that the columns match the column IDs passed to the iterator
  96. "SELECT rrtype, ttl, id, rdata, name FROM diffs " // DIFF_RECS
  97. "WHERE zone_id=?1 AND id>=?2 and id<=?3 "
  98. "ORDER BY id ASC",
  99. // Query to get the NSEC3 records
  100. //
  101. // The "1" in SELECT is for positioning the rdata column to the
  102. // expected position, so we can reuse the same code as for other
  103. // lookups.
  104. "SELECT rdtype, ttl, 1, rdata FROM nsec3 WHERE zone_id=?1 AND "
  105. "hash=?2",
  106. // For getting the previous NSEC3 hash
  107. "SELECT DISTINCT hash FROM nsec3 WHERE zone_id=?1 AND hash < ?2 "
  108. "ORDER BY hash DESC LIMIT 1",
  109. // And for wrap-around
  110. "SELECT DISTINCT hash FROM nsec3 WHERE zone_id=?1 "
  111. "ORDER BY hash DESC LIMIT 1",
  112. };
  113. struct SQLite3Parameters {
  114. SQLite3Parameters() :
  115. db_(NULL), version_(-1), in_transaction(false), updating_zone(false),
  116. updated_zone_id(-1)
  117. {
  118. for (int i = 0; i < NUM_STATEMENTS; ++i) {
  119. statements_[i] = NULL;
  120. }
  121. }
  122. // This method returns the specified ID of SQLITE3 statement. If it's
  123. // not yet prepared it internally creates a new one. This way we can
  124. // avoid preparing unnecessary statements and minimize the overhead.
  125. sqlite3_stmt*
  126. getStatement(int id) {
  127. assert(id < NUM_STATEMENTS);
  128. if (statements_[id] == NULL) {
  129. assert(db_ != NULL);
  130. sqlite3_stmt* prepared = NULL;
  131. if (sqlite3_prepare_v2(db_, text_statements[id], -1, &prepared,
  132. NULL) != SQLITE_OK) {
  133. isc_throw(SQLite3Error, "Could not prepare SQLite statement: "
  134. << text_statements[id] <<
  135. ": " << sqlite3_errmsg(db_));
  136. }
  137. statements_[id] = prepared;
  138. }
  139. return (statements_[id]);
  140. }
  141. void
  142. finalizeStatements() {
  143. for (int i = 0; i < NUM_STATEMENTS; ++i) {
  144. if (statements_[i] != NULL) {
  145. sqlite3_finalize(statements_[i]);
  146. statements_[i] = NULL;
  147. }
  148. }
  149. }
  150. sqlite3* db_;
  151. int version_;
  152. bool in_transaction; // whether or not a transaction has been started
  153. bool updating_zone; // whether or not updating the zone
  154. int updated_zone_id; // valid only when in_transaction is true
  155. private:
  156. // statements_ are private and must be accessed via getStatement() outside
  157. // of this structure.
  158. sqlite3_stmt* statements_[NUM_STATEMENTS];
  159. };
  160. // This is a helper class to encapsulate the code logic of executing
  161. // a specific SQLite3 statement, ensuring the corresponding prepared
  162. // statement is always reset whether the execution is completed successfully
  163. // or it results in an exception.
  164. // Note that an object of this class is intended to be used for "ephemeral"
  165. // statement, which is completed with a single "step" (normally within a
  166. // single call to an SQLite3Database method). In particular, it cannot be
  167. // used for "SELECT" variants, which generally expect multiple matching rows.
  168. class StatementProcessor {
  169. public:
  170. // desc will be used on failure in the what() message of the resulting
  171. // DataSourceError exception.
  172. StatementProcessor(SQLite3Parameters& dbparameters, StatementID stmt_id,
  173. const char* desc) :
  174. dbparameters_(dbparameters), stmt_(dbparameters.getStatement(stmt_id)),
  175. desc_(desc)
  176. {
  177. sqlite3_clear_bindings(stmt_);
  178. }
  179. ~StatementProcessor() {
  180. sqlite3_reset(stmt_);
  181. }
  182. void exec() {
  183. if (sqlite3_step(stmt_) != SQLITE_DONE) {
  184. sqlite3_reset(stmt_);
  185. isc_throw(DataSourceError, "failed to " << desc_ << ": " <<
  186. sqlite3_errmsg(dbparameters_.db_));
  187. }
  188. }
  189. private:
  190. SQLite3Parameters& dbparameters_;
  191. sqlite3_stmt* stmt_;
  192. const char* const desc_;
  193. };
  194. SQLite3Accessor::SQLite3Accessor(const std::string& filename,
  195. const string& rrclass) :
  196. dbparameters_(new SQLite3Parameters),
  197. filename_(filename),
  198. class_(rrclass),
  199. database_name_("sqlite3_" +
  200. isc::util::Filename(filename).nameAndExtension())
  201. {
  202. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_NEWCONN);
  203. open(filename);
  204. }
  205. boost::shared_ptr<DatabaseAccessor>
  206. SQLite3Accessor::clone() {
  207. return (boost::shared_ptr<DatabaseAccessor>(new SQLite3Accessor(filename_,
  208. class_)));
  209. }
  210. namespace {
  211. // This is a helper class to initialize a Sqlite3 DB safely. An object of
  212. // this class encapsulates all temporary resources that are necessary for
  213. // the initialization, and release them in the destructor. Once everything
  214. // is properly initialized, the move() method moves the allocated resources
  215. // to the main object in an exception free manner. This way, the main code
  216. // for the initialization can be exception safe, and can provide the strong
  217. // exception guarantee.
  218. class Initializer {
  219. public:
  220. ~Initializer() {
  221. if (params_.db_ != NULL) {
  222. sqlite3_close(params_.db_);
  223. }
  224. }
  225. void move(SQLite3Parameters* dst) {
  226. *dst = params_;
  227. params_ = SQLite3Parameters(); // clear everything
  228. }
  229. SQLite3Parameters params_;
  230. };
  231. const char* const SCHEMA_LIST[] = {
  232. "CREATE TABLE schema_version (version INTEGER NOT NULL)",
  233. "INSERT INTO schema_version VALUES (1)",
  234. "CREATE TABLE zones (id INTEGER PRIMARY KEY, "
  235. "name STRING NOT NULL COLLATE NOCASE, "
  236. "rdclass STRING NOT NULL COLLATE NOCASE DEFAULT 'IN', "
  237. "dnssec BOOLEAN NOT NULL DEFAULT 0)",
  238. "CREATE INDEX zones_byname ON zones (name)",
  239. "CREATE TABLE records (id INTEGER PRIMARY KEY, "
  240. "zone_id INTEGER NOT NULL, name STRING NOT NULL COLLATE NOCASE, "
  241. "rname STRING NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
  242. "rdtype STRING NOT NULL COLLATE NOCASE, sigtype STRING COLLATE NOCASE, "
  243. "rdata STRING NOT NULL)",
  244. "CREATE INDEX records_byname ON records (name)",
  245. "CREATE INDEX records_byrname ON records (rname)",
  246. "CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
  247. "hash STRING NOT NULL COLLATE NOCASE, "
  248. "owner STRING NOT NULL COLLATE NOCASE, "
  249. "ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
  250. "rdata STRING NOT NULL)",
  251. "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
  252. "CREATE TABLE diffs (id INTEGER PRIMARY KEY, "
  253. "zone_id INTEGER NOT NULL, "
  254. "version INTEGER NOT NULL, "
  255. "operation INTEGER NOT NULL, "
  256. "name STRING NOT NULL COLLATE NOCASE, "
  257. "rrtype STRING NOT NULL COLLATE NOCASE, "
  258. "ttl INTEGER NOT NULL, "
  259. "rdata STRING NOT NULL)",
  260. NULL
  261. };
  262. sqlite3_stmt*
  263. prepare(sqlite3* const db, const char* const statement) {
  264. sqlite3_stmt* prepared = NULL;
  265. if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) {
  266. isc_throw(SQLite3Error, "Could not prepare SQLite statement: " <<
  267. statement << ": " << sqlite3_errmsg(db));
  268. }
  269. return (prepared);
  270. }
  271. // small function to sleep for 0.1 seconds, needed when waiting for
  272. // exclusive database locks (which should only occur on startup, and only
  273. // when the database has not been created yet)
  274. void doSleep() {
  275. struct timespec req;
  276. req.tv_sec = 0;
  277. req.tv_nsec = 100000000;
  278. nanosleep(&req, NULL);
  279. }
  280. // returns the schema version if the schema version table exists
  281. // returns -1 if it does not
  282. int checkSchemaVersion(sqlite3* db) {
  283. sqlite3_stmt* prepared = NULL;
  284. // At this point in time, the database might be exclusively locked, in
  285. // which case even prepare() will return BUSY, so we may need to try a
  286. // few times
  287. for (size_t i = 0; i < 50; ++i) {
  288. int rc = sqlite3_prepare_v2(db, "SELECT version FROM schema_version",
  289. -1, &prepared, NULL);
  290. if (rc == SQLITE_ERROR) {
  291. // this is the error that is returned when the table does not
  292. // exist
  293. return (-1);
  294. } else if (rc == SQLITE_OK) {
  295. break;
  296. } else if (rc != SQLITE_BUSY || i == 50) {
  297. isc_throw(SQLite3Error, "Unable to prepare version query: "
  298. << rc << " " << sqlite3_errmsg(db));
  299. }
  300. doSleep();
  301. }
  302. if (sqlite3_step(prepared) != SQLITE_ROW) {
  303. isc_throw(SQLite3Error,
  304. "Unable to query version: " << sqlite3_errmsg(db));
  305. }
  306. int version = sqlite3_column_int(prepared, 0);
  307. sqlite3_finalize(prepared);
  308. return (version);
  309. }
  310. // return db version
  311. int create_database(sqlite3* db) {
  312. // try to get an exclusive lock. Once that is obtained, do the version
  313. // check *again*, just in case this process was racing another
  314. //
  315. // try for 5 secs (50*0.1)
  316. int rc;
  317. logger.info(DATASRC_SQLITE_SETUP);
  318. for (size_t i = 0; i < 50; ++i) {
  319. rc = sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL,
  320. NULL);
  321. if (rc == SQLITE_OK) {
  322. break;
  323. } else if (rc != SQLITE_BUSY || i == 50) {
  324. isc_throw(SQLite3Error, "Unable to acquire exclusive lock "
  325. "for database creation: " << sqlite3_errmsg(db));
  326. }
  327. doSleep();
  328. }
  329. int schema_version = checkSchemaVersion(db);
  330. if (schema_version == -1) {
  331. for (int i = 0; SCHEMA_LIST[i] != NULL; ++i) {
  332. if (sqlite3_exec(db, SCHEMA_LIST[i], NULL, NULL, NULL) !=
  333. SQLITE_OK) {
  334. isc_throw(SQLite3Error,
  335. "Failed to set up schema " << SCHEMA_LIST[i]);
  336. }
  337. }
  338. sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, NULL);
  339. return (SQLITE_SCHEMA_VERSION);
  340. } else {
  341. return (schema_version);
  342. }
  343. }
  344. void
  345. checkAndSetupSchema(Initializer* initializer) {
  346. sqlite3* const db = initializer->params_.db_;
  347. int schema_version = checkSchemaVersion(db);
  348. if (schema_version != SQLITE_SCHEMA_VERSION) {
  349. schema_version = create_database(db);
  350. }
  351. initializer->params_.version_ = schema_version;
  352. }
  353. }
  354. void
  355. SQLite3Accessor::open(const std::string& name) {
  356. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CONNOPEN).arg(name);
  357. if (dbparameters_->db_ != NULL) {
  358. // There shouldn't be a way to trigger this anyway
  359. isc_throw(DataSourceError, "Duplicate SQLite open with " << name);
  360. }
  361. Initializer initializer;
  362. if (sqlite3_open(name.c_str(), &initializer.params_.db_) != 0) {
  363. isc_throw(SQLite3Error, "Cannot open SQLite database file: " << name);
  364. }
  365. checkAndSetupSchema(&initializer);
  366. initializer.move(dbparameters_.get());
  367. }
  368. SQLite3Accessor::~SQLite3Accessor() {
  369. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_DROPCONN);
  370. if (dbparameters_->db_ != NULL) {
  371. close();
  372. }
  373. }
  374. void
  375. SQLite3Accessor::close(void) {
  376. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CONNCLOSE);
  377. if (dbparameters_->db_ == NULL) {
  378. isc_throw(DataSourceError,
  379. "SQLite data source is being closed before open");
  380. }
  381. dbparameters_->finalizeStatements();
  382. sqlite3_close(dbparameters_->db_);
  383. dbparameters_->db_ = NULL;
  384. }
  385. std::pair<bool, int>
  386. SQLite3Accessor::getZone(const std::string& name) const {
  387. int rc;
  388. sqlite3_stmt* const stmt = dbparameters_->getStatement(ZONE);
  389. // Take the statement (simple SELECT id FROM zones WHERE...)
  390. // and prepare it (bind the parameters to it)
  391. sqlite3_reset(stmt);
  392. rc = sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_STATIC);
  393. if (rc != SQLITE_OK) {
  394. isc_throw(SQLite3Error, "Could not bind " << name <<
  395. " to SQL statement (zone)");
  396. }
  397. rc = sqlite3_bind_text(stmt, 2, class_.c_str(), -1, SQLITE_STATIC);
  398. if (rc != SQLITE_OK) {
  399. isc_throw(SQLite3Error, "Could not bind " << class_ <<
  400. " to SQL statement (zone)");
  401. }
  402. // Get the data there and see if it found anything
  403. rc = sqlite3_step(stmt);
  404. if (rc == SQLITE_ROW) {
  405. const int zone_id = sqlite3_column_int(stmt, 0);
  406. sqlite3_reset(stmt);
  407. return (pair<bool, int>(true, zone_id));
  408. } else if (rc == SQLITE_DONE) {
  409. // Free resources
  410. sqlite3_reset(stmt);
  411. return (pair<bool, int>(false, 0));
  412. }
  413. sqlite3_reset(stmt);
  414. isc_throw(DataSourceError, "Unexpected failure in sqlite3_step: " <<
  415. sqlite3_errmsg(dbparameters_->db_));
  416. // Compilers might not realize isc_throw always throws
  417. return (std::pair<bool, int>(false, 0));
  418. }
  419. namespace {
  420. // Conversion to plain char
  421. const char*
  422. convertToPlainChar(const unsigned char* ucp, sqlite3 *db) {
  423. if (ucp == NULL) {
  424. // The field can really be NULL, in which case we return an
  425. // empty string, or sqlite may have run out of memory, in
  426. // which case we raise an error
  427. if (sqlite3_errcode(db) == SQLITE_NOMEM) {
  428. isc_throw(DataSourceError,
  429. "Sqlite3 backend encountered a memory allocation "
  430. "error in sqlite3_column_text()");
  431. } else {
  432. return ("");
  433. }
  434. }
  435. const void* p = ucp;
  436. return (static_cast<const char*>(p));
  437. }
  438. }
  439. class SQLite3Accessor::Context : public DatabaseAccessor::IteratorContext {
  440. public:
  441. // Construct an iterator for all records. When constructed this
  442. // way, the getNext() call will copy all fields
  443. Context(const boost::shared_ptr<const SQLite3Accessor>& accessor, int id) :
  444. iterator_type_(ITT_ALL),
  445. accessor_(accessor),
  446. statement_(NULL),
  447. name_("")
  448. {
  449. // We create the statement now and then just keep getting data from it
  450. statement_ = prepare(accessor->dbparameters_->db_,
  451. text_statements[ITERATE]);
  452. bindZoneId(id);
  453. }
  454. // What kind of query it is - selection of the statement for DB
  455. enum QueryType {
  456. QT_ANY, // Directly for a domain
  457. QT_SUBDOMAINS, // Subdomains of a given domain
  458. QT_NSEC3 // Domain in the NSEC3 namespace (the name is is the hash,
  459. // not the whole name)
  460. };
  461. // Construct an iterator for records with a specific name. When constructed
  462. // this way, the getNext() call will copy all fields except name
  463. Context(const boost::shared_ptr<const SQLite3Accessor>& accessor, int id,
  464. const std::string& name, QueryType qtype) :
  465. iterator_type_(qtype == QT_NSEC3 ? ITT_NSEC3 : ITT_NAME),
  466. accessor_(accessor),
  467. statement_(NULL),
  468. name_(name)
  469. {
  470. // Choose the statement text depending on the query type
  471. const char* statement(NULL);
  472. switch (qtype) {
  473. case QT_ANY:
  474. statement = text_statements[ANY];
  475. break;
  476. case QT_SUBDOMAINS:
  477. statement = text_statements[ANY_SUB];
  478. break;
  479. case QT_NSEC3:
  480. statement = text_statements[NSEC3];
  481. break;
  482. default:
  483. // Can Not Happen - there isn't any other type of query
  484. // and all the calls to the constructor are from this
  485. // file. Therefore no way to test it throws :-(.
  486. isc_throw(Unexpected,
  487. "Invalid qtype passed - unreachable code branch "
  488. "reached");
  489. }
  490. // We create the statement now and then just keep getting data from it
  491. statement_ = prepare(accessor->dbparameters_->db_, statement);
  492. bindZoneId(id);
  493. bindName(name_);
  494. }
  495. bool getNext(std::string (&data)[COLUMN_COUNT]) {
  496. // If there's another row, get it
  497. // If finalize has been called (e.g. when previous getNext() got
  498. // SQLITE_DONE), directly return false
  499. if (statement_ == NULL) {
  500. return false;
  501. }
  502. const int rc(sqlite3_step(statement_));
  503. if (rc == SQLITE_ROW) {
  504. // For both types, we copy the first four columns
  505. copyColumn(data, TYPE_COLUMN);
  506. copyColumn(data, TTL_COLUMN);
  507. // The NSEC3 lookup does not provide the SIGTYPE, it is not
  508. // necessary and not contained in the table.
  509. if (iterator_type_ != ITT_NSEC3) {
  510. copyColumn(data, SIGTYPE_COLUMN);
  511. }
  512. copyColumn(data, RDATA_COLUMN);
  513. // Only copy Name if we are iterating over every record
  514. if (iterator_type_ == ITT_ALL) {
  515. copyColumn(data, NAME_COLUMN);
  516. }
  517. return (true);
  518. } else if (rc != SQLITE_DONE) {
  519. isc_throw(DataSourceError,
  520. "Unexpected failure in sqlite3_step: " <<
  521. sqlite3_errmsg(accessor_->dbparameters_->db_));
  522. }
  523. finalize();
  524. return (false);
  525. }
  526. virtual ~Context() {
  527. finalize();
  528. }
  529. private:
  530. // Depending on which constructor is called, behaviour is slightly
  531. // different. We keep track of what to do with the iterator type
  532. // See description of getNext() and the constructors
  533. enum IteratorType {
  534. ITT_ALL,
  535. ITT_NAME,
  536. ITT_NSEC3
  537. };
  538. void copyColumn(std::string (&data)[COLUMN_COUNT], int column) {
  539. data[column] = convertToPlainChar(sqlite3_column_text(statement_,
  540. column),
  541. accessor_->dbparameters_->db_);
  542. }
  543. void bindZoneId(const int zone_id) {
  544. if (sqlite3_bind_int(statement_, 1, zone_id) != SQLITE_OK) {
  545. finalize();
  546. isc_throw(SQLite3Error, "Could not bind int " << zone_id <<
  547. " to SQL statement: " <<
  548. sqlite3_errmsg(accessor_->dbparameters_->db_));
  549. }
  550. }
  551. void bindName(const std::string& name) {
  552. if (sqlite3_bind_text(statement_, 2, name.c_str(), -1,
  553. SQLITE_TRANSIENT) != SQLITE_OK) {
  554. const char* errmsg = sqlite3_errmsg(accessor_->dbparameters_->db_);
  555. finalize();
  556. isc_throw(SQLite3Error, "Could not bind text '" << name <<
  557. "' to SQL statement: " << errmsg);
  558. }
  559. }
  560. void finalize() {
  561. sqlite3_finalize(statement_);
  562. statement_ = NULL;
  563. }
  564. const IteratorType iterator_type_;
  565. boost::shared_ptr<const SQLite3Accessor> accessor_;
  566. sqlite3_stmt* statement_;
  567. const std::string name_;
  568. };
  569. // Methods to retrieve the various iterators
  570. DatabaseAccessor::IteratorContextPtr
  571. SQLite3Accessor::getRecords(const std::string& name, int id,
  572. bool subdomains) const
  573. {
  574. return (IteratorContextPtr(new Context(shared_from_this(), id, name,
  575. subdomains ?
  576. Context::QT_SUBDOMAINS :
  577. Context::QT_ANY)));
  578. }
  579. DatabaseAccessor::IteratorContextPtr
  580. SQLite3Accessor::getNSEC3Records(const std::string& hash, int id) const {
  581. return (IteratorContextPtr(new Context(shared_from_this(), id, hash,
  582. Context::QT_NSEC3)));
  583. }
  584. DatabaseAccessor::IteratorContextPtr
  585. SQLite3Accessor::getAllRecords(int id) const {
  586. return (IteratorContextPtr(new Context(shared_from_this(), id)));
  587. }
  588. /// \brief Difference Iterator
  589. ///
  590. /// This iterator is used to search through the differences table for the
  591. /// resouce records making up an IXFR between two versions of a zone.
  592. class SQLite3Accessor::DiffContext : public DatabaseAccessor::IteratorContext {
  593. public:
  594. /// \brief Constructor
  595. ///
  596. /// Constructs the iterator for the difference sequence. It is
  597. /// passed two parameters, the first and last versions in the difference
  598. /// sequence. Note that because of serial number rollover, it may well
  599. /// be that the start serial number is greater than the end one.
  600. ///
  601. /// \param zone_id ID of the zone (in the zone table)
  602. /// \param start Serial number of first version in difference sequence
  603. /// \param end Serial number of last version in difference sequence
  604. ///
  605. /// \exception any A number of exceptions can be expected
  606. DiffContext(const boost::shared_ptr<const SQLite3Accessor>& accessor,
  607. int zone_id, uint32_t start, uint32_t end) :
  608. accessor_(accessor),
  609. last_status_(SQLITE_ROW)
  610. {
  611. try {
  612. int low_id = findIndex(LOW_DIFF_ID, zone_id, start, DIFF_DELETE);
  613. int high_id = findIndex(HIGH_DIFF_ID, zone_id, end, DIFF_ADD);
  614. // Prepare the statement that will return data values
  615. reset(DIFF_RECS);
  616. bindInt(DIFF_RECS, 1, zone_id);
  617. bindInt(DIFF_RECS, 2, low_id);
  618. bindInt(DIFF_RECS, 3, high_id);
  619. } catch (...) {
  620. // Something wrong, clear up everything.
  621. accessor_->dbparameters_->finalizeStatements();
  622. throw;
  623. }
  624. }
  625. /// \brief Destructor
  626. virtual ~DiffContext()
  627. {}
  628. /// \brief Get Next Diff Record
  629. ///
  630. /// Returns the next difference record in the difference sequence.
  631. ///
  632. /// \param data Array of std::strings COLUMN_COUNT long. The results
  633. /// are returned in this.
  634. ///
  635. /// \return bool true if data is returned, false if not.
  636. ///
  637. /// \exceptions any Varied
  638. bool getNext(std::string (&data)[COLUMN_COUNT]) {
  639. if (last_status_ != SQLITE_DONE) {
  640. // Last call (if any) didn't reach end of result set, so we
  641. // can read another row from it.
  642. //
  643. // Get a pointer to the statement for brevity (this does not
  644. // transfer ownership of the statement to this class, so there is
  645. // no need to tidy up after we have finished using it).
  646. sqlite3_stmt* stmt =
  647. accessor_->dbparameters_->getStatement(DIFF_RECS);
  648. const int rc(sqlite3_step(stmt));
  649. if (rc == SQLITE_ROW) {
  650. // Copy the data across to the output array
  651. copyColumn(DIFF_RECS, data, TYPE_COLUMN);
  652. copyColumn(DIFF_RECS, data, TTL_COLUMN);
  653. copyColumn(DIFF_RECS, data, NAME_COLUMN);
  654. copyColumn(DIFF_RECS, data, RDATA_COLUMN);
  655. } else if (rc != SQLITE_DONE) {
  656. isc_throw(DataSourceError,
  657. "Unexpected failure in sqlite3_step: " <<
  658. sqlite3_errmsg(accessor_->dbparameters_->db_));
  659. }
  660. last_status_ = rc;
  661. }
  662. return (last_status_ == SQLITE_ROW);
  663. }
  664. private:
  665. /// \brief Reset prepared statement
  666. ///
  667. /// Sets up the statement so that new parameters can be attached to it and
  668. /// that it can be used to query for another difference sequence.
  669. ///
  670. /// \param stindex Index of prepared statement to which to bind
  671. void reset(int stindex) {
  672. sqlite3_stmt* stmt = accessor_->dbparameters_->getStatement(stindex);
  673. if ((sqlite3_reset(stmt) != SQLITE_OK) ||
  674. (sqlite3_clear_bindings(stmt) != SQLITE_OK)) {
  675. isc_throw(SQLite3Error, "Could not clear statement bindings in '" <<
  676. text_statements[stindex] << "': " <<
  677. sqlite3_errmsg(accessor_->dbparameters_->db_));
  678. }
  679. }
  680. /// \brief Bind Int
  681. ///
  682. /// Binds an integer to a specific variable in a prepared statement.
  683. ///
  684. /// \param stindex Index of prepared statement to which to bind
  685. /// \param varindex Index of variable to which to bind
  686. /// \param value Value of variable to bind
  687. /// \exception SQLite3Error on an error
  688. void bindInt(int stindex, int varindex, sqlite3_int64 value) {
  689. if (sqlite3_bind_int64(accessor_->dbparameters_->getStatement(stindex),
  690. varindex, value) != SQLITE_OK) {
  691. isc_throw(SQLite3Error, "Could not bind value to parameter " <<
  692. varindex << " in statement '" <<
  693. text_statements[stindex] << "': " <<
  694. sqlite3_errmsg(accessor_->dbparameters_->db_));
  695. }
  696. }
  697. ///\brief Get Single Value
  698. ///
  699. /// Executes a prepared statement (which has parameters bound to it)
  700. /// for which the result of a single value is expected.
  701. ///
  702. /// \param stindex Index of prepared statement in statement table.
  703. ///
  704. /// \return Value of SELECT.
  705. ///
  706. /// \exception TooMuchData Multiple rows returned when one expected
  707. /// \exception TooLittleData Zero rows returned when one expected
  708. /// \exception DataSourceError SQLite3-related error
  709. int getSingleValue(StatementID stindex) {
  710. // Get a pointer to the statement for brevity (does not transfer
  711. // resources)
  712. sqlite3_stmt* stmt = accessor_->dbparameters_->getStatement(stindex);
  713. // Execute the data. Should be just one result
  714. int rc = sqlite3_step(stmt);
  715. int result = -1;
  716. if (rc == SQLITE_ROW) {
  717. // Got some data, extract the value
  718. result = sqlite3_column_int(stmt, 0);
  719. rc = sqlite3_step(stmt);
  720. if (rc == SQLITE_DONE) {
  721. // All OK, exit with the value.
  722. return (result);
  723. } else if (rc == SQLITE_ROW) {
  724. isc_throw(TooMuchData, "request to return one value from "
  725. "diffs table returned multiple values");
  726. }
  727. } else if (rc == SQLITE_DONE) {
  728. // No data in the table. A bare exception with no explanation is
  729. // thrown, as it will be replaced by a more informative one by
  730. // the caller.
  731. isc_throw(TooLittleData, "");
  732. }
  733. // We get here on an error.
  734. isc_throw(DataSourceError, "could not get data from diffs table: " <<
  735. sqlite3_errmsg(accessor_->dbparameters_->db_));
  736. // Keep the compiler happy with a return value.
  737. return (result);
  738. }
  739. /// \brief Find index
  740. ///
  741. /// Executes the prepared statement locating the high or low index in
  742. /// the diffs table and returns that index.
  743. ///
  744. /// \param stmt_id Index of the prepared statement to execute
  745. /// \param zone_id ID of the zone for which the index is being sought
  746. /// \param serial Zone serial number for which an index is being sought.
  747. /// \param diff Code to delete record additions or deletions
  748. ///
  749. /// \return int ID of the row in the difss table corresponding to the
  750. /// statement.
  751. ///
  752. /// \exception TooLittleData Internal error, no result returned when one
  753. /// was expected.
  754. /// \exception NoSuchSerial Serial number not found.
  755. /// \exception NoDiffsData No data for this zone found in diffs table
  756. int findIndex(StatementID stindex, int zone_id, uint32_t serial, int diff) {
  757. // Set up the statement
  758. reset(stindex);
  759. bindInt(stindex, 1, zone_id);
  760. bindInt(stindex, 2, serial);
  761. bindInt(stindex, 3, diff);
  762. // Execute the statement
  763. int result = -1;
  764. try {
  765. result = getSingleValue(stindex);
  766. } catch (const TooLittleData&) {
  767. // No data returned but the SQL query succeeded. Only possibility
  768. // is that there is no entry in the differences table for the given
  769. // zone and version.
  770. isc_throw(NoSuchSerial, "No entry in differences table for" <<
  771. " zone ID " << zone_id << ", serial number " << serial);
  772. }
  773. return (result);
  774. }
  775. /// \brief Copy Column to Output
  776. ///
  777. /// Copies the textual data in the result set to the specified column
  778. /// in the output.
  779. ///
  780. /// \param stindex Index of prepared statement used to access data
  781. /// \param data Array of columns passed to getNext
  782. /// \param column Column of output to copy
  783. void copyColumn(StatementID stindex, std::string (&data)[COLUMN_COUNT],
  784. int column) {
  785. // Get a pointer to the statement for brevity (does not transfer
  786. // resources)
  787. sqlite3_stmt* stmt = accessor_->dbparameters_->getStatement(stindex);
  788. data[column] = convertToPlainChar(sqlite3_column_text(stmt,
  789. column),
  790. accessor_->dbparameters_->db_);
  791. }
  792. // Attributes
  793. boost::shared_ptr<const SQLite3Accessor> accessor_; // Accessor object
  794. int last_status_; // Last status received from sqlite3_step
  795. };
  796. // ... and return the iterator
  797. DatabaseAccessor::IteratorContextPtr
  798. SQLite3Accessor::getDiffs(int id, uint32_t start, uint32_t end) const {
  799. return (IteratorContextPtr(new DiffContext(shared_from_this(), id, start,
  800. end)));
  801. }
  802. pair<bool, int>
  803. SQLite3Accessor::startUpdateZone(const string& zone_name, const bool replace) {
  804. if (dbparameters_->updating_zone) {
  805. isc_throw(DataSourceError,
  806. "duplicate zone update on SQLite3 data source");
  807. }
  808. if (dbparameters_->in_transaction) {
  809. isc_throw(DataSourceError,
  810. "zone update attempt in another SQLite3 transaction");
  811. }
  812. const pair<bool, int> zone_info(getZone(zone_name));
  813. if (!zone_info.first) {
  814. return (zone_info);
  815. }
  816. StatementProcessor(*dbparameters_, BEGIN,
  817. "start an SQLite3 update transaction").exec();
  818. if (replace) {
  819. try {
  820. StatementProcessor delzone_exec(*dbparameters_, DEL_ZONE_RECORDS,
  821. "delete zone records");
  822. sqlite3_stmt* stmt = dbparameters_->getStatement(DEL_ZONE_RECORDS);
  823. sqlite3_clear_bindings(stmt);
  824. if (sqlite3_bind_int(stmt, 1, zone_info.second) != SQLITE_OK) {
  825. isc_throw(DataSourceError,
  826. "failed to bind SQLite3 parameter: " <<
  827. sqlite3_errmsg(dbparameters_->db_));
  828. }
  829. delzone_exec.exec();
  830. } catch (const DataSourceError&) {
  831. // Once we start a transaction, if something unexpected happens
  832. // we need to rollback the transaction so that a subsequent update
  833. // is still possible with this accessor.
  834. StatementProcessor(*dbparameters_, ROLLBACK,
  835. "rollback an SQLite3 transaction").exec();
  836. throw;
  837. }
  838. }
  839. dbparameters_->in_transaction = true;
  840. dbparameters_->updating_zone = true;
  841. dbparameters_->updated_zone_id = zone_info.second;
  842. return (zone_info);
  843. }
  844. void
  845. SQLite3Accessor::startTransaction() {
  846. if (dbparameters_->in_transaction) {
  847. isc_throw(DataSourceError,
  848. "duplicate transaction on SQLite3 data source");
  849. }
  850. StatementProcessor(*dbparameters_, BEGIN,
  851. "start an SQLite3 transaction").exec();
  852. dbparameters_->in_transaction = true;
  853. }
  854. void
  855. SQLite3Accessor::commit() {
  856. if (!dbparameters_->in_transaction) {
  857. isc_throw(DataSourceError, "performing commit on SQLite3 "
  858. "data source without transaction");
  859. }
  860. StatementProcessor(*dbparameters_, COMMIT,
  861. "commit an SQLite3 transaction").exec();
  862. dbparameters_->in_transaction = false;
  863. dbparameters_->updated_zone_id = -1;
  864. }
  865. void
  866. SQLite3Accessor::rollback() {
  867. if (!dbparameters_->in_transaction) {
  868. isc_throw(DataSourceError, "performing rollback on SQLite3 "
  869. "data source without transaction");
  870. }
  871. StatementProcessor(*dbparameters_, ROLLBACK,
  872. "rollback an SQLite3 transaction").exec();
  873. dbparameters_->in_transaction = false;
  874. dbparameters_->updated_zone_id = -1;
  875. }
  876. namespace {
  877. // Commonly used code sequence for adding/deleting record
  878. template <typename COLUMNS_TYPE>
  879. void
  880. doUpdate(SQLite3Parameters& dbparams, StatementID stmt_id,
  881. COLUMNS_TYPE update_params, const char* exec_desc)
  882. {
  883. sqlite3_stmt* const stmt = dbparams.getStatement(stmt_id);
  884. StatementProcessor executer(dbparams, stmt_id, exec_desc);
  885. int param_id = 0;
  886. if (sqlite3_bind_int(stmt, ++param_id, dbparams.updated_zone_id)
  887. != SQLITE_OK) {
  888. isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
  889. sqlite3_errmsg(dbparams.db_));
  890. }
  891. const size_t column_count =
  892. sizeof(update_params) / sizeof(update_params[0]);
  893. for (int i = 0; i < column_count; ++i) {
  894. // The old sqlite3 data source API assumes NULL for an empty column.
  895. // We need to provide compatibility at least for now.
  896. if (sqlite3_bind_text(stmt, ++param_id,
  897. update_params[i].empty() ? NULL :
  898. update_params[i].c_str(),
  899. -1, SQLITE_TRANSIENT) != SQLITE_OK) {
  900. isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
  901. sqlite3_errmsg(dbparams.db_));
  902. }
  903. }
  904. executer.exec();
  905. }
  906. }
  907. void
  908. SQLite3Accessor::addRecordToZone(const string (&columns)[ADD_COLUMN_COUNT]) {
  909. if (!dbparameters_->updating_zone) {
  910. isc_throw(DataSourceError, "adding record to SQLite3 "
  911. "data source without transaction");
  912. }
  913. doUpdate<const string (&)[DatabaseAccessor::ADD_COLUMN_COUNT]>(
  914. *dbparameters_, ADD_RECORD, columns, "add record to zone");
  915. }
  916. void
  917. SQLite3Accessor::deleteRecordInZone(const string (&params)[DEL_PARAM_COUNT]) {
  918. if (!dbparameters_->updating_zone) {
  919. isc_throw(DataSourceError, "deleting record in SQLite3 "
  920. "data source without transaction");
  921. }
  922. doUpdate<const string (&)[DatabaseAccessor::DEL_PARAM_COUNT]>(
  923. *dbparameters_, DEL_RECORD, params, "delete record from zone");
  924. }
  925. void
  926. SQLite3Accessor::addRecordDiff(int zone_id, uint32_t serial,
  927. DiffOperation operation,
  928. const std::string (&params)[DIFF_PARAM_COUNT])
  929. {
  930. if (!dbparameters_->updating_zone) {
  931. isc_throw(DataSourceError, "adding record diff without update "
  932. "transaction on " << getDBName());
  933. }
  934. if (zone_id != dbparameters_->updated_zone_id) {
  935. isc_throw(DataSourceError, "bad zone ID for adding record diff on "
  936. << getDBName() << ": " << zone_id << ", must be "
  937. << dbparameters_->updated_zone_id);
  938. }
  939. sqlite3_stmt* const stmt = dbparameters_->getStatement(ADD_RECORD_DIFF);
  940. StatementProcessor executer(*dbparameters_, ADD_RECORD_DIFF,
  941. "add record diff");
  942. int param_id = 0;
  943. if (sqlite3_bind_int(stmt, ++param_id, zone_id)
  944. != SQLITE_OK) {
  945. isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
  946. sqlite3_errmsg(dbparameters_->db_));
  947. }
  948. if (sqlite3_bind_int64(stmt, ++param_id, serial)
  949. != SQLITE_OK) {
  950. isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
  951. sqlite3_errmsg(dbparameters_->db_));
  952. }
  953. if (sqlite3_bind_int(stmt, ++param_id, operation)
  954. != SQLITE_OK) {
  955. isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
  956. sqlite3_errmsg(dbparameters_->db_));
  957. }
  958. for (int i = 0; i < DIFF_PARAM_COUNT; ++i) {
  959. if (sqlite3_bind_text(stmt, ++param_id, params[i].c_str(),
  960. -1, SQLITE_TRANSIENT) != SQLITE_OK) {
  961. isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
  962. sqlite3_errmsg(dbparameters_->db_));
  963. }
  964. }
  965. executer.exec();
  966. }
  967. std::string
  968. SQLite3Accessor::findPreviousName(int zone_id, const std::string& rname)
  969. const
  970. {
  971. sqlite3_stmt* const stmt = dbparameters_->getStatement(FIND_PREVIOUS);
  972. sqlite3_reset(stmt);
  973. sqlite3_clear_bindings(stmt);
  974. if (sqlite3_bind_int(stmt, 1, zone_id) != SQLITE_OK) {
  975. isc_throw(SQLite3Error, "Could not bind zone ID " << zone_id <<
  976. " to SQL statement (find previous): " <<
  977. sqlite3_errmsg(dbparameters_->db_));
  978. }
  979. if (sqlite3_bind_text(stmt, 2, rname.c_str(), -1, SQLITE_STATIC) !=
  980. SQLITE_OK) {
  981. isc_throw(SQLite3Error, "Could not bind name " << rname <<
  982. " to SQL statement (find previous): " <<
  983. sqlite3_errmsg(dbparameters_->db_));
  984. }
  985. std::string result;
  986. const int rc = sqlite3_step(stmt);
  987. if (rc == SQLITE_ROW) {
  988. // We found it
  989. result = convertToPlainChar(sqlite3_column_text(stmt, 0),
  990. dbparameters_->db_);
  991. }
  992. sqlite3_reset(stmt);
  993. if (rc == SQLITE_DONE) {
  994. // No NSEC records here, this DB doesn't support DNSSEC or
  995. // we asked before the apex
  996. isc_throw(isc::NotImplemented, "The zone doesn't support DNSSEC or "
  997. "query before apex");
  998. }
  999. if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
  1000. // Some kind of error
  1001. isc_throw(SQLite3Error, "Could not get data for previous name");
  1002. }
  1003. return (result);
  1004. }
  1005. std::string
  1006. SQLite3Accessor::findPreviousNSEC3Hash(int zone_id, const std::string& hash)
  1007. const
  1008. {
  1009. sqlite3_stmt* const stmt = dbparameters_->getStatement(NSEC3_PREVIOUS);
  1010. sqlite3_reset(stmt);
  1011. sqlite3_clear_bindings(stmt);
  1012. if (sqlite3_bind_int(stmt, 1, zone_id) != SQLITE_OK) {
  1013. isc_throw(SQLite3Error, "Could not bind zone ID " << zone_id <<
  1014. " to SQL statement (find previous NSEC3): " <<
  1015. sqlite3_errmsg(dbparameters_->db_));
  1016. }
  1017. if (sqlite3_bind_text(stmt, 2, hash.c_str(), -1, SQLITE_STATIC) !=
  1018. SQLITE_OK) {
  1019. isc_throw(SQLite3Error, "Could not bind hash " << hash <<
  1020. " to SQL statement (find previous NSEC3): " <<
  1021. sqlite3_errmsg(dbparameters_->db_));
  1022. }
  1023. std::string result;
  1024. const int rc = sqlite3_step(stmt);
  1025. if (rc == SQLITE_ROW) {
  1026. // We found it
  1027. result = convertToPlainChar(sqlite3_column_text(stmt, 0),
  1028. dbparameters_->db_);
  1029. }
  1030. sqlite3_reset(stmt);
  1031. if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
  1032. // Some kind of error
  1033. isc_throw(SQLite3Error, "Could not get data for previous hash");
  1034. }
  1035. if (rc == SQLITE_DONE) {
  1036. // No NSEC3 records before this hash. This means we should wrap
  1037. // around and take the last one.
  1038. sqlite3_stmt* const stmt = dbparameters_->getStatement(NSEC3_LAST);
  1039. sqlite3_reset(stmt);
  1040. sqlite3_clear_bindings(stmt);
  1041. if (sqlite3_bind_int(stmt, 1, zone_id) != SQLITE_OK) {
  1042. isc_throw(SQLite3Error, "Could not bind zone ID " << zone_id <<
  1043. " to SQL statement (find last NSEC3): " <<
  1044. sqlite3_errmsg(dbparameters_->db_));
  1045. }
  1046. const int rc = sqlite3_step(stmt);
  1047. if (rc == SQLITE_ROW) {
  1048. // We found it
  1049. result = convertToPlainChar(sqlite3_column_text(stmt, 0),
  1050. dbparameters_->db_);
  1051. }
  1052. sqlite3_reset(stmt);
  1053. if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
  1054. // Some kind of error
  1055. isc_throw(SQLite3Error, "Could not get data for last hash");
  1056. }
  1057. if (rc == SQLITE_DONE) {
  1058. // No NSEC3 at all in the zone. Well, bad luck, but you should not
  1059. // have asked in the first place.
  1060. isc_throw(DataSourceError, "No NSEC3 in this zone");
  1061. }
  1062. }
  1063. return (result);
  1064. }
  1065. } // end of namespace datasrc
  1066. } // end of namespace isc