diff options
Diffstat (limited to 'server/src/sqlite3.cppm')
| -rw-r--r-- | server/src/sqlite3.cppm | 86 |
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 | ||
| 23 | public: | 23 | public: |
| 24 | mutex_guard(mutex_guard const&) = delete; | 24 | mutex_guard(mutex_guard const&) = delete; |
| @@ -29,13 +29,13 @@ private: | |||
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | auto do_guarded(::sqlite3_mutex* mut, std::invocable<mutex_guard const&> auto f) | 31 | auto 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 | ||
| 37 | auto do_guarded(::sqlite3* dbc, std::invocable<mutex_guard const&> auto f) | 37 | auto 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 | { |