blob: 49dcfa9ab5bf08e4447f3fd0c04fef1b4ff49f1b [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 Pesavento948c50c2020-12-26 21:30:45 -05003 * Copyright (c) 2014-2020, 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"
Davide Pesaventod01c1a42019-01-21 21:42:45 -050023#include "util/util.hpp"
Shock Jiang3016c982014-11-11 11:35:17 -080024
Shock Jiang3016c982014-11-11 11:35:17 -080025namespace ndn {
26namespace ndns {
27
Alexander Afanasyev08d18742018-03-15 16:31:28 -040028NDNS_LOG_INIT(DbMgr);
Shock Jiang3016c982014-11-11 11:35:17 -080029
Yumin Xia2c509c22017-02-09 14:37:36 -080030static const std::string NDNS_SCHEMA = R"VALUE(
31CREATE TABLE IF NOT EXISTS zones (
32 id INTEGER NOT NULL PRIMARY KEY,
33 name blob NOT NULL UNIQUE,
34 ttl integer(10) NOT NULL);
35
36CREATE TABLE IF NOT EXISTS zone_info (
37 zone_id INTEGER NOT NULL,
38 key VARCHAR(10) NOT NULL,
39 value blob NOT NULL,
40 PRIMARY KEY (zone_id, key),
41 FOREIGN KEY(zone_id) REFERENCES zones(id) ON UPDATE Cascade ON DELETE Cascade);
42
43CREATE TABLE IF NOT EXISTS rrsets (
44 id INTEGER NOT NULL PRIMARY KEY,
45 zone_id integer(10) NOT NULL,
46 label blob NOT NULL,
47 type blob NOT NULL,
48 version blob NOT NULL,
49 ttl integer(10) NOT NULL,
50 data blob NOT NULL,
51 FOREIGN KEY(zone_id) REFERENCES zones(id) ON UPDATE Cascade ON DELETE Cascade);
52
53CREATE UNIQUE INDEX rrsets_zone_id_label_type_version
54 ON rrsets (zone_id, label, type, version);
55)VALUE";
Shock Jiang3016c982014-11-11 11:35:17 -080056
Davide Pesaventod01c1a42019-01-21 21:42:45 -050057DbMgr::DbMgr(const std::string& dbFile)
Shock Jiang3016c982014-11-11 11:35:17 -080058 : m_dbFile(dbFile)
Davide Pesavento093ce1c2019-01-21 19:22:42 -050059 , m_conn(nullptr)
Shock Jiang3016c982014-11-11 11:35:17 -080060{
Davide Pesaventod01c1a42019-01-21 21:42:45 -050061 if (m_dbFile.empty())
62 m_dbFile = getDefaultDatabaseFile();
Shock Jiang3016c982014-11-11 11:35:17 -080063
Davide Pesavento093ce1c2019-01-21 19:22:42 -050064 open();
Shock Jiang3016c982014-11-11 11:35:17 -080065
66 NDNS_LOG_INFO("open database: " << m_dbFile);
67}
68
Shock Jiang3016c982014-11-11 11:35:17 -080069DbMgr::~DbMgr()
70{
Davide Pesavento093ce1c2019-01-21 19:22:42 -050071 close();
Shock Jiang3016c982014-11-11 11:35:17 -080072}
73
74void
75DbMgr::open()
76{
Davide Pesavento093ce1c2019-01-21 19:22:42 -050077 int res = sqlite3_open_v2(m_dbFile.data(), &m_conn,
Shock Jiang3016c982014-11-11 11:35:17 -080078 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
79#ifdef DISABLE_SQLITE3_FS_LOCKING
80 "unix-dotfile"
81#else
Davide Pesavento093ce1c2019-01-21 19:22:42 -050082 nullptr
Shock Jiang3016c982014-11-11 11:35:17 -080083#endif
84 );
85
86 if (res != SQLITE_OK) {
87 NDNS_LOG_FATAL("Cannot open the db file: " << m_dbFile);
Davide Pesavento948c50c2020-12-26 21:30:45 -050088 NDN_THROW(ConnectError("Cannot open the db file: " + m_dbFile));
Shock Jiang3016c982014-11-11 11:35:17 -080089 }
Davide Pesavento093ce1c2019-01-21 19:22:42 -050090
Shock Jiang3016c982014-11-11 11:35:17 -080091 // ignore any errors from DB creation (command will fail for the existing database, which is ok)
Davide Pesavento093ce1c2019-01-21 19:22:42 -050092 sqlite3_exec(m_conn, NDNS_SCHEMA.data(), nullptr, nullptr, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -080093}
94
95void
96DbMgr::close()
97{
Davide Pesavento093ce1c2019-01-21 19:22:42 -050098 if (m_conn == nullptr)
Shock Jiang3016c982014-11-11 11:35:17 -080099 return;
100
101 int ret = sqlite3_close(m_conn);
102 if (ret != SQLITE_OK) {
103 NDNS_LOG_FATAL("Cannot close the db: " << m_dbFile);
104 }
105 else {
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500106 m_conn = nullptr;
Shock Jiang3016c982014-11-11 11:35:17 -0800107 NDNS_LOG_INFO("Close database: " << m_dbFile);
108 }
109}
110
111void
112DbMgr::clearAllData()
113{
114 const char* sql = "DELETE FROM zones; DELETE FROM rrsets;";
115
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500116 // sqlite3_step cannot execute multiple SQL statements
117 int rc = sqlite3_exec(m_conn, sql, nullptr, nullptr, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800118 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500119 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800120 }
121
122 NDNS_LOG_INFO("clear all the data in the database: " << m_dbFile);
123}
124
Yumin Xia55a7cc42017-05-14 18:43:34 -0700125void
126DbMgr::saveName(const Name& name, sqlite3_stmt* stmt, int iCol, bool isStatic)
127{
128 const Block& wire = name.wireEncode();
129 sqlite3_bind_blob(stmt, iCol, wire.value(), wire.value_size(), isStatic ? SQLITE_STATIC : SQLITE_TRANSIENT);
130}
131
132Name
133DbMgr::restoreName(sqlite3_stmt* stmt, int iCol)
134{
135 Name name;
136
137 const uint8_t* buffer = static_cast<const uint8_t*>(sqlite3_column_blob(stmt, iCol));
138 size_t nBytesLeft = sqlite3_column_bytes(stmt, iCol);
139
140 while (nBytesLeft > 0) {
141 bool hasDecodingSucceeded;
142 name::Component component;
143 std::tie(hasDecodingSucceeded, component) = Block::fromBuffer(buffer, nBytesLeft);
144 if (!hasDecodingSucceeded) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500145 NDN_THROW(Error("Error while decoding name from the database"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700146 }
147 name.append(component);
148 buffer += component.size();
149 nBytesLeft -= component.size();
150 }
151
152 return name;
153}
154
Shock Jiang3016c982014-11-11 11:35:17 -0800155///////////////////////////////////////////////////////////////////////////////////////////////////
156// Zone
157///////////////////////////////////////////////////////////////////////////////////////////////////
158
159void
160DbMgr::insert(Zone& zone)
161{
162 if (zone.getId() > 0)
163 return;
164
165 sqlite3_stmt* stmt;
166 const char* sql = "INSERT INTO zones (name, ttl) VALUES (?, ?)";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500167 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800168 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500169 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800170 }
171
Yumin Xia55a7cc42017-05-14 18:43:34 -0700172 saveName(zone.getName(), stmt, 1);
Shock Jiang3016c982014-11-11 11:35:17 -0800173 sqlite3_bind_int(stmt, 2, zone.getTtl().count());
174
175 rc = sqlite3_step(stmt);
176 if (rc != SQLITE_DONE) {
177 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500178 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800179 }
180
181 zone.setId(sqlite3_last_insert_rowid(m_conn));
182 sqlite3_finalize(stmt);
183}
184
Yumin Xia2c509c22017-02-09 14:37:36 -0800185void
186DbMgr::setZoneInfo(Zone& zone,
187 const std::string& key,
188 const Block& value)
189{
190 if (zone.getId() == 0) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500191 NDN_THROW(Error("zone has not been initialized"));
Yumin Xia2c509c22017-02-09 14:37:36 -0800192 }
193
194 if (key.length() > 10) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500195 NDN_THROW(Error("key length should not exceed 10"));
Yumin Xia2c509c22017-02-09 14:37:36 -0800196 }
197
198 sqlite3_stmt* stmt;
199 const char* sql = "INSERT OR REPLACE INTO zone_info (zone_id, key, value) VALUES (?, ?, ?)";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500200 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia2c509c22017-02-09 14:37:36 -0800201 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500202 NDN_THROW(PrepareError(sql));
Yumin Xia2c509c22017-02-09 14:37:36 -0800203 }
204
205 sqlite3_bind_int(stmt, 1, zone.getId());
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500206 sqlite3_bind_text(stmt, 2, key.data(), key.length(), SQLITE_STATIC);
Yumin Xia2c509c22017-02-09 14:37:36 -0800207 sqlite3_bind_blob(stmt, 3, value.wire(), value.size(), SQLITE_STATIC);
208
209 rc = sqlite3_step(stmt);
210 if (rc != SQLITE_DONE) {
211 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500212 NDN_THROW(ExecuteError(sql));
Yumin Xia2c509c22017-02-09 14:37:36 -0800213 }
214
215 sqlite3_finalize(stmt);
216}
217
218std::map<std::string, Block>
219DbMgr::getZoneInfo(Zone& zone)
220{
221 using std::string;
222 std::map<string, Block> rtn;
223
224 if (zone.getId() == 0) {
225 find(zone);
226 }
227
228 if (zone.getId() == 0) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500229 NDN_THROW(Error("zone has not been initialized"));
Yumin Xia2c509c22017-02-09 14:37:36 -0800230 }
231
232 sqlite3_stmt* stmt;
233 const char* sql = "SELECT key, value FROM zone_info WHERE zone_id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500234 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia2c509c22017-02-09 14:37:36 -0800235 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500236 NDN_THROW(PrepareError(sql));
Yumin Xia2c509c22017-02-09 14:37:36 -0800237 }
238
239 sqlite3_bind_int(stmt, 1, zone.getId());
240
241 while (sqlite3_step(stmt) == SQLITE_ROW) {
242 const char* key = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
243 rtn[string(key)] = Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 1)),
244 sqlite3_column_bytes(stmt, 1));
245 }
246
247 sqlite3_finalize(stmt);
248 return rtn;
249}
250
Shock Jiang3016c982014-11-11 11:35:17 -0800251bool
252DbMgr::find(Zone& zone)
253{
254 sqlite3_stmt* stmt;
255 const char* sql = "SELECT id, ttl FROM zones WHERE name=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500256 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800257 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500258 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800259 }
260
Yumin Xia55a7cc42017-05-14 18:43:34 -0700261 saveName(zone.getName(), stmt, 1);
Shock Jiang3016c982014-11-11 11:35:17 -0800262
263 if (sqlite3_step(stmt) == SQLITE_ROW) {
264 zone.setId(sqlite3_column_int64(stmt, 0));
265 zone.setTtl(time::seconds(sqlite3_column_int(stmt, 1)));
Yumin Xia2c509c22017-02-09 14:37:36 -0800266 }
267 else {
Shock Jiang3016c982014-11-11 11:35:17 -0800268 zone.setId(0);
269 }
270
271 sqlite3_finalize(stmt);
272
273 return zone.getId() != 0;
274}
275
Jiewen Tan870b29b2014-11-17 19:09:49 -0800276std::vector<Zone>
277DbMgr::listZones()
278{
279 sqlite3_stmt* stmt;
280 const char* sql = "SELECT id, name, ttl FROM zones";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500281 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800282 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500283 NDN_THROW(PrepareError(sql));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800284 }
285
286 std::vector<Zone> vec;
287
288 while (sqlite3_step(stmt) == SQLITE_ROW) {
289 vec.emplace_back();
290 Zone& zone = vec.back();
291 zone.setId(sqlite3_column_int64(stmt, 0));
292 zone.setTtl(time::seconds(sqlite3_column_int(stmt, 2)));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700293 zone.setName(restoreName(stmt, 1));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800294 }
295 sqlite3_finalize(stmt);
296
297 return vec;
298}
299
Shock Jiang3016c982014-11-11 11:35:17 -0800300void
301DbMgr::remove(Zone& zone)
302{
303 if (zone.getId() == 0)
304 return;
305
306 sqlite3_stmt* stmt;
307 const char* sql = "DELETE FROM zones where id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500308 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800309 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500310 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800311 }
312
313 sqlite3_bind_int64(stmt, 1, zone.getId());
314
315 rc = sqlite3_step(stmt);
316 if (rc != SQLITE_DONE) {
317 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500318 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800319 }
320
321 sqlite3_finalize(stmt);
322
323 zone = Zone();
324}
325
Shock Jiang3016c982014-11-11 11:35:17 -0800326///////////////////////////////////////////////////////////////////////////////////////////////////
327// Rrset
328///////////////////////////////////////////////////////////////////////////////////////////////////
329
330void
331DbMgr::insert(Rrset& rrset)
332{
333 if (rrset.getId() != 0)
334 return;
335
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500336 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500337 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800338 }
339
340 if (rrset.getZone()->getId() == 0) {
341 insert(*rrset.getZone());
342 }
343
344 const char* sql =
345 "INSERT INTO rrsets (zone_id, label, type, version, ttl, data)"
346 " VALUES (?, ?, ?, ?, ?, ?)";
347
348 sqlite3_stmt* stmt;
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500349 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800350 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500351 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800352 }
353
354 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
355
Yumin Xia55a7cc42017-05-14 18:43:34 -0700356 saveName(rrset.getLabel(), stmt, 2);
Shock Jiang3016c982014-11-11 11:35:17 -0800357 sqlite3_bind_blob(stmt, 3, rrset.getType().wire(), rrset.getType().size(), SQLITE_STATIC);
358 sqlite3_bind_blob(stmt, 4, rrset.getVersion().wire(), rrset.getVersion().size(), SQLITE_STATIC);
359 sqlite3_bind_int64(stmt, 5, rrset.getTtl().count());
360 sqlite3_bind_blob(stmt, 6, rrset.getData().wire(), rrset.getData().size(), SQLITE_STATIC);
361
362 rc = sqlite3_step(stmt);
363 if (rc != SQLITE_DONE) {
364 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500365 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800366 }
367
368 rrset.setId(sqlite3_last_insert_rowid(m_conn));
369 sqlite3_finalize(stmt);
370}
371
372bool
373DbMgr::find(Rrset& rrset)
374{
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500375 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500376 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800377 }
378
379 if (rrset.getZone()->getId() == 0) {
380 bool isFound = find(*rrset.getZone());
381 if (!isFound) {
382 return false;
383 }
384 }
385
386 sqlite3_stmt* stmt;
387 const char* sql =
388 "SELECT id, ttl, version, data FROM rrsets"
389 " WHERE zone_id=? and label=? and type=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500390 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800391 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500392 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800393 }
394
395 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
396
Yumin Xia55a7cc42017-05-14 18:43:34 -0700397 saveName(rrset.getLabel(), stmt, 2);
398 sqlite3_bind_blob(stmt, 3, rrset.getType().wire(), rrset.getType().size(), SQLITE_STATIC);
399
400 if (sqlite3_step(stmt) == SQLITE_ROW) {
401 rrset.setId(sqlite3_column_int64(stmt, 0));
402 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
403 rrset.setVersion(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
404 sqlite3_column_bytes(stmt, 2)));
405 rrset.setData(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
406 sqlite3_column_bytes(stmt, 3)));
407 }
408 else {
409 rrset.setId(0);
410 }
411 sqlite3_finalize(stmt);
412
413 return rrset.getId() != 0;
414}
415
416bool
417DbMgr::findLowerBound(Rrset& rrset)
418{
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500419 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500420 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700421 }
422
423 if (rrset.getZone()->getId() == 0) {
424 bool isFound = find(*rrset.getZone());
425 if (!isFound) {
426 return false;
427 }
428 }
429
430 sqlite3_stmt* stmt;
431 const char* sql =
432 "SELECT id, ttl, version, data FROM rrsets"
433 " WHERE zone_id=? and label<? and type=? ORDER BY label DESC";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500434 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700435 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500436 NDN_THROW(PrepareError(sql));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700437 }
438
439 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
440
441 saveName(rrset.getLabel(), stmt, 2);
Shock Jiang3016c982014-11-11 11:35:17 -0800442 sqlite3_bind_blob(stmt, 3, rrset.getType().wire(), rrset.getType().size(), SQLITE_STATIC);
443
444 if (sqlite3_step(stmt) == SQLITE_ROW) {
445 rrset.setId(sqlite3_column_int64(stmt, 0));
446 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
447 rrset.setVersion(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
448 sqlite3_column_bytes(stmt, 2)));
449 rrset.setData(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
450 sqlite3_column_bytes(stmt, 3)));
Yumin Xia2c509c22017-02-09 14:37:36 -0800451 }
452 else {
Shock Jiang3016c982014-11-11 11:35:17 -0800453 rrset.setId(0);
454 }
455 sqlite3_finalize(stmt);
456
457 return rrset.getId() != 0;
458}
459
460std::vector<Rrset>
461DbMgr::findRrsets(Zone& zone)
462{
463 if (zone.getId() == 0)
464 find(zone);
465
466 if (zone.getId() == 0)
Davide Pesavento948c50c2020-12-26 21:30:45 -0500467 NDN_THROW(RrsetError("Attempting to find all the rrsets with a zone does not in the database"));
Shock Jiang3016c982014-11-11 11:35:17 -0800468
469 std::vector<Rrset> vec;
470 sqlite3_stmt* stmt;
471 const char* sql = "SELECT id, ttl, version, data, label, type "
Yumin Xia55a7cc42017-05-14 18:43:34 -0700472 "FROM rrsets where zone_id=? ORDER BY label";
Shock Jiang3016c982014-11-11 11:35:17 -0800473
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500474 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800475 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500476 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800477 }
478 sqlite3_bind_int64(stmt, 1, zone.getId());
479
480 while (sqlite3_step(stmt) == SQLITE_ROW) {
481 vec.emplace_back(&zone);
482 Rrset& rrset = vec.back();
483
484 rrset.setId(sqlite3_column_int64(stmt, 0));
485 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
486 rrset.setVersion(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
487 sqlite3_column_bytes(stmt, 2)));
488 rrset.setData(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
489 sqlite3_column_bytes(stmt, 3)));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700490 rrset.setLabel(restoreName(stmt, 4));
Shock Jiang3016c982014-11-11 11:35:17 -0800491 rrset.setType(Block(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 5)),
492 sqlite3_column_bytes(stmt, 5)));
493 }
494 sqlite3_finalize(stmt);
495
496 return vec;
497}
498
Yumin Xia55a7cc42017-05-14 18:43:34 -0700499void
500DbMgr::removeRrsetsOfZoneByType(Zone& zone, const name::Component& type)
501{
502 if (zone.getId() == 0)
503 find(zone);
504
505 if (zone.getId() == 0)
Davide Pesavento948c50c2020-12-26 21:30:45 -0500506 NDN_THROW(RrsetError("Attempting to find all the rrsets with a zone does not in the database"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700507
508 sqlite3_stmt* stmt;
509 const char* sql = "DELETE FROM rrsets WHERE zone_id = ? AND type = ?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500510 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700511 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500512 NDN_THROW(PrepareError(sql));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700513 }
514
515 sqlite3_bind_int64(stmt, 1, zone.getId());
516 sqlite3_bind_blob(stmt, 2, type.wire(), type.size(), SQLITE_STATIC);
517
518 rc = sqlite3_step(stmt);
519 if (rc != SQLITE_DONE) {
520 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500521 NDN_THROW(ExecuteError(sql));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700522 }
523 sqlite3_finalize(stmt);
524}
Shock Jiang3016c982014-11-11 11:35:17 -0800525
526void
527DbMgr::remove(Rrset& rrset)
528{
529 if (rrset.getId() == 0)
Davide Pesavento948c50c2020-12-26 21:30:45 -0500530 NDN_THROW(RrsetError("Attempting to remove Rrset that has no assigned id"));
Shock Jiang3016c982014-11-11 11:35:17 -0800531
532 sqlite3_stmt* stmt;
533 const char* sql = "DELETE FROM rrsets WHERE id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500534 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800535 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500536 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800537 }
538
539 sqlite3_bind_int64(stmt, 1, rrset.getId());
540
541 rc = sqlite3_step(stmt);
542 if (rc != SQLITE_DONE) {
543 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500544 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800545 }
546
547 sqlite3_finalize(stmt);
548
549 rrset = Rrset(rrset.getZone());
550}
551
552void
553DbMgr::update(Rrset& rrset)
554{
555 if (rrset.getId() == 0) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500556 NDN_THROW(RrsetError("Attempting to replace Rrset that has no assigned id"));
Shock Jiang3016c982014-11-11 11:35:17 -0800557 }
558
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500559 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500560 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800561 }
562
563 sqlite3_stmt* stmt;
564 const char* sql = "UPDATE rrsets SET ttl=?, version=?, data=? WHERE id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500565 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800566 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500567 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800568 }
569
570 sqlite3_bind_int64(stmt, 1, rrset.getTtl().count());
571 sqlite3_bind_blob(stmt, 2, rrset.getVersion().wire(), rrset.getVersion().size(), SQLITE_STATIC);
572 sqlite3_bind_blob(stmt, 3, rrset.getData().wire(), rrset.getData().size(), SQLITE_STATIC);
573 sqlite3_bind_int64(stmt, 4, rrset.getId());
574
575 sqlite3_step(stmt);
576 sqlite3_finalize(stmt);
577}
578
579} // namespace ndns
580} // namespace ndn