blob: 3c20f94bf62f956093196c6f0834ac8e08317a88 [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 Pesavento98026122022-03-14 22:00:03 -04003 * Copyright (c) 2014-2022, 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
Davide Pesavento38fd3982022-04-18 22:22:02 -040030const std::string NDNS_SCHEMA = R"SQL(
Yumin Xia2c509c22017-02-09 14:37:36 -080031CREATE TABLE IF NOT EXISTS zones (
32 id INTEGER NOT NULL PRIMARY KEY,
Davide Pesaventocaedf112021-05-09 20:21:53 -040033 name BLOB NOT NULL UNIQUE,
34 ttl INTEGER NOT NULL
35);
Yumin Xia2c509c22017-02-09 14:37:36 -080036
37CREATE TABLE IF NOT EXISTS zone_info (
Davide Pesaventocaedf112021-05-09 20:21:53 -040038 zone_id INTEGER NOT NULL,
39 key TEXT NOT NULL,
40 value BLOB NOT NULL,
41 PRIMARY KEY(zone_id, key),
42 FOREIGN KEY(zone_id) REFERENCES zones(id) ON UPDATE CASCADE ON DELETE CASCADE
43);
Yumin Xia2c509c22017-02-09 14:37:36 -080044
45CREATE TABLE IF NOT EXISTS rrsets (
46 id INTEGER NOT NULL PRIMARY KEY,
Davide Pesaventocaedf112021-05-09 20:21:53 -040047 zone_id INTEGER NOT NULL,
48 label BLOB NOT NULL,
49 type BLOB NOT NULL,
50 version BLOB NOT NULL,
51 ttl INTEGER NOT NULL,
52 data BLOB NOT NULL,
53 FOREIGN KEY(zone_id) REFERENCES zones(id) ON UPDATE CASCADE ON DELETE CASCADE
54);
Yumin Xia2c509c22017-02-09 14:37:36 -080055
56CREATE UNIQUE INDEX rrsets_zone_id_label_type_version
Davide Pesaventocaedf112021-05-09 20:21:53 -040057 ON rrsets(zone_id, label, type, version);
58)SQL";
Shock Jiang3016c982014-11-11 11:35:17 -080059
Davide Pesaventod01c1a42019-01-21 21:42:45 -050060DbMgr::DbMgr(const std::string& dbFile)
Shock Jiang3016c982014-11-11 11:35:17 -080061 : m_dbFile(dbFile)
Davide Pesavento093ce1c2019-01-21 19:22:42 -050062 , m_conn(nullptr)
Shock Jiang3016c982014-11-11 11:35:17 -080063{
Davide Pesaventod01c1a42019-01-21 21:42:45 -050064 if (m_dbFile.empty())
65 m_dbFile = getDefaultDatabaseFile();
Shock Jiang3016c982014-11-11 11:35:17 -080066
Davide Pesavento093ce1c2019-01-21 19:22:42 -050067 open();
Shock Jiang3016c982014-11-11 11:35:17 -080068
69 NDNS_LOG_INFO("open database: " << m_dbFile);
70}
71
Shock Jiang3016c982014-11-11 11:35:17 -080072DbMgr::~DbMgr()
73{
Davide Pesavento093ce1c2019-01-21 19:22:42 -050074 close();
Shock Jiang3016c982014-11-11 11:35:17 -080075}
76
77void
78DbMgr::open()
79{
Davide Pesavento093ce1c2019-01-21 19:22:42 -050080 int res = sqlite3_open_v2(m_dbFile.data(), &m_conn,
Shock Jiang3016c982014-11-11 11:35:17 -080081 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
82#ifdef DISABLE_SQLITE3_FS_LOCKING
83 "unix-dotfile"
84#else
Davide Pesavento093ce1c2019-01-21 19:22:42 -050085 nullptr
Shock Jiang3016c982014-11-11 11:35:17 -080086#endif
87 );
88
89 if (res != SQLITE_OK) {
90 NDNS_LOG_FATAL("Cannot open the db file: " << m_dbFile);
Davide Pesavento948c50c2020-12-26 21:30:45 -050091 NDN_THROW(ConnectError("Cannot open the db file: " + m_dbFile));
Shock Jiang3016c982014-11-11 11:35:17 -080092 }
Davide Pesavento093ce1c2019-01-21 19:22:42 -050093
Shock Jiang3016c982014-11-11 11:35:17 -080094 // ignore any errors from DB creation (command will fail for the existing database, which is ok)
Davide Pesavento093ce1c2019-01-21 19:22:42 -050095 sqlite3_exec(m_conn, NDNS_SCHEMA.data(), nullptr, nullptr, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -080096}
97
98void
99DbMgr::close()
100{
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500101 if (m_conn == nullptr)
Shock Jiang3016c982014-11-11 11:35:17 -0800102 return;
103
104 int ret = sqlite3_close(m_conn);
105 if (ret != SQLITE_OK) {
106 NDNS_LOG_FATAL("Cannot close the db: " << m_dbFile);
107 }
108 else {
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500109 m_conn = nullptr;
Shock Jiang3016c982014-11-11 11:35:17 -0800110 NDNS_LOG_INFO("Close database: " << m_dbFile);
111 }
112}
113
114void
115DbMgr::clearAllData()
116{
117 const char* sql = "DELETE FROM zones; DELETE FROM rrsets;";
118
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500119 // sqlite3_step cannot execute multiple SQL statements
120 int rc = sqlite3_exec(m_conn, sql, nullptr, nullptr, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800121 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500122 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800123 }
124
125 NDNS_LOG_INFO("clear all the data in the database: " << m_dbFile);
126}
127
Yumin Xia55a7cc42017-05-14 18:43:34 -0700128void
129DbMgr::saveName(const Name& name, sqlite3_stmt* stmt, int iCol, bool isStatic)
130{
Davide Pesaventocaedf112021-05-09 20:21:53 -0400131 static const uint8_t dummy = 0;
132 const auto& wire = name.wireEncode();
133 const auto* ptr = wire.value();
134 if (ptr == nullptr) {
135 // if value() returns nullptr (i.e., value_size() == 0), pass a non-null dummy
136 // pointer instead; we cannot bind nullptr because the column may be "NOT NULL"
137 ptr = &dummy;
138 }
139 sqlite3_bind_blob(stmt, iCol, ptr, wire.value_size(), isStatic ? SQLITE_STATIC : SQLITE_TRANSIENT);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700140}
141
142Name
143DbMgr::restoreName(sqlite3_stmt* stmt, int iCol)
144{
145 Name name;
Davide Pesavento38fd3982022-04-18 22:22:02 -0400146 span buffer(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, iCol)),
147 sqlite3_column_bytes(stmt, iCol));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700148
Davide Pesavento38fd3982022-04-18 22:22:02 -0400149 while (!buffer.empty()) {
Yumin Xia55a7cc42017-05-14 18:43:34 -0700150 name::Component component;
Davide Pesavento38fd3982022-04-18 22:22:02 -0400151 try {
152 component.wireDecode(Block(buffer));
153 }
154 catch (const ndn::tlv::Error&) {
155 NDN_THROW_NESTED(Error("Error while decoding name from the database"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700156 }
157 name.append(component);
Davide Pesavento38fd3982022-04-18 22:22:02 -0400158 buffer = buffer.subspan(component.size());
Yumin Xia55a7cc42017-05-14 18:43:34 -0700159 }
160
161 return name;
162}
163
Shock Jiang3016c982014-11-11 11:35:17 -0800164///////////////////////////////////////////////////////////////////////////////////////////////////
165// Zone
166///////////////////////////////////////////////////////////////////////////////////////////////////
167
168void
169DbMgr::insert(Zone& zone)
170{
171 if (zone.getId() > 0)
172 return;
173
174 sqlite3_stmt* stmt;
175 const char* sql = "INSERT INTO zones (name, ttl) VALUES (?, ?)";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500176 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800177 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500178 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800179 }
180
Yumin Xia55a7cc42017-05-14 18:43:34 -0700181 saveName(zone.getName(), stmt, 1);
Shock Jiang3016c982014-11-11 11:35:17 -0800182 sqlite3_bind_int(stmt, 2, zone.getTtl().count());
183
184 rc = sqlite3_step(stmt);
185 if (rc != SQLITE_DONE) {
186 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500187 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800188 }
189
190 zone.setId(sqlite3_last_insert_rowid(m_conn));
191 sqlite3_finalize(stmt);
192}
193
Yumin Xia2c509c22017-02-09 14:37:36 -0800194void
195DbMgr::setZoneInfo(Zone& zone,
196 const std::string& key,
197 const Block& value)
198{
199 if (zone.getId() == 0) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500200 NDN_THROW(Error("zone has not been initialized"));
Yumin Xia2c509c22017-02-09 14:37:36 -0800201 }
202
203 if (key.length() > 10) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500204 NDN_THROW(Error("key length should not exceed 10"));
Yumin Xia2c509c22017-02-09 14:37:36 -0800205 }
206
207 sqlite3_stmt* stmt;
208 const char* sql = "INSERT OR REPLACE INTO zone_info (zone_id, key, value) VALUES (?, ?, ?)";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500209 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia2c509c22017-02-09 14:37:36 -0800210 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500211 NDN_THROW(PrepareError(sql));
Yumin Xia2c509c22017-02-09 14:37:36 -0800212 }
213
214 sqlite3_bind_int(stmt, 1, zone.getId());
Davide Pesavento98026122022-03-14 22:00:03 -0400215 sqlite3_bind_text(stmt, 2, key.data(), key.length(), SQLITE_STATIC);
216 sqlite3_bind_blob(stmt, 3, value.data(), value.size(), SQLITE_STATIC);
Yumin Xia2c509c22017-02-09 14:37:36 -0800217
218 rc = sqlite3_step(stmt);
219 if (rc != SQLITE_DONE) {
220 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500221 NDN_THROW(ExecuteError(sql));
Yumin Xia2c509c22017-02-09 14:37:36 -0800222 }
223
224 sqlite3_finalize(stmt);
225}
226
227std::map<std::string, Block>
228DbMgr::getZoneInfo(Zone& zone)
229{
230 using std::string;
231 std::map<string, Block> rtn;
232
233 if (zone.getId() == 0) {
234 find(zone);
235 }
236
237 if (zone.getId() == 0) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500238 NDN_THROW(Error("zone has not been initialized"));
Yumin Xia2c509c22017-02-09 14:37:36 -0800239 }
240
241 sqlite3_stmt* stmt;
242 const char* sql = "SELECT key, value FROM zone_info WHERE zone_id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500243 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia2c509c22017-02-09 14:37:36 -0800244 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500245 NDN_THROW(PrepareError(sql));
Yumin Xia2c509c22017-02-09 14:37:36 -0800246 }
247
248 sqlite3_bind_int(stmt, 1, zone.getId());
249
250 while (sqlite3_step(stmt) == SQLITE_ROW) {
251 const char* key = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
Davide Pesavento38fd3982022-04-18 22:22:02 -0400252 rtn[string(key)] = Block(span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 1)),
253 sqlite3_column_bytes(stmt, 1)));
Yumin Xia2c509c22017-02-09 14:37:36 -0800254 }
255
256 sqlite3_finalize(stmt);
257 return rtn;
258}
259
Shock Jiang3016c982014-11-11 11:35:17 -0800260bool
261DbMgr::find(Zone& zone)
262{
263 sqlite3_stmt* stmt;
264 const char* sql = "SELECT id, ttl FROM zones WHERE name=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500265 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800266 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500267 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800268 }
269
Yumin Xia55a7cc42017-05-14 18:43:34 -0700270 saveName(zone.getName(), stmt, 1);
Shock Jiang3016c982014-11-11 11:35:17 -0800271
272 if (sqlite3_step(stmt) == SQLITE_ROW) {
273 zone.setId(sqlite3_column_int64(stmt, 0));
274 zone.setTtl(time::seconds(sqlite3_column_int(stmt, 1)));
Yumin Xia2c509c22017-02-09 14:37:36 -0800275 }
276 else {
Shock Jiang3016c982014-11-11 11:35:17 -0800277 zone.setId(0);
278 }
279
280 sqlite3_finalize(stmt);
281
282 return zone.getId() != 0;
283}
284
Jiewen Tan870b29b2014-11-17 19:09:49 -0800285std::vector<Zone>
286DbMgr::listZones()
287{
288 sqlite3_stmt* stmt;
289 const char* sql = "SELECT id, name, ttl FROM zones";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500290 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800291 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500292 NDN_THROW(PrepareError(sql));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800293 }
294
295 std::vector<Zone> vec;
296
297 while (sqlite3_step(stmt) == SQLITE_ROW) {
298 vec.emplace_back();
299 Zone& zone = vec.back();
300 zone.setId(sqlite3_column_int64(stmt, 0));
301 zone.setTtl(time::seconds(sqlite3_column_int(stmt, 2)));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700302 zone.setName(restoreName(stmt, 1));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800303 }
304 sqlite3_finalize(stmt);
305
306 return vec;
307}
308
Shock Jiang3016c982014-11-11 11:35:17 -0800309void
310DbMgr::remove(Zone& zone)
311{
312 if (zone.getId() == 0)
313 return;
314
315 sqlite3_stmt* stmt;
316 const char* sql = "DELETE FROM zones where id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500317 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800318 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500319 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800320 }
321
322 sqlite3_bind_int64(stmt, 1, zone.getId());
323
324 rc = sqlite3_step(stmt);
325 if (rc != SQLITE_DONE) {
326 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500327 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800328 }
329
330 sqlite3_finalize(stmt);
331
332 zone = Zone();
333}
334
Shock Jiang3016c982014-11-11 11:35:17 -0800335///////////////////////////////////////////////////////////////////////////////////////////////////
336// Rrset
337///////////////////////////////////////////////////////////////////////////////////////////////////
338
339void
340DbMgr::insert(Rrset& rrset)
341{
342 if (rrset.getId() != 0)
343 return;
344
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500345 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500346 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800347 }
348
349 if (rrset.getZone()->getId() == 0) {
350 insert(*rrset.getZone());
351 }
352
353 const char* sql =
354 "INSERT INTO rrsets (zone_id, label, type, version, ttl, data)"
355 " VALUES (?, ?, ?, ?, ?, ?)";
356
357 sqlite3_stmt* stmt;
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500358 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800359 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500360 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800361 }
362
363 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
364
Yumin Xia55a7cc42017-05-14 18:43:34 -0700365 saveName(rrset.getLabel(), stmt, 2);
Davide Pesavento98026122022-03-14 22:00:03 -0400366 sqlite3_bind_blob(stmt, 3, rrset.getType().data(), rrset.getType().size(), SQLITE_STATIC);
367 sqlite3_bind_blob(stmt, 4, rrset.getVersion().data(), rrset.getVersion().size(), SQLITE_STATIC);
Shock Jiang3016c982014-11-11 11:35:17 -0800368 sqlite3_bind_int64(stmt, 5, rrset.getTtl().count());
Davide Pesavento98026122022-03-14 22:00:03 -0400369 sqlite3_bind_blob(stmt, 6, rrset.getData().data(), rrset.getData().size(), SQLITE_STATIC);
Shock Jiang3016c982014-11-11 11:35:17 -0800370
371 rc = sqlite3_step(stmt);
372 if (rc != SQLITE_DONE) {
373 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500374 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800375 }
376
377 rrset.setId(sqlite3_last_insert_rowid(m_conn));
378 sqlite3_finalize(stmt);
379}
380
381bool
382DbMgr::find(Rrset& rrset)
383{
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500384 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500385 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800386 }
387
388 if (rrset.getZone()->getId() == 0) {
389 bool isFound = find(*rrset.getZone());
390 if (!isFound) {
391 return false;
392 }
393 }
394
395 sqlite3_stmt* stmt;
396 const char* sql =
397 "SELECT id, ttl, version, data FROM rrsets"
398 " WHERE zone_id=? and label=? and type=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500399 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800400 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500401 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800402 }
403
404 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
405
Yumin Xia55a7cc42017-05-14 18:43:34 -0700406 saveName(rrset.getLabel(), stmt, 2);
Davide Pesavento98026122022-03-14 22:00:03 -0400407 sqlite3_bind_blob(stmt, 3, rrset.getType().data(), rrset.getType().size(), SQLITE_STATIC);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700408
409 if (sqlite3_step(stmt) == SQLITE_ROW) {
410 rrset.setId(sqlite3_column_int64(stmt, 0));
411 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
Davide Pesavento38fd3982022-04-18 22:22:02 -0400412 rrset.setVersion(name::Component(Block(span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
413 sqlite3_column_bytes(stmt, 2)))));
414 rrset.setData(Block(span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
415 sqlite3_column_bytes(stmt, 3))));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700416 }
417 else {
418 rrset.setId(0);
419 }
420 sqlite3_finalize(stmt);
421
422 return rrset.getId() != 0;
423}
424
425bool
426DbMgr::findLowerBound(Rrset& rrset)
427{
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500428 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500429 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700430 }
431
432 if (rrset.getZone()->getId() == 0) {
433 bool isFound = find(*rrset.getZone());
434 if (!isFound) {
435 return false;
436 }
437 }
438
439 sqlite3_stmt* stmt;
440 const char* sql =
441 "SELECT id, ttl, version, data FROM rrsets"
442 " WHERE zone_id=? and label<? and type=? ORDER BY label DESC";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500443 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700444 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500445 NDN_THROW(PrepareError(sql));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700446 }
447
448 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
449
450 saveName(rrset.getLabel(), stmt, 2);
Davide Pesavento98026122022-03-14 22:00:03 -0400451 sqlite3_bind_blob(stmt, 3, rrset.getType().data(), rrset.getType().size(), SQLITE_STATIC);
Shock Jiang3016c982014-11-11 11:35:17 -0800452
453 if (sqlite3_step(stmt) == SQLITE_ROW) {
454 rrset.setId(sqlite3_column_int64(stmt, 0));
455 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
Davide Pesavento38fd3982022-04-18 22:22:02 -0400456 rrset.setVersion(name::Component(Block(span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
457 sqlite3_column_bytes(stmt, 2)))));
458 rrset.setData(Block(span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
459 sqlite3_column_bytes(stmt, 3))));
Yumin Xia2c509c22017-02-09 14:37:36 -0800460 }
461 else {
Shock Jiang3016c982014-11-11 11:35:17 -0800462 rrset.setId(0);
463 }
464 sqlite3_finalize(stmt);
465
466 return rrset.getId() != 0;
467}
468
469std::vector<Rrset>
470DbMgr::findRrsets(Zone& zone)
471{
472 if (zone.getId() == 0)
473 find(zone);
474
475 if (zone.getId() == 0)
Davide Pesavento948c50c2020-12-26 21:30:45 -0500476 NDN_THROW(RrsetError("Attempting to find all the rrsets with a zone does not in the database"));
Shock Jiang3016c982014-11-11 11:35:17 -0800477
478 std::vector<Rrset> vec;
479 sqlite3_stmt* stmt;
480 const char* sql = "SELECT id, ttl, version, data, label, type "
Yumin Xia55a7cc42017-05-14 18:43:34 -0700481 "FROM rrsets where zone_id=? ORDER BY label";
Shock Jiang3016c982014-11-11 11:35:17 -0800482
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500483 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800484 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500485 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800486 }
487 sqlite3_bind_int64(stmt, 1, zone.getId());
488
489 while (sqlite3_step(stmt) == SQLITE_ROW) {
490 vec.emplace_back(&zone);
491 Rrset& rrset = vec.back();
492
493 rrset.setId(sqlite3_column_int64(stmt, 0));
494 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
Davide Pesavento38fd3982022-04-18 22:22:02 -0400495 rrset.setVersion(name::Component(Block(span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
496 sqlite3_column_bytes(stmt, 2)))));
497 rrset.setData(Block(span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
498 sqlite3_column_bytes(stmt, 3))));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700499 rrset.setLabel(restoreName(stmt, 4));
Davide Pesavento38fd3982022-04-18 22:22:02 -0400500 rrset.setType(name::Component(Block(span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 5)),
501 sqlite3_column_bytes(stmt, 5)))));
Shock Jiang3016c982014-11-11 11:35:17 -0800502 }
503 sqlite3_finalize(stmt);
504
505 return vec;
506}
507
Yumin Xia55a7cc42017-05-14 18:43:34 -0700508void
509DbMgr::removeRrsetsOfZoneByType(Zone& zone, const name::Component& type)
510{
511 if (zone.getId() == 0)
512 find(zone);
513
514 if (zone.getId() == 0)
Davide Pesavento948c50c2020-12-26 21:30:45 -0500515 NDN_THROW(RrsetError("Attempting to find all the rrsets with a zone does not in the database"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700516
517 sqlite3_stmt* stmt;
518 const char* sql = "DELETE FROM rrsets WHERE zone_id = ? AND type = ?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500519 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700520 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500521 NDN_THROW(PrepareError(sql));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700522 }
523
524 sqlite3_bind_int64(stmt, 1, zone.getId());
Davide Pesavento98026122022-03-14 22:00:03 -0400525 sqlite3_bind_blob(stmt, 2, type.data(), type.size(), SQLITE_STATIC);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700526
527 rc = sqlite3_step(stmt);
528 if (rc != SQLITE_DONE) {
529 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500530 NDN_THROW(ExecuteError(sql));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700531 }
532 sqlite3_finalize(stmt);
533}
Shock Jiang3016c982014-11-11 11:35:17 -0800534
535void
536DbMgr::remove(Rrset& rrset)
537{
538 if (rrset.getId() == 0)
Davide Pesavento948c50c2020-12-26 21:30:45 -0500539 NDN_THROW(RrsetError("Attempting to remove Rrset that has no assigned id"));
Shock Jiang3016c982014-11-11 11:35:17 -0800540
541 sqlite3_stmt* stmt;
542 const char* sql = "DELETE FROM rrsets WHERE id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500543 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800544 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500545 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800546 }
547
548 sqlite3_bind_int64(stmt, 1, rrset.getId());
549
550 rc = sqlite3_step(stmt);
551 if (rc != SQLITE_DONE) {
552 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500553 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800554 }
555
556 sqlite3_finalize(stmt);
557
558 rrset = Rrset(rrset.getZone());
559}
560
561void
562DbMgr::update(Rrset& rrset)
563{
564 if (rrset.getId() == 0) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500565 NDN_THROW(RrsetError("Attempting to replace Rrset that has no assigned id"));
Shock Jiang3016c982014-11-11 11:35:17 -0800566 }
567
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500568 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500569 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800570 }
571
572 sqlite3_stmt* stmt;
573 const char* sql = "UPDATE rrsets SET ttl=?, version=?, data=? WHERE id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500574 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800575 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500576 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800577 }
578
579 sqlite3_bind_int64(stmt, 1, rrset.getTtl().count());
Davide Pesavento98026122022-03-14 22:00:03 -0400580 sqlite3_bind_blob(stmt, 2, rrset.getVersion().data(), rrset.getVersion().size(), SQLITE_STATIC);
581 sqlite3_bind_blob(stmt, 3, rrset.getData().data(), rrset.getData().size(), SQLITE_STATIC);
Shock Jiang3016c982014-11-11 11:35:17 -0800582 sqlite3_bind_int64(stmt, 4, rrset.getId());
583
584 sqlite3_step(stmt);
585 sqlite3_finalize(stmt);
586}
587
588} // namespace ndns
589} // namespace ndn