SQLite Containers
Loading...
Searching...
No Matches
Utils.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <sqlite3.h>
7#include <stdexcept>
8#include <string>
9#include <thread>
10#include <chrono>
11#include <vector>
12#include <deque>
13#include <list>
14#include <set>
15#include <unordered_set>
16#include <map>
17#include <unordered_map>
18#include <string>
19#include <cstring>
20#include <type_traits>
21
22#define SQLITE_CONTAINERS_BUSY_RETRY_DELAY_MS 50
23
24namespace sqlite_containers {
25
27 class sqlite_exception : public std::runtime_error {
28 public:
32 explicit sqlite_exception(const std::string &message, const int &error_code = -1) :
33 std::runtime_error(message), m_error_code(error_code) {}
34
37 int error_code() const noexcept {
38 return m_error_code;
39 }
40 private:
41 int m_error_code; // The SQLite error code
42 }; // sqlite_exception
43
47 inline void execute(sqlite3_stmt *stmt) {
48 if (!stmt) throw sqlite_exception("Invalid statement pointer.");
49 int err;
50 for (;;) {
51 while ((err = sqlite3_step(stmt)) == SQLITE_ROW);
52 switch (err) {
53 case SQLITE_DONE:
54 return;
55 case SQLITE_BUSY:
57 continue;
58 case SQLITE_FULL:
59 throw sqlite_exception("Disk full or IO error.", err);
60 case SQLITE_IOERR:
61 throw sqlite_exception("Failed to insert data into database.", err);
62 default:
63 throw sqlite_exception("SQLite error.", err);
64 }
65 }
66 }
67
72 inline void execute(sqlite3 *sqlite_db, sqlite3_stmt *stmt) {
73 if (!sqlite_db || !stmt) throw sqlite_exception("Invalid database or statement pointer.");
74 int err;
75 for (;;) {
76 while ((err = sqlite3_step(stmt)) == SQLITE_ROW);
77 switch (err) {
78 case SQLITE_DONE:
79 return;
80 case SQLITE_BUSY:
82 continue;
83 case SQLITE_FULL:
84 throw sqlite_exception("Disk full or IO error: " + std::string(sqlite3_errmsg(sqlite_db)) + ". Error code: " + std::to_string(err), err);
85 case SQLITE_IOERR:
86 throw sqlite_exception("Failed to insert data into database: " + std::string(sqlite3_errmsg(sqlite_db)) + ". Error code: " + std::to_string(err), err);
87 default:
88 throw sqlite_exception("SQLite error: " + std::string(sqlite3_errmsg(sqlite_db)) + ". Error code: " + std::to_string(err), err);
89 }
90 }
91 }
92
97 inline void execute(sqlite3 *sqlite_db, const char *query) {
98 if (!sqlite_db) throw sqlite_exception("Invalid database pointer.");
99 if (!query || std::strlen(query) == 0) throw sqlite_exception("Empty SQL request.");
100 int err;
101 do {
102 err = sqlite3_exec(sqlite_db, query, nullptr, nullptr, nullptr);
103 if (err == SQLITE_BUSY) {
105 } else
106 if (err != SQLITE_OK) {
107 std::string err_msg = "SQLite error during prepare: ";
108 err_msg += sqlite3_errmsg(sqlite_db);
109 err_msg += ". Error code: ";
110 err_msg += std::to_string(err);
111 throw sqlite_exception(err_msg, err);
112 }
113 } while (err == SQLITE_BUSY);
114 }
115
120 inline void execute(sqlite3 *sqlite_db, const std::string &query) {
121 execute(sqlite_db, query.c_str());
122 }
123
124//------------------------------------------------------------------------------
125
129 template<typename T>
130 inline std::string get_sqlite_type(
131 typename std::enable_if<std::is_integral<T>::value>::type* = 0) {
132 return "INTEGER";
133 }
134
135 template<typename T>
136 inline std::string get_sqlite_type(
137 typename std::enable_if<std::is_floating_point<T>::value>::type* = 0) {
138 return "REAL";
139 }
140
141 template<typename T>
142 inline std::string get_sqlite_type(
143 typename std::enable_if<std::is_same<T, std::string>::value>::type* = 0) {
144 return "TEXT";
145 }
146
147 template<typename T>
148 inline std::string get_sqlite_type(
149 typename std::enable_if<
150 !std::is_integral<T>::value &&
151 !std::is_floating_point<T>::value &&
152 std::is_trivially_copyable<T>::value>::type* = 0) {
153 return "BLOB";
154 }
155
156 template<typename T>
157 inline typename std::enable_if<
158 std::is_trivially_copyable<
159 typename T::value_type>::value &&
160 std::is_same<T, std::vector<typename T::value_type>>::value,
161 std::string
162 >::type get_sqlite_type() {
163 return "BLOB";
164 }
165
166 template<typename T>
167 inline typename std::enable_if<
168 std::is_trivially_copyable<
169 typename T::value_type>::value &&
170 std::is_same<T, std::deque<typename T::value_type>>::value,
171 std::string
172 >::type get_sqlite_type() {
173 return "BLOB";
174 }
175
176//------------------------------------------------------------------------------
177
183 template<template <class...> class ContainerT, class T>
184 inline void add_value(ContainerT<T> &container, T &value,
185 typename std::enable_if<
186 std::is_same<ContainerT<T>, std::set<T>>::value ||
187 std::is_same<ContainerT<T>, std::unordered_set<T>>::value>::type* = 0) {
188 container.insert(std::move(value));
189 }
190
197 template<template <class...> class ContainerT, class T>
198 inline void add_value(ContainerT<T> &container, const T &value, const size_t& value_count = 0,
199 typename std::enable_if<
200 std::is_same<ContainerT<T>, std::multiset<T>>::value ||
201 std::is_same<ContainerT<T>, std::unordered_multiset<T>>::value>::type* = 0) {
202 for (size_t i = 0; i < value_count; ++i) {
203 container.insert(value);
204 }
205 }
206
212 template<template <class...> class ContainerT, class T>
213 inline void add_value(ContainerT<T> &container, T &value,
214 typename std::enable_if<
215 std::is_same<ContainerT<T>, std::list<T>>::value ||
216 std::is_same<ContainerT<T>, std::vector<T>>::value ||
217 std::is_same<ContainerT<T>, std::deque<T>>::value>::type* = 0) {
218 container.emplace(container.end(), std::move(value));
219 }
220
227 template<template <class...> class ContainerT, class T>
228 inline void add_value(ContainerT<T> &container, const T &value, const size_t& value_count,
229 typename std::enable_if<
230 std::is_same<ContainerT<T>, std::list<T>>::value ||
231 std::is_same<ContainerT<T>, std::vector<T>>::value ||
232 std::is_same<ContainerT<T>, std::deque<T>>::value>::type* = 0) {
233 for (size_t i = 0; i < value_count; ++i) {
234 container.emplace(container.end(), value);
235 }
236 }
237
244 template<template <class...> class ContainerT, class T>
245 inline void add_value(ContainerT<T> &container, const T &value, const size_t& value_count,
246 typename std::enable_if<
247 std::is_same<ContainerT<T>, std::set<T>>::value ||
248 std::is_same<ContainerT<T>, std::multiset<T>>::value ||
249 std::is_same<ContainerT<T>, std::unordered_set<T>>::value ||
250 std::is_same<ContainerT<T>, std::unordered_multiset<T>>::value>::type* = 0) {
251 for (size_t i = 0; i < value_count; ++i) {
252 container.emplace(value);
253 }
254 }
255
264 template <template <class...> class ContainerT, typename KeyT, typename ValueT>
265 inline void add_value(ContainerT<KeyT, ValueT> &container, KeyT& key, ValueT& value, const size_t& value_count,
266 typename std::enable_if<
267 std::is_same<ContainerT<KeyT, ValueT>, std::multimap<KeyT, ValueT>>::value ||
268 std::is_same<ContainerT<KeyT, ValueT>, std::unordered_multimap<KeyT, ValueT>>::value>::type* = 0) {
269 for (size_t i = 0; i < value_count; ++i) {
270 container.emplace(key, value);
271 }
272 }
273
274//------------------------------------------------------------------------------
275
283 template <template <class...> class ContainerT, typename KeyT, typename ValueT>
284 inline std::list<ValueT> get_values(ContainerT<KeyT, ValueT> &container, const KeyT& key,
285 typename std::enable_if<
286 std::is_same<ContainerT<KeyT, ValueT>, std::map<KeyT, ValueT>>::value ||
287 std::is_same<ContainerT<KeyT, ValueT>, std::unordered_map<KeyT, ValueT>>::value>::type* = 0) {
288 std::list<ValueT> values;
289 auto it = container.find(key);
290 if (it == container.end()) return values;
291 values.push_back(it->second);
292 return values;
293 }
294
303 template<template <class...> class ContainerT, template <class...> class ValueContainerT, typename KeyT, typename ValueT>
304 inline std::list<ValueT> get_values(ContainerT<KeyT, ValueContainerT<ValueT>> &container, const KeyT& key,
305 typename std::enable_if<
306 std::is_same<ContainerT<KeyT, ValueT>, std::map<KeyT, ValueContainerT<ValueT>>>::value ||
307 std::is_same<ContainerT<KeyT, ValueT>, std::unordered_map<KeyT, ValueContainerT<ValueT>>>::value>::type* = 0) {
308 auto it = container.find(key);
309 std::list<ValueT> values;
310 for (const auto& item : it->second) {
311 values.push_back(item);
312 }
313 return values;
314 }
315
323 template <template <class...> class ContainerT, typename KeyT, typename ValueT>
324 inline std::list<ValueT> get_values(ContainerT<KeyT, ValueT> &container, const KeyT& key,
325 typename std::enable_if<
326 std::is_same<ContainerT<KeyT, ValueT>, std::multimap<KeyT, ValueT>>::value ||
327 std::is_same<ContainerT<KeyT, ValueT>, std::unordered_multimap<KeyT, ValueT>>::value>::type* = 0) {
328 auto range = container.equal_range(key);
329 std::list<ValueT> values;
330 for (auto it = range.first; it != range.second; ++it) {
331 values.push_back(it->second);
332 }
333 return values;
334 }
335
336//------------------------------------------------------------------------------
337
338 template <typename T>
339 bool byte_compare(const T& a, const T& b) {
340 return std::memcmp(&a, &b, sizeof(T)) == 0;
341 }
342
343}; // namespace sqlite_containers
#define SQLITE_CONTAINERS_BUSY_RETRY_DELAY_MS
Definition Utils.hpp:22
Exception class for SQLite errors.
Definition Utils.hpp:27
int error_code() const noexcept
Definition Utils.hpp:37
sqlite_exception(const std::string &message, const int &error_code=-1)
Constructs a new sqlite_exception with the given message. param message The error message....
Definition Utils.hpp:32
void execute(sqlite3_stmt *stmt)
Executes a SQLite statement.
Definition Utils.hpp:47
std::enable_if< std::is_trivially_copyable< typenameT::value_type >::value &&std::is_same< T, std::vector< typenameT::value_type > >::value, std::string >::type get_sqlite_type()
Definition Utils.hpp:162
bool byte_compare(const T &a, const T &b)
Definition Utils.hpp:339
std::list< ValueT > get_values(ContainerT< KeyT, ValueT > &container, const KeyT &key, typename std::enable_if< std::is_same< ContainerT< KeyT, ValueT >, std::map< KeyT, ValueT > >::value||std::is_same< ContainerT< KeyT, ValueT >, std::unordered_map< KeyT, ValueT > >::value >::type *=0)
Retrieves values from a container (map or unordered_map) based on the key.
Definition Utils.hpp:284
void add_value(ContainerT< T > &container, T &value, typename std::enable_if< std::is_same< ContainerT< T >, std::set< T > >::value||std::is_same< ContainerT< T >, std::unordered_set< T > >::value >::type *=0)
Adds a value to a container (set or unordered_set).
Definition Utils.hpp:184