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