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
98/// \copydoc SQLiteOutput::RetrieveColumn
99template <>
100int
101SQLiteOutput::RetrieveColumn(sqlite3_stmt* stmt, int pos) const
102{
103 return sqlite3_column_int(stmt, pos);
104}
105
106/// \copydoc SQLiteOutput::RetrieveColumn
107template <>
109SQLiteOutput::RetrieveColumn(sqlite3_stmt* stmt, int pos) const
110{
111 return static_cast<uint32_t>(sqlite3_column_int(stmt, pos));
112}
113
114/// \copydoc SQLiteOutput::RetrieveColumn
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
130//! \copydoc SQLiteOutput::Bind
131template <>
132bool
133SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const Time& value) const
134{
135 return sqlite3_bind_double(stmt, pos, value.GetSeconds()) == SQLITE_OK;
136}
137
138//! \copydoc SQLiteOutput::Bind
139template <>
140bool
141SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const double& value) const
142{
143 return sqlite3_bind_double(stmt, pos, value) == SQLITE_OK;
144}
145
146//! \copydoc SQLiteOutput::Bind
147template <>
148bool
149SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const uint32_t& value) const
150{
151 return sqlite3_bind_int(stmt, pos, static_cast<int>(value)) == SQLITE_OK;
152}
153
154//! \copydoc SQLiteOutput::Bind
155template <>
156bool
157SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const long& value) const
158{
159 return sqlite3_bind_int64(stmt, pos, value) == SQLITE_OK;
160}
161
162//! \copydoc SQLiteOutput::Bind
163template <>
164bool
165SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const long long& value) const
166{
167 return sqlite3_bind_int64(stmt, pos, value) == SQLITE_OK;
168}
169
170//! \copydoc SQLiteOutput::Bind
171template <>
172bool
173SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const uint16_t& value) const
174{
175 return sqlite3_bind_int(stmt, pos, static_cast<int>(value)) == SQLITE_OK;
176}
177
178//! \copydoc SQLiteOutput::Bind
179template <>
180bool
181SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const uint8_t& value) const
182{
183 return sqlite3_bind_int(stmt, pos, static_cast<int>(value)) == SQLITE_OK;
184}
185
186//! \copydoc SQLiteOutput::Bind
187template <>
188bool
189SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const int& value) const
190{
191 return sqlite3_bind_int(stmt, pos, value) == SQLITE_OK;
192}
193
194//! \copydoc SQLiteOutput::Bind
195template <>
196bool
197SQLiteOutput::Bind(sqlite3_stmt* stmt, int pos, const std::string& value) const
198{
199 return sqlite3_bind_text(stmt, pos, value.c_str(), -1, SQLITE_STATIC) == SQLITE_OK;
200}
201
202int
203SQLiteOutput::WaitPrepare(sqlite3* db, sqlite3_stmt** stmt, const std::string& cmd) const
204{
205 int rc;
206 bool ret;
207
208 std::unique_lock lock{m_mutex};
209
210 rc = sqlite3_prepare_v2(db, cmd.c_str(), static_cast<int>(cmd.size()), stmt, nullptr);
211
212 ret = CheckError(db, rc, cmd, false);
213 if (ret)
214 {
215 return rc;
216 }
217
218 return rc;
219}
220
221int
222SQLiteOutput::SpinPrepare(sqlite3* db, sqlite3_stmt** stmt, const std::string& cmd)
223{
224 int rc;
225
226 do
227 {
228 rc = sqlite3_prepare_v2(db, cmd.c_str(), static_cast<int>(cmd.size()), stmt, nullptr);
229 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
230 return rc;
231}
232
233int
234SQLiteOutput::SpinStep(sqlite3_stmt* stmt)
235{
236 int rc;
237 do
238 {
239 rc = sqlite3_step(stmt);
240 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
241
242 return rc;
243}
244
245int
246SQLiteOutput::SpinFinalize(sqlite3_stmt* stmt)
247{
248 int rc;
249 do
250 {
251 rc = sqlite3_finalize(stmt);
252 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
253
254 return rc;
255}
256
257int
258SQLiteOutput::SpinReset(sqlite3_stmt* stmt)
259{
260 int rc;
261
262 do
263 {
264 rc = sqlite3_reset(stmt);
265 } while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
266
267 return rc;
268}
269
270void
271SQLiteOutput::Error(sqlite3* db, const std::string& cmd)
272{
273 NS_ABORT_MSG(cmd << " error " << sqlite3_errmsg(db));
274}
275
276bool
277SQLiteOutput::CheckError(sqlite3* db, int rc, const std::string& cmd, bool hardExit)
278{
279 if (rc != SQLITE_OK && rc != SQLITE_DONE)
280 {
281 if (hardExit)
282 {
283 Error(db, cmd);
284 }
285 else
286 {
287 std::cerr << sqlite3_errmsg(db) << std::endl;
288 }
289 return true;
290 }
291 return false;
292}
293
294int
295SQLiteOutput::SpinExec(sqlite3* db, const std::string& cmd)
296{
297 sqlite3_stmt* stmt;
298 bool ret;
299
300 int rc = SpinPrepare(db, &stmt, cmd);
301 ret = CheckError(db, rc, cmd, false);
302 if (ret)
303 {
304 return rc;
305 }
306
307 rc = SpinStep(stmt);
308 ret = CheckError(db, rc, cmd, false);
309 if (ret)
310 {
311 return rc;
312 }
313
314 rc = SpinFinalize(stmt);
315 CheckError(db, rc, cmd, false);
316
317 return rc;
318}
319
320int
321SQLiteOutput::SpinExec(sqlite3* db, sqlite3_stmt* stmt)
322{
323 bool ret;
324 int rc = SpinStep(stmt);
325 ret = CheckError(db, rc, "", false);
326 if (ret)
327 {
328 return rc;
329 }
330
331 rc = SpinFinalize(stmt);
332 return rc;
333}
334
335int
336SQLiteOutput::WaitExec(sqlite3* db, sqlite3_stmt* stmt) const
337{
338 bool ret;
339 int rc = SQLITE_ERROR;
340
341 std::unique_lock lock{m_mutex};
342
343 rc = SpinStep(stmt);
344
345 ret = CheckError(db, rc, "", false);
346 if (ret)
347 {
348 return rc;
349 }
350
351 rc = SpinFinalize(stmt);
352
353 return rc;
354}
355
356int
357SQLiteOutput::WaitExec(sqlite3* db, const std::string& cmd) const
358{
359 sqlite3_stmt* stmt;
360 bool ret;
361 int rc = SQLITE_ERROR;
362
363 std::unique_lock lock{m_mutex};
364
365 rc = SpinPrepare(db, &stmt, cmd);
366 ret = CheckError(db, rc, cmd, false);
367 if (ret)
368 {
369 return rc;
370 }
371
372 rc = SpinStep(stmt);
373
374 ret = CheckError(db, rc, cmd, false);
375 if (ret)
376 {
377 return rc;
378 }
379
380 rc = SpinFinalize(stmt);
381
382 return rc;
383}
384
385} // 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.