A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
sqlite-output.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018 Natale Patriciello <natale.patriciello@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 */
18#include "sqlite-output.h"
19
20#include "ns3/abort.h"
21#include "ns3/log.h"
22#include "ns3/nstime.h"
23
24#include <fcntl.h>
25#include <sys/stat.h>
26
27namespace ns3
28{
29
30NS_LOG_COMPONENT_DEFINE("SQLiteOutput");
31
32SQLiteOutput::SQLiteOutput(const std::string& name)
33{
34 int rc = sqlite3_open(name.c_str(), &m_db);
35 NS_ABORT_MSG_UNLESS(rc == SQLITE_OK, "Failed to open DB");
36}
37
39{
40 int rc = SQLITE_FAIL;
41
42 rc = sqlite3_close_v2(m_db);
43 NS_ABORT_MSG_UNLESS(rc == SQLITE_OK, "Failed to close DB");
44}
45
46void
48{
49 NS_LOG_FUNCTION(this);
50 SpinExec("PRAGMA journal_mode = MEMORY");
51}
52
53bool
54SQLiteOutput::SpinExec(const std::string& cmd) const
55{
56 return (SpinExec(m_db, cmd) == SQLITE_OK);
57}
58
59bool
60SQLiteOutput::SpinExec(sqlite3_stmt* stmt) const
61{
62 int rc = SpinExec(m_db, stmt);
63 return !CheckError(m_db, rc, "", false);
64}
65
66bool
67SQLiteOutput::WaitExec(const std::string& cmd) const
68{
69 int rc = WaitExec(m_db, cmd);
70 return !CheckError(m_db, rc, cmd, false);
71}
72
73bool
74SQLiteOutput::WaitExec(sqlite3_stmt* stmt) const
75{
76 return (WaitExec(m_db, stmt) == SQLITE_OK);
77}
78
79bool
80SQLiteOutput::WaitPrepare(sqlite3_stmt** stmt, const std::string& cmd) const
81{
82 return (WaitPrepare(m_db, stmt, cmd) == SQLITE_OK);
83}
84
85bool
86SQLiteOutput::SpinPrepare(sqlite3_stmt** stmt, const std::string& cmd) const
87{
88 return (SpinPrepare(m_db, stmt, cmd) == SQLITE_OK);
89}
90
91template <typename T>
92T
93SQLiteOutput::RetrieveColumn(sqlite3_stmt* /* stmt */, int /* pos */) const
94{
95 NS_FATAL_ERROR("Can't call generic fn");
96}
97
99template <>
100int
101SQLiteOutput::RetrieveColumn(sqlite3_stmt* stmt, int pos) const
102{
103 return sqlite3_column_int(stmt, pos);
104}
105
107template <>
109SQLiteOutput::RetrieveColumn(sqlite3_stmt* stmt, int pos) const
110{
111 return static_cast<uint32_t>(sqlite3_column_int(stmt, pos));
112}
113
115template <>
116double
117SQLiteOutput::RetrieveColumn(sqlite3_stmt* stmt, int pos) const
118{
119 return sqlite3_column_double(stmt, pos);
120}
121
122template <typename T>
123bool
124SQLiteOutput::Bind(sqlite3_stmt* /* stmt */, int /* pos */, const T& /* value */) const
125{
126 NS_FATAL_ERROR("Can't call generic fn");
127 return false;
128}
129
131template <>
132bool
133SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const Time& value) const
134{
135 if (sqlite3_bind_double(stmt, pos, value.GetSeconds()) == SQLITE_OK)
136 {
137 return true;
138 }
139 return false;
140}
141
143template <>
144bool
145SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const double& value) const
146{
147 if (sqlite3_bind_double(stmt, pos, value) == SQLITE_OK)
148 {
149 return true;
150 }
151 return false;
152}
153
155template <>
156bool
157SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const uint32_t& value) const
158{
159 if (sqlite3_bind_int(stmt, pos, static_cast<int>(value)) == SQLITE_OK)
160 {
161 return true;
162 }
163 return false;
164}
165
167template <>
168bool
169SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const long& value) const
170{
171 if (sqlite3_bind_int64(stmt, pos, value) == SQLITE_OK)
172 {
173 return true;
174 }
175 return false;
176}
177
179template <>
180bool
181SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const long long& value) const
182{
183 if (sqlite3_bind_int64(stmt, pos, value) == SQLITE_OK)
184 {
185 return true;
186 }
187 return false;
188}
189
191template <>
192bool
193SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const uint16_t& value) const
194{
195 if (sqlite3_bind_int(stmt, pos, static_cast<int>(value)) == SQLITE_OK)
196 {
197 return true;
198 }
199 return false;
200}
201
203template <>
204bool
205SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const uint8_t& value) const
206{
207 if (sqlite3_bind_int(stmt, pos, static_cast<int>(value)) == SQLITE_OK)
208 {
209 return true;
210 }
211 return false;
212}
213
215template <>
216bool
217SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const int& value) const
218{
219 if (sqlite3_bind_int(stmt, pos, value) == SQLITE_OK)
220 {
221 return true;
222 }
223 return false;
224}
225
227template <>
228bool
229SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const std::string& value) const
230{
231 if (sqlite3_bind_text(stmt, pos, value.c_str(), -1, SQLITE_STATIC) == SQLITE_OK)
232 {
233 return true;
234 }
235 return false;
236}
237
238int
239SQLiteOutput::WaitPrepare(sqlite3* db, sqlite3_stmt** stmt, const std::string& cmd) const
240{
241 int rc;
242 bool ret;
243
244 std::unique_lock lock{m_mutex};
245
246 rc = sqlite3_prepare_v2(db, cmd.c_str(), static_cast<int>(cmd.size()), stmt, nullptr);
247
248 ret = CheckError(db, rc, cmd, false);
249 if (ret)
250 {
251 return rc;
252 }
253
254 return rc;
255}
256
257int
258SQLiteOutput::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(), static_cast<int>(cmd.size()), stmt, nullptr);
265 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
266 return rc;
267}
268
269int
270SQLiteOutput::SpinStep(sqlite3_stmt* stmt)
271{
272 int rc;
273 do
274 {
275 rc = sqlite3_step(stmt);
276 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
277
278 return rc;
279}
280
281int
282SQLiteOutput::SpinFinalize(sqlite3_stmt* stmt)
283{
284 int rc;
285 do
286 {
287 rc = sqlite3_finalize(stmt);
288 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
289
290 return rc;
291}
292
293int
294SQLiteOutput::SpinReset(sqlite3_stmt* stmt)
295{
296 int rc;
297
298 do
299 {
300 rc = sqlite3_reset(stmt);
301 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
302
303 return rc;
304}
305
306void
307SQLiteOutput::Error(sqlite3* db, const std::string& cmd)
308{
309 NS_ABORT_MSG(cmd << " error " << sqlite3_errmsg(db));
310}
311
312bool
313SQLiteOutput::CheckError(sqlite3* db, int rc, const std::string& cmd, bool hardExit)
314{
315 if (rc != SQLITE_OK && rc != SQLITE_DONE)
316 {
317 if (hardExit)
318 {
319 Error(db, cmd);
320 }
321 else
322 {
323 std::cerr << sqlite3_errmsg(db) << std::endl;
324 }
325 return true;
326 }
327 return false;
328}
329
330int
331SQLiteOutput::SpinExec(sqlite3* db, const std::string& cmd)
332{
333 sqlite3_stmt* stmt;
334 bool ret;
335
336 int rc = SpinPrepare(db, &stmt, cmd);
337 ret = CheckError(db, rc, cmd, false);
338 if (ret)
339 {
340 return rc;
341 }
342
343 rc = SpinStep(stmt);
344 ret = CheckError(db, rc, cmd, false);
345 if (ret)
346 {
347 return rc;
348 }
349
350 rc = SpinFinalize(stmt);
351 CheckError(db, rc, cmd, false);
352
353 return rc;
354}
355
356int
357SQLiteOutput::SpinExec(sqlite3* db, sqlite3_stmt* stmt)
358{
359 bool ret;
360 int rc = SpinStep(stmt);
361 ret = CheckError(db, rc, "", false);
362 if (ret)
363 {
364 return rc;
365 }
366
367 rc = SpinFinalize(stmt);
368 return rc;
369}
370
371int
372SQLiteOutput::WaitExec(sqlite3* db, sqlite3_stmt* stmt) const
373{
374 bool ret;
375 int rc = SQLITE_ERROR;
376
377 std::unique_lock lock{m_mutex};
378
379 rc = SpinStep(stmt);
380
381 ret = CheckError(db, rc, "", false);
382 if (ret)
383 {
384 return rc;
385 }
386
387 rc = SpinFinalize(stmt);
388
389 return rc;
390}
391
392int
393SQLiteOutput::WaitExec(sqlite3* db, const std::string& cmd) const
394{
395 sqlite3_stmt* stmt;
396 bool ret;
397 int rc = SQLITE_ERROR;
398
399 std::unique_lock lock{m_mutex};
400
401 rc = SpinPrepare(db, &stmt, cmd);
402 ret = CheckError(db, rc, cmd, false);
403 if (ret)
404 {
405 return rc;
406 }
407
408 rc = SpinStep(stmt);
409
410 ret = CheckError(db, rc, cmd, false);
411 if (ret)
412 {
413 return rc;
414 }
415
416 rc = SpinFinalize(stmt);
417
418 return rc;
419}
420
421} // 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:105
#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:179
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#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.