blob: 1cd0d3a7645341f42b9388cde09ca46f66c3477d [file] [log] [blame]
Shock Jiang3c723182014-09-10 16:41:18 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014, Regents of the University of California.
4 *
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"
Shock Jiang4e0ab7c2014-09-11 16:23:21 -070021#include "logger.hpp"
Shock Jiang3c723182014-09-10 16:41:18 -070022
23#include <boost/algorithm/string/predicate.hpp>
24
25#include <iostream>
26#include <fstream>
27
28namespace ndn {
29namespace ndns {
30
31NDNS_LOG_INIT("DbMgr");
32
33static const std::string NDNS_SCHEMA = "\
34CREATE TABLE IF NOT EXISTS zones ( \n\
35 id INTEGER NOT NULL PRIMARY KEY, \n\
36 name blob NOT NULL UNIQUE, \n\
37 ttl integer(10) NOT NULL); \n\
38 \n\
39CREATE TABLE IF NOT EXISTS rrsets ( \n\
40 id INTEGER NOT NULL PRIMARY KEY, \n\
41 zone_id integer(10) NOT NULL, \n\
42 label blob NOT NULL, \n\
43 type blob NOT NULL, \n\
44 version blob NOT NULL, \n\
45 ttl integer(10) NOT NULL, \n\
46 data blob NOT NULL, \n\
47 FOREIGN KEY(zone_id) REFERENCES zones(id) ON UPDATE Cascade ON DELETE Cascade); \n\
48 \n\
49CREATE UNIQUE INDEX rrsets_zone_id_label_type_version \n\
50 ON rrsets (zone_id, label, type, version); \n\
51";
52
53DbMgr::DbMgr(const std::string& dbFile/* = DEFAULT_CONFIG_PATH "/" "ndns.conf"*/)
54 : m_dbFile(dbFile)
55 , m_conn(0)
56 , m_status(DB_CLOSED)
57{
58 this->open();
59}
60
61
62DbMgr::~DbMgr()
63{
64 if (m_status != DB_CLOSED) {
65 this->close();
66 }
67}
68
69void
70DbMgr::open()
71{
72 if (m_status == DB_CONNECTED)
73 return;
74
75 int res = sqlite3_open_v2(m_dbFile.c_str(), &m_conn,
76 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
77#ifdef DISABLE_SQLITE3_FS_LOCKING
78 "unix-dotfile"
79#else
80 0
81#endif
82 );
83
84 if (res != SQLITE_OK) {
85 m_err = "Cannot open the db file: " + m_dbFile;
86 NDNS_LOG_FATAL(m_err);
87 m_status = DB_ERROR;
88 }
89
90 // ignore any errors from DB creation (command will fail for the existing database, which is ok)
91 sqlite3_exec(m_conn, NDNS_SCHEMA.c_str(), 0, 0, 0);
92
93 m_status = DB_CONNECTED;
94}
95
96void
97DbMgr::close()
98{
99 if (m_status == DB_CLOSED)
100 return;
101
102 int ret = sqlite3_close(m_conn);
103 if (ret != SQLITE_OK) {
104 m_err = "Cannot close the db: " + m_dbFile;
105 NDNS_LOG_FATAL(m_err);
106 m_status = DB_ERROR;
107 }
108 m_status = DB_CLOSED;
109}
110
Shock Jiang4e0ab7c2014-09-11 16:23:21 -0700111///////////////////////////////////////////////////////////////////////////////////////////////////
112
113bool
114DbMgr::lookup(Zone& zone)
115{
116 sqlite3_stmt* stmt;
117 const char* sql = "SELECT id, ttl FROM zones WHERE name=?";
118 int rc = sqlite3_prepare_v2(m_conn, sql, strlen(sql), &stmt, 0);
119 if (rc != SQLITE_OK) {
120 throw PrepareError(sql);
121 }
122
123 const Block& zoneName = zone.getName().wireEncode();
124 sqlite3_bind_blob(stmt, 1, zoneName.wire(), zoneName.size(), SQLITE_STATIC);
125
126 if (sqlite3_step(stmt) == SQLITE_ROW) {
127 zone.setId(sqlite3_column_int64(stmt, 0));
128 zone.setTtl(time::seconds(sqlite3_column_int(stmt, 1)));
129 } else {
130 zone.setId(0);
131 }
132
133 sqlite3_finalize(stmt);
134
135 return zone.getId() != 0;
136}
137
138void
139DbMgr::insert(Zone& zone)
140{
141 if (zone.getId() > 0)
142 return;
143
144 sqlite3_stmt* stmt;
145 const char* sql = "INSERT INTO zones (name, ttl) VALUES (?, ?)";
146 int rc = sqlite3_prepare_v2(m_conn, sql, strlen(sql), &stmt, 0);
147 if (rc != SQLITE_OK) {
148 throw PrepareError(sql);
149 }
150
151 const Block& zoneName = zone.getName().wireEncode();
152 sqlite3_bind_blob(stmt, 1, zoneName.wire(), zoneName.size(), SQLITE_STATIC);
153 sqlite3_bind_int(stmt, 2, zone.getTtl().count());
154
155 rc = sqlite3_step(stmt);
156 if (rc != SQLITE_DONE) {
157 sqlite3_finalize(stmt);
158 throw ExecuteError(sql);
159 }
160
161 zone.setId(sqlite3_last_insert_rowid(m_conn));
162 sqlite3_finalize(stmt);
163}
164
165void
166DbMgr::remove(Zone& zone)
167{
168 if (zone.getId() == 0)
169 return;
170
171 sqlite3_stmt* stmt;
172 const char* sql = "DELETE FROM zones where id=?";
173 int rc = sqlite3_prepare_v2(m_conn, sql, strlen(sql), &stmt, 0);
174 if (rc != SQLITE_OK) {
175 throw PrepareError(sql);
176 }
177
178 sqlite3_bind_int64(stmt, 1, zone.getId());
179
180 rc = sqlite3_step(stmt);
181 if (rc != SQLITE_DONE) {
182 sqlite3_finalize(stmt);
183 throw ExecuteError(sql);
184 }
185
186 sqlite3_finalize(stmt);
187
188 zone.setId(0);
189 zone.setTtl(time::seconds(3600));
190}
191
192
Shock Jiang3c723182014-09-10 16:41:18 -0700193} // namespace ndns
194} // namespace ndn