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 
26 namespace ns3 {
27 
28 NS_LOG_COMPONENT_DEFINE ("SQLiteOutput");
29 
30 SQLiteOutput::SQLiteOutput (const std::string &name)
31 {
32  int rc = sqlite3_open (name.c_str (), &m_db);
33  NS_ABORT_MSG_UNLESS (rc == SQLITE_OK, "Failed to open DB");
34 }
35 
37 {
38  int rc = SQLITE_FAIL;
39 
40  rc = sqlite3_close_v2 (m_db);
41  NS_ABORT_MSG_UNLESS (rc == SQLITE_OK, "Failed to close DB");
42 }
43 
44 void
46 {
47  NS_LOG_FUNCTION (this);
48  SpinExec ("PRAGMA journal_mode = MEMORY");
49 }
50 
51 bool
52 SQLiteOutput::SpinExec (const std::string &cmd) const
53 {
54  return (SpinExec (m_db, cmd) == SQLITE_OK);
55 }
56 
57 bool
58 SQLiteOutput::SpinExec (sqlite3_stmt *stmt) const
59 {
60  int rc = SpinExec (m_db, stmt);
61  return !CheckError (m_db, rc, "", false);
62 }
63 
64 bool
65 SQLiteOutput::WaitExec (const std::string &cmd) const
66 {
67  int rc = WaitExec (m_db, cmd);
68  return !CheckError (m_db, rc, cmd, false);
69 }
70 
71 bool
72 SQLiteOutput::WaitExec (sqlite3_stmt *stmt) const
73 {
74  return (WaitExec (m_db, stmt) == SQLITE_OK);
75 }
76 
77 bool
78 SQLiteOutput::WaitPrepare (sqlite3_stmt **stmt, const std::string &cmd) const
79 {
80  return (WaitPrepare (m_db, stmt, cmd) == SQLITE_OK);
81 }
82 
83 bool
84 SQLiteOutput::SpinPrepare (sqlite3_stmt **stmt, const std::string &cmd) const
85 {
86  return (SpinPrepare (m_db, stmt, cmd) == SQLITE_OK);
87 }
88 
89 template<typename T>
90 T
91 SQLiteOutput::RetrieveColumn ([[maybe_unused]] sqlite3_stmt *stmt, [[maybe_unused]] int pos) const
92 {
93  NS_FATAL_ERROR ("Can't call generic fn");
94 }
95 
97 template<>
98 int
99 SQLiteOutput::RetrieveColumn (sqlite3_stmt *stmt, int pos) const
100 {
101  return sqlite3_column_int (stmt, pos);
102 }
103 
105 template<>
106 uint32_t
107 SQLiteOutput::RetrieveColumn (sqlite3_stmt *stmt, int pos) const
108 {
109  return static_cast<uint32_t> (sqlite3_column_int (stmt, pos));
110 }
111 
113 template<>
114 double
115 SQLiteOutput::RetrieveColumn (sqlite3_stmt *stmt, int pos) const
116 {
117  return sqlite3_column_double (stmt, pos);
118 }
119 
120 template<typename T>
121 bool
122 SQLiteOutput::Bind ([[maybe_unused]] sqlite3_stmt *stmt, [[maybe_unused]] int pos, [[maybe_unused]] const T &value) const
123 {
124  NS_FATAL_ERROR ("Can't call generic fn");
125  return false;
126 }
127 
129 template<>
130 bool
131 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const Time &value) const
132 {
133  if (sqlite3_bind_double (stmt, pos, value.GetSeconds ()) == SQLITE_OK)
134  {
135  return true;
136  }
137  return false;
138 }
139 
141 template<>
142 bool
143 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const double &value) const
144 {
145  if (sqlite3_bind_double (stmt, pos, value) == SQLITE_OK)
146  {
147  return true;
148  }
149  return false;
150 }
151 
153 template<>
154 bool
155 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const uint32_t &value) const
156 {
157  if (sqlite3_bind_int (stmt, pos, static_cast<int> (value)) == SQLITE_OK)
158  {
159  return true;
160  }
161  return false;
162 }
163 
165 template<>
166 bool
167 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const long &value) const
168 {
169  if (sqlite3_bind_int64 (stmt, pos, value) == SQLITE_OK)
170  {
171  return true;
172  }
173  return false;
174 }
175 
177 template<>
178 bool
179 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const long long &value) const
180 {
181  if (sqlite3_bind_int64 (stmt, pos, value) == SQLITE_OK)
182  {
183  return true;
184  }
185  return false;
186 }
187 
189 template<>
190 bool
191 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const uint16_t &value) const
192 {
193  if (sqlite3_bind_int (stmt, pos, static_cast<int> (value)) == SQLITE_OK)
194  {
195  return true;
196  }
197  return false;
198 }
199 
201 template<>
202 bool
203 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const uint8_t &value) const
204 {
205  if (sqlite3_bind_int (stmt, pos, static_cast<int> (value)) == SQLITE_OK)
206  {
207  return true;
208  }
209  return false;
210 }
211 
213 template<>
214 bool
215 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const int &value) const
216 {
217  if (sqlite3_bind_int (stmt, pos, value) == SQLITE_OK)
218  {
219  return true;
220  }
221  return false;
222 }
223 
225 template<>
226 bool
227 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const std::string &value) const
228 {
229  if (sqlite3_bind_text (stmt, pos, value.c_str (), -1, SQLITE_STATIC) == SQLITE_OK)
230  {
231  return true;
232  }
233  return false;
234 }
235 
236 int
237 SQLiteOutput::WaitPrepare (sqlite3 *db, sqlite3_stmt **stmt, const std::string &cmd) const
238 {
239  int rc;
240  bool ret;
241 
242  std::unique_lock lock {m_mutex};
243 
244  rc = sqlite3_prepare_v2 (db, cmd.c_str (),
245  static_cast<int> (cmd.size ()),
246  stmt, nullptr);
247 
248  ret = CheckError (db, rc, cmd, false);
249  if (ret)
250  {
251  return rc;
252  }
253 
254  return rc;
255 }
256 
257 int
258 SQLiteOutput::SpinPrepare (sqlite3 *db, sqlite3_stmt **stmt, const std::string &cmd)
259 {
260  int rc;
261 
262  do
263  {
264  rc = sqlite3_prepare_v2 (db, cmd.c_str (),
265  static_cast<int> (cmd.size ()),
266  stmt, nullptr);
267  }
268  while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
269  return rc;
270 }
271 
272 int
273 SQLiteOutput::SpinStep (sqlite3_stmt *stmt)
274 {
275  int rc;
276  do
277  {
278  rc = sqlite3_step (stmt);
279  }
280  while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
281 
282  return rc;
283 }
284 
285 int
286 SQLiteOutput::SpinFinalize (sqlite3_stmt *stmt)
287 {
288  int rc;
289  do
290  {
291  rc = sqlite3_finalize (stmt);
292  }
293  while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
294 
295  return rc;
296 }
297 
298 int SQLiteOutput::SpinReset (sqlite3_stmt *stmt)
299 {
300  int rc;
301 
302  do
303  {
304  rc = sqlite3_reset (stmt);
305  }
306  while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
307 
308  return rc;
309 }
310 
311 void
312 SQLiteOutput::Error (sqlite3 *db, const std::string &cmd)
313 {
314  NS_ABORT_MSG (cmd << " error " << sqlite3_errmsg (db));
315 }
316 
317 bool
318 SQLiteOutput::CheckError (sqlite3 *db, int rc, const std::string &cmd,
319  bool hardExit)
320 {
321  if (rc != SQLITE_OK && rc != SQLITE_DONE)
322  {
323  if (hardExit)
324  {
325  Error (db, cmd);
326  }
327  else
328  {
329  std::cerr << sqlite3_errmsg (db) << std::endl;
330  }
331  return true;
332  }
333  return false;
334 }
335 
336 int
337 SQLiteOutput::SpinExec (sqlite3 *db, const std::string &cmd)
338 {
339  sqlite3_stmt *stmt;
340  bool ret;
341 
342  int rc = SpinPrepare (db, &stmt, cmd);
343  ret = CheckError (db, rc, cmd, false);
344  if (ret)
345  {
346  return rc;
347  }
348 
349  rc = SpinStep (stmt);
350  ret = CheckError (db, rc, cmd, false);
351  if (ret)
352  {
353  return rc;
354  }
355 
356  rc = SpinFinalize (stmt);
357  CheckError (db, rc, cmd, false);
358 
359  return rc;
360 }
361 
362 int
363 SQLiteOutput::SpinExec (sqlite3 *db, sqlite3_stmt *stmt)
364 {
365  bool ret;
366  int rc = SpinStep (stmt);
367  ret = CheckError (db, rc, "", false);
368  if (ret)
369  {
370  return rc;
371  }
372 
373  rc = SpinFinalize (stmt);
374  return rc;
375 }
376 
377 int
378 SQLiteOutput::WaitExec (sqlite3 *db, sqlite3_stmt *stmt) const
379 {
380  bool ret;
381  int rc = SQLITE_ERROR;
382 
383  std::unique_lock lock {m_mutex};
384 
385  rc = SpinStep (stmt);
386 
387  ret = CheckError (db, rc, "", false);
388  if (ret)
389  {
390  return rc;
391  }
392 
393  rc = SpinFinalize (stmt);
394 
395  return rc;
396 }
397 
398 int
399 SQLiteOutput::WaitExec (sqlite3 *db, const std::string &cmd) const
400 {
401  sqlite3_stmt *stmt;
402  bool ret;
403  int rc = SQLITE_ERROR;
404 
405  std::unique_lock lock {m_mutex};
406 
407  rc = SpinPrepare (db, &stmt, cmd);
408  ret = CheckError (db, rc, cmd, false);
409  if (ret)
410  {
411  return rc;
412  }
413 
414  rc = SpinStep (stmt);
415 
416  ret = CheckError (db, rc, cmd, false);
417  if (ret)
418  {
419  return rc;
420  }
421 
422  rc = SpinFinalize (stmt);
423 
424  return rc;
425 }
426 
427 } // 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.
static bool CheckError(sqlite3 *db, int rc, const std::string &cmd, bool hardExit)
Check any error in the db.
~SQLiteOutput()
Destructor.
static int SpinStep(sqlite3_stmt *stmt)
Execute a step operation on a statement until the result is ok or an error.
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.
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.
std::mutex m_mutex
Mutex.
bool WaitExec(const std::string &cmd) const
Execute a command, waiting on a mutex.
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.
SQLiteOutput(const std::string &name)
SQLiteOutput constructor.
bool WaitPrepare(sqlite3_stmt **stmt, const std::string &cmd) const
Prepare a statement, waiting on a mutex.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
#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_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