Nix 2.93.3
Lix: A modern, delicious implementation of the Nix package manager; unstable internal interfaces
Loading...
Searching...
No Matches
sqlite.hh
Go to the documentation of this file.
1#pragma once
3
4#include <chrono>
5#include <kj/async.h>
6#include <string>
7#include <type_traits>
8
10#include "lix/libutil/result.hh"
11#include "lix/libutil/types.hh"
12#include "lix/libutil/error.hh"
13
14struct sqlite3;
15struct sqlite3_stmt;
16
17namespace nix {
18
39
63
64struct SQLiteError;
65class SQLiteStmt;
66class SQLiteTxn;
67
71class SQLite
72{
73 friend SQLiteError;
74
75 struct Close {
76 void operator()(sqlite3 * db);
77 };
78 std::unique_ptr<sqlite3, Close> db;
79
80public:
81 SQLite() = default;
82 SQLite(const Path & path, SQLiteOpenMode mode = SQLiteOpenMode::Normal);
83
87 void isCache();
88
89 void exec(const std::string & stmt, NeverAsync = {});
90
91 SQLiteStmt create(const std::string & stmt);
92
93 SQLiteTxn beginTransaction(SQLiteTxnType type = SQLiteTxnType::Deferred);
94
95 void setPersistWAL(bool persist);
96
97 uint64_t getLastInsertedRowId();
98 uint64_t getRowsChanged();
99};
100
104class SQLiteStmt
105{
106 friend SQLite;
107
108 struct Finalize {
109 SQLiteStmt * parent;
110 void operator()(sqlite3_stmt * stmt);
111 };
112
113 sqlite3 * db = 0;
114 std::unique_ptr<sqlite3_stmt, Finalize> stmt;
115 std::string sql;
116
117 SQLiteStmt(sqlite3 * db, const std::string & sql);
118
119public:
120 SQLiteStmt() = default;
121
125 class Use
126 {
127 friend class SQLiteStmt;
128 private:
129 SQLiteStmt & stmt;
130 unsigned int curArg = 1;
131 Use(SQLiteStmt & stmt);
132
133 public:
134
135 ~Use();
136
140 Use & operator () (std::string_view value, bool notNull = true);
141 Use & operator () (const unsigned char * data, size_t len, bool notNull = true);
142 Use & operator () (int64_t value, bool notNull = true);
143 Use & bind(); // null
144
148 void exec();
149
154 bool next();
155
156 std::string getStr(int col);
157 std::optional<std::string> getStrNullable(int col);
158 int64_t getInt(int col);
159 bool isNull(int col);
160 };
161
162 Use use()
163 {
164 return Use(*this);
165 }
166};
167
172class SQLiteTxn
173{
174 friend SQLite;
175
176 struct Rollback {
177 void operator()(sqlite3 * db);
178 };
179 std::unique_ptr<sqlite3, Rollback> db;
180
181 explicit SQLiteTxn(sqlite3 * db, SQLiteTxnType type);
182
183public:
184 void commit();
185};
186
187
188struct SQLiteError : Error
189{
190 friend SQLite;
191 friend SQLiteStmt;
192 friend SQLiteTxn;
193
194 std::string path;
195 std::string errMsg;
196 int errNo, extendedErrNo, offset;
197
198 SQLiteError(const char *path, const char *errMsg, int errNo, int extendedErrNo, int offset, HintFmt && hf);
199
200protected:
201
202 template<typename... Args>
203 SQLiteError(const char *path, const char *errMsg, int errNo, int extendedErrNo, int offset, const std::string & fs, const Args & ... args)
204 : SQLiteError(path, errMsg, errNo, extendedErrNo, offset, HintFmt(fs, args...))
205 { }
206
207 template<typename... Args>
208 [[noreturn]] static void throw_(sqlite3 * db, const std::string & fs, const Args & ... args) {
209 throw_(db, HintFmt(fs, args...));
210 }
211
212 [[noreturn]] static void throw_(sqlite3 * db, HintFmt && hf);
213
214};
215
216MakeError(SQLiteBusy, SQLiteError);
217
218void handleSQLiteBusy(const SQLiteBusy & e, std::chrono::time_point<std::chrono::steady_clock> & nextWarning);
219kj::Promise<Result<void>> handleSQLiteBusyAsync(const SQLiteBusy & e, std::chrono::time_point<std::chrono::steady_clock> & nextWarning);
220
225template<typename F>
226 requires(!requires(F f) { []<typename T>(kj::Promise<T>) {}(f()); })
227auto retrySQLite(F fun, NeverAsync = {})
228{
229 auto nextWarning = std::chrono::steady_clock::now() + std::chrono::seconds(1);
230
231 while (true) {
232 try {
233 return fun();
234 } catch (SQLiteBusy & e) {
235 handleSQLiteBusy(e, nextWarning);
236 }
237 }
238}
239
240template<typename F>
241 requires requires(F f) { []<typename T>(kj::Promise<Result<T>>) {}(f()); }
242auto retrySQLite(F fun)
243{
244 return [](F fun) -> decltype(fun()) {
245 auto nextWarning = std::chrono::steady_clock::now() + std::chrono::seconds(1);
246
247 while (true) {
248 kj::Promise<Result<void>> handleBusy{nullptr};
249 try {
250 if constexpr (std::is_same_v<decltype(fun()), kj::Promise<Result<void>>>) {
251 LIX_TRY_AWAIT(fun());
252 co_return result::success();
253 } else {
254 co_return LIX_TRY_AWAIT(fun());
255 }
256 } catch (SQLiteBusy & e) {
257 handleBusy = handleSQLiteBusyAsync(e, nextWarning);
258 } catch (...) {
259 co_return result::current_exception();
260 }
261 LIX_TRY_AWAIT(handleBusy);
262 }
263 }(std::move(fun));
264}
265}
Definition args.hh:31
Definition fmt.hh:157
Definition sqlite.hh:126
bool next()
Definition sqlite.cc:227
void exec()
Definition sqlite.cc:221
Use & operator()(std::string_view value, bool notNull=true)
Definition sqlite.cc:179
Definition sqlite.hh:105
Definition sqlite.hh:173
void isCache()
Definition sqlite.cc:102
This file defines two main structs/classes used in nix error handling.
SQLiteTxnType
Definition sqlite.hh:40
@ Exclusive
Definition sqlite.hh:61
@ Immediate
Definition sqlite.hh:55
@ Deferred
Definition sqlite.hh:49
SQLiteOpenMode
Definition sqlite.hh:19
@ Immutable
Definition sqlite.hh:37
@ NoCreate
Definition sqlite.hh:29
@ Normal
Definition sqlite.hh:24
auto retrySQLite(F fun, NeverAsync={})
Definition sqlite.hh:227
Definition types.hh:172
Definition sqlite.hh:189
std::string Path
Definition types.hh:28