sqlite3_datasrc.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. // Copyright (C) 2010 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. // $Id$
  15. #include <string>
  16. #include <sstream>
  17. #include <sqlite3.h>
  18. #include "sqlite3_datasrc.h"
  19. #include <dns/rrttl.h>
  20. #include <dns/rdata.h>
  21. #include <dns/rdataclass.h>
  22. #include <dns/rrset.h>
  23. #include <dns/rrsetlist.h>
  24. using namespace std;
  25. using namespace isc::dns;
  26. using namespace isc::dns::rdata;
  27. namespace isc {
  28. namespace datasrc {
  29. struct Sqlite3Parameters {
  30. Sqlite3Parameters() : db_(NULL), version_(-1),
  31. q_zone_(NULL), q_record_(NULL), q_addrs_(NULL), q_referral_(NULL),
  32. q_any_(NULL), q_count_(NULL), q_previous_(NULL), q_nsec3_(NULL),
  33. q_prevnsec3_(NULL)
  34. {}
  35. sqlite3* db_;
  36. int version_;
  37. sqlite3_stmt* q_zone_;
  38. sqlite3_stmt* q_record_;
  39. sqlite3_stmt* q_addrs_;
  40. sqlite3_stmt* q_referral_;
  41. sqlite3_stmt* q_any_;
  42. sqlite3_stmt* q_count_;
  43. sqlite3_stmt* q_previous_;
  44. sqlite3_stmt* q_nsec3_;
  45. sqlite3_stmt* q_prevnsec3_;
  46. };
  47. namespace {
  48. const char* const SCHEMA_LIST[] = {
  49. "CREATE TABLE schema_version (version INTEGER NOT NULL)",
  50. "INSERT INTO schema_version VALUES (1)",
  51. "CREATE TABLE zones (id INTEGER PRIMARY KEY, "
  52. "name STRING NOT NULL COLLATE NOCASE, "
  53. "rdclass STRING NOT NULL COLLATE NOCASE DEFAULT 'IN', "
  54. "dnssec BOOLEAN NOT NULL DEFAULT 0)",
  55. "CREATE INDEX zones_byname ON zones (name)",
  56. "CREATE TABLE records (id INTEGER PRIMARY KEY, "
  57. "zone_id INTEGER NOT NULL, name STRING NOT NULL COLLATE NOCASE, "
  58. "rname STRING NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
  59. "rdtype STRING NOT NULL COLLATE NOCASE, sigtype STRING COLLATE NOCASE, "
  60. "rdata STRING NOT NULL)",
  61. "CREATE INDEX records_byname ON records (name)",
  62. "CREATE INDEX records_byrname ON records (rname)",
  63. "CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
  64. "hash STRING NOT NULL COLLATE NOCASE, "
  65. "owner STRING NOT NULL COLLATE NOCASE, "
  66. "ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
  67. "rdata STRING NOT NULL)",
  68. "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
  69. NULL
  70. };
  71. const char* const q_zone_str = "SELECT id FROM zones WHERE name=?1";
  72. const char* const q_record_str = "SELECT rdtype, ttl, sigtype, rdata "
  73. "FROM records WHERE zone_id=?1 AND name=?2 AND "
  74. "((rdtype=?3 OR sigtype=?3) OR "
  75. "(rdtype='CNAME' OR sigtype='CNAME') OR "
  76. "(rdtype='NS' OR sigtype='NS'))";
  77. const char* const q_addrs_str = "SELECT rdtype, ttl, sigtype, rdata "
  78. "FROM records WHERE zone_id=?1 AND name=?2 AND "
  79. "(rdtype='A' OR sigtype='A' OR rdtype='AAAA' OR sigtype='AAAA')";
  80. const char* const q_referral_str = "SELECT rdtype, ttl, sigtype, rdata FROM "
  81. "records WHERE zone_id=?1 AND name=?2 AND"
  82. "(rdtype='NS' OR sigtype='NS' OR rdtype='DS' OR sigtype='DS' OR "
  83. "rdtype='DNAME' OR sigtype='DNAME')";
  84. const char* const q_any_str = "SELECT rdtype, ttl, sigtype, rdata "
  85. "FROM records WHERE zone_id=?1 AND name=?2";
  86. const char* const q_count_str = "SELECT COUNT(*) FROM records "
  87. "WHERE zone_id=?1 AND rname LIKE (?2 || '%');";
  88. const char* const q_previous_str = "SELECT name FROM records "
  89. "WHERE zone_id=?1 AND rdtype = 'NSEC' AND "
  90. "rname < $2 ORDER BY rname DESC LIMIT 1";
  91. const char* const q_nsec3_str = "SELECT rdtype, ttl, rdata FROM nsec3 "
  92. "WHERE zone_id = ?1 AND hash = $2";
  93. const char* const q_prevnsec3_str = "SELECT hash FROM nsec3 "
  94. "WHERE zone_id = ?1 AND hash <= $2 ORDER BY hash DESC LIMIT 1";
  95. }
  96. //
  97. // Find the exact zone match. Return -1 if not found, or the zone's
  98. // ID if found. This will always be >= 0 if found.
  99. //
  100. int
  101. Sqlite3DataSrc::hasExactZone(const char* const name) const {
  102. int rc;
  103. sqlite3_reset(dbparameters->q_zone_);
  104. rc = sqlite3_bind_text(dbparameters->q_zone_, 1, name, -1, SQLITE_STATIC);
  105. if (rc != SQLITE_OK) {
  106. isc_throw(Sqlite3Error, "Could not bind " << name <<
  107. " to SQL statement (zone)");
  108. }
  109. rc = sqlite3_step(dbparameters->q_zone_);
  110. const int i = (rc == SQLITE_ROW) ?
  111. sqlite3_column_int(dbparameters->q_zone_, 0) : -1;
  112. sqlite3_reset(dbparameters->q_zone_);
  113. return (i);
  114. }
  115. namespace {
  116. int
  117. importSqlite3Rows(sqlite3_stmt* query, const Name& qname, const RRClass& qclass,
  118. const RRType& qtype, const bool nsec3_tree,
  119. RRsetList& result_sets, uint32_t& flags)
  120. {
  121. int rows = 0;
  122. int rc = sqlite3_step(query);
  123. const bool qtype_is_any = (qtype == RRType::ANY());
  124. while (rc == SQLITE_ROW) {
  125. const char* type = (const char*)sqlite3_column_text(query, 0);
  126. int ttl = sqlite3_column_int(query, 1);
  127. const char* sigtype = NULL;
  128. const char* rdata;
  129. if (nsec3_tree) {
  130. rdata = (const char*)sqlite3_column_text(query, 2);
  131. if (RRType(type) == RRType::RRSIG()) {
  132. sigtype = "NSEC3";
  133. }
  134. } else {
  135. sigtype = (const char*)sqlite3_column_text(query, 2);
  136. rdata = (const char*)sqlite3_column_text(query, 3);
  137. }
  138. const RRType base_rrtype(sigtype != NULL ? sigtype : type);
  139. // found an NS; we need to inform the caller that this might be a
  140. // referral, but we do not return the NS RRset to the caller
  141. // unless asked for it.
  142. if (base_rrtype == RRType::NS()) {
  143. flags |= DataSrc::REFERRAL;
  144. if (!qtype_is_any && qtype != RRType::NS()) {
  145. rc = sqlite3_step(query);
  146. continue;
  147. }
  148. }
  149. ++rows;
  150. // Looking for something else but found CNAME
  151. if (base_rrtype == RRType::CNAME() && qtype != RRType::CNAME()) {
  152. if (qtype == RRType::NSEC()) {
  153. // NSEC query, just skip the CNAME
  154. rc = sqlite3_step(query);
  155. continue;
  156. } else if (!qtype_is_any) {
  157. // include the CNAME, but don't flag it for chasing if
  158. // this is an ANY query
  159. flags |= DataSrc::CNAME_FOUND;
  160. }
  161. }
  162. RRsetPtr rrset = result_sets.findRRset(base_rrtype, qclass);
  163. if (rrset == NULL) {
  164. rrset = RRsetPtr(new RRset(qname, qclass, base_rrtype, RRTTL(ttl)));
  165. result_sets.addRRset(rrset);
  166. }
  167. if (sigtype == NULL && base_rrtype == rrset->getType()) {
  168. rrset->addRdata(createRdata(rrset->getType(), qclass, rdata));
  169. if (ttl > rrset->getTTL().getValue()) {
  170. rrset->setTTL(RRTTL(ttl));
  171. }
  172. } else if (sigtype != NULL && base_rrtype == rrset->getType()) {
  173. RdataPtr rrsig = createRdata(RRType::RRSIG(), qclass, rdata);
  174. if (rrset->getRRsig()) {
  175. rrset->getRRsig()->addRdata(rrsig);
  176. } else {
  177. RRsetPtr sigs = RRsetPtr(new RRset(qname, qclass,
  178. RRType::RRSIG(),
  179. RRTTL(ttl)));
  180. sigs->addRdata(rrsig);
  181. rrset->addRRsig(sigs);
  182. }
  183. if (ttl > rrset->getRRsig()->getTTL().getValue()) {
  184. rrset->getRRsig()->setTTL(RRTTL(ttl));
  185. }
  186. }
  187. rc = sqlite3_step(query);
  188. }
  189. return (rows);
  190. }
  191. }
  192. int
  193. Sqlite3DataSrc::findRecords(const Name& name, const RRType& rdtype,
  194. RRsetList& target, const Name* zonename,
  195. const Mode mode, uint32_t& flags) const
  196. {
  197. flags = 0;
  198. int zone_id = (zonename == NULL) ? findClosest(name, NULL) :
  199. findClosest(*zonename, NULL);
  200. if (zone_id < 0) {
  201. flags = NO_SUCH_ZONE;
  202. return (0);
  203. }
  204. sqlite3_stmt* query;
  205. switch (mode) {
  206. case ADDRESS:
  207. query = dbparameters->q_addrs_;
  208. break;
  209. case DELEGATION:
  210. query = dbparameters->q_referral_;
  211. break;
  212. default:
  213. if (rdtype == RRType::ANY()) {
  214. query = dbparameters->q_any_;
  215. } else {
  216. query = dbparameters->q_record_;
  217. }
  218. break;
  219. }
  220. sqlite3_reset(query);
  221. sqlite3_clear_bindings(query);
  222. int rc;
  223. rc = sqlite3_bind_int(query, 1, zone_id);
  224. if (rc != SQLITE_OK) {
  225. isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
  226. " to SQL statement (query)");
  227. }
  228. const string name_text = name.toText();
  229. rc = sqlite3_bind_text(query, 2, name_text.c_str(), -1, SQLITE_STATIC);
  230. if (rc != SQLITE_OK) {
  231. isc_throw(Sqlite3Error, "Could not bind name " << name_text <<
  232. " to SQL statement (query)");
  233. }
  234. const string rdtype_text = rdtype.toText();
  235. if (query == dbparameters->q_record_) {
  236. rc = sqlite3_bind_text(query, 3, rdtype_text.c_str(), -1,
  237. SQLITE_STATIC);
  238. if (rc != SQLITE_OK) {
  239. isc_throw(Sqlite3Error, "Could not bind RR type " <<
  240. rdtype.toText() << " to SQL statement (query)");
  241. }
  242. }
  243. const int rows = importSqlite3Rows(query, name, getClass(), rdtype, false,
  244. target, flags);
  245. sqlite3_reset(query);
  246. if (rows > 0) {
  247. return (rows);
  248. }
  249. //
  250. // No rows were found. We need to find out whether there are
  251. // any RRs with that name to determine whether this is NXDOMAIN or
  252. // NXRRSET
  253. //
  254. sqlite3_reset(dbparameters->q_count_);
  255. sqlite3_clear_bindings(dbparameters->q_count_);
  256. rc = sqlite3_bind_int(dbparameters->q_count_, 1, zone_id);
  257. if (rc != SQLITE_OK) {
  258. isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
  259. " to SQL statement (qcount)");
  260. }
  261. const string revname_text = name.reverse().toText();
  262. rc = sqlite3_bind_text(dbparameters->q_count_, 2, revname_text.c_str(),
  263. -1, SQLITE_STATIC);
  264. if (rc != SQLITE_OK) {
  265. isc_throw(Sqlite3Error, "Could not bind name " << name.reverse() <<
  266. " to SQL statement (qcount)");
  267. }
  268. rc = sqlite3_step(dbparameters->q_count_);
  269. if (rc == SQLITE_ROW) {
  270. if (sqlite3_column_int(dbparameters->q_count_, 0) != 0) {
  271. flags |= TYPE_NOT_FOUND;
  272. sqlite3_reset(dbparameters->q_count_);
  273. return (0);
  274. }
  275. }
  276. flags |= NAME_NOT_FOUND;
  277. sqlite3_reset(dbparameters->q_count_);
  278. return (0);
  279. }
  280. //
  281. // Search for the closest enclosing zone. Will return -1 if not found,
  282. // >= 0 if found. If position is not NULL, it will be filled in with the
  283. // longest match found.
  284. //
  285. int
  286. Sqlite3DataSrc::findClosest(const Name& name, unsigned int* position) const {
  287. const unsigned int nlabels = name.getLabelCount();
  288. for (unsigned int i = 0; i < nlabels; ++i) {
  289. const Name matchname(name.split(i));
  290. const int rc = hasExactZone(matchname.toText().c_str());
  291. if (rc >= 0) {
  292. if (position != NULL) {
  293. *position = i;
  294. }
  295. return (rc);
  296. }
  297. }
  298. return (-1);
  299. }
  300. void
  301. Sqlite3DataSrc::findClosestEnclosure(DataSrcMatch& match) const {
  302. if (match.getClass() != getClass() && match.getClass() != RRClass::ANY()) {
  303. return;
  304. }
  305. unsigned int position;
  306. if (findClosest(match.getName(), &position) == -1) {
  307. return;
  308. }
  309. match.update(*this, match.getName().split(position));
  310. }
  311. DataSrc::Result
  312. Sqlite3DataSrc::findPreviousName(const Name& qname,
  313. Name& target,
  314. const Name* zonename) const
  315. {
  316. const int zone_id = (zonename == NULL) ?
  317. findClosest(qname, NULL) : findClosest(*zonename, NULL);
  318. if (zone_id < 0) {
  319. return (ERROR);
  320. }
  321. sqlite3_reset(dbparameters->q_previous_);
  322. sqlite3_clear_bindings(dbparameters->q_previous_);
  323. int rc = sqlite3_bind_int(dbparameters->q_previous_, 1, zone_id);
  324. if (rc != SQLITE_OK) {
  325. isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
  326. " to SQL statement (qprevious)");
  327. }
  328. const string revname_text = qname.reverse().toText();
  329. rc = sqlite3_bind_text(dbparameters->q_previous_, 2,
  330. revname_text.c_str(), -1, SQLITE_STATIC);
  331. if (rc != SQLITE_OK) {
  332. isc_throw(Sqlite3Error, "Could not bind name " << qname <<
  333. " to SQL statement (qprevious)");
  334. }
  335. rc = sqlite3_step(dbparameters->q_previous_);
  336. if (rc != SQLITE_ROW) {
  337. sqlite3_reset(dbparameters->q_previous_);
  338. return (ERROR);
  339. }
  340. // XXX: bad cast. we should revisit this.
  341. target = Name((const char*)sqlite3_column_text(dbparameters->q_previous_,
  342. 0));
  343. sqlite3_reset(dbparameters->q_previous_);
  344. return (SUCCESS);
  345. }
  346. DataSrc::Result
  347. Sqlite3DataSrc::findCoveringNSEC3(const Name& zonename,
  348. string& hashstr,
  349. RRsetList& target) const
  350. {
  351. const int zone_id = findClosest(zonename, NULL);
  352. if (zone_id < 0) {
  353. return (ERROR);
  354. }
  355. sqlite3_reset(dbparameters->q_prevnsec3_);
  356. sqlite3_clear_bindings(dbparameters->q_prevnsec3_);
  357. int rc = sqlite3_bind_int(dbparameters->q_prevnsec3_, 1, zone_id);
  358. if (rc != SQLITE_OK) {
  359. isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
  360. " to SQL statement (previous NSEC3)");
  361. }
  362. rc = sqlite3_bind_text(dbparameters->q_prevnsec3_, 2, hashstr.c_str(),
  363. -1, SQLITE_STATIC);
  364. if (rc != SQLITE_OK) {
  365. isc_throw(Sqlite3Error, "Could not bind hash " << hashstr <<
  366. " to SQL statement (previous NSEC3)");
  367. }
  368. rc = sqlite3_step(dbparameters->q_prevnsec3_);
  369. const char* hash;
  370. if (rc == SQLITE_ROW) {
  371. hash = (const char*) sqlite3_column_text(dbparameters->q_prevnsec3_, 0);
  372. } else {
  373. // We need to find the final NSEC3 in the chain.
  374. // A valid NSEC3 hash is in base32, which contains no
  375. // letters higher than V, so a search for the previous
  376. // NSEC3 from "w" will always find it.
  377. sqlite3_reset(dbparameters->q_prevnsec3_);
  378. rc = sqlite3_bind_text(dbparameters->q_prevnsec3_, 2, "w", -1,
  379. SQLITE_STATIC);
  380. if (rc != SQLITE_OK) {
  381. isc_throw(Sqlite3Error, "Could not bind \"w\""
  382. " to SQL statement (previous NSEC3)");
  383. }
  384. rc = sqlite3_step(dbparameters->q_prevnsec3_);
  385. if (rc != SQLITE_ROW) {
  386. return (ERROR);
  387. }
  388. hash = (const char*) sqlite3_column_text(dbparameters->q_prevnsec3_, 0);
  389. }
  390. sqlite3_reset(dbparameters->q_nsec3_);
  391. sqlite3_clear_bindings(dbparameters->q_nsec3_);
  392. rc = sqlite3_bind_int(dbparameters->q_nsec3_, 1, zone_id);
  393. if (rc != SQLITE_OK) {
  394. isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
  395. " to SQL statement (NSEC3)");
  396. }
  397. rc = sqlite3_bind_text(dbparameters->q_nsec3_, 2, hash, -1, SQLITE_STATIC);
  398. if (rc != SQLITE_OK) {
  399. isc_throw(Sqlite3Error, "Could not bind hash " << hash <<
  400. " to SQL statement (NSEC3)");
  401. }
  402. DataSrc::Result result = SUCCESS;
  403. uint32_t flags = 0;
  404. if (importSqlite3Rows(dbparameters->q_nsec3_,
  405. Name(hash).concatenate(zonename),
  406. getClass(), RRType::NSEC3(), true, target,
  407. flags) == 0 || flags != 0) {
  408. result = ERROR;
  409. }
  410. hashstr = string(hash);
  411. sqlite3_reset(dbparameters->q_nsec3_);
  412. return (result);
  413. }
  414. DataSrc::Result
  415. Sqlite3DataSrc::findRRset(const Name& qname,
  416. const RRClass& qclass,
  417. const RRType& qtype,
  418. RRsetList& target,
  419. uint32_t& flags,
  420. const Name* zonename) const
  421. {
  422. if (qclass != getClass() && qclass != RRClass::ANY()) {
  423. return (ERROR);
  424. }
  425. findRecords(qname, qtype, target, zonename, NORMAL, flags);
  426. return (SUCCESS);
  427. }
  428. DataSrc::Result
  429. Sqlite3DataSrc::findExactRRset(const Name& qname,
  430. const RRClass& qclass,
  431. const RRType& qtype,
  432. RRsetList& target,
  433. uint32_t& flags,
  434. const Name* zonename) const
  435. {
  436. if (qclass != getClass() && qclass != RRClass::ANY()) {
  437. return (ERROR);
  438. }
  439. findRecords(qname, qtype, target, zonename, NORMAL, flags);
  440. // Ignore referrals in this case
  441. flags &= ~REFERRAL;
  442. // CNAMEs don't count in this case
  443. if (flags & CNAME_FOUND) {
  444. flags &= ~CNAME_FOUND;
  445. flags |= TYPE_NOT_FOUND;
  446. }
  447. return (SUCCESS);
  448. }
  449. DataSrc::Result
  450. Sqlite3DataSrc::findAddrs(const Name& qname,
  451. const RRClass& qclass,
  452. RRsetList& target,
  453. uint32_t& flags,
  454. const Name* zonename) const
  455. {
  456. if (qclass != getClass() && qclass != RRClass::ANY()) {
  457. return (ERROR);
  458. }
  459. findRecords(qname, RRType::ANY(), target, zonename, ADDRESS, flags);
  460. return (SUCCESS);
  461. }
  462. DataSrc::Result
  463. Sqlite3DataSrc::findReferral(const Name& qname,
  464. const RRClass& qclass,
  465. RRsetList& target,
  466. uint32_t& flags,
  467. const Name* zonename) const
  468. {
  469. if (qclass != getClass() && qclass != RRClass::ANY()) {
  470. return (ERROR);
  471. }
  472. findRecords(qname, RRType::ANY(), target, zonename, DELEGATION, flags);
  473. return (SUCCESS);
  474. }
  475. Sqlite3DataSrc::Sqlite3DataSrc() :
  476. dbparameters(new Sqlite3Parameters)
  477. {}
  478. Sqlite3DataSrc::~Sqlite3DataSrc() {
  479. if (dbparameters->db_ != NULL) {
  480. close();
  481. }
  482. delete dbparameters;
  483. }
  484. DataSrc::Result
  485. Sqlite3DataSrc::init(const isc::data::ElementPtr config) {
  486. if (config && config->contains("database_file")) {
  487. open(config->get("database_file")->stringValue());
  488. } else {
  489. isc_throw(DataSourceError, "No SQLite database file specified");
  490. }
  491. return (SUCCESS);
  492. }
  493. namespace {
  494. // This is a helper class to initialize a Sqlite3 DB safely. An object of
  495. // this class encapsulates all temporary resources that are necessary for
  496. // the initialization, and release them in the destructor. Once everything
  497. // is properly initialized, the move() method moves the allocated resources
  498. // to the main object in an exception free manner. This way, the main code
  499. // for the initialization can be exception safe, and can provide the strong
  500. // exception guarantee.
  501. class Sqlite3Initializer {
  502. public:
  503. ~Sqlite3Initializer() {
  504. if (params_.q_zone_ != NULL) {
  505. sqlite3_finalize(params_.q_zone_);
  506. }
  507. if (params_.q_record_ != NULL) {
  508. sqlite3_finalize(params_.q_record_);
  509. }
  510. if (params_.q_addrs_ != NULL) {
  511. sqlite3_finalize(params_.q_addrs_);
  512. }
  513. if (params_.q_referral_ != NULL) {
  514. sqlite3_finalize(params_.q_referral_);
  515. }
  516. if (params_.q_any_ != NULL) {
  517. sqlite3_finalize(params_.q_any_);
  518. }
  519. if (params_.q_count_ != NULL) {
  520. sqlite3_finalize(params_.q_count_);
  521. }
  522. if (params_.q_previous_ != NULL) {
  523. sqlite3_finalize(params_.q_previous_);
  524. }
  525. if (params_.q_nsec3_ != NULL) {
  526. sqlite3_finalize(params_.q_nsec3_);
  527. }
  528. if (params_.q_prevnsec3_ != NULL) {
  529. sqlite3_finalize(params_.q_prevnsec3_);
  530. }
  531. if (params_.db_ != NULL) {
  532. sqlite3_close(params_.db_);
  533. }
  534. }
  535. void move(Sqlite3Parameters* dst) {
  536. *dst = params_;
  537. params_ = Sqlite3Parameters(); // clear everything
  538. }
  539. Sqlite3Parameters params_;
  540. };
  541. sqlite3_stmt*
  542. prepare(sqlite3* const db, const char* const statement) {
  543. sqlite3_stmt* prepared = NULL;
  544. if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) {
  545. isc_throw(Sqlite3Error, "Could not prepare SQLite statement: " <<
  546. statement);
  547. }
  548. return (prepared);
  549. }
  550. void
  551. checkAndSetupSchema(Sqlite3Initializer* initializer) {
  552. sqlite3* const db = initializer->params_.db_;
  553. sqlite3_stmt* prepared = NULL;
  554. if (sqlite3_prepare_v2(db, "SELECT version FROM schema_version", -1,
  555. &prepared, NULL) == SQLITE_OK &&
  556. sqlite3_step(prepared) == SQLITE_ROW) {
  557. initializer->params_.version_ = sqlite3_column_int(prepared, 0);
  558. sqlite3_finalize(prepared);
  559. } else {
  560. if (prepared != NULL) {
  561. sqlite3_finalize(prepared);
  562. }
  563. for (int i = 0; SCHEMA_LIST[i] != NULL; ++i) {
  564. if (sqlite3_exec(db, SCHEMA_LIST[i], NULL, NULL, NULL) !=
  565. SQLITE_OK) {
  566. isc_throw(Sqlite3Error,
  567. "Failed to set up schema " << SCHEMA_LIST[i]);
  568. }
  569. }
  570. }
  571. initializer->params_.q_zone_ = prepare(db, q_zone_str);
  572. initializer->params_.q_record_ = prepare(db, q_record_str);
  573. initializer->params_.q_addrs_ = prepare(db, q_addrs_str);
  574. initializer->params_.q_referral_ = prepare(db, q_referral_str);
  575. initializer->params_.q_any_ = prepare(db, q_any_str);
  576. initializer->params_.q_count_ = prepare(db, q_count_str);
  577. initializer->params_.q_previous_ = prepare(db, q_previous_str);
  578. initializer->params_.q_nsec3_ = prepare(db, q_nsec3_str);
  579. initializer->params_.q_prevnsec3_ = prepare(db, q_prevnsec3_str);
  580. }
  581. }
  582. //
  583. // Open the database.
  584. //
  585. void
  586. Sqlite3DataSrc::open(const string& name) {
  587. if (dbparameters->db_ != NULL) {
  588. isc_throw(DataSourceError, "Duplicate SQLite open with " << name);
  589. }
  590. Sqlite3Initializer initializer;
  591. if (sqlite3_open(name.c_str(), &initializer.params_.db_) != 0) {
  592. isc_throw(Sqlite3Error, "Cannot open SQLite database file: " << name);
  593. }
  594. checkAndSetupSchema(&initializer);
  595. initializer.move(dbparameters);
  596. }
  597. //
  598. // Close the database.
  599. //
  600. DataSrc::Result
  601. Sqlite3DataSrc::close(void) {
  602. if (dbparameters->db_ == NULL) {
  603. isc_throw(DataSourceError,
  604. "SQLite data source is being closed before open");
  605. }
  606. // XXX: sqlite3_finalize() could fail. What should we do in that case?
  607. sqlite3_finalize(dbparameters->q_zone_);
  608. dbparameters->q_zone_ = NULL;
  609. sqlite3_finalize(dbparameters->q_record_);
  610. dbparameters->q_record_ = NULL;
  611. sqlite3_finalize(dbparameters->q_addrs_);
  612. dbparameters->q_addrs_ = NULL;
  613. sqlite3_finalize(dbparameters->q_referral_);
  614. dbparameters->q_referral_ = NULL;
  615. sqlite3_finalize(dbparameters->q_any_);
  616. dbparameters->q_any_ = NULL;
  617. sqlite3_finalize(dbparameters->q_count_);
  618. dbparameters->q_count_ = NULL;
  619. sqlite3_finalize(dbparameters->q_previous_);
  620. dbparameters->q_previous_ = NULL;
  621. sqlite3_finalize(dbparameters->q_prevnsec3_);
  622. dbparameters->q_prevnsec3_ = NULL;
  623. sqlite3_finalize(dbparameters->q_nsec3_);
  624. dbparameters->q_nsec3_ = NULL;
  625. sqlite3_close(dbparameters->db_);
  626. dbparameters->db_ = NULL;
  627. return (SUCCESS);
  628. }
  629. }
  630. }