summaryrefslogtreecommitdiffstats
path: root/server/src/sqlite3.cppm
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/sqlite3.cppm')
-rw-r--r--server/src/sqlite3.cppm86
1 files changed, 43 insertions, 43 deletions
diff --git a/server/src/sqlite3.cppm b/server/src/sqlite3.cppm
index 70f58c0..45366b8 100644
--- a/server/src/sqlite3.cppm
+++ b/server/src/sqlite3.cppm
@@ -18,7 +18,7 @@ class mutex_guard
18 18
19 friend auto 19 friend auto
20 do_guarded(::sqlite3_mutex* mut, std::invocable<mutex_guard const&> auto f) 20 do_guarded(::sqlite3_mutex* mut, std::invocable<mutex_guard const&> auto f)
21 -> decltype(f(std::declval<mutex_guard const&>())); 21 -> decltype(f(std::declval<mutex_guard const&>()));
22 22
23public: 23public:
24 mutex_guard(mutex_guard const&) = delete; 24 mutex_guard(mutex_guard const&) = delete;
@@ -29,13 +29,13 @@ private:
29}; 29};
30 30
31auto do_guarded(::sqlite3_mutex* mut, std::invocable<mutex_guard const&> auto f) 31auto do_guarded(::sqlite3_mutex* mut, std::invocable<mutex_guard const&> auto f)
32 -> decltype(f(std::declval<mutex_guard const&>())) 32 -> decltype(f(std::declval<mutex_guard const&>()))
33{ 33{
34 return f(mutex_guard{mut}); 34 return f(mutex_guard{mut});
35} 35}
36 36
37auto do_guarded(::sqlite3* dbc, std::invocable<mutex_guard const&> auto f) 37auto do_guarded(::sqlite3* dbc, std::invocable<mutex_guard const&> auto f)
38 -> decltype(f(std::declval<mutex_guard const&>())) 38 -> decltype(f(std::declval<mutex_guard const&>()))
39{ 39{
40 return do_guarded(::sqlite3_db_mutex(dbc), f); 40 return do_guarded(::sqlite3_db_mutex(dbc), f);
41} 41}
@@ -143,16 +143,16 @@ public:
143 { 143 {
144 ::sqlite3* dbc = ::sqlite3_db_handle(stmt_.get()); 144 ::sqlite3* dbc = ::sqlite3_db_handle(stmt_.get());
145 return do_guarded( 145 return do_guarded(
146 dbc, 146 dbc,
147 [&](auto const& guard) -> bool 147 [&](auto const& guard) -> bool
148 { 148 {
149 auto const s = ::sqlite3_step(stmt_.get()); 149 auto const s = ::sqlite3_step(stmt_.get());
150 if (s == SQLITE_ROW) 150 if (s == SQLITE_ROW)
151 return true; 151 return true;
152 if (s == SQLITE_DONE) 152 if (s == SQLITE_DONE)
153 return false; 153 return false;
154 throw error{guard, s, dbc}; 154 throw error{guard, s, dbc};
155 }); 155 });
156 } 156 }
157 157
158 auto scan(scannable auto&... args) -> void 158 auto scan(scannable auto&... args) -> void
@@ -162,7 +162,7 @@ public:
162 throw std::logic_error{"got unexpected negative amount of columns"}; 162 throw std::logic_error{"got unexpected negative amount of columns"};
163 if (sizeof...(args) > *ncols) 163 if (sizeof...(args) > *ncols)
164 throw std::invalid_argument{ 164 throw std::invalid_argument{
165 "more scanning arguments provided than columns in result set" 165 "more scanning arguments provided than columns in result set"
166 }; 166 };
167 auto col = 0; 167 auto col = 0;
168 (..., scan(col++, args)); 168 (..., scan(col++, args));
@@ -192,15 +192,15 @@ public:
192 auto text(std::string const& param_name, std::string_view str) -> void 192 auto text(std::string const& param_name, std::string_view str) -> void
193 { 193 {
194 int const i = 194 int const i =
195 ::sqlite3_bind_parameter_index(stmt_.get(), param_name.c_str()); 195 ::sqlite3_bind_parameter_index(stmt_.get(), param_name.c_str());
196 if (i == 0) 196 if (i == 0)
197 throw std::invalid_argument{std::format( 197 throw std::invalid_argument{std::format(
198 "bind: no parameter with name {} found", param_name)}; 198 "bind: no parameter with name {} found", param_name)};
199 auto str_size = util::int_from_size(str.size()); 199 auto str_size = util::int_from_size(str.size());
200 if (!str_size.has_value()) 200 if (!str_size.has_value())
201 throw std::invalid_argument{"bind: provided text is too long"}; 201 throw std::invalid_argument{"bind: provided text is too long"};
202 if (auto s = ::sqlite3_bind_text( 202 if (auto s = ::sqlite3_bind_text(
203 stmt_.get(), i, str.data(), *str_size, SQLITE_TRANSIENT); 203 stmt_.get(), i, str.data(), *str_size, SQLITE_TRANSIENT);
204 s != SQLITE_OK) 204 s != SQLITE_OK)
205 { 205 {
206 throw error{s}; 206 throw error{s};
@@ -232,8 +232,8 @@ public:
232 } 232 }
233 233
234 [[nodiscard]] auto query( 234 [[nodiscard]] auto query(
235 std::string const& sql, 235 std::string const& sql,
236 std::function<void(binder&)> const& bf = binder::noop) -> row_reader 236 std::function<void(binder&)> const& bf = binder::noop) -> row_reader
237 { 237 {
238 ::sqlite3_stmt* pstmt = nullptr; 238 ::sqlite3_stmt* pstmt = nullptr;
239 char const* sql_tail = nullptr; 239 char const* sql_tail = nullptr;
@@ -242,31 +242,31 @@ public:
242 || *sql_size >= std::numeric_limits<int>::max() - 1) 242 || *sql_size >= std::numeric_limits<int>::max() - 1)
243 throw std::invalid_argument{"provided input text too large"}; 243 throw std::invalid_argument{"provided input text too large"};
244 do_guarded( 244 do_guarded(
245 mut_, 245 mut_,
246 [&](auto const& guard) -> void 246 [&](auto const& guard) -> void
247 {
248 if (auto s = ::sqlite3_prepare_v2(
249 dbc_, sql.data(), *sql_size + 1, &pstmt, &sql_tail);
250 s != SQLITE_OK)
247 { 251 {
248 if (auto s = ::sqlite3_prepare_v2( 252 if (pstmt != nullptr)
249 dbc_, sql.data(), *sql_size + 1, &pstmt, &sql_tail);
250 s != SQLITE_OK)
251 { 253 {
252 if (pstmt != nullptr) 254 // Use contract_assert when having a compiler with
253 { 255 // contracts available
254 // Use contract_assert when having a compiler with 256 ::sqlite3_finalize(pstmt);
255 // contracts available 257 throw std::logic_error{
256 ::sqlite3_finalize(pstmt); 258 "expected stmt to be null after failed preparation"
257 throw std::logic_error{ 259 };
258 "expected stmt to be null after failed preparation"
259 };
260 }
261 throw error{guard, s, dbc_};
262 } 260 }
263 }); 261 throw error{guard, s, dbc_};
262 }
263 });
264 if (!pstmt) 264 if (!pstmt)
265 throw std::invalid_argument{"provided input text contains no SQL"}; 265 throw std::invalid_argument{"provided input text contains no SQL"};
266 auto stmt = statement{pstmt}; 266 auto stmt = statement{pstmt};
267 if (sql_tail && std::strlen(sql_tail) > 0) 267 if (sql_tail && std::strlen(sql_tail) > 0)
268 throw std::invalid_argument{ 268 throw std::invalid_argument{
269 "provided input text contains more than one SQL statement" 269 "provided input text contains more than one SQL statement"
270 }; 270 };
271 auto b = binder{stmt}; 271 auto b = binder{stmt};
272 bf(b); 272 bf(b);
@@ -274,8 +274,8 @@ public:
274 } 274 }
275 275
276 auto exec( 276 auto exec(
277 std::string const& sql, 277 std::string const& sql,
278 std::function<void(binder&)> const& bf = binder::noop) -> void 278 std::function<void(binder&)> const& bf = binder::noop) -> void
279 { 279 {
280 auto reader = query(sql, bf); 280 auto reader = query(sql, bf);
281 while (reader.next()) 281 while (reader.next())
@@ -289,16 +289,16 @@ export auto open(std::string const& filename) -> connection
289{ 289{
290 ::sqlite3* dbc = nullptr; 290 ::sqlite3* dbc = nullptr;
291 auto s = ::sqlite3_open_v2( 291 auto s = ::sqlite3_open_v2(
292 filename.c_str(), &dbc, 292 filename.c_str(), &dbc,
293 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX 293 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX
294 | SQLITE_OPEN_EXRESCODE, 294 | SQLITE_OPEN_EXRESCODE,
295 nullptr); 295 nullptr);
296 if (s != SQLITE_OK) 296 if (s != SQLITE_OK)
297 { 297 {
298 if (dbc) 298 if (dbc)
299 { 299 {
300 do_guarded( 300 do_guarded(
301 dbc, [&](auto const& guard) -> void { throw error{guard, s, dbc}; }); 301 dbc, [&](auto const& guard) -> void { throw error{guard, s, dbc}; });
302 } 302 }
303 else 303 else
304 { 304 {