Line data Source code
1 : /*
2 : * Copyright (c) 2016 Sebastian Weber, Henri Menke. All rights reserved.
3 : *
4 : * This file is part of the pairinteraction library.
5 : *
6 : * The pairinteraction library is free software: you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as published by
8 : * the Free Software Foundation, either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * The pairinteraction library is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public License
17 : * along with the pairinteraction library. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #ifndef SQLITE_BINDINGS
21 : #define SQLITE_BINDINGS
22 :
23 : #include <iostream>
24 : #include <memory>
25 : #include <random>
26 : #include <sstream>
27 : #include <string>
28 : #include <thread>
29 : #include <type_traits>
30 :
31 : #include <sqlite3.h>
32 : #include <utility>
33 :
34 : #include "utils.hpp"
35 :
36 : namespace sqlite {
37 :
38 : /** \brief SQLite error
39 : *
40 : * Exception to identify SQLite errors.
41 : * \code
42 : * try
43 : * {
44 : * // code with sqlite
45 : * }
46 : * catch (sqlite::error &e)
47 : * {
48 : * // handle exception
49 : * }
50 : * \endcode
51 : */
52 : struct error : public std::exception {
53 : public:
54 : /** \brief Constructor
55 : *
56 : * \param[in] err error code
57 : * \param[in] msg error message
58 : */
59 5 : explicit error(int err, std::string const &msg)
60 5 : : m_msg(std::string("SQLite error ") + std::to_string(err) + ": " + msg) {}
61 :
62 : /** \brief %what() function
63 : *
64 : * \returns error message
65 : */
66 5 : const char *what() const noexcept override { return m_msg.c_str(); }
67 :
68 : private:
69 : std::string m_msg;
70 : };
71 :
72 : /** \brief SQLite Statement handle
73 : *
74 : * This object wraps an SQLite statement. It is iterable in a while
75 : * loop with the step() function or in a range-based for loop.
76 : */
77 : class statement {
78 : sqlite3 *m_db;
79 : std::unique_ptr<sqlite3_stmt, int (*)(sqlite3_stmt *)> m_stmt;
80 : std::string m_sql;
81 : bool m_prepared;
82 : bool m_valid;
83 :
84 77313 : void handle_error(int err) {
85 77313 : if (err != 0) {
86 4 : throw error(err, sqlite3_errstr(err));
87 : }
88 77309 : }
89 :
90 : public:
91 : /** \brief Constructor
92 : *
93 : * This is called in the query function of the the handle object.
94 : *
95 : * \param[in] db unmanaged raw pointer to the sqlite database
96 : */
97 1540 : explicit statement(sqlite3 *db) : statement{db, {}} {}
98 :
99 : /** \brief Constructor
100 : *
101 : * This is called in the query function of the the handle object.
102 : * This variant also sets a default query.
103 : *
104 : * \param[in] db unmanaged raw pointer to the sqlite database
105 : * \param[in] sql an initial query as a string
106 : */
107 1631 : explicit statement(sqlite3 *db, std::string sql)
108 3262 : : m_db{db}, m_stmt{nullptr, sqlite3_finalize}, m_sql{std::move(sql)},
109 1631 : m_prepared{false}, m_valid{true} {}
110 :
111 : /** \brief Set the query string
112 : *
113 : * \param[in] sql the query string
114 : * \throws sqlite::error
115 : */
116 12399 : void set(std::string const &sql) {
117 12399 : m_sql = sql;
118 12399 : m_prepared = false;
119 12399 : }
120 :
121 : /** \overload void set(std::string const &sql) */
122 1 : void set(std::stringstream const &ss) { return set(ss.str()); }
123 :
124 : /** \brief Prepare the statement
125 : *
126 : * Prepare the statement for stepping.
127 : *
128 : * \throws sqlite::error
129 : */
130 7940 : void prepare() {
131 : sqlite3_stmt *pStmt; // is managed below
132 7940 : auto err = sqlite3_prepare_v2(m_db, m_sql.c_str(), -1, &pStmt, nullptr);
133 7940 : m_stmt.reset(pStmt);
134 :
135 7940 : handle_error(err);
136 :
137 7939 : m_prepared = true;
138 7939 : }
139 :
140 : /** \brief Step the statement
141 : *
142 : * This steps the statement.
143 : *
144 : * \returns true if there is a row, false otherwise
145 : *
146 : * \throws sqlite::error
147 : */
148 13250 : bool step() {
149 13250 : if (!m_prepared) {
150 1 : handle_error(SQLITE_MISUSE);
151 : }
152 13249 : if (!m_valid) {
153 1 : handle_error(SQLITE_DONE);
154 : }
155 :
156 13248 : auto err = sqlite3_step(m_stmt.get());
157 :
158 13248 : switch (err) {
159 4615 : case SQLITE_DONE:
160 4615 : m_valid = false;
161 4615 : return false;
162 8633 : case SQLITE_ROW:
163 8633 : m_valid = true;
164 8633 : return true;
165 : }
166 :
167 0 : m_valid = false;
168 0 : handle_error(err);
169 0 : return false;
170 : }
171 :
172 : /** \brief Reset the statement
173 : *
174 : * Reset the statement so you can rebind values.
175 : *
176 : * \throws sqlite::error
177 : */
178 11253 : void reset() {
179 11253 : handle_error(sqlite3_reset(m_stmt.get()));
180 11253 : m_valid = true;
181 11253 : }
182 :
183 : /** \brief Execute SQLite statements
184 : *
185 : * The SQL statements are passed to this function as a string and
186 : * are executed in-place.
187 : *
188 : * \param[in] sql SQL statements
189 : * \throws sqlite::error
190 : */
191 4551 : void exec(std::string const &sql) {
192 4551 : set(sql);
193 4551 : auto err = sqlite3_exec(m_db, m_sql.c_str(), nullptr, nullptr, nullptr);
194 4551 : handle_error(err);
195 4550 : }
196 :
197 : /** \brief Bind a value to a position in the query
198 : *
199 : * \param[in] where position in the query (one-based)
200 : * \param[in] s string to bind
201 : * \throws sqlite::error
202 : */
203 9865 : void bind(int where, std::string const &s) {
204 9865 : handle_error(sqlite3_bind_text(m_stmt.get(), where, s.c_str(), s.length(), SQLITE_STATIC));
205 9865 : }
206 :
207 : /** \overload void bind(int where, std::string const &s) */
208 2 : void bind(int where, std::string &&s) {
209 2 : handle_error(
210 2 : sqlite3_bind_text(m_stmt.get(), where, s.c_str(), s.length(), SQLITE_TRANSIENT));
211 2 : }
212 :
213 : /** \overload void bind(int where, std::string const &s) */
214 19037 : void bind(int where, double d) { handle_error(sqlite3_bind_double(m_stmt.get(), where, d)); }
215 :
216 : /** \overload void bind(int where, std::string const &s) */
217 24663 : void bind(int where, int i) { handle_error(sqlite3_bind_int(m_stmt.get(), where, i)); }
218 :
219 : #ifdef SCANNED_BY_DOXYGEN
220 : /** \brief Get value of a field
221 : *
222 : * Retrieve the value stored at position \p field as datatype \p
223 : * ReturnType.
224 : *
225 : * \tparam ReturnType requested return type
226 : * \param[in] field
227 : * \returns the value stored in \p field as datatype \p
228 : * ReturnType
229 : */
230 : template <typename ReturnType>
231 : ReturnType get(int field);
232 : #else
233 : template <typename T,
234 : typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
235 21377 : double get(int field) {
236 21377 : return sqlite3_column_double(m_stmt.get(), field);
237 : }
238 :
239 : template <typename T, typename = typename std::enable_if<std::is_same<T, int>::value>::type>
240 5414 : int get(int field) {
241 5414 : return sqlite3_column_int(m_stmt.get(), field);
242 : }
243 :
244 : template <typename T,
245 : typename = typename std::enable_if<std::is_same<T, std::string>::value>::type>
246 4 : std::string get(int field) {
247 4 : return std::string(
248 8 : reinterpret_cast<char const *>(sqlite3_column_text(m_stmt.get(), field)));
249 : }
250 : #endif
251 :
252 : /** \brief Statement iterator
253 : *
254 : * The iterator builds upon Boost Iterator Facade to implement an
255 : * iterator over the statement with minimal boilerplate. We refer
256 : * to the official documentation for the internal functions:
257 : * http://www.boost.org/libs/iterator/
258 : */
259 : class iterator {
260 : private:
261 : statement *m_stmt;
262 : bool m_done;
263 : bool m_end;
264 :
265 : public:
266 2 : iterator() : m_stmt{nullptr}, m_done{true}, m_end{true} {}
267 :
268 1 : explicit iterator(statement *p) : m_stmt{p}, m_done{false}, m_end{false} { m_stmt->step(); }
269 :
270 3 : statement &operator*() const {
271 : #ifndef NDEBUG
272 3 : if (m_end)
273 1 : throw std::out_of_range("iterator out of range");
274 : #endif
275 2 : return *m_stmt;
276 : }
277 2 : iterator &operator++() {
278 2 : if (!m_done) {
279 1 : m_done = m_stmt->step();
280 : } else {
281 1 : m_end = true;
282 : }
283 2 : return *this;
284 : }
285 3 : bool operator!=(iterator const & /* unused */) const { return !m_end; }
286 : };
287 :
288 : /** \brief returns an iterator to the beginning
289 : *
290 : * With this, a statement can be iterated in a C++11 range-based for loop.
291 : *
292 : * \warning This is *not* zero overhead! If you care about
293 : * performance use a while loop using step() instead.
294 : * \code
295 : * while(stmt.step())
296 : * stmt.get<...>(...);
297 : * \endcode
298 : *
299 : * \returns iterator to the beginning
300 : */
301 1 : iterator begin() { return iterator{this}; }
302 :
303 : /** \brief returns an empty iterator
304 : *
305 : * The iterator for the SQLite statement is a forward iterator
306 : * which is implemented in terms of the step() function. Since
307 : * the step() function will determine the end by itself, this
308 : * iterator is merely a sentinel.
309 : *
310 : * \returns empty iterator
311 : */
312 2 : iterator end() { return iterator{}; }
313 : };
314 :
315 : /** \brief SQLite Database handle
316 : *
317 : * This object handles the connection to the underlying SQLite databse. It
318 : * provides a high-level object oriented RAII interface to the C-bindings of
319 : * SQLite3.
320 : */
321 : class handle final {
322 : std::unique_ptr<sqlite3, decltype(&sqlite3_close)> m_db;
323 : int m_threshold;
324 :
325 0 : static int busy_handler(void *self, int num_prior_calls) {
326 0 : int thresh = static_cast<handle *>(self)->m_threshold;
327 : // Sleep if handler has been called less than num_prior_calls
328 0 : if (num_prior_calls < thresh) {
329 0 : std::this_thread::sleep_for(std::chrono::microseconds(utils::randint(2000, 20000)));
330 0 : return 1;
331 : }
332 :
333 0 : return 0; // Make sqlite3 return SQLITE_BUSY
334 : }
335 :
336 99 : void install_busy_handler() {
337 99 : auto err = sqlite3_busy_handler(m_db.get(), busy_handler, this);
338 :
339 99 : if (err != 0) {
340 0 : throw error(err, sqlite3_errmsg(m_db.get()));
341 : }
342 99 : }
343 :
344 : public:
345 : /** \brief Conversion operator
346 : *
347 : * The handle object implicitly behaves like the underlying
348 : * pointer.
349 : *
350 : * \returns the raw database pointer
351 : */
352 166305 : operator sqlite3 *() { return m_db.get(); }
353 :
354 : /** \brief Constructor
355 : *
356 : * It takes a filename and a bitmask of parameters to open the
357 : * database connection. This is useful if you have to open the
358 : * connection, e.g., read-only. By default it uses the standard
359 : * flags for opening a database connection. See
360 : * https://www.sqlite.org/c3ref/open.html for details.
361 : *
362 : * \param[in] filename fully-qualified filename of the database
363 : * \param[in] flags options to open the database (optional)
364 : * \throws sqlite::error
365 : */
366 100 : explicit handle(std::string const &filename,
367 : int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
368 101 : : m_db{nullptr, sqlite3_close}, m_threshold{100000} {
369 : sqlite3 *tmp_db;
370 100 : auto err = sqlite3_open_v2(filename.c_str(), &tmp_db, flags, nullptr);
371 100 : m_db.reset(tmp_db);
372 :
373 100 : if (err != 0) {
374 1 : throw error(err, sqlite3_errmsg(m_db.get()));
375 : }
376 :
377 99 : install_busy_handler();
378 99 : }
379 :
380 : /** \brief Move constructor
381 : *
382 : * Reinstalls the busy handler.
383 : */
384 : handle(handle &&other) noexcept : m_db{std::move(other.m_db)}, m_threshold{other.m_threshold} {
385 : install_busy_handler();
386 : }
387 :
388 : /** \brief Move assignment operator
389 : *
390 : * Reinstalls the busy handler.
391 : */
392 : handle &operator=(handle &&other) noexcept {
393 : if (this != std::addressof(other)) // skip self-assignment
394 : {
395 : m_db = std::move(other.m_db);
396 : m_threshold = other.m_threshold;
397 : install_busy_handler();
398 : }
399 : return *this;
400 : }
401 : };
402 :
403 : } // namespace sqlite
404 :
405 : #endif // SQLITE_BINDINGS
|