blob: 02598a90406827c11da716eff9e264c208e3d1c2 [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)) {
445 if (!filterNameChild(interest.getName(), interest.getChildSelector(), names, resultName)) {
446 return false;
447 }
448 }
449 return readData(resultName, data);
450 }
451}
452
453// This function is the first version of data read following longest prefix match.
454// It will return the leftmost data
455bool
456SqliteHandle::readDataPlain(const Name& name, Data& data)
457{
458 vector<Name> names;
459 Name resultName;
460 readDataName(name, names);
461 filterNameChild(name, 0, names, resultName);
462 if (!resultName.empty()) {
463 return readData(resultName, data);
464 }
465 else
466 {
467 return false;
468 }
469}
470
471// retrieve all the leaf nodes of a subtree
472bool
473SqliteHandle::readDataName(const Name& name, vector<Name>& names) const
474{
475 if (name.empty()) {
476 std::cerr << "The name is empty" << std::endl;
477 return false;
478 }
479 Name tmpName = name;
480 //This queue is for internal node;
481 queue<Name> internalNames;
482
483 // Step 1. Check if the requested name corresponds to a leaf (data is not NULL)
484 string sql = string("SELECT * FROM NDN_REPO WHERE name = ? AND data IS NOT NULL;");
485 sqlite3_stmt* queryStmt = 0;
486 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
487 if (rc != SQLITE_OK)
488 throw Error("prepare error");
489
490 if (sqlite3_bind_blob(queryStmt, 1,
491 tmpName.wireEncode().wire(),
492 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
493 rc = sqlite3_step(queryStmt);
494 if (rc == SQLITE_ROW) {
495 int nChildren = sqlite3_column_int(queryStmt, 3);
496 Name elementName;
497 elementName.wireDecode(Block(sqlite3_column_blob(queryStmt, 0),
498 sqlite3_column_bytes(queryStmt, 0)));
499 names.push_back(elementName);
500 if (nChildren == 0) {
501 sqlite3_finalize(queryStmt);
502 return true;
503 }
504 }
505 else if (rc == SQLITE_DONE) {
506 // ignore
507 }
508 else {
509 std::cerr << "read error rc:" << rc << std::endl;
510 sqlite3_finalize(queryStmt);
511 throw Error("read error");
512 }
513 }
514 sqlite3_finalize(queryStmt);
515
516
517 // Step 2. Recursively find all data packets with the specified prefix
518 string psql = string("SELECT * FROM NDN_REPO WHERE parentName = ?;");
519 sqlite3_stmt* queryParentStmt = 0;
520 rc = sqlite3_prepare_v2(m_db, psql.c_str(), -1, &queryParentStmt, 0);
521 if (rc != SQLITE_OK)
522 throw Error("prepare error");
523
524 internalNames.push(tmpName);
525 while (!internalNames.empty()) {
526 tmpName = internalNames.front();
527 internalNames.pop();
528 if (sqlite3_bind_blob(queryParentStmt, 1,
529 tmpName.wireEncode().wire(),
530 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
531 while (true) {
532 rc = sqlite3_step(queryParentStmt);
533 if (rc == SQLITE_ROW) {
534 Name elementName;
535 elementName.wireDecode(Block(sqlite3_column_blob(queryParentStmt, 0),
536 sqlite3_column_bytes(queryParentStmt, 0)));
537 int nChildren = sqlite3_column_int(queryParentStmt, 3);
538 if (nChildren > 0) {
539 internalNames.push(elementName);
540 }
Alexander Afanasyevb0c78ea2014-04-15 18:12:04 -0700541 if (sqlite3_column_type(queryParentStmt, 1) != SQLITE_NULL) {
Shuo Chen7c6b4d72014-03-26 15:20:30 -0700542 names.push_back(elementName);
543 }
544 }
545 else if (rc == SQLITE_DONE) {
546 break;
547 }
548 else {
549 std::cerr << "read error rc:" << rc << std::endl;
550 sqlite3_finalize(queryParentStmt);
551 throw Error("read error");
552 }
553 }
554 sqlite3_reset(queryParentStmt);
555 }
556 else {
557 std::cerr << "bind error" << std::endl;
558 sqlite3_finalize(queryParentStmt);
559 throw Error("bind error");
560 }
561 }
562 sqlite3_finalize(queryParentStmt);
563 return true;
564}
565
566bool
567SqliteHandle::readNameSelector(const Interest& interest, vector<Name>& names) const
568{
569 if (interest.getName().empty()) {
570 std::cerr << "The name of interest is empty" << std::endl;
571 return false;
572 }
573 Name tmpName = interest.getName();
574 //This queue is for internal node;
575 queue<Name> internalNames;
576
577 // Step 1. Check if the requested Data corresponds to a leaf (data is not NULL)
578 sqlite3_stmt* queryStmt = 0;
579 string sql = string("SELECT * FROM NDN_REPO WHERE name = ? AND data IS NOT NULL;");
580 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
581 if (rc != SQLITE_OK)
582 throw Error("prepare error");
583
584 if (sqlite3_bind_blob(queryStmt, 1,
585 tmpName.wireEncode().wire(),
586 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
587 rc = sqlite3_step(queryStmt);
588 if (rc == SQLITE_ROW) {
589 Data elementData;
590 elementData.wireDecode(Block(sqlite3_column_blob(queryStmt, 1),
591 sqlite3_column_bytes(queryStmt, 1)));
592 if (interest.matchesData(elementData)) {
593 names.push_back(elementData.getName());
594 }
595
596 int nChildren = sqlite3_column_int(queryStmt, 3);
597 if (nChildren == 0) {
598 sqlite3_finalize(queryStmt);
599 return true;
600 }
601 }
602 else if (rc == SQLITE_DONE) {
603 // ignore
604 }
605 else {
606 std::cerr << "read error rc:" << rc << std::endl;
607 sqlite3_finalize(queryStmt);
608 throw Error("read error");
609 }
610 }
611 sqlite3_finalize(queryStmt);
612
613 // Step 2. Recursively find all data packets that match the Interest
614 internalNames.push(tmpName);
615 sqlite3_stmt* queryParentStmt = 0;
616 string psql = string("SELECT * FROM NDN_REPO WHERE parentName = ?;");
617 rc = sqlite3_prepare_v2(m_db, psql.c_str(), -1, &queryParentStmt, 0);
618 if (rc != SQLITE_OK)
619 throw Error("prepare error");
620
621 while (!internalNames.empty()) {
622 tmpName = internalNames.front();
623 internalNames.pop();
624 if (sqlite3_bind_blob(queryParentStmt, 1,
625 tmpName.wireEncode().wire(),
626 tmpName.wireEncode().size(), 0) == SQLITE_OK) {
627 while (true) {
628 rc = sqlite3_step(queryParentStmt);
629 if (rc == SQLITE_ROW) {
630 if (sqlite3_column_type(queryParentStmt, 1) != SQLITE_NULL) {
631 Data elementData;
632 elementData.wireDecode(Block(sqlite3_column_blob(queryParentStmt, 1),
633 sqlite3_column_bytes(queryParentStmt, 1)));
634 if (interest.matchesData(elementData)) {
635 names.push_back(elementData.getName());
636 }
637 }
638
639 Name elementName;
640 elementName.wireDecode(Block(sqlite3_column_blob(queryParentStmt, 0),
641 sqlite3_column_bytes(queryParentStmt, 0)));
642
643 int nChildren = sqlite3_column_int(queryParentStmt, 3);
644 if (nChildren > 0) {
645 internalNames.push(elementName);
646 }
647 }
648 else if (rc == SQLITE_DONE) {
649 break;
650 }
651 else {
652 std::cerr << "read error rc:" << rc << std::endl;
653 sqlite3_finalize(queryParentStmt);
654 throw Error("read error");
655 }
656 }
657 sqlite3_reset(queryParentStmt);
658 }
659 else {
660 std::cerr << "bind error" << std::endl;
661 sqlite3_finalize(queryParentStmt);
662 throw Error("bind error");
663 }
664 }
665 sqlite3_finalize(queryParentStmt);
666 return true;
667}
668
669bool
670SqliteHandle::filterNameChild(const Name& name, int childSelector,
671 const vector<Name>& names, Name& resultName)
672{
673 if (childSelector == 0) {
674 if (!names.empty()) {
675 resultName = *std::min_element(names.begin(), names.end());
676 }
677 else {
678 return false;
679 }
680 }
681 else if (childSelector == 1) {
682 if (!names.empty()) {
683 resultName = *std::max_element(names.begin(), names.end());
684 }
685 else {
686 return false;
687 }
688 }
689 else {
690 return false;
691 }
692 return true;
693}
694
695bool
696SqliteHandle::readNameAny(const Name& name, const Selectors& selectors, vector<Name>& names)
697{
698 if (selectors.empty()) {
699 if (hasName(name)) {
700 names.push_back(name);
701 }
702 return true;
703 }
704 else {
705 Interest interest(name);
706 interest.setSelectors(selectors);
707 readNameSelector(interest, names);
708 if (selectors.getChildSelector() >= 0) {
709 Name resultName;
710 if (!filterNameChild(name, selectors.getChildSelector(), names, resultName))
711 return false;
712 names.clear();
713 names.push_back(resultName);
714 return true;
715 }
716 else {
717 return true;
718 }
719 }
720}
721
722bool
723SqliteHandle::readData(const Name& name, Data& data)
724{
725 sqlite3_stmt* queryStmt = 0;
726 string sql = string("SELECT * FROM NDN_REPO WHERE name = ? AND data IS NOT NULL;");
727 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
728 if (rc == SQLITE_OK) {
729 if (sqlite3_bind_blob(queryStmt, 1,
730 name.wireEncode().wire(),
731 name.wireEncode().size(), 0) == SQLITE_OK) {
732 rc = sqlite3_step(queryStmt);
733 if (rc == SQLITE_ROW) {
734 data.wireDecode(Block(sqlite3_column_blob(queryStmt, 1),
735 sqlite3_column_bytes(queryStmt, 1)));
736 sqlite3_finalize(queryStmt);
737 return true;
738 }
739 else if (rc == SQLITE_DONE) {
740 return false;
741 }
742 else {
743 std::cerr << "Database query failure rc:" << rc << std::endl;
744 sqlite3_finalize(queryStmt);
745 throw Error("Database query failure");
746 }
747 }
748 sqlite3_finalize(queryStmt);
749 }
750 return true;
751}
752
753
754//This is the exact name query in database.
755bool
756SqliteHandle::hasName(const Name& name)
757{
758 sqlite3_stmt* queryStmt = 0;
759 string sql = string("select * from NDN_REPO where name = ?;");
760 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
761 if (rc == SQLITE_OK) {
762 if (sqlite3_bind_blob(queryStmt, 1,
763 name.wireEncode().wire(),
764 name.wireEncode().size(), 0) == SQLITE_OK) {
765 rc = sqlite3_step(queryStmt);
766 if (rc == SQLITE_ROW) {
767 sqlite3_finalize(queryStmt);
768 return true;
769 }
770 else if (rc == SQLITE_DONE) {
771 sqlite3_finalize(queryStmt);
772 return false;
773 }
774 else {
775 std::cerr << "Database query failure rc:" << rc << std::endl;
776 sqlite3_finalize(queryStmt);
777 return false;
778 }
779 }
780 sqlite3_finalize(queryStmt);
781 }
782 return true;
783}
784
785//This is the exact parent name query in database.
786bool
787SqliteHandle::hasParentName(const Name& parentName) const
788{
789 sqlite3_stmt* queryStmt = 0;
790 string sql = string("SELECT * FROM NDN_REPO WHERE parentName = ?;");
791 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
792 if (rc == SQLITE_OK) {
793 if (sqlite3_bind_blob(queryStmt, 1,
794 parentName.wireEncode().wire(),
795 parentName.wireEncode().size(), 0) == SQLITE_OK) {
796 rc = sqlite3_step(queryStmt);
797 if (rc == SQLITE_ROW) {
798 sqlite3_finalize(queryStmt);
799 return true;
800 }
801 else if (rc == SQLITE_DONE) {
802 sqlite3_finalize(queryStmt);
803 return false;
804 }
805 else {
806 std::cerr << "Database query failure rc:" << rc << std::endl;
807 sqlite3_finalize(queryStmt);
808 return false;
809 }
810 }
811 sqlite3_finalize(queryStmt);
812 }
813 return true;
814}
815
Alexander Afanasyevb0c78ea2014-04-15 18:12:04 -0700816size_t
817SqliteHandle::size()
818{
819 sqlite3_stmt* queryStmt = 0;
820 string sql("SELECT count(*) FROM NDN_REPO WHERE data IS NOT NULL");
821 int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
822 if (rc != SQLITE_OK)
823 {
824 std::cerr << "Database query failure rc:" << rc << std::endl;
825 sqlite3_finalize(queryStmt);
826 throw Error("Database query failure");
827 }
828
829 rc = sqlite3_step(queryStmt);
830 if (rc != SQLITE_ROW)
831 {
832 std::cerr << "Database query failure rc:" << rc << std::endl;
833 sqlite3_finalize(queryStmt);
834 throw Error("Database query failure");
835 }
836
837 size_t nDatas = static_cast<size_t>(sqlite3_column_int64(queryStmt, 0));
838 return nDatas;
839}
840
Shuo Chen7c6b4d72014-03-26 15:20:30 -0700841} //namespace repo