blob: e1ab0fc713130cdfa7a9b7f233238ac29ff1e738 [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 Pesaventocaedf112021-05-09 20:21:53 -040030static const 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;
146
147 const uint8_t* buffer = static_cast<const uint8_t*>(sqlite3_column_blob(stmt, iCol));
148 size_t nBytesLeft = sqlite3_column_bytes(stmt, iCol);
149
150 while (nBytesLeft > 0) {
151 bool hasDecodingSucceeded;
152 name::Component component;
Davide Pesavento98026122022-03-14 22:00:03 -0400153 std::tie(hasDecodingSucceeded, component) = Block::fromBuffer({buffer, nBytesLeft});
Yumin Xia55a7cc42017-05-14 18:43:34 -0700154 if (!hasDecodingSucceeded) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500155 NDN_THROW(Error("Error while decoding name from the database"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700156 }
157 name.append(component);
158 buffer += component.size();
159 nBytesLeft -= component.size();
160 }
161
162 return name;
163}
164
Shock Jiang3016c982014-11-11 11:35:17 -0800165///////////////////////////////////////////////////////////////////////////////////////////////////
166// Zone
167///////////////////////////////////////////////////////////////////////////////////////////////////
168
169void
170DbMgr::insert(Zone& zone)
171{
172 if (zone.getId() > 0)
173 return;
174
175 sqlite3_stmt* stmt;
176 const char* sql = "INSERT INTO zones (name, ttl) VALUES (?, ?)";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500177 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800178 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500179 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800180 }
181
Yumin Xia55a7cc42017-05-14 18:43:34 -0700182 saveName(zone.getName(), stmt, 1);
Shock Jiang3016c982014-11-11 11:35:17 -0800183 sqlite3_bind_int(stmt, 2, zone.getTtl().count());
184
185 rc = sqlite3_step(stmt);
186 if (rc != SQLITE_DONE) {
187 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500188 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800189 }
190
191 zone.setId(sqlite3_last_insert_rowid(m_conn));
192 sqlite3_finalize(stmt);
193}
194
Yumin Xia2c509c22017-02-09 14:37:36 -0800195void
196DbMgr::setZoneInfo(Zone& zone,
197 const std::string& key,
198 const Block& value)
199{
200 if (zone.getId() == 0) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500201 NDN_THROW(Error("zone has not been initialized"));
Yumin Xia2c509c22017-02-09 14:37:36 -0800202 }
203
204 if (key.length() > 10) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500205 NDN_THROW(Error("key length should not exceed 10"));
Yumin Xia2c509c22017-02-09 14:37:36 -0800206 }
207
208 sqlite3_stmt* stmt;
209 const char* sql = "INSERT OR REPLACE INTO zone_info (zone_id, key, value) VALUES (?, ?, ?)";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500210 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia2c509c22017-02-09 14:37:36 -0800211 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500212 NDN_THROW(PrepareError(sql));
Yumin Xia2c509c22017-02-09 14:37:36 -0800213 }
214
215 sqlite3_bind_int(stmt, 1, zone.getId());
Davide Pesavento98026122022-03-14 22:00:03 -0400216 sqlite3_bind_text(stmt, 2, key.data(), key.length(), SQLITE_STATIC);
217 sqlite3_bind_blob(stmt, 3, value.data(), value.size(), SQLITE_STATIC);
Yumin Xia2c509c22017-02-09 14:37:36 -0800218
219 rc = sqlite3_step(stmt);
220 if (rc != SQLITE_DONE) {
221 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500222 NDN_THROW(ExecuteError(sql));
Yumin Xia2c509c22017-02-09 14:37:36 -0800223 }
224
225 sqlite3_finalize(stmt);
226}
227
228std::map<std::string, Block>
229DbMgr::getZoneInfo(Zone& zone)
230{
231 using std::string;
232 std::map<string, Block> rtn;
233
234 if (zone.getId() == 0) {
235 find(zone);
236 }
237
238 if (zone.getId() == 0) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500239 NDN_THROW(Error("zone has not been initialized"));
Yumin Xia2c509c22017-02-09 14:37:36 -0800240 }
241
242 sqlite3_stmt* stmt;
243 const char* sql = "SELECT key, value FROM zone_info WHERE zone_id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500244 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia2c509c22017-02-09 14:37:36 -0800245 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500246 NDN_THROW(PrepareError(sql));
Yumin Xia2c509c22017-02-09 14:37:36 -0800247 }
248
249 sqlite3_bind_int(stmt, 1, zone.getId());
250
251 while (sqlite3_step(stmt) == SQLITE_ROW) {
252 const char* key = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
Davide Pesavento98026122022-03-14 22:00:03 -0400253 rtn[string(key)] = Block(make_span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 1)),
254 sqlite3_column_bytes(stmt, 1)));
Yumin Xia2c509c22017-02-09 14:37:36 -0800255 }
256
257 sqlite3_finalize(stmt);
258 return rtn;
259}
260
Shock Jiang3016c982014-11-11 11:35:17 -0800261bool
262DbMgr::find(Zone& zone)
263{
264 sqlite3_stmt* stmt;
265 const char* sql = "SELECT id, ttl FROM zones WHERE name=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500266 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800267 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500268 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800269 }
270
Yumin Xia55a7cc42017-05-14 18:43:34 -0700271 saveName(zone.getName(), stmt, 1);
Shock Jiang3016c982014-11-11 11:35:17 -0800272
273 if (sqlite3_step(stmt) == SQLITE_ROW) {
274 zone.setId(sqlite3_column_int64(stmt, 0));
275 zone.setTtl(time::seconds(sqlite3_column_int(stmt, 1)));
Yumin Xia2c509c22017-02-09 14:37:36 -0800276 }
277 else {
Shock Jiang3016c982014-11-11 11:35:17 -0800278 zone.setId(0);
279 }
280
281 sqlite3_finalize(stmt);
282
283 return zone.getId() != 0;
284}
285
Jiewen Tan870b29b2014-11-17 19:09:49 -0800286std::vector<Zone>
287DbMgr::listZones()
288{
289 sqlite3_stmt* stmt;
290 const char* sql = "SELECT id, name, ttl FROM zones";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500291 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800292 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500293 NDN_THROW(PrepareError(sql));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800294 }
295
296 std::vector<Zone> vec;
297
298 while (sqlite3_step(stmt) == SQLITE_ROW) {
299 vec.emplace_back();
300 Zone& zone = vec.back();
301 zone.setId(sqlite3_column_int64(stmt, 0));
302 zone.setTtl(time::seconds(sqlite3_column_int(stmt, 2)));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700303 zone.setName(restoreName(stmt, 1));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800304 }
305 sqlite3_finalize(stmt);
306
307 return vec;
308}
309
Shock Jiang3016c982014-11-11 11:35:17 -0800310void
311DbMgr::remove(Zone& zone)
312{
313 if (zone.getId() == 0)
314 return;
315
316 sqlite3_stmt* stmt;
317 const char* sql = "DELETE FROM zones where id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500318 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800319 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500320 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800321 }
322
323 sqlite3_bind_int64(stmt, 1, zone.getId());
324
325 rc = sqlite3_step(stmt);
326 if (rc != SQLITE_DONE) {
327 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500328 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800329 }
330
331 sqlite3_finalize(stmt);
332
333 zone = Zone();
334}
335
Shock Jiang3016c982014-11-11 11:35:17 -0800336///////////////////////////////////////////////////////////////////////////////////////////////////
337// Rrset
338///////////////////////////////////////////////////////////////////////////////////////////////////
339
340void
341DbMgr::insert(Rrset& rrset)
342{
343 if (rrset.getId() != 0)
344 return;
345
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500346 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500347 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800348 }
349
350 if (rrset.getZone()->getId() == 0) {
351 insert(*rrset.getZone());
352 }
353
354 const char* sql =
355 "INSERT INTO rrsets (zone_id, label, type, version, ttl, data)"
356 " VALUES (?, ?, ?, ?, ?, ?)";
357
358 sqlite3_stmt* stmt;
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500359 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800360 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500361 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800362 }
363
364 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
365
Yumin Xia55a7cc42017-05-14 18:43:34 -0700366 saveName(rrset.getLabel(), stmt, 2);
Davide Pesavento98026122022-03-14 22:00:03 -0400367 sqlite3_bind_blob(stmt, 3, rrset.getType().data(), rrset.getType().size(), SQLITE_STATIC);
368 sqlite3_bind_blob(stmt, 4, rrset.getVersion().data(), rrset.getVersion().size(), SQLITE_STATIC);
Shock Jiang3016c982014-11-11 11:35:17 -0800369 sqlite3_bind_int64(stmt, 5, rrset.getTtl().count());
Davide Pesavento98026122022-03-14 22:00:03 -0400370 sqlite3_bind_blob(stmt, 6, rrset.getData().data(), rrset.getData().size(), SQLITE_STATIC);
Shock Jiang3016c982014-11-11 11:35:17 -0800371
372 rc = sqlite3_step(stmt);
373 if (rc != SQLITE_DONE) {
374 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500375 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800376 }
377
378 rrset.setId(sqlite3_last_insert_rowid(m_conn));
379 sqlite3_finalize(stmt);
380}
381
382bool
383DbMgr::find(Rrset& rrset)
384{
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500385 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500386 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800387 }
388
389 if (rrset.getZone()->getId() == 0) {
390 bool isFound = find(*rrset.getZone());
391 if (!isFound) {
392 return false;
393 }
394 }
395
396 sqlite3_stmt* stmt;
397 const char* sql =
398 "SELECT id, ttl, version, data FROM rrsets"
399 " WHERE zone_id=? and label=? and type=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500400 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800401 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500402 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800403 }
404
405 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
406
Yumin Xia55a7cc42017-05-14 18:43:34 -0700407 saveName(rrset.getLabel(), stmt, 2);
Davide Pesavento98026122022-03-14 22:00:03 -0400408 sqlite3_bind_blob(stmt, 3, rrset.getType().data(), rrset.getType().size(), SQLITE_STATIC);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700409
410 if (sqlite3_step(stmt) == SQLITE_ROW) {
411 rrset.setId(sqlite3_column_int64(stmt, 0));
412 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
Davide Pesavento98026122022-03-14 22:00:03 -0400413 rrset.setVersion(Block(make_span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
414 sqlite3_column_bytes(stmt, 2))));
415 rrset.setData(Block(make_span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
416 sqlite3_column_bytes(stmt, 3))));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700417 }
418 else {
419 rrset.setId(0);
420 }
421 sqlite3_finalize(stmt);
422
423 return rrset.getId() != 0;
424}
425
426bool
427DbMgr::findLowerBound(Rrset& rrset)
428{
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500429 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500430 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700431 }
432
433 if (rrset.getZone()->getId() == 0) {
434 bool isFound = find(*rrset.getZone());
435 if (!isFound) {
436 return false;
437 }
438 }
439
440 sqlite3_stmt* stmt;
441 const char* sql =
442 "SELECT id, ttl, version, data FROM rrsets"
443 " WHERE zone_id=? and label<? and type=? ORDER BY label DESC";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500444 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700445 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500446 NDN_THROW(PrepareError(sql));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700447 }
448
449 sqlite3_bind_int64(stmt, 1, rrset.getZone()->getId());
450
451 saveName(rrset.getLabel(), stmt, 2);
Davide Pesavento98026122022-03-14 22:00:03 -0400452 sqlite3_bind_blob(stmt, 3, rrset.getType().data(), rrset.getType().size(), SQLITE_STATIC);
Shock Jiang3016c982014-11-11 11:35:17 -0800453
454 if (sqlite3_step(stmt) == SQLITE_ROW) {
455 rrset.setId(sqlite3_column_int64(stmt, 0));
456 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
Davide Pesavento98026122022-03-14 22:00:03 -0400457 rrset.setVersion(Block(make_span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
458 sqlite3_column_bytes(stmt, 2))));
459 rrset.setData(Block(make_span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
460 sqlite3_column_bytes(stmt, 3))));
Yumin Xia2c509c22017-02-09 14:37:36 -0800461 }
462 else {
Shock Jiang3016c982014-11-11 11:35:17 -0800463 rrset.setId(0);
464 }
465 sqlite3_finalize(stmt);
466
467 return rrset.getId() != 0;
468}
469
470std::vector<Rrset>
471DbMgr::findRrsets(Zone& zone)
472{
473 if (zone.getId() == 0)
474 find(zone);
475
476 if (zone.getId() == 0)
Davide Pesavento948c50c2020-12-26 21:30:45 -0500477 NDN_THROW(RrsetError("Attempting to find all the rrsets with a zone does not in the database"));
Shock Jiang3016c982014-11-11 11:35:17 -0800478
479 std::vector<Rrset> vec;
480 sqlite3_stmt* stmt;
481 const char* sql = "SELECT id, ttl, version, data, label, type "
Yumin Xia55a7cc42017-05-14 18:43:34 -0700482 "FROM rrsets where zone_id=? ORDER BY label";
Shock Jiang3016c982014-11-11 11:35:17 -0800483
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500484 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800485 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500486 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800487 }
488 sqlite3_bind_int64(stmt, 1, zone.getId());
489
490 while (sqlite3_step(stmt) == SQLITE_ROW) {
491 vec.emplace_back(&zone);
492 Rrset& rrset = vec.back();
493
494 rrset.setId(sqlite3_column_int64(stmt, 0));
495 rrset.setTtl(time::seconds(sqlite3_column_int64(stmt, 1)));
Davide Pesavento98026122022-03-14 22:00:03 -0400496 rrset.setVersion(Block(make_span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 2)),
497 sqlite3_column_bytes(stmt, 2))));
498 rrset.setData(Block(make_span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 3)),
499 sqlite3_column_bytes(stmt, 3))));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700500 rrset.setLabel(restoreName(stmt, 4));
Davide Pesavento98026122022-03-14 22:00:03 -0400501 rrset.setType(Block(make_span(static_cast<const uint8_t*>(sqlite3_column_blob(stmt, 5)),
502 sqlite3_column_bytes(stmt, 5))));
Shock Jiang3016c982014-11-11 11:35:17 -0800503 }
504 sqlite3_finalize(stmt);
505
506 return vec;
507}
508
Yumin Xia55a7cc42017-05-14 18:43:34 -0700509void
510DbMgr::removeRrsetsOfZoneByType(Zone& zone, const name::Component& type)
511{
512 if (zone.getId() == 0)
513 find(zone);
514
515 if (zone.getId() == 0)
Davide Pesavento948c50c2020-12-26 21:30:45 -0500516 NDN_THROW(RrsetError("Attempting to find all the rrsets with a zone does not in the database"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700517
518 sqlite3_stmt* stmt;
519 const char* sql = "DELETE FROM rrsets WHERE zone_id = ? AND type = ?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500520 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700521 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500522 NDN_THROW(PrepareError(sql));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700523 }
524
525 sqlite3_bind_int64(stmt, 1, zone.getId());
Davide Pesavento98026122022-03-14 22:00:03 -0400526 sqlite3_bind_blob(stmt, 2, type.data(), type.size(), SQLITE_STATIC);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700527
528 rc = sqlite3_step(stmt);
529 if (rc != SQLITE_DONE) {
530 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500531 NDN_THROW(ExecuteError(sql));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700532 }
533 sqlite3_finalize(stmt);
534}
Shock Jiang3016c982014-11-11 11:35:17 -0800535
536void
537DbMgr::remove(Rrset& rrset)
538{
539 if (rrset.getId() == 0)
Davide Pesavento948c50c2020-12-26 21:30:45 -0500540 NDN_THROW(RrsetError("Attempting to remove Rrset that has no assigned id"));
Shock Jiang3016c982014-11-11 11:35:17 -0800541
542 sqlite3_stmt* stmt;
543 const char* sql = "DELETE FROM rrsets WHERE id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500544 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800545 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500546 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800547 }
548
549 sqlite3_bind_int64(stmt, 1, rrset.getId());
550
551 rc = sqlite3_step(stmt);
552 if (rc != SQLITE_DONE) {
553 sqlite3_finalize(stmt);
Davide Pesavento948c50c2020-12-26 21:30:45 -0500554 NDN_THROW(ExecuteError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800555 }
556
557 sqlite3_finalize(stmt);
558
559 rrset = Rrset(rrset.getZone());
560}
561
562void
563DbMgr::update(Rrset& rrset)
564{
565 if (rrset.getId() == 0) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500566 NDN_THROW(RrsetError("Attempting to replace Rrset that has no assigned id"));
Shock Jiang3016c982014-11-11 11:35:17 -0800567 }
568
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500569 if (rrset.getZone() == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500570 NDN_THROW(RrsetError("Rrset has not been assigned to a zone"));
Shock Jiang3016c982014-11-11 11:35:17 -0800571 }
572
573 sqlite3_stmt* stmt;
574 const char* sql = "UPDATE rrsets SET ttl=?, version=?, data=? WHERE id=?";
Davide Pesavento093ce1c2019-01-21 19:22:42 -0500575 int rc = sqlite3_prepare_v2(m_conn, sql, -1, &stmt, nullptr);
Shock Jiang3016c982014-11-11 11:35:17 -0800576 if (rc != SQLITE_OK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500577 NDN_THROW(PrepareError(sql));
Shock Jiang3016c982014-11-11 11:35:17 -0800578 }
579
580 sqlite3_bind_int64(stmt, 1, rrset.getTtl().count());
Davide Pesavento98026122022-03-14 22:00:03 -0400581 sqlite3_bind_blob(stmt, 2, rrset.getVersion().data(), rrset.getVersion().size(), SQLITE_STATIC);
582 sqlite3_bind_blob(stmt, 3, rrset.getData().data(), rrset.getData().size(), SQLITE_STATIC);
Shock Jiang3016c982014-11-11 11:35:17 -0800583 sqlite3_bind_int64(stmt, 4, rrset.getId());
584
585 sqlite3_step(stmt);
586 sqlite3_finalize(stmt);
587}
588
589} // namespace ndns
590} // namespace ndn