blob: ef5f23c39e4ba423599d8f85e4d0e9e6af316851 [file] [log] [blame]
Shock Jiang3016c982014-11-11 11:35:17 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yumin Xia2c509c22017-02-09 14:37:36 -08002/*
Davide Pesavento093ce1c2019-01-21 19:22:42 -05003 * Copyright (c) 2014-2019, Regents of the University of California.
Shock Jiang3016c982014-11-11 11:35:17 -08004 *
5 * This file is part of NDNS (Named Data Networking Domain Name Service).
6 * See AUTHORS.md for complete list of NDNS authors and contributors.
7 *
8 * NDNS is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * NDNS, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "db-mgr.hpp"
21#include "logger.hpp"
22#include "clients/response.hpp"
23
Shock Jiang3016c982014-11-11 11:35:17 -080024namespace ndn {
25namespace ndns {
26
Alexander Afanasyev08d18742018-03-15 16:31:28 -040027NDNS_LOG_INIT(DbMgr);
Shock Jiang3016c982014-11-11 11:35:17 -080028
Yumin Xia2c509c22017-02-09 14:37:36 -080029static const std::string NDNS_SCHEMA = R"VALUE(
30CREATE TABLE IF NOT EXISTS zones (
31 id INTEGER NOT NULL PRIMARY KEY,
32 name blob NOT NULL UNIQUE,
33 ttl integer(10) NOT NULL);
34
35CREATE TABLE IF NOT EXISTS zone_info (
36 zone_id INTEGER NOT NULL,
37 key VARCHAR(10) NOT NULL,
38 value blob NOT NULL,
39 PRIMARY KEY (zone_id, key),
40 FOREIGN KEY(zone_id) REFERENCES zones(id) ON UPDATE Cascade ON DELETE Cascade);
41
42CREATE TABLE IF NOT EXISTS rrsets (
43 id INTEGER NOT NULL PRIMARY KEY,
44 zone_id integer(10) NOT NULL,
45 label blob NOT NULL,
46 type blob NOT NULL,
47 version blob NOT NULL,
48 ttl integer(10) NOT NULL,
49 data blob NOT NULL,
50 FOREIGN KEY(zone_id) REFERENCES zones(id) ON UPDATE Cascade ON DELETE Cascade);
51
52CREATE UNIQUE INDEX rrsets_zone_id_label_type_version
53 ON rrsets (zone_id, label, type, version);
54)VALUE";
Shock Jiang3016c982014-11-11 11:35:17 -080055
56DbMgr::DbMgr(const std::string& dbFile/* = DEFAULT_CONFIG_PATH "/" "ndns.db"*/)
57 : m_dbFile(dbFile)
Davide Pesavento093ce1c2019-01-21 19:22:42 -050058 , m_conn(nullptr)
Shock Jiang3016c982014-11-11 11:35:17 -080059{
60 if (dbFile.empty())
61 m_dbFile = DEFAULT_DATABASE_PATH "/" "ndns.db";
62
Davide Pesavento093ce1c2019-01-21 19:22:42 -050063 open();
Shock Jiang3016c982014-11-11 11:35:17 -080064
65 NDNS_LOG_INFO("open database: " << m_dbFile);
66}
67
Shock Jiang3016c982014-11-11 11:35:17 -080068DbMgr::~DbMgr()
69{
Davide Pesavento093ce1c2019-01-21 19:22:42 -050070 close();
Shock Jiang3016c982014-11-11 11:35:17 -080071}
72
73void
74DbMgr::open()
75{
Davide Pesavento093ce1c2019-01-21 19:22:42 -050076 int res = sqlite3_open_v2(m_dbFile.data(), &m_conn,
Shock Jiang3016c982014-11-11 11:35:17 -080077 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
78#ifdef DISABLE_SQLITE3_FS_LOCKING
79 "unix-dotfile"
80#else
Davide Pesavento093ce1c2019-01-21 19:22:42 -050081 nullptr
Shock Jiang3016c982014-11-11 11:35:17 -080082#endif
83 );
84
85 if (res != SQLITE_OK) {
86 NDNS_LOG_FATAL("Cannot open the db file: " << m_dbFile);
Yumin Xia2c509c22017-02-09 14:37:36 -080087 BOOST_THROW_EXCEPTION(ConnectError("Cannot open the db file: " + m_dbFile));
Shock Jiang3016c982014-11-11 11:35:17 -080088 }
Davide Pesavento093ce1c2019-01-21 19:22:42 -050089
Shock Jiang3016c982014-11-11 11:35:17 -080090 // ignore any errors from DB creation (command will fail for the existing database, which is ok)
Davide Pesavento093ce1c2019-01-21 19:22:42 -050091 sqlite3_exec(m_conn, NDNS_SCHEMA.data(), nullptr, nullptr, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -080092}
93
94void
95DbMgr::close()
96{
Davide Pesavento093ce1c2019-01-21 19:22:42 -050097 if (m_conn == nullptr)
Shock Jiang3016c982014-11-11 11:35:17 -080098 return;
99
100 int ret = sqlite3_close(m_conn);
101 if (ret != SQLITE_OK) {
102 NDNS_LOG_FATAL("Cannot close the db: " << m_dbFile);
103 }
104 else {
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500105 m_conn = nullptr;
Shock Jiang3016c982014-11-11 11:35:17 -0800106 NDNS_LOG_INFO("Close database: " << m_dbFile);
107 }
108}
109
110void
111DbMgr::clearAllData()
112{
113 const char* sql = "DELETE FROM zones; DELETE FROM rrsets;";
114
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500115 // sqlite3_step cannot execute multiple SQL statements
116 int rc = sqlite3_exec(m_conn, sql, nullptr, nullptr, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800117 if (rc != SQLITE_OK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800118 BOOST_THROW_EXCEPTION(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800119 }
120
121 NDNS_LOG_INFO("clear all the data in the database: " << m_dbFile);
122}
123
Yumin Xia55a7cc42017-05-14 18:43:34 -0700124void
125DbMgr::saveName(const Name& name, sqlite3_stmt* stmt, int iCol, bool isStatic)
126{
127 const Block& wire = name.wireEncode();
128 sqlite3_bind_blob(stmt, iCol, wire.value(), wire.value_size(), isStatic ? SQLITE_STATIC : SQLITE_TRANSIENT);
129}
130
131Name
132DbMgr::restoreName(sqlite3_stmt* stmt, int iCol)
133{
134 Name name;
135
136 const uint8_t* buffer = static_cast<const uint8_t*>(sqlite3_column_blob(stmt, iCol));
137 size_t nBytesLeft = sqlite3_column_bytes(stmt, iCol);
138
139 while (nBytesLeft > 0) {
140 bool hasDecodingSucceeded;
141 name::Component component;
142 std::tie(hasDecodingSucceeded, component) = Block::fromBuffer(buffer, nBytesLeft);
143 if (!hasDecodingSucceeded) {
144 BOOST_THROW_EXCEPTION(Error("Error while decoding name from the database"));
145 }
146 name.append(component);
147 buffer += component.size();
148 nBytesLeft -= component.size();
149 }
150
151 return name;
152}
153
Shock Jiang3016c982014-11-11 11:35:17 -0800154///////////////////////////////////////////////////////////////////////////////////////////////////
155// Zone
156///////////////////////////////////////////////////////////////////////////////////////////////////
157
158void
159DbMgr::insert(Zone& zone)
160{
161 if (zone.getId() > 0)
162 return;
163
164 sqlite3_stmt* stmt;
165 const char* sql = "INSERT INTO zones (name, ttl) VALUES (?, ?)";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500166 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800167 if (rc != SQLITE_OK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800168 BOOST_THROW_EXCEPTION(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800169 }
170
Yumin Xia55a7cc42017-05-14 18:43:34 -0700171 saveName(zone.getName(), stmt, 1);
Shock Jiang3016c982014-11-11 11:35:17 -0800172 sqlite3_bind_int(stmt, 2, zone.getTtl().count());
173
174 rc = sqlite3_step(stmt);
175 if (rc != SQLITE_DONE) {
176 sqlite3_finalize(stmt);
Yumin Xia2c509c22017-02-09 14:37:36 -0800177 BOOST_THROW_EXCEPTION(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800178 }
179
180 zone.setId(sqlite3_last_insert_rowid(m_conn));
181 sqlite3_finalize(stmt);
182}
183
Yumin Xia2c509c22017-02-09 14:37:36 -0800184void
185DbMgr::setZoneInfo(Zone& zone,
186 const std::string& key,
187 const Block& value)
188{
189 if (zone.getId() == 0) {
190 BOOST_THROW_EXCEPTION(Error("zone has not been initialized"));
191 }
192
193 if (key.length() > 10) {
194 BOOST_THROW_EXCEPTION(Error("key length should not exceed 10"));
195 }
196
197 sqlite3_stmt* stmt;
198 const char* sql = "INSERT OR REPLACE INTO zone_info (zone_id, key, value) VALUES (?, ?, ?)";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500199 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia2c509c22017-02-09 14:37:36 -0800200 if (rc != SQLITE_OK) {
201 BOOST_THROW_EXCEPTION(PrepareError(sql));
202 }
203
204 sqlite3_bind_int(stmt, 1, zone.getId());
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500205 sqlite3_bind_text(stmt, 2, key.data(), key.length(), SQLITE_STATIC);
Yumin Xia2c509c22017-02-09 14:37:36 -0800206 sqlite3_bind_blob(stmt, 3, value.wire(), value.size(), SQLITE_STATIC);
207
208 rc = sqlite3_step(stmt);
209 if (rc != SQLITE_DONE) {
210 sqlite3_finalize(stmt);
211 BOOST_THROW_EXCEPTION(ExecuteError(sql));
212 }
213
214 sqlite3_finalize(stmt);
215}
216
217std::map<std::string, Block>
218DbMgr::getZoneInfo(Zone& zone)
219{
220 using std::string;
221 std::map<string, Block> rtn;
222
223 if (zone.getId() == 0) {
224 find(zone);
225 }
226
227 if (zone.getId() == 0) {
228 BOOST_THROW_EXCEPTION(Error("zone has not been initialized"));
229 }
230
231 sqlite3_stmt* stmt;
232 const char* sql = "SELECT key, value FROM zone_info WHERE zone_id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500233 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia2c509c22017-02-09 14:37:36 -0800234 if (rc != SQLITE_OK) {
235 BOOST_THROW_EXCEPTION(PrepareError(sql));
236 }
237
238 sqlite3_bind_int(stmt, 1, zone.getId());
239
240 while (sqlite3_step(stmt) == SQLITE_ROW) {
241 const char* key = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
242 rtn[string(key)] = Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 1)),
243 sqlite3_column_bytes(stmt, 1));
244 }
245
246 sqlite3_finalize(stmt);
247 return rtn;
248}
249
Shock Jiang3016c982014-11-11 11:35:17 -0800250bool
251DbMgr::find(Zone& zone)
252{
253 sqlite3_stmt* stmt;
254 const char* sql = "SELECT id, ttl FROM zones WHERE name=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500255 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800256 if (rc != SQLITE_OK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800257 BOOST_THROW_EXCEPTION(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800258 }
259
Yumin Xia55a7cc42017-05-14 18:43:34 -0700260 saveName(zone.getName(), stmt, 1);
Shock Jiang3016c982014-11-11 11:35:17 -0800261
262 if (sqlite3_step(stmt) == SQLITE_ROW) {
263 zone.setId(sqlite3_column_int64(stmt, 0));
264 zone.setTtl(time::seconds(sqlite3_column_int(stmt, 1)));
Yumin Xia2c509c22017-02-09 14:37:36 -0800265 }
266 else {
Shock Jiang3016c982014-11-11 11:35:17 -0800267 zone.setId(0);
268 }
269
270 sqlite3_finalize(stmt);
271
272 return zone.getId() != 0;
273}
274
Jiewen Tan870b29b2014-11-17 19:09:49 -0800275std::vector<Zone>
276DbMgr::listZones()
277{
278 sqlite3_stmt* stmt;
279 const char* sql = "SELECT id, name, ttl FROM zones";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500280 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800281 if (rc != SQLITE_OK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800282 BOOST_THROW_EXCEPTION(PrepareError(sql));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800283 }
284
285 std::vector<Zone> vec;
286
287 while (sqlite3_step(stmt) == SQLITE_ROW) {
288 vec.emplace_back();
289 Zone& zone = vec.back();
290 zone.setId(sqlite3_column_int64(stmt, 0));
291 zone.setTtl(time::seconds(sqlite3_column_int(stmt, 2)));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700292 zone.setName(restoreName(stmt, 1));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800293 }
294 sqlite3_finalize(stmt);
295
296 return vec;
297}
298
Shock Jiang3016c982014-11-11 11:35:17 -0800299void
300DbMgr::remove(Zone& zone)
301{
302 if (zone.getId() == 0)
303 return;
304
305 sqlite3_stmt* stmt;
306 const char* sql = "DELETE FROM zones where id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500307 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800308 if (rc != SQLITE_OK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800309 BOOST_THROW_EXCEPTION(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800310 }
311
312 sqlite3_bind_int64(stmt, 1, zone.getId());
313
314 rc = sqlite3_step(stmt);
315 if (rc != SQLITE_DONE) {
316 sqlite3_finalize(stmt);
Yumin Xia2c509c22017-02-09 14:37:36 -0800317 BOOST_THROW_EXCEPTION(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800318 }
319
320 sqlite3_finalize(stmt);
321
322 zone = Zone();
323}
324
Shock Jiang3016c982014-11-11 11:35:17 -0800325///////////////////////////////////////////////////////////////////////////////////////////////////
326// Rrset
327///////////////////////////////////////////////////////////////////////////////////////////////////
328
329void
330DbMgr::insert(Rrset& rrset)
331{
332 if (rrset.getId() != 0)
333 return;
334
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500335 if (rrset.getZone() == nullptr) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800336 BOOST_THROW_EXCEPTION(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800337 }
338
339 if (rrset.getZone()->getId() == 0) {
340 insert(*rrset.getZone());
341 }
342
343 const char* sql =
344 "INSERT INTO rrsets (zone_id, label, type, version, ttl, data)"
345 " VALUES (?, ?, ?, ?, ?, ?)";
346
347 sqlite3_stmt* stmt;
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500348 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800349 if (rc != SQLITE_OK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800350 BOOST_THROW_EXCEPTION(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800351 }
352
353 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
354
Yumin Xia55a7cc42017-05-14 18:43:34 -0700355 saveName(rrset.getLabel(), stmt, 2);
Shock Jiang3016c982014-11-11 11:35:17 -0800356 sqlite3_bind_blob(stmt, 3, rrset.getType().wire(), rrset.getType().size(), SQLITE_STATIC);
357 sqlite3_bind_blob(stmt, 4, rrset.getVersion().wire(), rrset.getVersion().size(), SQLITE_STATIC);
358 sqlite3_bind_int64(stmt, 5, rrset.getTtl().count());
359 sqlite3_bind_blob(stmt, 6, rrset.getData().wire(), rrset.getData().size(), SQLITE_STATIC);
360
361 rc = sqlite3_step(stmt);
362 if (rc != SQLITE_DONE) {
363 sqlite3_finalize(stmt);
Yumin Xia2c509c22017-02-09 14:37:36 -0800364 BOOST_THROW_EXCEPTION(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800365 }
366
367 rrset.setId(sqlite3_last_insert_rowid(m_conn));
368 sqlite3_finalize(stmt);
369}
370
371bool
372DbMgr::find(Rrset& rrset)
373{
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500374 if (rrset.getZone() == nullptr) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800375 BOOST_THROW_EXCEPTION(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800376 }
377
378 if (rrset.getZone()->getId() == 0) {
379 bool isFound = find(*rrset.getZone());
380 if (!isFound) {
381 return false;
382 }
383 }
384
385 sqlite3_stmt* stmt;
386 const char* sql =
387 "SELECT id, ttl, version, data FROM rrsets"
388 " WHERE zone_id=? and label=? and type=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500389 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800390 if (rc != SQLITE_OK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800391 BOOST_THROW_EXCEPTION(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800392 }
393
394 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
395
Yumin Xia55a7cc42017-05-14 18:43:34 -0700396 saveName(rrset.getLabel(), stmt, 2);
397 sqlite3_bind_blob(stmt, 3, rrset.getType().wire(), rrset.getType().size(), SQLITE_STATIC);
398
399 if (sqlite3_step(stmt) == SQLITE_ROW) {
400 rrset.setId(sqlite3_column_int64(stmt, 0));
401 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
402 rrset.setVersion(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
403 sqlite3_column_bytes(stmt, 2)));
404 rrset.setData(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
405 sqlite3_column_bytes(stmt, 3)));
406 }
407 else {
408 rrset.setId(0);
409 }
410 sqlite3_finalize(stmt);
411
412 return rrset.getId() != 0;
413}
414
415bool
416DbMgr::findLowerBound(Rrset& rrset)
417{
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500418 if (rrset.getZone() == nullptr) {
Yumin Xia55a7cc42017-05-14 18:43:34 -0700419 BOOST_THROW_EXCEPTION(RrsetError("Rrset has not been assigned to a zone"));
420 }
421
422 if (rrset.getZone()->getId() == 0) {
423 bool isFound = find(*rrset.getZone());
424 if (!isFound) {
425 return false;
426 }
427 }
428
429 sqlite3_stmt* stmt;
430 const char* sql =
431 "SELECT id, ttl, version, data FROM rrsets"
432 " WHERE zone_id=? and label<? and type=? ORDER BY label DESC";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500433 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700434 if (rc != SQLITE_OK) {
435 BOOST_THROW_EXCEPTION(PrepareError(sql));
436 }
437
438 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
439
440 saveName(rrset.getLabel(), stmt, 2);
Shock Jiang3016c982014-11-11 11:35:17 -0800441 sqlite3_bind_blob(stmt, 3, rrset.getType().wire(), rrset.getType().size(), SQLITE_STATIC);
442
443 if (sqlite3_step(stmt) == SQLITE_ROW) {
444 rrset.setId(sqlite3_column_int64(stmt, 0));
445 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
446 rrset.setVersion(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
447 sqlite3_column_bytes(stmt, 2)));
448 rrset.setData(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
449 sqlite3_column_bytes(stmt, 3)));
Yumin Xia2c509c22017-02-09 14:37:36 -0800450 }
451 else {
Shock Jiang3016c982014-11-11 11:35:17 -0800452 rrset.setId(0);
453 }
454 sqlite3_finalize(stmt);
455
456 return rrset.getId() != 0;
457}
458
459std::vector<Rrset>
460DbMgr::findRrsets(Zone& zone)
461{
462 if (zone.getId() == 0)
463 find(zone);
464
465 if (zone.getId() == 0)
Yumin Xia2c509c22017-02-09 14:37:36 -0800466 BOOST_THROW_EXCEPTION(RrsetError("Attempting to find all the rrsets with a zone does not in the database"));
Shock Jiang3016c982014-11-11 11:35:17 -0800467
468 std::vector<Rrset> vec;
469 sqlite3_stmt* stmt;
470 const char* sql = "SELECT id, ttl, version, data, label, type "
Yumin Xia55a7cc42017-05-14 18:43:34 -0700471 "FROM rrsets where zone_id=? ORDER BY label";
Shock Jiang3016c982014-11-11 11:35:17 -0800472
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500473 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800474 if (rc != SQLITE_OK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800475 BOOST_THROW_EXCEPTION(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800476 }
477 sqlite3_bind_int64(stmt, 1, zone.getId());
478
479 while (sqlite3_step(stmt) == SQLITE_ROW) {
480 vec.emplace_back(&zone);
481 Rrset& rrset = vec.back();
482
483 rrset.setId(sqlite3_column_int64(stmt, 0));
484 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
485 rrset.setVersion(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
486 sqlite3_column_bytes(stmt, 2)));
487 rrset.setData(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
488 sqlite3_column_bytes(stmt, 3)));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700489 rrset.setLabel(restoreName(stmt, 4));
Shock Jiang3016c982014-11-11 11:35:17 -0800490 rrset.setType(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 5)),
491 sqlite3_column_bytes(stmt, 5)));
492 }
493 sqlite3_finalize(stmt);
494
495 return vec;
496}
497
Yumin Xia55a7cc42017-05-14 18:43:34 -0700498void
499DbMgr::removeRrsetsOfZoneByType(Zone& zone, const name::Component& type)
500{
501 if (zone.getId() == 0)
502 find(zone);
503
504 if (zone.getId() == 0)
505 BOOST_THROW_EXCEPTION(RrsetError("Attempting to find all the rrsets with a zone does not in the database"));
506
507 sqlite3_stmt* stmt;
508 const char* sql = "DELETE FROM rrsets WHERE zone_id = ? AND type = ?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500509 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700510 if (rc != SQLITE_OK) {
511 BOOST_THROW_EXCEPTION(PrepareError(sql));
512 }
513
514 sqlite3_bind_int64(stmt, 1, zone.getId());
515 sqlite3_bind_blob(stmt, 2, type.wire(), type.size(), SQLITE_STATIC);
516
517 rc = sqlite3_step(stmt);
518 if (rc != SQLITE_DONE) {
519 sqlite3_finalize(stmt);
520 BOOST_THROW_EXCEPTION(ExecuteError(sql));
521 }
522 sqlite3_finalize(stmt);
523}
Shock Jiang3016c982014-11-11 11:35:17 -0800524
525void
526DbMgr::remove(Rrset& rrset)
527{
528 if (rrset.getId() == 0)
Yumin Xia2c509c22017-02-09 14:37:36 -0800529 BOOST_THROW_EXCEPTION(RrsetError("Attempting to remove Rrset that has no assigned id"));
Shock Jiang3016c982014-11-11 11:35:17 -0800530
531 sqlite3_stmt* stmt;
532 const char* sql = "DELETE FROM rrsets WHERE id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500533 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800534 if (rc != SQLITE_OK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800535 BOOST_THROW_EXCEPTION(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800536 }
537
538 sqlite3_bind_int64(stmt, 1, rrset.getId());
539
540 rc = sqlite3_step(stmt);
541 if (rc != SQLITE_DONE) {
542 sqlite3_finalize(stmt);
Yumin Xia2c509c22017-02-09 14:37:36 -0800543 BOOST_THROW_EXCEPTION(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800544 }
545
546 sqlite3_finalize(stmt);
547
548 rrset = Rrset(rrset.getZone());
549}
550
551void
552DbMgr::update(Rrset& rrset)
553{
554 if (rrset.getId() == 0) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800555 BOOST_THROW_EXCEPTION(RrsetError("Attempting to replace Rrset that has no assigned id"));
Shock Jiang3016c982014-11-11 11:35:17 -0800556 }
557
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500558 if (rrset.getZone() == nullptr) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800559 BOOST_THROW_EXCEPTION(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800560 }
561
562 sqlite3_stmt* stmt;
563 const char* sql = "UPDATE rrsets SET ttl=?, version=?, data=? WHERE id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500564 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800565 if (rc != SQLITE_OK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800566 BOOST_THROW_EXCEPTION(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800567 }
568
569 sqlite3_bind_int64(stmt, 1, rrset.getTtl().count());
570 sqlite3_bind_blob(stmt, 2, rrset.getVersion().wire(), rrset.getVersion().size(), SQLITE_STATIC);
571 sqlite3_bind_blob(stmt, 3, rrset.getData().wire(), rrset.getData().size(), SQLITE_STATIC);
572 sqlite3_bind_int64(stmt, 4, rrset.getId());
573
574 sqlite3_step(stmt);
575 sqlite3_finalize(stmt);
576}
577
578} // namespace ndns
579} // namespace ndn