Branch data Line data Source code
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 : :
15 : : #include <string>
16 : : #include <sstream>
17 : : #include <utility>
18 : :
19 : : #include <sqlite3.h>
20 : :
21 : : #include <datasrc/sqlite3_datasrc.h>
22 : : #include <datasrc/logger.h>
23 : : #include <exceptions/exceptions.h>
24 : : #include <dns/rrttl.h>
25 : : #include <dns/rdata.h>
26 : : #include <dns/rdataclass.h>
27 : : #include <dns/rrset.h>
28 : : #include <dns/rrsetlist.h>
29 : :
30 : : namespace {
31 : : // Expected schema. The major version must match else there is an error. If
32 : : // the minor version of the database is less than this, a warning is output.
33 : : //
34 : : // It is assumed that a program written to run on m.n of the database will run
35 : : // with a database version m.p, where p is any number. However, if p < n,
36 : : // we assume that the database structure was upgraded for some reason, and that
37 : : // some advantage may result if the database is upgraded. Conversely, if p > n,
38 : : // The database is at a later version than the program was written for and the
39 : : // program may not be taking advantage of features (possibly performance
40 : : // improvements) added to the database.
41 : : const int SQLITE_SCHEMA_MAJOR_VERSION = 2;
42 : : const int SQLITE_SCHEMA_MINOR_VERSION = 0;
43 : : }
44 : :
45 : : using namespace std;
46 : : using namespace isc::dns;
47 : : using namespace isc::dns::rdata;
48 : :
49 : : namespace isc {
50 : : namespace datasrc {
51 : :
52 : : struct Sqlite3Parameters {
53 : : Sqlite3Parameters() : db_(NULL), major_version_(-1), minor_version_(-1),
54 : : q_zone_(NULL), q_record_(NULL), q_addrs_(NULL), q_referral_(NULL),
55 : : q_any_(NULL), q_count_(NULL), q_previous_(NULL), q_nsec3_(NULL),
56 : 196 : q_prevnsec3_(NULL)
57 : : {}
58 : : sqlite3* db_;
59 : : int major_version_;
60 : : int minor_version_;
61 : : sqlite3_stmt* q_zone_;
62 : : sqlite3_stmt* q_record_;
63 : : sqlite3_stmt* q_addrs_;
64 : : sqlite3_stmt* q_referral_;
65 : : sqlite3_stmt* q_any_;
66 : : sqlite3_stmt* q_count_;
67 : : sqlite3_stmt* q_previous_;
68 : : sqlite3_stmt* q_nsec3_;
69 : : sqlite3_stmt* q_prevnsec3_;
70 : : };
71 : :
72 : : namespace {
73 : : const char* const SCHEMA_LIST[] = {
74 : : "CREATE TABLE schema_version (version INTEGER NOT NULL, "
75 : : "minor INTEGER NOT NULL DEFAULT 0)",
76 : : "INSERT INTO schema_version VALUES (2, 0)",
77 : : "CREATE TABLE zones (id INTEGER PRIMARY KEY, "
78 : : "name TEXT NOT NULL COLLATE NOCASE, "
79 : : "rdclass TEXT NOT NULL COLLATE NOCASE DEFAULT 'IN', "
80 : : "dnssec BOOLEAN NOT NULL DEFAULT 0)",
81 : : "CREATE INDEX zones_byname ON zones (name)",
82 : : "CREATE TABLE records (id INTEGER PRIMARY KEY, "
83 : : "zone_id INTEGER NOT NULL, name TEXT NOT NULL COLLATE NOCASE, "
84 : : "rname TEXT NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
85 : : "rdtype TEXT NOT NULL COLLATE NOCASE, sigtype TEXT COLLATE NOCASE, "
86 : : "rdata TEXT NOT NULL)",
87 : : "CREATE INDEX records_byname ON records (name)",
88 : : "CREATE INDEX records_byrname ON records (rname)",
89 : : "CREATE INDEX records_bytype_and_rname ON records (rdtype, rname)",
90 : : "CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
91 : : "hash TEXT NOT NULL COLLATE NOCASE, "
92 : : "owner TEXT NOT NULL COLLATE NOCASE, "
93 : : "ttl INTEGER NOT NULL, rdtype TEXT NOT NULL COLLATE NOCASE, "
94 : : "rdata TEXT NOT NULL)",
95 : : "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
96 : : "CREATE TABLE diffs (id INTEGER PRIMARY KEY, "
97 : : "zone_id INTEGER NOT NULL, "
98 : : "version INTEGER NOT NULL, "
99 : : "operation INTEGER NOT NULL, "
100 : : "name TEXT NOT NULL COLLATE NOCASE, "
101 : : "rrtype TEXT NOT NULL COLLATE NOCASE, "
102 : : "ttl INTEGER NOT NULL, "
103 : : "rdata TEXT NOT NULL)",
104 : : NULL
105 : : };
106 : :
107 : : const char* const q_version_str = "SELECT version FROM schema_version";
108 : : const char* const q_minor_str = "SELECT minor FROM schema_version";
109 : :
110 : : const char* const q_zone_str = "SELECT id FROM zones WHERE name=?1";
111 : :
112 : : const char* const q_record_str = "SELECT rdtype, ttl, sigtype, rdata "
113 : : "FROM records WHERE zone_id=?1 AND name=?2 AND "
114 : : "((rdtype=?3 OR sigtype=?3) OR "
115 : : "(rdtype='CNAME' OR sigtype='CNAME') OR "
116 : : "(rdtype='NS' OR sigtype='NS'))";
117 : :
118 : : const char* const q_addrs_str = "SELECT rdtype, ttl, sigtype, rdata "
119 : : "FROM records WHERE zone_id=?1 AND name=?2 AND "
120 : : "(rdtype='A' OR sigtype='A' OR rdtype='AAAA' OR sigtype='AAAA')";
121 : :
122 : : const char* const q_referral_str = "SELECT rdtype, ttl, sigtype, rdata FROM "
123 : : "records WHERE zone_id=?1 AND name=?2 AND"
124 : : "(rdtype='NS' OR sigtype='NS' OR rdtype='DS' OR sigtype='DS' OR "
125 : : "rdtype='DNAME' OR sigtype='DNAME')";
126 : :
127 : : const char* const q_any_str = "SELECT rdtype, ttl, sigtype, rdata "
128 : : "FROM records WHERE zone_id=?1 AND name=?2";
129 : :
130 : : // Note: the wildcard symbol '%' is expected to be added to the text
131 : : // for the placeholder for LIKE given via sqlite3_bind_text(). We don't
132 : : // use the expression such as (?2 || '%') because it would disable the use
133 : : // of indices and could result in terrible performance.
134 : : const char* const q_count_str = "SELECT COUNT(*) FROM records "
135 : : "WHERE zone_id=?1 AND rname LIKE ?2;";
136 : :
137 : : const char* const q_previous_str = "SELECT name FROM records "
138 : : "WHERE rname < ?2 AND zone_id=?1 AND rdtype = 'NSEC' "
139 : : "ORDER BY rname DESC LIMIT 1";
140 : :
141 : : const char* const q_nsec3_str = "SELECT rdtype, ttl, rdata FROM nsec3 "
142 : : "WHERE zone_id = ?1 AND hash = $2";
143 : :
144 : : const char* const q_prevnsec3_str = "SELECT hash FROM nsec3 "
145 : : "WHERE zone_id = ?1 AND hash <= $2 ORDER BY hash DESC LIMIT 1";
146 : :
147 : : }
148 : :
149 : : //
150 : : // Find the exact zone match. Return -1 if not found, or the zone's
151 : : // ID if found. This will always be >= 0 if found.
152 : : //
153 : : int
154 : 787 : Sqlite3DataSrc::hasExactZone(const char* const name) const {
155 : : int rc;
156 : :
157 : 787 : sqlite3_reset(dbparameters->q_zone_);
158 : 787 : rc = sqlite3_bind_text(dbparameters->q_zone_, 1, name, -1, SQLITE_STATIC);
159 [ - + ]: 787 : if (rc != SQLITE_OK) {
160 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind " << name <<
[ # # ][ # # ]
161 : : " to SQL statement (zone)");
162 : : }
163 : :
164 : 787 : rc = sqlite3_step(dbparameters->q_zone_);
165 : : const int i = (rc == SQLITE_ROW) ?
166 [ + + ]: 787 : sqlite3_column_int(dbparameters->q_zone_, 0) : -1;
167 : 787 : sqlite3_reset(dbparameters->q_zone_);
168 : 787 : return (i);
169 : : }
170 : :
171 : : namespace {
172 : : int
173 : 86 : importSqlite3Rows(sqlite3_stmt* query, const Name& qname, const RRClass& qclass,
174 : : const RRType& qtype, const bool nsec3_tree,
175 : : RRsetList& result_sets, uint32_t& flags)
176 : : {
177 : 86 : int rows = 0;
178 : 86 : int rc = sqlite3_step(query);
179 : 86 : const bool qtype_is_any = (qtype == RRType::ANY());
180 : :
181 [ + + ]: 330 : while (rc == SQLITE_ROW) {
182 : 245 : const char* type = (const char*)sqlite3_column_text(query, 0);
183 : 245 : int ttl = sqlite3_column_int(query, 1);
184 : 245 : const char* sigtype = NULL;
185 : : const char* rdata;
186 : :
187 [ + + ]: 245 : if (nsec3_tree) {
188 : 2 : rdata = (const char*)sqlite3_column_text(query, 2);
189 [ + - ][ + + ]: 2 : if (RRType(type) == RRType::RRSIG()) {
190 : 1 : sigtype = "NSEC3";
191 : : }
192 : : } else {
193 : 243 : sigtype = (const char*)sqlite3_column_text(query, 2);
194 : 243 : rdata = (const char*)sqlite3_column_text(query, 3);
195 : : }
196 : :
197 [ + + ][ + - ]: 245 : const RRType base_rrtype(sigtype != NULL ? sigtype : type);
198 : :
199 : : // found an NS; we need to inform the caller that this might be a
200 : : // referral, but we do not return the NS RRset to the caller
201 : : // unless asked for it.
202 [ + + ]: 245 : if (base_rrtype == RRType::NS()) {
203 : 114 : flags |= DataSrc::REFERRAL;
204 [ + + ][ + + ]: 114 : if (!qtype_is_any && qtype != RRType::NS()) {
[ + + ]
205 : 78 : rc = sqlite3_step(query);
206 : 78 : continue;
207 : : }
208 : : }
209 : :
210 : 167 : ++rows;
211 : :
212 : : // Looking for something else but found CNAME
213 [ + + ][ + + ]: 167 : if (base_rrtype == RRType::CNAME() && qtype != RRType::CNAME()) {
[ + + ]
214 [ + + ]: 11 : if (qtype == RRType::NSEC()) {
215 : : // NSEC query, just skip the CNAME
216 : 4 : rc = sqlite3_step(query);
217 : 4 : continue;
218 [ + - ]: 7 : } else if (!qtype_is_any) {
219 : : // include the CNAME, but don't flag it for chasing if
220 : : // this is an ANY query
221 : 7 : flags |= DataSrc::CNAME_FOUND;
222 : : }
223 : : }
224 : :
225 : 163 : RRsetPtr rrset = result_sets.findRRset(base_rrtype, qclass);
226 [ + + ]: 163 : if (rrset == NULL) {
227 [ + - ][ + - ]: 77 : rrset = RRsetPtr(new RRset(qname, qclass, base_rrtype, RRTTL(ttl)));
[ + - ][ + - ]
228 [ + - ]: 77 : result_sets.addRRset(rrset);
229 : : }
230 : :
231 [ + + ][ + - ]: 163 : if (sigtype == NULL && base_rrtype == rrset->getType()) {
[ - + ][ + + ]
232 [ + - ][ + - ]: 313 : rrset->addRdata(createRdata(rrset->getType(), qclass, rdata));
[ + + ][ + - ]
233 [ + - ][ + + ]: 104 : if (ttl > rrset->getTTL().getValue()) {
234 [ + - ]: 4 : rrset->setTTL(RRTTL(ttl));
235 : : }
236 [ + - ][ + - ]: 58 : } else if (sigtype != NULL && base_rrtype == rrset->getType()) {
[ - + ][ + - ]
237 [ + - ][ + - ]: 58 : RdataPtr rrsig = createRdata(RRType::RRSIG(), qclass, rdata);
238 [ + - ][ + + ]: 116 : if (rrset->getRRsig()) {
239 [ + - ][ + - ]: 4 : rrset->getRRsig()->addRdata(rrsig);
240 : : } else {
241 : : RRsetPtr sigs = RRsetPtr(new RRset(qname, qclass,
242 : : RRType::RRSIG(),
243 [ + - ][ + - ]: 56 : RRTTL(ttl)));
[ + - ]
244 [ + - ]: 112 : sigs->addRdata(rrsig);
245 [ + - ]: 56 : rrset->addRRsig(sigs);
246 : : }
247 : :
248 [ + - ][ + - ]: 116 : if (ttl > rrset->getRRsig()->getTTL().getValue()) {
[ - + ]
249 [ # # ][ # # ]: 0 : rrset->getRRsig()->setTTL(RRTTL(ttl));
250 : : }
251 : : }
252 : :
253 [ + - ]: 162 : rc = sqlite3_step(query);
254 : : }
255 : :
256 : 85 : return (rows);
257 : : }
258 : : }
259 : :
260 : : int
261 : 88 : Sqlite3DataSrc::findRecords(const Name& name, const RRType& rdtype,
262 : : RRsetList& target, const Name* zonename,
263 : : const Mode mode, uint32_t& flags) const
264 : : {
265 [ + - ][ + - ]: 176 : LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_SQLITE_FINDREC).arg(name).
266 [ + - ]: 88 : arg(rdtype);
267 : 88 : flags = 0;
268 : : int zone_id = (zonename == NULL) ? findClosest(name, NULL) :
269 [ + + ]: 88 : findClosest(*zonename, NULL);
270 [ + + ]: 88 : if (zone_id < 0) {
271 : 3 : flags = NO_SUCH_ZONE;
272 : 3 : return (0);
273 : : }
274 : :
275 : : sqlite3_stmt* query;
276 [ + + + ]: 85 : switch (mode) {
277 : : case ADDRESS:
278 : 14 : query = dbparameters->q_addrs_;
279 : 14 : break;
280 : : case DELEGATION:
281 : 15 : query = dbparameters->q_referral_;
282 : 15 : break;
283 : : default:
284 [ + + ]: 56 : if (rdtype == RRType::ANY()) {
285 : 7 : query = dbparameters->q_any_;
286 : : } else {
287 : 49 : query = dbparameters->q_record_;
288 : : }
289 : : break;
290 : : }
291 : :
292 : 85 : sqlite3_reset(query);
293 : 85 : sqlite3_clear_bindings(query);
294 : :
295 : : int rc;
296 : 85 : rc = sqlite3_bind_int(query, 1, zone_id);
297 [ - + ]: 85 : if (rc != SQLITE_OK) {
298 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
[ # # ][ # # ]
299 : : " to SQL statement (query)");
300 : : }
301 : 173 : const string name_text = name.toText();
302 [ + - ]: 85 : rc = sqlite3_bind_text(query, 2, name_text.c_str(), -1, SQLITE_STATIC);
303 [ - + ]: 85 : if (rc != SQLITE_OK) {
304 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind name " << name_text <<
[ # # ][ # # ]
[ # # ]
305 : : " to SQL statement (query)");
306 : : }
307 : :
308 [ + - ]: 170 : const string rdtype_text = rdtype.toText();
309 [ + + ]: 85 : if (query == dbparameters->q_record_) {
310 : : rc = sqlite3_bind_text(query, 3, rdtype_text.c_str(), -1,
311 [ + - ]: 49 : SQLITE_STATIC);
312 [ - + ]: 49 : if (rc != SQLITE_OK) {
313 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind RR type " <<
[ # # ][ # # ]
[ # # ][ # # ]
314 : : rdtype.toText() << " to SQL statement (query)");
315 : : }
316 : : }
317 : :
318 : 85 : const int rows = importSqlite3Rows(query, name, getClass(), rdtype, false,
319 [ + + ]: 85 : target, flags);
320 [ + - ]: 84 : sqlite3_reset(query);
321 [ + + ]: 84 : if (rows > 0) {
322 : : return (rows);
323 : : }
324 : :
325 : : //
326 : : // No rows were found. We need to find out whether there are
327 : : // any RRs with that name to determine whether this is NXDOMAIN or
328 : : // NXRRSET
329 : : //
330 [ + - ]: 28 : sqlite3_reset(dbparameters->q_count_);
331 [ + - ]: 28 : sqlite3_clear_bindings(dbparameters->q_count_);
332 : :
333 [ + - ]: 28 : rc = sqlite3_bind_int(dbparameters->q_count_, 1, zone_id);
334 [ - + ]: 28 : if (rc != SQLITE_OK) {
335 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
[ # # ][ # # ]
[ # # ]
336 : : " to SQL statement (qcount)");
337 : : }
338 : :
339 [ + - ][ + - ]: 84 : const string revname_text = name.reverse().toText() + "%";
340 : : rc = sqlite3_bind_text(dbparameters->q_count_, 2,
341 : : revname_text.c_str(),
342 [ + - ]: 28 : -1, SQLITE_STATIC);
343 [ - + ]: 28 : if (rc != SQLITE_OK) {
344 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind name " << name.reverse() <<
[ # # ][ # # ]
[ # # ][ # # ]
345 : : " to SQL statement (qcount)");
346 : : }
347 : :
348 [ + - ]: 28 : rc = sqlite3_step(dbparameters->q_count_);
349 [ + - ]: 28 : if (rc == SQLITE_ROW) {
350 [ + - ][ + + ]: 28 : if (sqlite3_column_int(dbparameters->q_count_, 0) != 0) {
351 : 23 : flags |= TYPE_NOT_FOUND;
352 [ + - ]: 23 : sqlite3_reset(dbparameters->q_count_);
353 : : return (0);
354 : : }
355 : : }
356 : :
357 : 5 : flags |= NAME_NOT_FOUND;
358 [ + - ]: 5 : sqlite3_reset(dbparameters->q_count_);
359 : : return (0);
360 : : }
361 : :
362 : : //
363 : : // Search for the closest enclosing zone. Will return -1 if not found,
364 : : // >= 0 if found. If position is not NULL, it will be filled in with the
365 : : // longest match found.
366 : : //
367 : : int
368 : 266 : Sqlite3DataSrc::findClosest(const Name& name, unsigned int* position) const {
369 : 266 : const unsigned int nlabels = name.getLabelCount();
370 [ + + ]: 1053 : for (unsigned int i = 0; i < nlabels; ++i) {
371 : 1574 : const Name matchname(name.split(i));
372 [ + - ][ + - ]: 787 : const int rc = hasExactZone(matchname.toText().c_str());
373 [ + + ]: 787 : if (rc >= 0) {
374 [ + + ]: 103 : if (position != NULL) {
375 : 17 : *position = i;
376 : : }
377 : : return (rc);
378 : : }
379 : : }
380 : :
381 : : return (-1);
382 : : }
383 : :
384 : : void
385 : 181 : Sqlite3DataSrc::findClosestEnclosure(DataSrcMatch& match) const {
386 [ + - ]: 362 : LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE).
387 [ + - ]: 181 : arg(match.getName());
388 [ + + ][ + + ]: 181 : if (match.getClass() != getClass() && match.getClass() != RRClass::ANY()) {
[ + + ]
389 : : return;
390 : : }
391 : :
392 : : unsigned int position;
393 [ + + ]: 177 : if (findClosest(match.getName(), &position) == -1) {
394 [ + - ]: 320 : LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE_NOT_FOUND)
395 [ + - ]: 160 : .arg(match.getName());
396 : : return;
397 : : }
398 : :
399 [ + - ]: 181 : match.update(*this, match.getName().split(position));
400 : : }
401 : :
402 : : DataSrc::Result
403 : 0 : Sqlite3DataSrc::findPreviousName(const Name& qname,
404 : : Name& target,
405 : : const Name* zonename) const
406 : : {
407 [ # # ][ # # ]: 0 : LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_PREVIOUS).arg(qname);
408 : : const int zone_id = (zonename == NULL) ?
409 [ # # ]: 0 : findClosest(qname, NULL) : findClosest(*zonename, NULL);
410 [ # # ]: 0 : if (zone_id < 0) {
411 [ # # ][ # # ]: 0 : LOG_ERROR(logger, DATASRC_SQLITE_PREVIOUS_NO_ZONE).arg(qname.toText());
[ # # ][ # # ]
412 : : return (ERROR);
413 : : }
414 : :
415 : 0 : sqlite3_reset(dbparameters->q_previous_);
416 : 0 : sqlite3_clear_bindings(dbparameters->q_previous_);
417 : :
418 : 0 : int rc = sqlite3_bind_int(dbparameters->q_previous_, 1, zone_id);
419 [ # # ]: 0 : if (rc != SQLITE_OK) {
420 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
[ # # ][ # # ]
421 : : " to SQL statement (qprevious)");
422 : : }
423 [ # # ]: 0 : const string revname_text = qname.reverse().toText();
424 : : rc = sqlite3_bind_text(dbparameters->q_previous_, 2,
425 [ # # ]: 0 : revname_text.c_str(), -1, SQLITE_STATIC);
426 [ # # ]: 0 : if (rc != SQLITE_OK) {
427 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind name " << qname <<
[ # # ][ # # ]
[ # # ]
428 : : " to SQL statement (qprevious)");
429 : : }
430 : :
431 [ # # ]: 0 : rc = sqlite3_step(dbparameters->q_previous_);
432 [ # # ]: 0 : if (rc != SQLITE_ROW) {
433 [ # # ]: 0 : sqlite3_reset(dbparameters->q_previous_);
434 : : return (ERROR);
435 : : }
436 : :
437 : : // XXX: bad cast. we should revisit this.
438 : : target = Name((const char*)sqlite3_column_text(dbparameters->q_previous_,
439 [ # # ][ # # ]: 0 : 0));
[ # # ]
440 [ # # ]: 0 : sqlite3_reset(dbparameters->q_previous_);
441 : : return (SUCCESS);
442 : : }
443 : :
444 : : DataSrc::Result
445 : 1 : Sqlite3DataSrc::findCoveringNSEC3(const Name& zonename,
446 : : string& hashstr,
447 : : RRsetList& target) const
448 : : {
449 [ + - ]: 2 : LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FIND_NSEC3).
450 [ + - ][ + - ]: 1 : arg(zonename).arg(hashstr);
451 : 1 : const int zone_id = findClosest(zonename, NULL);
452 [ - + ]: 1 : if (zone_id < 0) {
453 [ # # ][ # # ]: 0 : LOG_ERROR(logger, DATASRC_SQLITE_FIND_NSEC3_NO_ZONE).arg(zonename);
454 : : return (ERROR);
455 : : }
456 : :
457 : 1 : sqlite3_reset(dbparameters->q_prevnsec3_);
458 : 1 : sqlite3_clear_bindings(dbparameters->q_prevnsec3_);
459 : :
460 : 1 : int rc = sqlite3_bind_int(dbparameters->q_prevnsec3_, 1, zone_id);
461 [ - + ]: 1 : if (rc != SQLITE_OK) {
462 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
[ # # ][ # # ]
463 : : " to SQL statement (previous NSEC3)");
464 : : }
465 : :
466 : : rc = sqlite3_bind_text(dbparameters->q_prevnsec3_, 2, hashstr.c_str(),
467 : 1 : -1, SQLITE_STATIC);
468 [ - + ]: 1 : if (rc != SQLITE_OK) {
469 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind hash " << hashstr <<
[ # # ][ # # ]
470 : : " to SQL statement (previous NSEC3)");
471 : : }
472 : :
473 : 1 : rc = sqlite3_step(dbparameters->q_prevnsec3_);
474 : : const char* hash;
475 [ + - ]: 1 : if (rc == SQLITE_ROW) {
476 : 1 : hash = (const char*) sqlite3_column_text(dbparameters->q_prevnsec3_, 0);
477 : : } else {
478 : : // We need to find the final NSEC3 in the chain.
479 : : // A valid NSEC3 hash is in base32, which contains no
480 : : // letters higher than V, so a search for the previous
481 : : // NSEC3 from "w" will always find it.
482 : 0 : sqlite3_reset(dbparameters->q_prevnsec3_);
483 : : rc = sqlite3_bind_text(dbparameters->q_prevnsec3_, 2, "w", -1,
484 : 0 : SQLITE_STATIC);
485 [ # # ]: 0 : if (rc != SQLITE_OK) {
486 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind \"w\""
487 : : " to SQL statement (previous NSEC3)");
488 : : }
489 : :
490 : 0 : rc = sqlite3_step(dbparameters->q_prevnsec3_);
491 [ # # ]: 0 : if (rc != SQLITE_ROW) {
492 : : return (ERROR);
493 : : }
494 : :
495 : 0 : hash = (const char*) sqlite3_column_text(dbparameters->q_prevnsec3_, 0);
496 : : }
497 : :
498 : 1 : sqlite3_reset(dbparameters->q_nsec3_);
499 : 1 : sqlite3_clear_bindings(dbparameters->q_nsec3_);
500 : :
501 : 1 : rc = sqlite3_bind_int(dbparameters->q_nsec3_, 1, zone_id);
502 [ - + ]: 1 : if (rc != SQLITE_OK) {
503 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
[ # # ][ # # ]
504 : : " to SQL statement (NSEC3)");
505 : : }
506 : :
507 : 1 : rc = sqlite3_bind_text(dbparameters->q_nsec3_, 2, hash, -1, SQLITE_STATIC);
508 [ - + ]: 1 : if (rc != SQLITE_OK) {
509 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not bind hash " << hash <<
[ # # ][ # # ]
510 : : " to SQL statement (NSEC3)");
511 : : }
512 : :
513 : 1 : DataSrc::Result result = SUCCESS;
514 : 1 : uint32_t flags = 0;
515 [ + - ][ + - ]: 2 : if (importSqlite3Rows(dbparameters->q_nsec3_,
[ - + ]
516 : 1 : Name(hash).concatenate(zonename),
517 : 1 : getClass(), RRType::NSEC3(), true, target,
518 [ + - ][ + - ]: 1 : flags) == 0 || flags != 0) {
[ + - ][ + - ]
[ # # ][ # # ]
[ # # ]
519 : 0 : result = ERROR;
520 : : }
521 : 2 : hashstr = string(hash);
522 : 1 : sqlite3_reset(dbparameters->q_nsec3_);
523 : 1 : return (result);
524 : : }
525 : :
526 : : DataSrc::Result
527 : 51 : Sqlite3DataSrc::findRRset(const Name& qname,
528 : : const RRClass& qclass,
529 : : const RRType& qtype,
530 : : RRsetList& target,
531 : : uint32_t& flags,
532 : : const Name* zonename) const
533 : : {
534 [ + - ][ + - ]: 102 : LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FIND).arg(qname).
535 [ + - ]: 51 : arg(qtype);
536 [ + + ][ + + ]: 51 : if (qclass != getClass() && qclass != RRClass::ANY()) {
[ + + ]
537 [ + - ][ + - ]: 2 : LOG_ERROR(logger, DATASRC_SQLITE_FIND_BAD_CLASS).arg(getClass()).
538 [ + - ]: 1 : arg(qclass);
539 : : return (ERROR);
540 : : }
541 : 50 : findRecords(qname, qtype, target, zonename, NORMAL, flags);
542 : 50 : return (SUCCESS);
543 : : }
544 : :
545 : : DataSrc::Result
546 : 10 : Sqlite3DataSrc::findExactRRset(const Name& qname,
547 : : const RRClass& qclass,
548 : : const RRType& qtype,
549 : : RRsetList& target,
550 : : uint32_t& flags,
551 : : const Name* zonename) const
552 : : {
553 [ + - ][ + - ]: 20 : LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDEXACT).arg(qname).
554 [ + - ]: 10 : arg(qtype);
555 [ + + ][ + + ]: 10 : if (qclass != getClass() && qclass != RRClass::ANY()) {
[ + + ]
556 [ + - ][ + - ]: 2 : LOG_ERROR(logger, DATASRC_SQLITE_FINDEXACT_BAD_CLASS).arg(getClass()).
557 [ + - ]: 1 : arg(qclass);
558 : : return (ERROR);
559 : : }
560 : 9 : findRecords(qname, qtype, target, zonename, NORMAL, flags);
561 : :
562 : : // Ignore referrals in this case
563 : 9 : flags &= ~REFERRAL;
564 : :
565 : : // CNAMEs don't count in this case
566 [ + + ]: 9 : if (flags & CNAME_FOUND) {
567 : 1 : flags &= ~CNAME_FOUND;
568 : 10 : flags |= TYPE_NOT_FOUND;
569 : : }
570 : :
571 : : return (SUCCESS);
572 : : }
573 : :
574 : : DataSrc::Result
575 : 15 : Sqlite3DataSrc::findAddrs(const Name& qname,
576 : : const RRClass& qclass,
577 : : RRsetList& target,
578 : : uint32_t& flags,
579 : : const Name* zonename) const
580 : : {
581 [ + - ][ + - ]: 15 : LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDADDRS).arg(qname);
582 [ + + ][ + + ]: 15 : if (qclass != getClass() && qclass != RRClass::ANY()) {
[ + + ]
583 [ + - ][ + - ]: 2 : LOG_ERROR(logger, DATASRC_SQLITE_FINDADDRS_BAD_CLASS).arg(getClass()).
584 [ + - ]: 1 : arg(qclass);
585 : : return (ERROR);
586 : : }
587 : 14 : findRecords(qname, RRType::ANY(), target, zonename, ADDRESS, flags);
588 : 15 : return (SUCCESS);
589 : : }
590 : :
591 : : DataSrc::Result
592 : 16 : Sqlite3DataSrc::findReferral(const Name& qname,
593 : : const RRClass& qclass,
594 : : RRsetList& target,
595 : : uint32_t& flags,
596 : : const Name* zonename) const
597 : : {
598 [ + - ][ + - ]: 16 : LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDREF).arg(qname);
599 [ + + ][ + + ]: 16 : if (qclass != getClass() && qclass != RRClass::ANY()) {
[ + + ]
600 [ + - ][ + - ]: 2 : LOG_ERROR(logger, DATASRC_SQLITE_FINDREF_BAD_CLASS).arg(getClass()).
601 [ + - ]: 1 : arg(qclass);
602 : : return (ERROR);
603 : : }
604 : 15 : findRecords(qname, RRType::ANY(), target, zonename, DELEGATION, flags);
605 : 16 : return (SUCCESS);
606 : : }
607 : :
608 : 94 : Sqlite3DataSrc::Sqlite3DataSrc() :
609 [ + - ]: 94 : dbparameters(new Sqlite3Parameters)
610 : : {
611 [ + - ][ + - ]: 94 : LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CREATE);
[ + - ][ + - ]
612 : 94 : }
613 : :
614 : 144 : Sqlite3DataSrc::~Sqlite3DataSrc() {
615 [ + - ][ + - ]: 94 : LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_DESTROY);
[ + - ][ + - ]
616 [ + + ]: 94 : if (dbparameters->db_ != NULL) {
617 [ + - ]: 89 : close();
618 : : }
619 : 94 : delete dbparameters;
620 : 144 : }
621 : :
622 : : DataSrc::Result
623 : 103 : Sqlite3DataSrc::init(isc::data::ConstElementPtr config) {
624 [ + - ][ + - ]: 103 : if (config && config->contains("database_file")) {
[ + - ][ - + ]
[ + - ][ + - ]
[ # # ]
625 [ + - ][ + - ]: 206 : open(config->get("database_file")->stringValue());
[ + + ]
626 : : } else {
627 [ # # ]: 0 : isc_throw(DataSourceError, "No SQLite database file specified");
628 : : }
629 : 97 : return (SUCCESS);
630 : : }
631 : :
632 : : namespace {
633 : : // This is a helper class to initialize a Sqlite3 DB safely. An object of
634 : : // this class encapsulates all temporary resources that are necessary for
635 : : // the initialization, and release them in the destructor. Once everything
636 : : // is properly initialized, the move() method moves the allocated resources
637 : : // to the main object in an exception free manner. This way, the main code
638 : : // for the initialization can be exception safe, and can provide the strong
639 : : // exception guarantee.
640 : 102 : class Sqlite3Initializer {
641 : : public:
642 : 102 : ~Sqlite3Initializer() {
643 [ - + ]: 102 : if (params_.q_zone_ != NULL) {
644 : 0 : sqlite3_finalize(params_.q_zone_);
645 : : }
646 [ - + ]: 102 : if (params_.q_record_ != NULL) {
647 : 0 : sqlite3_finalize(params_.q_record_);
648 : : }
649 [ - + ]: 102 : if (params_.q_addrs_ != NULL) {
650 : 0 : sqlite3_finalize(params_.q_addrs_);
651 : : }
652 [ - + ]: 102 : if (params_.q_referral_ != NULL) {
653 : 0 : sqlite3_finalize(params_.q_referral_);
654 : : }
655 [ - + ]: 102 : if (params_.q_any_ != NULL) {
656 : 0 : sqlite3_finalize(params_.q_any_);
657 : : }
658 [ - + ]: 102 : if (params_.q_count_ != NULL) {
659 : 0 : sqlite3_finalize(params_.q_count_);
660 : : }
661 [ - + ]: 102 : if (params_.q_previous_ != NULL) {
662 : 0 : sqlite3_finalize(params_.q_previous_);
663 : : }
664 [ - + ]: 102 : if (params_.q_nsec3_ != NULL) {
665 : 0 : sqlite3_finalize(params_.q_nsec3_);
666 : : }
667 [ - + ]: 102 : if (params_.q_prevnsec3_ != NULL) {
668 : 0 : sqlite3_finalize(params_.q_prevnsec3_);
669 : : }
670 [ + + ]: 102 : if (params_.db_ != NULL) {
671 : 5 : sqlite3_close(params_.db_);
672 : : }
673 : 102 : }
674 : : void move(Sqlite3Parameters* dst) {
675 : 97 : *dst = params_;
676 : 97 : params_ = Sqlite3Parameters(); // clear everything
677 : : }
678 : : Sqlite3Parameters params_;
679 : : };
680 : :
681 : : sqlite3_stmt*
682 : 873 : prepare(sqlite3* const db, const char* const statement) {
683 : 873 : sqlite3_stmt* prepared = NULL;
684 [ - + ]: 873 : if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) {
685 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Could not prepare SQLite statement: " <<
[ # # ]
686 : : statement);
687 : : }
688 : 873 : return (prepared);
689 : : }
690 : :
691 : : // small function to sleep for 0.1 seconds, needed when waiting for
692 : : // exclusive database locks (which should only occur on startup, and only
693 : : // when the database has not been created yet)
694 : 0 : void do_sleep() {
695 : : struct timespec req;
696 : 0 : req.tv_sec = 0;
697 : 0 : req.tv_nsec = 100000000;
698 : 0 : nanosleep(&req, NULL);
699 : 0 : }
700 : :
701 : : // returns the schema version element if the schema version table exists
702 : : // returns -1 if it does not
703 : 200 : int check_schema_version_element(sqlite3* db, const char* const version_query) {
704 : 200 : sqlite3_stmt* prepared = NULL;
705 : : // At this point in time, the database might be exclusively locked, in
706 : : // which case even prepare() will return BUSY, so we may need to try a
707 : : // few times
708 [ + - ]: 200 : for (size_t i = 0; i < 50; ++i) {
709 : 200 : int rc = sqlite3_prepare_v2(db, version_query, -1, &prepared, NULL);
710 [ + + ]: 200 : if (rc == SQLITE_ERROR) {
711 : : // this is the error that is returned when the table does not
712 : : // exist
713 : : return (-1);
714 [ - + ]: 198 : } else if (rc == SQLITE_OK) {
715 : : break;
716 [ # # ]: 0 : } else if (rc != SQLITE_BUSY || i == 50) {
717 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Unable to prepare version query: "
[ # # ][ # # ]
[ # # ][ # # ]
718 : : << rc << " " << sqlite3_errmsg(db));
719 : : }
720 : 0 : do_sleep();
721 : : }
722 [ + + ]: 198 : if (sqlite3_step(prepared) != SQLITE_ROW) {
723 [ + - ][ + - ]: 2 : isc_throw(Sqlite3Error,
[ + - ][ + - ]
724 : : "Unable to query version: " << sqlite3_errmsg(db));
725 : : }
726 : 197 : int version = sqlite3_column_int(prepared, 0);
727 : 197 : sqlite3_finalize(prepared);
728 : 199 : return (version);
729 : : }
730 : :
731 : : // Returns the schema major and minor version numbers in a pair.
732 : : // Returns (-1, -1) if the table does not exist, (1, 0) for a V1
733 : : // database, and (n, m) for any other.
734 : 102 : pair<int, int> check_schema_version(sqlite3* db) {
735 : 102 : int major = check_schema_version_element(db, q_version_str);
736 [ + + ]: 101 : if (major == -1) {
737 : : return (make_pair(-1, -1));
738 [ + + ]: 99 : } else if (major == 1) {
739 : : return (make_pair(1, 0));
740 : : } else {
741 : 98 : int minor = check_schema_version_element(db, q_minor_str);
742 : : return (make_pair(major, minor));
743 : : }
744 : : }
745 : :
746 : : // A helper class used in create_database() below so we manage the one shot
747 : : // transaction safely.
748 : : class ScopedTransaction {
749 : : public:
750 : 1 : ScopedTransaction(sqlite3* db) : db_(NULL) {
751 : : // try for 5 secs (50*0.1)
752 [ + - ]: 1 : for (size_t i = 0; i < 50; ++i) {
753 : : const int rc = sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION",
754 : 1 : NULL, NULL, NULL);
755 [ - + ]: 1 : if (rc == SQLITE_OK) {
756 : : break;
757 [ # # ]: 0 : } else if (rc != SQLITE_BUSY || i == 50) {
758 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Unable to acquire exclusive lock "
[ # # ][ # # ]
759 : : "for database creation: " << sqlite3_errmsg(db));
760 : : }
761 : 0 : do_sleep();
762 : : }
763 : : // Hold the DB pointer once we have successfully acquired the lock.
764 : 1 : db_ = db;
765 : : }
766 : 1 : ~ScopedTransaction() {
767 [ - + ]: 1 : if (db_ != NULL) {
768 : : // Note: even rollback could fail in theory, but in that case
769 : : // we cannot do much for safe recovery anyway. We could at least
770 : : // log the event, but for now don't even bother to do that, with
771 : : // the expectation that we'll soon stop creating the schema in this
772 : : // module.
773 : 0 : sqlite3_exec(db_, "ROLLBACK", NULL, NULL, NULL);
774 : : }
775 : 1 : }
776 : : void commit() {
777 [ + - ][ - + ]: 1 : if (sqlite3_exec(db_, "COMMIT TRANSACTION", NULL, NULL, NULL) !=
778 : : SQLITE_OK) {
779 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error, "Unable to commit newly created database "
[ # # ][ # # ]
[ # # ]
780 : : "schema: " << sqlite3_errmsg(db_));
781 : : }
782 : 1 : db_ = NULL;
783 : : }
784 : :
785 : : private:
786 : : sqlite3* db_;
787 : : };
788 : :
789 : : // return db version
790 : 1 : pair<int, int> create_database(sqlite3* db) {
791 : 1 : logger.info(DATASRC_SQLITE_SETUP);
792 : :
793 : : // try to get an exclusive lock. Once that is obtained, do the version
794 : : // check *again*, just in case this process was racing another
795 : 1 : ScopedTransaction transaction(db);
796 [ + - ]: 1 : pair<int, int> schema_version = check_schema_version(db);
797 [ + - ]: 1 : if (schema_version.first == -1) {
798 [ + + ]: 12 : for (int i = 0; SCHEMA_LIST[i] != NULL; ++i) {
799 [ + - ][ - + ]: 11 : if (sqlite3_exec(db, SCHEMA_LIST[i], NULL, NULL, NULL) !=
800 : : SQLITE_OK) {
801 [ # # ][ # # ]: 0 : isc_throw(Sqlite3Error,
[ # # ][ # # ]
802 : : "Failed to set up schema " << SCHEMA_LIST[i]);
803 : : }
804 : : }
805 : : transaction.commit();
806 : :
807 : : // Return the version. We query again to ensure that the only point
808 : : // in which the current schema version is defined is in the
809 : : // CREATE statements.
810 [ + - ]: 1 : schema_version = check_schema_version(db);
811 : : }
812 : 1 : return (schema_version);
813 : : }
814 : :
815 : : void
816 : 100 : checkAndSetupSchema(Sqlite3Initializer* initializer) {
817 : 100 : sqlite3* const db = initializer->params_.db_;
818 : :
819 : : // Note: we use the same SCHEMA_xxx_VERSION log IDs here and in
820 : : // sqlite3_accessor.cc, which is against our policy of ID uniqueness.
821 : : // The assumption is that this file will soon be deprecated, and we don't
822 : : // bother to define separate IDs for the short period.
823 : 100 : pair<int, int> schema_version = check_schema_version(db);
824 [ + + ]: 99 : if (schema_version.first == -1) {
825 : 1 : schema_version = create_database(db);
826 [ + + ]: 98 : } else if (schema_version.first != SQLITE_SCHEMA_MAJOR_VERSION) {
827 [ + - ]: 4 : LOG_ERROR(logger, DATASRC_SQLITE_INCOMPATIBLE_VERSION)
828 [ + - ][ + - ]: 2 : .arg(schema_version.first).arg(schema_version.second)
829 [ + - ][ + - ]: 2 : .arg(SQLITE_SCHEMA_MAJOR_VERSION).arg(SQLITE_SCHEMA_MINOR_VERSION);
830 [ + - ]: 4 : isc_throw(IncompatibleDbVersion, "Incompatible database version");
831 [ - + ]: 96 : } else if (schema_version.second < SQLITE_SCHEMA_MINOR_VERSION) {
832 [ # # ]: 0 : LOG_WARN(logger, DATASRC_SQLITE_COMPATIBLE_VERSION)
833 [ # # ][ # # ]: 0 : .arg(schema_version.first).arg(schema_version.second)
834 [ # # ][ # # ]: 0 : .arg(SQLITE_SCHEMA_MAJOR_VERSION).arg(SQLITE_SCHEMA_MINOR_VERSION);
835 : : }
836 : :
837 : 97 : initializer->params_.major_version_ = schema_version.first;
838 : 97 : initializer->params_.minor_version_ = schema_version.second;
839 : 97 : initializer->params_.q_zone_ = prepare(db, q_zone_str);
840 : 97 : initializer->params_.q_record_ = prepare(db, q_record_str);
841 : 97 : initializer->params_.q_addrs_ = prepare(db, q_addrs_str);
842 : 97 : initializer->params_.q_referral_ = prepare(db, q_referral_str);
843 : 97 : initializer->params_.q_any_ = prepare(db, q_any_str);
844 : 97 : initializer->params_.q_count_ = prepare(db, q_count_str);
845 : 97 : initializer->params_.q_previous_ = prepare(db, q_previous_str);
846 : 97 : initializer->params_.q_nsec3_ = prepare(db, q_nsec3_str);
847 : 97 : initializer->params_.q_prevnsec3_ = prepare(db, q_prevnsec3_str);
848 : 97 : }
849 : : }
850 : :
851 : : //
852 : : // Open the database.
853 : : //
854 : : void
855 : 103 : Sqlite3DataSrc::open(const string& name) {
856 [ + - ][ + - ]: 103 : LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_OPEN).arg(name);
857 [ + + ]: 103 : if (dbparameters->db_ != NULL) {
858 [ + - ][ + - ]: 2 : isc_throw(DataSourceError, "Duplicate SQLite open with " << name);
859 : : }
860 : :
861 : 102 : Sqlite3Initializer initializer;
862 : :
863 [ + - ][ + + ]: 102 : if (sqlite3_open(name.c_str(), &initializer.params_.db_) != 0) {
864 [ + - ][ + - ]: 4 : isc_throw(Sqlite3Error, "Cannot open SQLite database file: " << name);
[ + - ][ + - ]
865 : : }
866 : :
867 [ + + ]: 100 : checkAndSetupSchema(&initializer);
868 : 97 : initializer.move(dbparameters);
869 : 97 : }
870 : :
871 : : //
872 : : // Close the database.
873 : : //
874 : : DataSrc::Result
875 : 98 : Sqlite3DataSrc::close(void) {
876 [ + - ]: 98 : LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CLOSE);
877 [ + + ]: 98 : if (dbparameters->db_ == NULL) {
878 [ + - ]: 2 : isc_throw(DataSourceError,
879 : : "SQLite data source is being closed before open");
880 : : }
881 : :
882 : : // XXX: sqlite3_finalize() could fail. What should we do in that case?
883 : 97 : sqlite3_finalize(dbparameters->q_zone_);
884 : 97 : dbparameters->q_zone_ = NULL;
885 : :
886 : 97 : sqlite3_finalize(dbparameters->q_record_);
887 : 97 : dbparameters->q_record_ = NULL;
888 : :
889 : 97 : sqlite3_finalize(dbparameters->q_addrs_);
890 : 97 : dbparameters->q_addrs_ = NULL;
891 : :
892 : 97 : sqlite3_finalize(dbparameters->q_referral_);
893 : 97 : dbparameters->q_referral_ = NULL;
894 : :
895 : 97 : sqlite3_finalize(dbparameters->q_any_);
896 : 97 : dbparameters->q_any_ = NULL;
897 : :
898 : 97 : sqlite3_finalize(dbparameters->q_count_);
899 : 97 : dbparameters->q_count_ = NULL;
900 : :
901 : 97 : sqlite3_finalize(dbparameters->q_previous_);
902 : 97 : dbparameters->q_previous_ = NULL;
903 : :
904 : 97 : sqlite3_finalize(dbparameters->q_prevnsec3_);
905 : 97 : dbparameters->q_prevnsec3_ = NULL;
906 : :
907 : 97 : sqlite3_finalize(dbparameters->q_nsec3_);
908 : 97 : dbparameters->q_nsec3_ = NULL;
909 : :
910 : 97 : sqlite3_close(dbparameters->db_);
911 : 97 : dbparameters->db_ = NULL;
912 : :
913 : 97 : return (SUCCESS);
914 : : }
915 : :
916 : : }
917 : 208 : }
|