A Discrete-Event Network Simulator
API
sqlite-output.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2018 Natale Patriciello <natale.patriciello@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19#include "sqlite-output.h"
20#include <sys/stat.h>
21#include <fcntl.h>
22#include "ns3/abort.h"
23#include "ns3/log.h"
24#include "ns3/nstime.h"
25
26namespace ns3 {
27
28NS_LOG_COMPONENT_DEFINE ("SQLiteOutput");
29
30SQLiteOutput::SQLiteOutput (const std::string &name, const std::string &semName)
31 : m_semName (semName)
32{
33 int rc = sqlite3_open (name.c_str (), &m_db);
34 NS_ABORT_MSG_UNLESS (rc == SQLITE_OK, "Failed to open DB");
35}
36
38{
39 int rc = SQLITE_FAIL;
40
41 rc = sqlite3_close_v2 (m_db);
42 NS_ABORT_MSG_UNLESS (rc == SQLITE_OK, "Failed to close DB");
43}
44
45void
47{
48 NS_LOG_FUNCTION (this);
49 SpinExec ("PRAGMA journal_mode = MEMORY");
50}
51
52bool
53SQLiteOutput::SpinExec (const std::string &cmd) const
54{
55 return (SpinExec (m_db, cmd) == SQLITE_OK);
56}
57
58bool
59SQLiteOutput::SpinExec (sqlite3_stmt *stmt) const
60{
61 int rc = SpinExec (m_db, stmt);
62 return !CheckError (m_db, rc, "", nullptr, false);
63}
64
65bool
66SQLiteOutput::WaitExec (const std::string &cmd) const
67{
68 int rc = WaitExec (m_db, cmd);
69 return !CheckError (m_db, rc, cmd, nullptr, false);
70}
71
72bool
73SQLiteOutput::WaitExec (sqlite3_stmt *stmt) const
74{
75 return (WaitExec (m_db, stmt) == SQLITE_OK);
76}
77
78bool
79SQLiteOutput::WaitPrepare (sqlite3_stmt **stmt, const std::string &cmd) const
80{
81 return (WaitPrepare (m_db, stmt, cmd) == SQLITE_OK);
82}
83
84bool
85SQLiteOutput::SpinPrepare (sqlite3_stmt **stmt, const std::string &cmd) const
86{
87 return (SpinPrepare (m_db, stmt, cmd) == SQLITE_OK);
88}
89
90template<typename T>
91T
92SQLiteOutput::RetrieveColumn ([[maybe_unused]] sqlite3_stmt *stmt, [[maybe_unused]] int pos) const
93{
94 NS_FATAL_ERROR ("Can't call generic fn");
95}
96
98template<>
99int
100SQLiteOutput::RetrieveColumn (sqlite3_stmt *stmt, int pos) const
101{
102 return sqlite3_column_int (stmt, pos);
103}
104
106template<>
108SQLiteOutput::RetrieveColumn (sqlite3_stmt *stmt, int pos) const
109{
110 return static_cast<uint32_t> (sqlite3_column_int (stmt, pos));
111}
112
114template<>
115double
116SQLiteOutput::RetrieveColumn (sqlite3_stmt *stmt, int pos) const
117{
118 return sqlite3_column_double (stmt, pos);
119}
120
121template<typename T>
122bool
123SQLiteOutput::Bind ([[maybe_unused]] sqlite3_stmt *stmt, [[maybe_unused]] int pos, [[maybe_unused]] const T &value) const
124{
125 NS_FATAL_ERROR ("Can't call generic fn");
126 return false;
127}
128
130template<>
131bool
132SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const Time &value) const
133{
134 if (sqlite3_bind_double (stmt, pos, value.GetSeconds ()) == SQLITE_OK)
135 {
136 return true;
137 }
138 return false;
139}
140
142template<>
143bool
144SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const double &value) const
145{
146 if (sqlite3_bind_double (stmt, pos, value) == SQLITE_OK)
147 {
148 return true;
149 }
150 return false;
151}
152
154template<>
155bool
156SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const uint32_t &value) const
157{
158 if (sqlite3_bind_int (stmt, pos, static_cast<int> (value)) == SQLITE_OK)
159 {
160 return true;
161 }
162 return false;
163}
164
166template<>
167bool
168SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const long &value) const
169{
170 if (sqlite3_bind_int64 (stmt, pos, value) == SQLITE_OK)
171 {
172 return true;
173 }
174 return false;
175}
176
178template<>
179bool
180SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const long long &value) const
181{
182 if (sqlite3_bind_int64 (stmt, pos, value) == SQLITE_OK)
183 {
184 return true;
185 }
186 return false;
187}
188
190template<>
191bool
192SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const uint16_t &value) const
193{
194 if (sqlite3_bind_int (stmt, pos, static_cast<int> (value)) == SQLITE_OK)
195 {
196 return true;
197 }
198 return false;
199}
200
202template<>
203bool
204SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const uint8_t &value) const
205{
206 if (sqlite3_bind_int (stmt, pos, static_cast<int> (value)) == SQLITE_OK)
207 {
208 return true;
209 }
210 return false;
211}
212
214template<>
215bool
216SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const int &value) const
217{
218 if (sqlite3_bind_int (stmt, pos, value) == SQLITE_OK)
219 {
220 return true;
221 }
222 return false;
223}
224
226template<>
227bool
228SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const std::string &value) const
229{
230 if (sqlite3_bind_text (stmt, pos, value.c_str (), -1, SQLITE_STATIC) == SQLITE_OK)
231 {
232 return true;
233 }
234 return false;
235}
236
237int
238SQLiteOutput::WaitPrepare (sqlite3 *db, sqlite3_stmt **stmt, const std::string &cmd) const
239{
240 int rc;
241 bool ret;
242 sem_t *sem = sem_open (m_semName.c_str (), O_CREAT, S_IRUSR | S_IWUSR, 1);
243
244 NS_ABORT_MSG_IF (sem == SEM_FAILED,
245 "FAILED to open system semaphore, errno: " << errno);
246
247 if (sem_wait (sem) == 0)
248 {
249 rc = sqlite3_prepare_v2 (db, cmd.c_str (),
250 static_cast<int> (cmd.size ()),
251 stmt, nullptr);
252
253 ret = CheckError (db, rc, cmd, sem, false);
254 if (ret)
255 {
256 return rc;
257 }
258
259 sem_post (sem);
260 }
261 else
262 {
263 NS_FATAL_ERROR ("Can't lock semaphore");
264 }
265
266 sem_close (sem);
267 sem = nullptr;
268
269 return rc;
270}
271
272int
273SQLiteOutput::SpinPrepare (sqlite3 *db, sqlite3_stmt **stmt, const std::string &cmd)
274{
275 int rc;
276
277 do
278 {
279 rc = sqlite3_prepare_v2 (db, cmd.c_str (),
280 static_cast<int> (cmd.size ()),
281 stmt, nullptr);
282 }
283 while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
284 return rc;
285}
286
287int
288SQLiteOutput::SpinStep (sqlite3_stmt *stmt)
289{
290 int rc;
291 do
292 {
293 rc = sqlite3_step (stmt);
294 }
295 while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
296
297 return rc;
298}
299
300int
301SQLiteOutput::SpinFinalize (sqlite3_stmt *stmt)
302{
303 int rc;
304 do
305 {
306 rc = sqlite3_finalize (stmt);
307 }
308 while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
309
310 return rc;
311}
312
313int SQLiteOutput::SpinReset (sqlite3_stmt *stmt)
314{
315 int rc;
316
317 do
318 {
319 rc = sqlite3_reset (stmt);
320 }
321 while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
322
323 return rc;
324}
325
326void
327SQLiteOutput::Error (sqlite3 *db, const std::string &cmd)
328{
329 NS_ABORT_MSG (cmd << " error " << sqlite3_errmsg (db));
330}
331
332bool
333SQLiteOutput::CheckError (sqlite3 *db, int rc, const std::string &cmd,
334 sem_t *sem, bool hardExit)
335{
336 if (rc != SQLITE_OK && rc != SQLITE_DONE)
337 {
338 if (sem != nullptr)
339 {
340 sem_post (sem);
341 sem_close (sem);
342 }
343 if (hardExit)
344 {
345 Error (db, cmd);
346 }
347 else
348 {
349 std::cerr << sqlite3_errmsg (db) << std::endl;
350 }
351 return true;
352 }
353 return false;
354}
355
356int
357SQLiteOutput::SpinExec (sqlite3 *db, const std::string &cmd)
358{
359 sqlite3_stmt *stmt;
360 bool ret;
361
362 int rc = SpinPrepare (db, &stmt, cmd);
363 ret = CheckError (db, rc, cmd, nullptr, false);
364 if (ret)
365 {
366 return rc;
367 }
368
369 rc = SpinStep (stmt);
370 ret = CheckError (db, rc, cmd, nullptr, false);
371 if (ret)
372 {
373 return rc;
374 }
375
376 rc = SpinFinalize (stmt);
377 CheckError (db, rc, cmd, nullptr, false);
378
379 return rc;
380}
381
382int
383SQLiteOutput::SpinExec (sqlite3 *db, sqlite3_stmt *stmt)
384{
385 bool ret;
386 int rc = SpinStep (stmt);
387 ret = CheckError (db, rc, "", nullptr, false);
388 if (ret)
389 {
390 return rc;
391 }
392
393 rc = SpinFinalize (stmt);
394 return rc;
395}
396
397int
398SQLiteOutput::WaitExec (sqlite3 *db, sqlite3_stmt *stmt) const
399{
400 bool ret;
401 int rc = SQLITE_ERROR;
402
403 sem_t *sem = sem_open (m_semName.c_str (), O_CREAT, S_IRUSR | S_IWUSR, 1);
404
405 NS_ABORT_MSG_IF (sem == SEM_FAILED,
406 "FAILED to open system semaphore, errno: " << errno);
407
408 if (sem_wait (sem) == 0)
409 {
410 rc = SpinStep (stmt);
411
412 ret = CheckError (db, rc, "", sem, false);
413 if (ret)
414 {
415 return rc;
416 }
417
418 rc = SpinFinalize (stmt);
419
420 sem_post (sem);
421 }
422 else
423 {
424 NS_FATAL_ERROR ("Can't lock system semaphore");
425 }
426
427 sem_close (sem);
428
429 return rc;
430}
431
432int
433SQLiteOutput::WaitExec (sqlite3 *db, const std::string &cmd) const
434{
435 sqlite3_stmt *stmt;
436 bool ret;
437 int rc = SQLITE_ERROR;
438
439 sem_t *sem = sem_open (m_semName.c_str (), O_CREAT, S_IRUSR | S_IWUSR, 1);
440
441 NS_ABORT_MSG_IF (sem == SEM_FAILED,
442 "FAILED to open system semaphore, errno: " << errno);
443
444 if (sem_wait (sem) == 0)
445 {
446 rc = SpinPrepare (db, &stmt, cmd);
447 ret = CheckError (db, rc, cmd, sem, false);
448 if (ret)
449 {
450 return rc;
451 }
452
453 rc = SpinStep (stmt);
454
455 ret = CheckError (db, rc, cmd, sem, false);
456 if (ret)
457 {
458 return rc;
459 }
460
461 rc = SpinFinalize (stmt);
462
463 sem_post (sem);
464 }
465
466 sem_close (sem);
467
468 return rc;
469}
470
471} // namespace ns3;
sqlite3 * m_db
Database pointer.
bool SpinExec(const std::string &cmd) const
Execute a command until the return value is OK or an ERROR.
~SQLiteOutput()
Destructor.
static bool CheckError(sqlite3 *db, int rc, const std::string &cmd, sem_t *sem, bool hardExit)
Check any error in the db.
static int SpinStep(sqlite3_stmt *stmt)
Execute a step operation on a statement until the result is ok or an error.
SQLiteOutput(const std::string &name, const std::string &semName)
SQLiteOutput constructor.
void SetJournalInMemory()
Instruct SQLite to store the journal in memory.
T RetrieveColumn(sqlite3_stmt *stmt, int pos) const
Retrieve a value from an executed statement.
bool Bind(sqlite3_stmt *stmt, int pos, const T &value) const
Bind a value to a sqlite statement.
std::string m_semName
System semaphore name.
static int SpinReset(sqlite3_stmt *stmt)
Reset a statement until the result is ok or an error.
static int SpinFinalize(sqlite3_stmt *stmt)
Finalize a statement until the result is ok or an error.
bool WaitExec(const std::string &cmd) const
Execute a command, waiting on a system semaphore.
static void Error(sqlite3 *db, const std::string &cmd)
Fail, printing an error message from sqlite.
bool SpinPrepare(sqlite3_stmt **stmt, const std::string &cmd) const
Prepare a statement.
bool WaitPrepare(sqlite3_stmt **stmt, const std::string &cmd) const
Prepare a statement, waiting on a system semaphore.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:379
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Every class exported by the ns3 library is enclosed in the ns3 namespace.
cmd
Definition: second.py:35