SQLite Containers
Loading...
Searching...
No Matches
SqliteStmt.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include "Utils.hpp"
7
8namespace sqlite_containers {
9
11 class SqliteStmt {
12 public:
13
15 SqliteStmt() = default;
16
21 SqliteStmt(sqlite3 *sqlite_db, const char *query) {
22 init(sqlite_db, query);
23 }
24
29 SqliteStmt(sqlite3 *sqlite_db, const std::string &query) {
30 init(sqlite_db, query);
31 }
32
35 if (!m_stmt) return;
36 sqlite3_finalize(m_stmt);
37 m_stmt = nullptr;
38 }
39
44 void init(sqlite3 *sqlite_db, const char *query) {
45 int err;
46 do {
47 err = sqlite3_prepare_v2(sqlite_db, query, -1, &m_stmt, nullptr);
48 if (err == SQLITE_BUSY) {
50 } else
51 if (err != SQLITE_OK) {
52 std::string err_msg = "Failed to prepare SQL statement: ";
53 err_msg += std::string(query);
54 err_msg += ". Error code: ";
55 err_msg += std::to_string(err);
56 throw sqlite_exception(err_msg, err);
57 }
58 } while (err == SQLITE_BUSY);
59 }
60
65 void init(sqlite3 *sqlite_db, const std::string &query) {
66 init(sqlite_db, query.c_str());
67 }
68
71 sqlite3_stmt *get_stmt() noexcept {
72 return m_stmt;
73 }
74
77 void reset() {
78 const int err = sqlite3_reset(m_stmt);
79 if (err == SQLITE_OK) return;
80 throw sqlite_exception("Failed to reset SQL statement. Error code: " + std::to_string(err), err);
81 }
82
86 const int err = sqlite3_clear_bindings(m_stmt);
87 if (err == SQLITE_OK) return;
88 throw sqlite_exception("Failed to clear bindings on SQL statement. Error code: " + std::to_string(err), err);
89 }
90
94 void execute(sqlite3 *sqlite_db) {
96 }
97
103
106 int step() {
107 return sqlite3_step(m_stmt);
108 }
109
113 template<typename T>
114 inline T extract_column(const int &index,
115 typename std::enable_if<std::is_integral<T>::value>::type* = 0) {
116 return static_cast<T>(sqlite3_column_int64(m_stmt, index));
117 }
118
119 template<typename T>
120 inline T extract_column(const int &index,
121 typename std::enable_if<std::is_floating_point<T>::value>::type* = 0) {
122 return static_cast<T>(sqlite3_column_double(m_stmt, index));
123 }
124
125 template<typename T>
126 inline T extract_column(const int &index,
127 typename std::enable_if<std::is_same<T, std::string>::value>::type* = 0) {
128 const unsigned char *text = sqlite3_column_text(m_stmt, index);
129 if (text) {
130 return std::string(reinterpret_cast<const char*>(text));
131 }
132 return std::string();
133 }
134
135 template<typename T>
136 inline T extract_column(const int &index,
137 typename std::enable_if<std::is_same<T, std::vector<char>>::value>::type* = 0) {
138 const void* blob = sqlite3_column_blob(m_stmt, index);
139 const int blob_size = sqlite3_column_bytes(m_stmt, index);
140 return std::vector<char>(static_cast<const char*>(blob), static_cast<const char*>(blob) + blob_size);
141 }
142
143 template<typename T>
144 inline T extract_column(const int &index,
145 typename std::enable_if<std::is_same<T, std::vector<uint8_t>>::value>::type* = 0) {
146 const void* blob = sqlite3_column_blob(m_stmt, index);
147 const int blob_size = sqlite3_column_bytes(m_stmt, index);
148 return std::vector<uint8_t>(static_cast<const uint8_t*>(blob), static_cast<const uint8_t*>(blob) + blob_size);
149 }
150
151 template<typename T>
152 inline T extract_column(const int &index,
153 typename std::enable_if<
154 !std::is_integral<T>::value &&
155 !std::is_floating_point<T>::value &&
156 !std::is_same<T, std::string>::value &&
157 !std::is_same<T, std::vector<char>>::value &&
158 !std::is_same<T, std::vector<uint8_t>>::value &&
159 std::is_trivially_copyable<T>::value
160 >::type* = 0) {
161 T value;
162 const void* blob = sqlite3_column_blob(m_stmt, index);
163 const int blob_size = sqlite3_column_bytes(m_stmt, index);
164 if (blob_size == sizeof(T)) {
165 std::memcpy(&value, blob, sizeof(T));
166 } else {
167 throw sqlite_exception("Blob size does not match POD size.");
168 }
169 return value;
170 }
171
176 template<typename T>
177 inline bool bind_value(const int &index, const T& value,
178 typename std::enable_if<std::is_integral<T>::value>::type* = 0) {
179 return (sqlite3_bind_int64(m_stmt, index, static_cast<int64_t>(value)) == SQLITE_OK);
180 }
181
182 template<typename T>
183 inline bool bind_value(const int &index, const T& value,
184 typename std::enable_if<std::is_floating_point<T>::value>::type* = 0) {
185 return (sqlite3_bind_double(m_stmt, index, static_cast<double>(value)) == SQLITE_OK);
186 }
187
188 template<typename T>
189 inline bool bind_value(const int &index, const T& value,
190 typename std::enable_if<std::is_same<T, std::string>::value>::type* = 0) {
191 return (sqlite3_bind_text(m_stmt, index, value.c_str(), -1, SQLITE_STATIC) == SQLITE_OK);
192 }
193
194 template<typename T>
195 inline bool bind_value(const int &index, const T& value,
196 typename std::enable_if<std::is_same<T, std::vector<char>>::value>::type* = 0) {
197 return (sqlite3_bind_blob(m_stmt, index, value.data(), value.size(), SQLITE_STATIC) == SQLITE_OK);
198 }
199
200 template<typename T>
201 inline bool bind_value(const int &index, const T& value,
202 typename std::enable_if<std::is_same<T, std::vector<uint8_t>>::value>::type* = 0) {
203 return (sqlite3_bind_blob(m_stmt, index, value.data(), value.size(), SQLITE_STATIC) == SQLITE_OK);
204 }
205
206 template<typename T>
207 inline bool bind_value(const int &index, const T& value,
208 typename std::enable_if<
209 !std::is_integral<T>::value &&
210 !std::is_floating_point<T>::value &&
211 !std::is_same<T, std::string>::value &&
212 !std::is_same<T, std::vector<char>>::value &&
213 !std::is_same<T, std::vector<uint8_t>>::value &&
214 std::is_trivially_copyable<T>::value
215 >::type* = 0) {
216 return (sqlite3_bind_blob(m_stmt, index, &value, sizeof(T), SQLITE_STATIC) == SQLITE_OK);
217 }
218
219 private:
220 sqlite3_stmt *m_stmt = nullptr;
221 }; // SqliteStmt
222
223}; // namespace sqlite_containers
Utility functions for working with SQLite in sqlite_containers.
#define SQLITE_CONTAINERS_BUSY_RETRY_DELAY_MS
Definition Utils.hpp:22
Class for managing SQLite prepared statements.
SqliteStmt(sqlite3 *sqlite_db, const char *query)
Constructs a SqliteStmt and prepares the statement.
T extract_column(const int &index, typename std::enable_if< !std::is_integral< T >::value &&!std::is_floating_point< T >::value &&!std::is_same< T, std::string >::value &&!std::is_same< T, std::vector< char > >::value &&!std::is_same< T, std::vector< uint8_t > >::value &&std::is_trivially_copyable< T >::value >::type *=0)
void clear_bindings()
Clears all bindings on the prepared statement.
SqliteStmt()=default
Default constructor.
bool bind_value(const int &index, const T &value, typename std::enable_if< std::is_same< T, std::vector< uint8_t > >::value >::type *=0)
sqlite3_stmt * m_stmt
Pointer to the prepared SQLite statement.
void execute(sqlite3 *sqlite_db)
Executes the prepared statement.
T extract_column(const int &index, typename std::enable_if< std::is_floating_point< T >::value >::type *=0)
sqlite3_stmt * get_stmt() noexcept
Gets the prepared SQLite statement.
T extract_column(const int &index, typename std::enable_if< std::is_integral< T >::value >::type *=0)
Extracts a value from a SQLite statement column.
void init(sqlite3 *sqlite_db, const std::string &query)
Initializes the statement.
void reset()
Resets the prepared statement.
bool bind_value(const int &index, const T &value, typename std::enable_if< std::is_floating_point< T >::value >::type *=0)
SqliteStmt(sqlite3 *sqlite_db, const std::string &query)
Constructs a SqliteStmt and prepares the statement.
void init(sqlite3 *sqlite_db, const char *query)
Initializes the statement.
bool bind_value(const int &index, const T &value, typename std::enable_if< std::is_same< T, std::string >::value >::type *=0)
T extract_column(const int &index, typename std::enable_if< std::is_same< T, std::string >::value >::type *=0)
bool bind_value(const int &index, const T &value, typename std::enable_if< !std::is_integral< T >::value &&!std::is_floating_point< T >::value &&!std::is_same< T, std::string >::value &&!std::is_same< T, std::vector< char > >::value &&!std::is_same< T, std::vector< uint8_t > >::value &&std::is_trivially_copyable< T >::value >::type *=0)
bool bind_value(const int &index, const T &value, typename std::enable_if< std::is_integral< T >::value >::type *=0)
Binds a value to a SQLite statement.
T extract_column(const int &index, typename std::enable_if< std::is_same< T, std::vector< char > >::value >::type *=0)
void execute()
Executes the prepared statement.
bool bind_value(const int &index, const T &value, typename std::enable_if< std::is_same< T, std::vector< char > >::value >::type *=0)
T extract_column(const int &index, typename std::enable_if< std::is_same< T, std::vector< uint8_t > >::value >::type *=0)
Exception class for SQLite errors.
Definition Utils.hpp:27
void execute(sqlite3_stmt *stmt)
Executes a SQLite statement.
Definition Utils.hpp:47