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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7#include "sqlite-output.h"
8
9#include "ns3/abort.h"
10#include "ns3/log.h"
11#include "ns3/nstime.h"
12
13#include <fcntl.h>
14#include <sys/stat.h>
15
16namespace ns3
17{
18
19NS_LOG_COMPONENT_DEFINE("SQLiteOutput");
20
21SQLiteOutput::SQLiteOutput(const std::string& name)
22{
23 int rc = sqlite3_open(name.c_str(), &m_db);
24 NS_ABORT_MSG_UNLESS(rc == SQLITE_OK, "Failed to open DB");
25 sqlite3_busy_timeout(m_db, 100); // set 100 ms timeout for sqlite3 operations
26}
27
29{
30 int rc = SQLITE_FAIL;
31
32 rc = sqlite3_close_v2(m_db);
33 NS_ABORT_MSG_UNLESS(rc == SQLITE_OK, "Failed to close DB");
34}
35
36void
38{
39 NS_LOG_FUNCTION(this);
40 SpinExec("PRAGMA journal_mode = MEMORY");
41}
42
43bool
44SQLiteOutput::SpinExec(const std::string& cmd) const
45{
46 return (SpinExec(m_db, cmd) == SQLITE_OK);
47}
48
49bool
50SQLiteOutput::SpinExec(sqlite3_stmt* stmt) const
51{
52 int rc = SpinExec(m_db, stmt);
53 return !CheckError(m_db, rc, "", false);
54}
55
56bool
57SQLiteOutput::WaitExec(const std::string& cmd) const
58{
59 int rc = WaitExec(m_db, cmd);
60 return !CheckError(m_db, rc, cmd, false);
61}
62
63bool
64SQLiteOutput::WaitExec(sqlite3_stmt* stmt) const
65{
66 return (WaitExec(m_db, stmt) == SQLITE_OK);
67}
68
69bool
70SQLiteOutput::WaitPrepare(sqlite3_stmt** stmt, const std::string& cmd) const
71{
72 return (WaitPrepare(m_db, stmt, cmd) == SQLITE_OK);
73}
74
75bool
76SQLiteOutput::SpinPrepare(sqlite3_stmt** stmt, const std::string& cmd) const
77{
78 return (SpinPrepare(m_db, stmt, cmd) == SQLITE_OK);
79}
80
81template <typename T>
82T
83SQLiteOutput::RetrieveColumn(sqlite3_stmt* /* stmt */, int /* pos */) const
84{
85 NS_FATAL_ERROR("Can't call generic fn");
86}
87
88/// @copydoc SQLiteOutput::RetrieveColumn
89template <>
90int
91SQLiteOutput::RetrieveColumn(sqlite3_stmt* stmt, int pos) const
92{
93 return sqlite3_column_int(stmt, pos);
94}
95
96/// @copydoc SQLiteOutput::RetrieveColumn
97template <>
99SQLiteOutput::RetrieveColumn(sqlite3_stmt* stmt, int pos) const
100{
101 return static_cast<uint32_t>(sqlite3_column_int(stmt, pos));
102}
103
104/// @copydoc SQLiteOutput::RetrieveColumn
105template <>
106double
107SQLiteOutput::RetrieveColumn(sqlite3_stmt* stmt, int pos) const
108{
109 return sqlite3_column_double(stmt, pos);
110}
111
112template <typename T>
113bool
114SQLiteOutput::Bind(sqlite3_stmt* /* stmt */, int /* pos */, const T& /* value */) const
115{
116 NS_FATAL_ERROR("Can't call generic fn");
117 return false;
118}
119
120//! \copydoc SQLiteOutput::Bind
121template <>
122bool
123SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const Time& value) const
124{
125 return sqlite3_bind_double(stmt, pos, value.GetSeconds()) == SQLITE_OK;
126}
127
128//! \copydoc SQLiteOutput::Bind
129template <>
130bool
131SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const double& value) const
132{
133 return sqlite3_bind_double(stmt, pos, value) == SQLITE_OK;
134}
135
136//! \copydoc SQLiteOutput::Bind
137template <>
138bool
139SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const uint32_t& value) const
140{
141 return sqlite3_bind_int(stmt, pos, static_cast<int>(value)) == SQLITE_OK;
142}
143
144//! \copydoc SQLiteOutput::Bind
145template <>
146bool
147SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const long& value) const
148{
149 return sqlite3_bind_int64(stmt, pos, value) == SQLITE_OK;
150}
151
152//! \copydoc SQLiteOutput::Bind
153template <>
154bool
155SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const long long& value) const
156{
157 return sqlite3_bind_int64(stmt, pos, value) == SQLITE_OK;
158}
159
160//! \copydoc SQLiteOutput::Bind
161template <>
162bool
163SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const uint16_t& value) const
164{
165 return sqlite3_bind_int(stmt, pos, static_cast<int>(value)) == SQLITE_OK;
166}
167
168//! \copydoc SQLiteOutput::Bind
169template <>
170bool
171SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const uint8_t& value) const
172{
173 return sqlite3_bind_int(stmt, pos, static_cast<int>(value)) == SQLITE_OK;
174}
175
176//! \copydoc SQLiteOutput::Bind
177template <>
178bool
179SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const int& value) const
180{
181 return sqlite3_bind_int(stmt, pos, value) == SQLITE_OK;
182}
183
184//! \copydoc SQLiteOutput::Bind
185template <>
186bool
187SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const std::string& value) const
188{
189 return sqlite3_bind_text(stmt, pos, value.c_str(), -1, SQLITE_STATIC) == SQLITE_OK;
190}
191
192int
193SQLiteOutput::WaitPrepare(sqlite3* db, sqlite3_stmt** stmt, const std::string& cmd) const
194{
195 int rc;
196 bool ret;
197
198 std::unique_lock lock{m_mutex};
199
200 rc = sqlite3_prepare_v2(db, cmd.c_str(), static_cast<int>(cmd.size()), stmt, nullptr);
201
202 ret = CheckError(db, rc, cmd, false);
203 if (ret)
204 {
205 return rc;
206 }
207
208 return rc;
209}
210
211int
212SQLiteOutput::SpinPrepare(sqlite3* db, sqlite3_stmt** stmt, const std::string& cmd)
213{
214 int rc;
215
216 do
217 {
218 rc = sqlite3_prepare_v2(db, cmd.c_str(), static_cast<int>(cmd.size()), stmt, nullptr);
219 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
220 return rc;
221}
222
223int
224SQLiteOutput::SpinStep(sqlite3_stmt* stmt)
225{
226 int rc;
227 do
228 {
229 rc = sqlite3_step(stmt);
230 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
231
232 return rc;
233}
234
235int
236SQLiteOutput::SpinFinalize(sqlite3_stmt* stmt)
237{
238 int rc;
239 do
240 {
241 rc = sqlite3_finalize(stmt);
242 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
243
244 return rc;
245}
246
247int
248SQLiteOutput::SpinReset(sqlite3_stmt* stmt)
249{
250 int rc;
251
252 do
253 {
254 rc = sqlite3_reset(stmt);
255 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
256
257 return rc;
258}
259
260void
261SQLiteOutput::Error(sqlite3* db, const std::string& cmd)
262{
263 NS_ABORT_MSG(cmd << " error " << sqlite3_errmsg(db));
264}
265
266bool
267SQLiteOutput::CheckError(sqlite3* db, int rc, const std::string& cmd, bool hardExit)
268{
269 if (rc != SQLITE_OK && rc != SQLITE_DONE)
270 {
271 if (hardExit)
272 {
273 Error(db, cmd);
274 }
275 else
276 {
277 std::cerr << sqlite3_errmsg(db) << std::endl;
278 }
279 return true;
280 }
281 return false;
282}
283
284int
285SQLiteOutput::SpinExec(sqlite3* db, const std::string& cmd)
286{
287 sqlite3_stmt* stmt;
288 bool ret;
289
290 int rc = SpinPrepare(db, &stmt, cmd);
291 ret = CheckError(db, rc, cmd, false);
292 if (ret)
293 {
294 return rc;
295 }
296
297 rc = SpinStep(stmt);
298 ret = CheckError(db, rc, cmd, false);
299 if (ret)
300 {
301 return rc;
302 }
303
304 rc = SpinFinalize(stmt);
305 CheckError(db, rc, cmd, false);
306
307 return rc;
308}
309
310int
311SQLiteOutput::SpinExec(sqlite3* db, sqlite3_stmt* stmt)
312{
313 bool ret;
314 int rc = SpinStep(stmt);
315 ret = CheckError(db, rc, "", false);
316 if (ret)
317 {
318 return rc;
319 }
320
321 rc = SpinFinalize(stmt);
322 return rc;
323}
324
325int
326SQLiteOutput::WaitExec(sqlite3* db, sqlite3_stmt* stmt) const
327{
328 bool ret;
329 int rc = SQLITE_ERROR;
330
331 std::unique_lock lock{m_mutex};
332
333 rc = SpinStep(stmt);
334
335 ret = CheckError(db, rc, "", false);
336 if (ret)
337 {
338 return rc;
339 }
340
341 rc = SpinFinalize(stmt);
342
343 return rc;
344}
345
346int
347SQLiteOutput::WaitExec(sqlite3* db, const std::string& cmd) const
348{
349 sqlite3_stmt* stmt;
350 bool ret;
351 int rc = SQLITE_ERROR;
352
353 std::unique_lock lock{m_mutex};
354
355 rc = SpinPrepare(db, &stmt, cmd);
356 ret = CheckError(db, rc, cmd, false);
357 if (ret)
358 {
359 return rc;
360 }
361
362 rc = SpinStep(stmt);
363
364 ret = CheckError(db, rc, cmd, false);
365 if (ret)
366 {
367 return rc;
368 }
369
370 rc = SpinFinalize(stmt);
371
372 return rc;
373}
374
375} // 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:94
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition abort.h:133
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#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.