blob: 633a12189a6c862a47cc6d521a6d08319bfc18b3 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
#pragma once
#include <functional>
#include <string>
#include "types.hh"
class sqlite3;
class sqlite3_stmt;
namespace nix {
/* RAII wrapper to close a SQLite database automatically. */
struct SQLite {
sqlite3* db = 0;
SQLite() {}
SQLite(const Path& path);
SQLite(const SQLite& from) = delete;
SQLite& operator=(const SQLite& from) = delete;
SQLite& operator=(SQLite&& from) {
db = from.db;
from.db = 0;
return *this;
}
~SQLite();
operator sqlite3*() { return db; }
void exec(const std::string& stmt);
};
/* RAII wrapper to create and destroy SQLite prepared statements. */
struct SQLiteStmt {
sqlite3* db = 0;
sqlite3_stmt* stmt = 0;
std::string sql;
SQLiteStmt() {}
SQLiteStmt(sqlite3* db, const std::string& sql) { create(db, sql); }
void create(sqlite3* db, const std::string& s);
~SQLiteStmt();
operator sqlite3_stmt*() { return stmt; }
/* Helper for binding / executing statements. */
class Use {
friend struct SQLiteStmt;
private:
SQLiteStmt& stmt;
unsigned int curArg = 1;
Use(SQLiteStmt& stmt);
public:
~Use();
/* Bind the next parameter. */
Use& operator()(const std::string& value, bool notNull = true);
Use& operator()(int64_t value, bool notNull = true);
Use& bind(); // null
int step();
/* Execute a statement that does not return rows. */
void exec();
/* For statements that return 0 or more rows. Returns true iff
a row is available. */
bool next();
std::string getStr(int col);
int64_t getInt(int col);
bool isNull(int col);
};
Use use() { return Use(*this); }
};
/* RAII helper that ensures transactions are aborted unless explicitly
committed. */
struct SQLiteTxn {
bool active = false;
sqlite3* db;
SQLiteTxn(sqlite3* db);
void commit();
~SQLiteTxn();
};
MakeError(SQLiteError, Error);
MakeError(SQLiteBusy, SQLiteError);
[[noreturn]] void throwSQLiteError(sqlite3* db, const FormatOrString& fs);
void handleSQLiteBusy(const SQLiteBusy& e);
/* Convenience function for retrying a SQLite transaction when the
database is busy. */
template <typename T>
T retrySQLite(std::function<T()> fun) {
while (true) {
try {
return fun();
} catch (SQLiteBusy& e) {
handleSQLiteBusy(e);
}
}
}
} // namespace nix
|