blob: 5842947b6d6ea9d9f2e270b2c621320f9d981a68 [file] [log] [blame]
Shuo Chen7c6b4d72014-03-26 15:20:30 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyeve1e6f2a2014-04-25 11:28:12 -07003 * Copyright (c) 2014, Regents of the University of California.
4 *
5 * This file is part of NDN repo-ng (Next generation of NDN repository).
6 * See AUTHORS.md for complete list of repo-ng authors and contributors.
7 *
8 * repo-ng 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 * repo-ng 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 * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Shuo Chen7c6b4d72014-03-26 15:20:30 -070018 */
19
Shuo Chen478204c2014-03-18 18:27:04 -070020#include "config.hpp"
Shuo Chen7c6b4d72014-03-26 15:20:30 -070021#include "sqlite-handle.hpp"
Shuo Chen478204c2014-03-18 18:27:04 -070022#include <boost/filesystem.hpp>
Shuo Chen7c6b4d72014-03-26 15:20:30 -070023
24namespace repo {
25
26SqliteHandle::SqliteHandle(const string& dbPath)
27 : StorageHandle(STORAGE_METHOD_SQLITE)
28{
29 if (dbPath.empty()) {
30 std::cerr << "Create db file in local location [" << dbPath << "]. " << std::endl
31 << "You can assign the path using -d option" << std::endl;
32 m_dbPath = string("ndn_repo.db");
33 }
34 else {
Shuo Chen478204c2014-03-18 18:27:04 -070035 boost::filesystem::path fsPath(dbPath);
36 boost::filesystem::file_status fsPathStatus = boost::filesystem::status(fsPath);
37 if (!boost::filesystem::is_directory(fsPathStatus)) {
38 if (!boost::filesystem::create_directory(boost::filesystem::path(fsPath))) {
39 throw Error("Folder '" + dbPath + "' does not exists and cannot be created");
40 }
41 }
42
Shuo Chen7c6b4d72014-03-26 15:20:30 -070043 m_dbPath = dbPath + "/ndn_repo.db";
44 }
45 initializeRepo();
46}
47
48void
49SqliteHandle::initializeRepo()
50{
51 char* errMsg = 0;
Shuo Chen478204c2014-03-18 18:27:04 -070052
53 int rc = sqlite3_open_v2(m_dbPath.c_str(), &m_db,
54 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
55#ifdef DISABLE_SQLITE3_FS_LOCKING
56 "unix-dotfile"
57#else
58 0
59#endif
60 );
61
Shuo Chen7c6b4d72014-03-26 15:20:30 -070062 if (rc == SQLITE_OK) {
63 sqlite3_exec(m_db, "CREATE TABLE NDN_REPO ("
64 "name BLOB PRIMARY KEY, "
65 "data BLOB, "
66 "parentName BLOB, "
67 "nChildren INTEGER);\n"
Alexander Afanasyevb0c78ea2014-04-15 18:12:04 -070068 "CREATE INDEX NdnRepoParentName ON NDN_REPO (parentName);\n"
69 "CREATE INDEX NdnRepoData ON NDN_REPO (data);\n"
70 , 0, 0, &errMsg);
Shuo Chen7c6b4d72014-03-26 15:20:30 -070071 // Ignore errors (when database already exists, errors are expected)
72 }
73 else {
74 std::cerr << "Database file open failure rc:" << rc << std::endl;
75 throw Error("Database file open failure");
76 }
77
78 Name rootName;
79 string sql = string("SELECT * FROM NDN_REPO WHERE name = ?;");
80
81 sqlite3_stmt* queryStmt = 0;
82
83 rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
84 if (rc == SQLITE_OK) {
85 if (sqlite3_bind_blob(queryStmt, 1, rootName.wireEncode().wire(),
86 rootName.wireEncode().size(), 0) == SQLITE_OK) {
87 rc = sqlite3_step(queryStmt);
88 if (rc == SQLITE_ROW) {
89 std::cerr << "root has been created" << std::endl;
90 }
91 else if (rc == SQLITE_DONE) {
92 sqlite3_stmt* p2Stmt = 0;
93 sql = string("INSERT INTO NDN_REPO (name, data, parentName, nChildren) "
94 " VALUES (?, ?, ?, ?);");
95 rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &p2Stmt, 0);
96 if (rc == SQLITE_OK) {
97 if (sqlite3_bind_blob(p2Stmt, 1, rootName.wireEncode().wire(),
98 rootName.wireEncode().size(), 0) == SQLITE_OK &&
99 sqlite3_bind_null(p2Stmt, 2) == SQLITE_OK &&
100 sqlite3_bind_null(p2Stmt, 3) == SQLITE_OK &&
101 sqlite3_bind_int(p2Stmt, 4, 0) == SQLITE_OK) {
102 rc = sqlite3_step(p2Stmt);;
103 if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
104 std::cerr << "Root name insert failure rc:" << rc << std::endl;
105 sqlite3_finalize(p2Stmt);
106 throw Error("Root name insert failure");
107 }
108 }
109 else {
110 std::cerr << "bind blob failure rc:" << rc << std::endl;
111 sqlite3_finalize(p2Stmt);
112 throw Error("bind blob failure");
113 }
114 }
115 else {
116 std::cerr << "p2Stmt prepared rc:" << rc << std::endl;
117 sqlite3_finalize(p2Stmt);
118 throw Error("p2Stmt prepared");
119 }
120 sqlite3_finalize(p2Stmt);
121 }
122 else {
123 std::cerr << "Database query failure rc:" << rc << std::endl;
124 sqlite3_finalize(queryStmt);
125 throw Error("Database query failure");
126 }
127 }
128 sqlite3_finalize(queryStmt);
129 }
130 sqlite3_exec(m_db, "PRAGMA synchronous = OFF", 0, 0, &errMsg);
131 sqlite3_exec(m_db, "PRAGMA journal_mode = WAL", 0, 0, &errMsg);
132}
133
134SqliteHandle::~SqliteHandle()
135{
136 sqlite3_close(m_db);
137}
138
139
140//Temporarily assigned the datatype of every component. needs to be further discussed
141
142bool
143SqliteHandle::insertData(const Data& data)
144{
145 Name name = data.getName();
146
147 if (name.empty()) {
148 std::cerr << "name is empty" << std::endl;
149 return false;
150 }
151
152 int rc = 0;
153
154 string updateSql2 = string("UPDATE NDN_REPO SET data = ? WHERE name = ?;");
155 //std::cerr << "update" << std::endl;
156 sqlite3_stmt* update2Stmt = 0;
157 if (sqlite3_prepare_v2(m_db, updateSql2.c_str(), -1, &update2Stmt, 0) != SQLITE_OK) {
158 sqlite3_finalize(update2Stmt);
159 std::cerr << "update sql2 not prepared" << std::endl;
160 throw Error("update sql2 not prepared");
161 }
162 if (sqlite3_bind_blob(update2Stmt, 1,
163 data.wireEncode().wire(),
164 data.wireEncode().size(), 0) == SQLITE_OK &&
165 sqlite3_bind_blob(update2Stmt, 2,
166 name.wireEncode().wire(),
167 name.wireEncode().size(), 0) == SQLITE_OK) {
168 rc = sqlite3_step(update2Stmt);
169 sqlite3_finalize(update2Stmt);
170 if (rc != SQLITE_DONE) {
171 return false;
172 }
173 //what error??
174 //std::cerr << "update rc:" << rc << std::endl;
175 /// \todo Do something with rc
176 }
177 int changeCount = sqlite3_changes(m_db);
178 //std::cerr << "changeCount: " << changeCount << std::endl;
179 if (changeCount > 0) {
180 return true;
181 }
182
183 sqlite3_stmt* insertStmt = 0;
184 sqlite3_stmt* updateStmt = 0;
185 string insertSql = string("INSERT INTO NDN_REPO (name, data, parentName, nChildren) "
186 "VALUES (?, ?, ?, ?)");
187 string updateSql = string("UPDATE NDN_REPO SET nChildren = nChildren + 1 WHERE name = ?");
188
189 Name rootName;
190
191
192 if (sqlite3_prepare_v2(m_db, insertSql.c_str(), -1, &insertStmt, 0) != SQLITE_OK) {
193 sqlite3_finalize(insertStmt);
194 std::cerr << "insert sql not prepared" << std::endl;
195 }
196 if (sqlite3_prepare_v2(m_db, updateSql.c_str(), -1, &updateStmt, 0) != SQLITE_OK) {
197 sqlite3_finalize(updateStmt);
198 std::cerr << "update sql not prepared" << std::endl;
199 throw Error("update sql not prepared");
200 }
201
202 //Insert and read the prefix
203 Name parentName = name;
204 Name grandName;
205 do {
206 parentName = parentName.getPrefix(-1);
207 if (!hasName(parentName)) {
208 grandName = parentName.getPrefix(-1);
209 if (sqlite3_bind_blob(insertStmt, 1,
210 parentName.wireEncode().wire(),
211 parentName.wireEncode().size(), 0) == SQLITE_OK &&
212 sqlite3_bind_null(insertStmt, 2) == SQLITE_OK &&
213 sqlite3_bind_blob(insertStmt, 3,
214 grandName.wireEncode().wire(),
215 grandName.wireEncode().size(), 0) == SQLITE_OK &&
216 sqlite3_bind_int(insertStmt, 4, 1) == SQLITE_OK) {
217 rc = sqlite3_step(insertStmt);
218 if (rc == SQLITE_CONSTRAINT) {
219 std::cerr << "Insert parent prefix failed" << std::endl;
220 sqlite3_finalize(insertStmt);
221 throw Error("Insert parent prefix failed");
222 }
223 sqlite3_reset(insertStmt);
224 }
225 }
226 else {
227 break;
228 }
229 } while (!parentName.empty());
230
231 //The existed parent nChildren + 1
232
233 if (sqlite3_bind_blob(updateStmt, 1, parentName.wireEncode().wire(),
234 parentName.wireEncode().size(), 0) == SQLITE_OK) {
235 rc = sqlite3_step(updateStmt);
236 if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
237 std::cerr << "update error rc:" << rc << std::endl;
238 sqlite3_finalize(updateStmt);
239 sqlite3_finalize(insertStmt);
240 throw Error("update error");
241 }
242 sqlite3_reset(updateStmt);
243 }
244
245 //Insert the name and the data, if this data name exists update, else insert data
246
247 parentName = name.getPrefix(-1);
248 sqlite3_reset(insertStmt);
249 if (sqlite3_bind_blob(insertStmt, 1,
250 name.wireEncode().wire(),
251 name.wireEncode().size(), 0) == SQLITE_OK &&
252 sqlite3_bind_blob(insertStmt, 2,
253 data.wireEncode().wire(),
254 data.wireEncode().size(), 0) == SQLITE_OK &&
255 sqlite3_bind_blob(insertStmt, 3,
256 parentName.wireEncode().wire(),
257 parentName.wireEncode().size(), 0) == SQLITE_OK &&
258 sqlite3_bind_int(insertStmt, 4, 0) == SQLITE_OK) {
259 rc = sqlite3_step(insertStmt);
260 //std::cerr << "insert rc:" << rc << std::endl;
261 //std::cerr << "insert the data: " << data.wireEncode().wire() << std::endl;
262 if (rc == SQLITE_CONSTRAINT) {
263 std::cerr << "The name of the data has existed!" << std::endl;
264 sqlite3_finalize(insertStmt);
265 return false;
266 }
267 }
268
269 sqlite3_finalize(updateStmt);
270 sqlite3_finalize(insertStmt);
271 return true;
272}
273
274bool
275SqliteHandle::deleteData(const Name& name)
276{
277 sqlite3_stmt* queryStmt = 0;
278 sqlite3_stmt* deleteStmt = 0;
279 sqlite3_stmt* updateStmt = 0;
280 sqlite3_stmt* update2Stmt = 0;
281
282 string querySql = string("SELECT * from NDN_REPO where name = ?;");
283 string deleteSql = string("DELETE from NDN_REPO where name = ?;");
284
285 string updateSql = string("UPDATE NDN_REPO SET nChildren = nChildren - 1 WHERE name = ?;");
286 string updateSql2 = string("UPDATE NDN_REPO SET data = NULL WHERE name = ?;");
287
288 int rc = sqlite3_prepare_v2(m_db, querySql.c_str(), -1, &queryStmt, 0);
289 Name tmpName = name;
290 int nChildren = -1;
291 if (sqlite3_prepare_v2(m_db, deleteSql.c_str(), -1, &deleteStmt, 0) != SQLITE_OK) {
292 sqlite3_finalize(deleteStmt);
293 std::cerr << "delete statement prepared failed" << std::endl;
294 throw Error("delete statement prepared failed");
295 }
296 if (sqlite3_prepare_v2(m_db, updateSql.c_str(), -1, &updateStmt, 0) != SQLITE_OK) {
297 sqlite3_finalize(updateStmt);
298 std::cerr << "delete update prepared failed" << std::endl;
299 throw Error("delete update prepared failed");
300 }
301 if (rc == SQLITE_OK) {
302 if (sqlite3_bind_blob(queryStmt, 1,
303 tmpName.wireEncode().wire(),
304 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
305 rc = sqlite3_step(queryStmt);
306 if (rc == SQLITE_ROW) {
307 nChildren = sqlite3_column_int(queryStmt, 3);
308 }
309 else {
310 std::cerr << "Database query no such name or failure rc:" << rc << std::endl;
311 sqlite3_finalize(queryStmt);
312 return false;
313 }
314 }
315 if (nChildren > 0) {
316 //update internal node, so just update and return
317 if (sqlite3_prepare_v2(m_db, updateSql2.c_str(), -1, &update2Stmt, 0) != SQLITE_OK) {
318 sqlite3_finalize(update2Stmt);
319 std::cerr << "delete update prepared failed" << std::endl;
320 throw Error("delete update prepared failed");
321 }
322 if (sqlite3_bind_blob(update2Stmt, 1,
323 tmpName.wireEncode().wire(),
324 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
325 rc = sqlite3_step(update2Stmt);
326 std::cerr << "deleteData update" << std::endl;
327 }
328 else {
329 std::cerr << "delete bind error" << std::endl;
330 sqlite3_finalize(update2Stmt);
331 throw Error("delete bind error");
332 }
333 return true;
334 }
335 else {
336 //Delete the leaf node
337 if (sqlite3_bind_blob(deleteStmt, 1,
338 tmpName.wireEncode().wire(),
339 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
340 rc = sqlite3_step(deleteStmt);
341 if (rc != SQLITE_DONE && rc !=SQLITE_ROW) {
342 std::cerr << "leaf node delete error rc:" << rc << std::endl;
343 sqlite3_finalize(deleteStmt);
344 throw Error("leaf node delete error");
345 }
346 }
347 else {
348 std::cerr << "delete bind error" << std::endl;
349 sqlite3_finalize(deleteStmt);
350 throw Error("delete bind error");
351 }
352 sqlite3_reset(deleteStmt);
353 }
354 queryStmt = 0;
355 rc = sqlite3_prepare_v2(m_db, querySql.c_str(), -1, &queryStmt, 0);
356 if (rc != SQLITE_OK) {
357 std::cerr << "prepare error" << std::endl;
358 sqlite3_finalize(queryStmt);
359 throw Error("prepare error");
360 }
361 //read prefix if nChildren is 0 and data is 0
362 int dataSize = 0;
363 do {
364 tmpName = tmpName.getPrefix(-1);
365 if (sqlite3_bind_blob(queryStmt, 1,
366 tmpName.wireEncode().wire(),
367 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
368 rc = sqlite3_step(queryStmt);
369 if (rc == SQLITE_ROW) {
370 nChildren = sqlite3_column_int(queryStmt, 3);
371 dataSize = sqlite3_column_bytes(queryStmt, 1);
372 }
373 else {
374 std::cerr << "Database query no such name or failure rc:" << rc << std::endl;
375 sqlite3_finalize(queryStmt);
376 return false;
377 }
378 if (nChildren == 1 && !tmpName.empty() && dataSize == 0) {
379 //Delete this internal node
380 if (sqlite3_bind_blob(deleteStmt, 1,
381 tmpName.wireEncode().wire(),
382 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
383 rc = sqlite3_step(deleteStmt);
384 if (rc != SQLITE_DONE && rc !=SQLITE_ROW) {
385 std::cerr << "internal node delete error rc:" << rc << std::endl;
386 sqlite3_finalize(deleteStmt);
387 throw Error("internal node delete error");
388 }
389 }
390 else {
391 std::cerr << "delete bind error" << std::endl;
392 sqlite3_finalize(deleteStmt);
393 throw Error("delete bind error");
394 }
395 sqlite3_reset(deleteStmt);
396 }
397 else {
398 //nChildren - 1
399 if (sqlite3_bind_blob(updateStmt, 1,
400 tmpName.wireEncode().wire(),
401 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
402 rc = sqlite3_step(updateStmt);
403 if (rc != SQLITE_DONE && rc !=SQLITE_ROW) {
404 std::cerr << "internal node nChildren update error rc:" << rc << std::endl;
405 sqlite3_finalize(updateStmt);
406 throw Error("internal node nChildren update error");
407 }
408 }
409 else {
410 std::cerr << "update bind error" << std::endl;
411 sqlite3_finalize(updateStmt);
412 throw Error("update bind error");
413 }
414 sqlite3_reset(updateStmt);
415 break;
416 }
417 }
418 else {
419 std::cerr << "query bind error" << std::endl;
420 sqlite3_finalize(queryStmt);
421 throw Error("query bind error");
422 }
423 sqlite3_reset(queryStmt);
424 } while (!tmpName.empty());
425
426 }
427 else {
428 std::cerr << "query prepared failure rc:" << rc << std::endl;
429 sqlite3_finalize(queryStmt);
430 throw Error("query prepared failure");
431 }
432 return true;
433}
434
435bool
436SqliteHandle::readData(const Interest& interest, Data& data)
437{
438 vector<Name> names;
439 Name resultName;
440 if (!interest.hasSelectors()) {
441 return readDataPlain(interest.getName(), data);
442 }
443 else {
444 if (readNameSelector(interest, names)) {
Shuo Chenca329182014-03-19 18:05:18 -0700445 if (names.empty())
446 return false;
Shuo Chen7c6b4d72014-03-26 15:20:30 -0700447 if (!filterNameChild(interest.getName(), interest.getChildSelector(), names, resultName)) {
448 return false;
449 }
450 }
451 return readData(resultName, data);
452 }
453}
454
455// This function is the first version of data read following longest prefix match.
456// It will return the leftmost data
457bool
458SqliteHandle::readDataPlain(const Name& name, Data& data)
459{
460 vector<Name> names;
461 Name resultName;
462 readDataName(name, names);
Shuo Chenca329182014-03-19 18:05:18 -0700463 if (names.empty())
464 return false;
465 bool isOk = filterNameChild(name, 0, names, resultName);
466 if (isOk) {
Shuo Chen7c6b4d72014-03-26 15:20:30 -0700467 return readData(resultName, data);
468 }
469 else
470 {
471 return false;
472 }
473}
474
475// retrieve all the leaf nodes of a subtree
476bool
477SqliteHandle::readDataName(const Name& name, vector<Name>& names) const
478{
479 if (name.empty()) {
480 std::cerr << "The name is empty" << std::endl;
481 return false;
482 }
483 Name tmpName = name;
484 //This queue is for internal node;
485 queue<Name> internalNames;
486
487 // Step 1. Check if the requested name corresponds to a leaf (data is not NULL)
488 string sql = string("SELECT * FROM NDN_REPO WHERE name = ? AND data IS NOT NULL;");
489 sqlite3_stmt* queryStmt = 0;
490 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
491 if (rc != SQLITE_OK)
492 throw Error("prepare error");
493
494 if (sqlite3_bind_blob(queryStmt, 1,
495 tmpName.wireEncode().wire(),
496 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
497 rc = sqlite3_step(queryStmt);
498 if (rc == SQLITE_ROW) {
499 int nChildren = sqlite3_column_int(queryStmt, 3);
500 Name elementName;
501 elementName.wireDecode(Block(sqlite3_column_blob(queryStmt, 0),
502 sqlite3_column_bytes(queryStmt, 0)));
503 names.push_back(elementName);
504 if (nChildren == 0) {
505 sqlite3_finalize(queryStmt);
506 return true;
507 }
508 }
509 else if (rc == SQLITE_DONE) {
510 // ignore
511 }
512 else {
513 std::cerr << "read error rc:" << rc << std::endl;
514 sqlite3_finalize(queryStmt);
515 throw Error("read error");
516 }
517 }
518 sqlite3_finalize(queryStmt);
519
520
521 // Step 2. Recursively find all data packets with the specified prefix
522 string psql = string("SELECT * FROM NDN_REPO WHERE parentName = ?;");
523 sqlite3_stmt* queryParentStmt = 0;
524 rc = sqlite3_prepare_v2(m_db, psql.c_str(), -1, &queryParentStmt, 0);
525 if (rc != SQLITE_OK)
526 throw Error("prepare error");
527
528 internalNames.push(tmpName);
529 while (!internalNames.empty()) {
530 tmpName = internalNames.front();
531 internalNames.pop();
532 if (sqlite3_bind_blob(queryParentStmt, 1,
533 tmpName.wireEncode().wire(),
534 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
535 while (true) {
536 rc = sqlite3_step(queryParentStmt);
537 if (rc == SQLITE_ROW) {
538 Name elementName;
539 elementName.wireDecode(Block(sqlite3_column_blob(queryParentStmt, 0),
540 sqlite3_column_bytes(queryParentStmt, 0)));
541 int nChildren = sqlite3_column_int(queryParentStmt, 3);
542 if (nChildren > 0) {
543 internalNames.push(elementName);
544 }
Alexander Afanasyevb0c78ea2014-04-15 18:12:04 -0700545 if (sqlite3_column_type(queryParentStmt, 1) != SQLITE_NULL) {
Shuo Chen7c6b4d72014-03-26 15:20:30 -0700546 names.push_back(elementName);
547 }
548 }
549 else if (rc == SQLITE_DONE) {
550 break;
551 }
552 else {
553 std::cerr << "read error rc:" << rc << std::endl;
554 sqlite3_finalize(queryParentStmt);
555 throw Error("read error");
556 }
557 }
558 sqlite3_reset(queryParentStmt);
559 }
560 else {
561 std::cerr << "bind error" << std::endl;
562 sqlite3_finalize(queryParentStmt);
563 throw Error("bind error");
564 }
565 }
566 sqlite3_finalize(queryParentStmt);
567 return true;
568}
569
570bool
571SqliteHandle::readNameSelector(const Interest& interest, vector<Name>& names) const
572{
573 if (interest.getName().empty()) {
574 std::cerr << "The name of interest is empty" << std::endl;
575 return false;
576 }
577 Name tmpName = interest.getName();
578 //This queue is for internal node;
579 queue<Name> internalNames;
580
581 // Step 1. Check if the requested Data corresponds to a leaf (data is not NULL)
582 sqlite3_stmt* queryStmt = 0;
583 string sql = string("SELECT * FROM NDN_REPO WHERE name = ? AND data IS NOT NULL;");
584 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
585 if (rc != SQLITE_OK)
586 throw Error("prepare error");
587
588 if (sqlite3_bind_blob(queryStmt, 1,
589 tmpName.wireEncode().wire(),
590 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
591 rc = sqlite3_step(queryStmt);
592 if (rc == SQLITE_ROW) {
593 Data elementData;
594 elementData.wireDecode(Block(sqlite3_column_blob(queryStmt, 1),
595 sqlite3_column_bytes(queryStmt, 1)));
596 if (interest.matchesData(elementData)) {
597 names.push_back(elementData.getName());
598 }
599
600 int nChildren = sqlite3_column_int(queryStmt, 3);
601 if (nChildren == 0) {
602 sqlite3_finalize(queryStmt);
603 return true;
604 }
605 }
606 else if (rc == SQLITE_DONE) {
607 // ignore
608 }
609 else {
610 std::cerr << "read error rc:" << rc << std::endl;
611 sqlite3_finalize(queryStmt);
612 throw Error("read error");
613 }
614 }
615 sqlite3_finalize(queryStmt);
616
617 // Step 2. Recursively find all data packets that match the Interest
618 internalNames.push(tmpName);
619 sqlite3_stmt* queryParentStmt = 0;
620 string psql = string("SELECT * FROM NDN_REPO WHERE parentName = ?;");
621 rc = sqlite3_prepare_v2(m_db, psql.c_str(), -1, &queryParentStmt, 0);
622 if (rc != SQLITE_OK)
623 throw Error("prepare error");
624
625 while (!internalNames.empty()) {
626 tmpName = internalNames.front();
627 internalNames.pop();
628 if (sqlite3_bind_blob(queryParentStmt, 1,
629 tmpName.wireEncode().wire(),
630 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
631 while (true) {
632 rc = sqlite3_step(queryParentStmt);
633 if (rc == SQLITE_ROW) {
634 if (sqlite3_column_type(queryParentStmt, 1) != SQLITE_NULL) {
635 Data elementData;
636 elementData.wireDecode(Block(sqlite3_column_blob(queryParentStmt, 1),
637 sqlite3_column_bytes(queryParentStmt, 1)));
638 if (interest.matchesData(elementData)) {
639 names.push_back(elementData.getName());
640 }
641 }
642
643 Name elementName;
644 elementName.wireDecode(Block(sqlite3_column_blob(queryParentStmt, 0),
645 sqlite3_column_bytes(queryParentStmt, 0)));
646
647 int nChildren = sqlite3_column_int(queryParentStmt, 3);
648 if (nChildren > 0) {
649 internalNames.push(elementName);
650 }
651 }
652 else if (rc == SQLITE_DONE) {
653 break;
654 }
655 else {
656 std::cerr << "read error rc:" << rc << std::endl;
657 sqlite3_finalize(queryParentStmt);
658 throw Error("read error");
659 }
660 }
661 sqlite3_reset(queryParentStmt);
662 }
663 else {
664 std::cerr << "bind error" << std::endl;
665 sqlite3_finalize(queryParentStmt);
666 throw Error("bind error");
667 }
668 }
669 sqlite3_finalize(queryParentStmt);
670 return true;
671}
672
673bool
674SqliteHandle::filterNameChild(const Name& name, int childSelector,
675 const vector<Name>& names, Name& resultName)
676{
Shuo Chenca329182014-03-19 18:05:18 -0700677 BOOST_ASSERT(!names.empty());
678
679 if (childSelector < 0) {
680 resultName = *names.begin();
681 }
682 else if (childSelector == 0) {
Shuo Chen7c6b4d72014-03-26 15:20:30 -0700683 if (!names.empty()) {
684 resultName = *std::min_element(names.begin(), names.end());
685 }
686 else {
687 return false;
688 }
689 }
690 else if (childSelector == 1) {
691 if (!names.empty()) {
692 resultName = *std::max_element(names.begin(), names.end());
693 }
694 else {
695 return false;
696 }
697 }
698 else {
Shuo Chenca329182014-03-19 18:05:18 -0700699 std::cerr << "Unknown ChildSelector specified" << std::endl;
Shuo Chen7c6b4d72014-03-26 15:20:30 -0700700 return false;
701 }
702 return true;
703}
704
705bool
706SqliteHandle::readNameAny(const Name& name, const Selectors& selectors, vector<Name>& names)
707{
708 if (selectors.empty()) {
709 if (hasName(name)) {
710 names.push_back(name);
711 }
712 return true;
713 }
714 else {
715 Interest interest(name);
716 interest.setSelectors(selectors);
717 readNameSelector(interest, names);
Shuo Chenca329182014-03-19 18:05:18 -0700718 if (names.empty())
719 return false;
Shuo Chen7c6b4d72014-03-26 15:20:30 -0700720 if (selectors.getChildSelector() >= 0) {
721 Name resultName;
722 if (!filterNameChild(name, selectors.getChildSelector(), names, resultName))
723 return false;
724 names.clear();
725 names.push_back(resultName);
726 return true;
727 }
728 else {
729 return true;
730 }
731 }
732}
733
734bool
735SqliteHandle::readData(const Name& name, Data& data)
736{
737 sqlite3_stmt* queryStmt = 0;
738 string sql = string("SELECT * FROM NDN_REPO WHERE name = ? AND data IS NOT NULL;");
739 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
740 if (rc == SQLITE_OK) {
741 if (sqlite3_bind_blob(queryStmt, 1,
742 name.wireEncode().wire(),
743 name.wireEncode().size(), 0) == SQLITE_OK) {
744 rc = sqlite3_step(queryStmt);
745 if (rc == SQLITE_ROW) {
746 data.wireDecode(Block(sqlite3_column_blob(queryStmt, 1),
747 sqlite3_column_bytes(queryStmt, 1)));
748 sqlite3_finalize(queryStmt);
749 return true;
750 }
751 else if (rc == SQLITE_DONE) {
752 return false;
753 }
754 else {
755 std::cerr << "Database query failure rc:" << rc << std::endl;
756 sqlite3_finalize(queryStmt);
757 throw Error("Database query failure");
758 }
759 }
760 sqlite3_finalize(queryStmt);
761 }
762 return true;
763}
764
765
766//This is the exact name query in database.
767bool
768SqliteHandle::hasName(const Name& name)
769{
770 sqlite3_stmt* queryStmt = 0;
771 string sql = string("select * from NDN_REPO where name = ?;");
772 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
773 if (rc == SQLITE_OK) {
774 if (sqlite3_bind_blob(queryStmt, 1,
775 name.wireEncode().wire(),
776 name.wireEncode().size(), 0) == SQLITE_OK) {
777 rc = sqlite3_step(queryStmt);
778 if (rc == SQLITE_ROW) {
779 sqlite3_finalize(queryStmt);
780 return true;
781 }
782 else if (rc == SQLITE_DONE) {
783 sqlite3_finalize(queryStmt);
784 return false;
785 }
786 else {
787 std::cerr << "Database query failure rc:" << rc << std::endl;
788 sqlite3_finalize(queryStmt);
789 return false;
790 }
791 }
792 sqlite3_finalize(queryStmt);
793 }
794 return true;
795}
796
797//This is the exact parent name query in database.
798bool
799SqliteHandle::hasParentName(const Name& parentName) const
800{
801 sqlite3_stmt* queryStmt = 0;
802 string sql = string("SELECT * FROM NDN_REPO WHERE parentName = ?;");
803 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
804 if (rc == SQLITE_OK) {
805 if (sqlite3_bind_blob(queryStmt, 1,
806 parentName.wireEncode().wire(),
807 parentName.wireEncode().size(), 0) == SQLITE_OK) {
808 rc = sqlite3_step(queryStmt);
809 if (rc == SQLITE_ROW) {
810 sqlite3_finalize(queryStmt);
811 return true;
812 }
813 else if (rc == SQLITE_DONE) {
814 sqlite3_finalize(queryStmt);
815 return false;
816 }
817 else {
818 std::cerr << "Database query failure rc:" << rc << std::endl;
819 sqlite3_finalize(queryStmt);
820 return false;
821 }
822 }
823 sqlite3_finalize(queryStmt);
824 }
825 return true;
826}
827
Alexander Afanasyevb0c78ea2014-04-15 18:12:04 -0700828size_t
829SqliteHandle::size()
830{
831 sqlite3_stmt* queryStmt = 0;
832 string sql("SELECT count(*) FROM NDN_REPO WHERE data IS NOT NULL");
833 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
834 if (rc != SQLITE_OK)
835 {
836 std::cerr << "Database query failure rc:" << rc << std::endl;
837 sqlite3_finalize(queryStmt);
838 throw Error("Database query failure");
839 }
840
841 rc = sqlite3_step(queryStmt);
842 if (rc != SQLITE_ROW)
843 {
844 std::cerr << "Database query failure rc:" << rc << std::endl;
845 sqlite3_finalize(queryStmt);
846 throw Error("Database query failure");
847 }
848
849 size_t nDatas = static_cast<size_t>(sqlite3_column_int64(queryStmt, 0));
850 return nDatas;
851}
852
Shuo Chen7c6b4d72014-03-26 15:20:30 -0700853} //namespace repo