sqlite_web_vfs 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE-3RD-PARTY.md +32 -0
- data/README.md +118 -0
- data/examples/sqlite3_example.rb +21 -0
- data/examples/sqlite3_ffi_example.rb +25 -0
- data/ext/sqlite_web_vfs/Makefile +267 -0
- data/ext/sqlite_web_vfs/_wrap_web_vfs.o +0 -0
- data/ext/sqlite_web_vfs/extconf.rb +177 -0
- data/ext/sqlite_web_vfs/readerwriterqueue.h +5 -0
- data/ext/sqlite_web_vfs/shim.c +16 -0
- data/ext/sqlite_web_vfs/shim.o +0 -0
- data/ext/sqlite_web_vfs/upstream/HTTP.h +435 -0
- data/ext/sqlite_web_vfs/upstream/SQLiteVFS.h +530 -0
- data/ext/sqlite_web_vfs/upstream/ThreadPool.h +209 -0
- data/ext/sqlite_web_vfs/upstream/atomicops.h +772 -0
- data/ext/sqlite_web_vfs/upstream/dbi.h +203 -0
- data/ext/sqlite_web_vfs/upstream/readerwriterqueue.h +979 -0
- data/ext/sqlite_web_vfs/upstream/web_vfs.cc +21 -0
- data/ext/sqlite_web_vfs/upstream/web_vfs.h +823 -0
- data/lib/sqlite_web_vfs/loader.rb +69 -0
- data/lib/sqlite_web_vfs.rb +12 -0
- data/spec/integration/sq_lite_web_vfs_integration_spec.rb +45 -0
- data/spec/integration/sqlite_web_vfs_integration_spec.rb +45 -0
- data/spec/spec_helper.rb +7 -0
- metadata +67 -0
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* C++ base classes to assist implementing the SQLite VFS API:
|
|
3
|
+
* https://www.sqlite.org/vfs.html
|
|
4
|
+
*/
|
|
5
|
+
#pragma once
|
|
6
|
+
|
|
7
|
+
#include <assert.h>
|
|
8
|
+
#include <iostream>
|
|
9
|
+
#include <memory>
|
|
10
|
+
#include <string.h>
|
|
11
|
+
#include <string>
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
Omitted so that includer can choose whether to use sqlite3.h or sqlite3ext.h
|
|
15
|
+
#include <sqlite3.h>
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
namespace SQLiteVFS {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* VFS logging helpers:
|
|
22
|
+
*
|
|
23
|
+
* In SQLiteVFS::File and SQLiteVFS::Base implementations, the macro
|
|
24
|
+
*
|
|
25
|
+
* SQLITE_VFS_LOG(int level, message << for << cerr)
|
|
26
|
+
*
|
|
27
|
+
* logs the message to cerr if level is at least the active level. The active level is
|
|
28
|
+
* determined as follows:
|
|
29
|
+
*
|
|
30
|
+
* 1. SQLITE_VFS_LOG environment variable
|
|
31
|
+
* 2. vfs_log URI parameter (for URI-opened File)
|
|
32
|
+
* 3. When compiled in DEBUG mode, 5.
|
|
33
|
+
* 4. Otherwise 0 (but default can be overridden by implementation)
|
|
34
|
+
*
|
|
35
|
+
* Recommended levels: 1=error, 2=warning, 3=notice, 4=info, 5=debug.
|
|
36
|
+
*/
|
|
37
|
+
class Logger : public std::ostream {
|
|
38
|
+
public:
|
|
39
|
+
Logger(const char *zName = nullptr, const int DEFAULT_LEVEL = 0)
|
|
40
|
+
: std::ostream(std::cerr.rdbuf()) {
|
|
41
|
+
DetectLevel(zName, DEFAULT_LEVEL);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
void DetectLevel(const char *zName = nullptr, const int DEFAULT_LEVEL = 0) {
|
|
45
|
+
int log_level = DEFAULT_LEVEL; // default from caller (we keep it even in debug builds)
|
|
46
|
+
|
|
47
|
+
const char *env_log = getenv("SQLITE_VFS_LOG");
|
|
48
|
+
bool env_ok = false;
|
|
49
|
+
if (env_log && *env_log) {
|
|
50
|
+
errno = 0;
|
|
51
|
+
unsigned long env_log_level = strtoul(env_log, nullptr, 10);
|
|
52
|
+
if (errno == 0 && env_log_level != ULONG_MAX) {
|
|
53
|
+
log_level = env_log_level;
|
|
54
|
+
env_ok = true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!env_ok && zName) {
|
|
59
|
+
auto uri_log_level = sqlite3_uri_int64(zName, "vfs_log", -1);
|
|
60
|
+
if (uri_log_level >= 0) {
|
|
61
|
+
log_level = (unsigned long)uri_log_level;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
level_ = log_level;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
template <typename T> Logger &operator<<(const T &t) {
|
|
69
|
+
std::cerr << t;
|
|
70
|
+
return *this;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Logger &operator<<(std::ostream &(*manip)(std::ostream &)) {
|
|
74
|
+
std::cerr << manip;
|
|
75
|
+
return *this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
int level() const { return level_; }
|
|
79
|
+
|
|
80
|
+
private:
|
|
81
|
+
int level_;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
|
85
|
+
#define SQLITE_VFS_LOG(msg_level, msg) \
|
|
86
|
+
if (log_.level() >= msg_level) { \
|
|
87
|
+
log_ << '[' << __FILENAME__ << ":" << __LINE__ << ':' << msg_level << "] " << msg << '\n' \
|
|
88
|
+
<< std::flush; \
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Abstract base class for sqlite3_file implementations. VFS xOpen() implementations can
|
|
93
|
+
* instantiate a subclass implementing all of the pure methods, then call InitHandle() to fill out
|
|
94
|
+
* a sqlite3_file* Handle to hand back to the caller. The instance self-deletes upon xClose().
|
|
95
|
+
*/
|
|
96
|
+
class File {
|
|
97
|
+
protected:
|
|
98
|
+
sqlite3_io_methods methods_;
|
|
99
|
+
Logger log_;
|
|
100
|
+
|
|
101
|
+
virtual int Close() {
|
|
102
|
+
delete this;
|
|
103
|
+
return SQLITE_OK;
|
|
104
|
+
}
|
|
105
|
+
virtual int Read(void *zBuf, int iAmt, sqlite3_int64 iOfst) = 0;
|
|
106
|
+
virtual int Write(const void *zBuf, int iAmt, sqlite3_int64 iOfst) = 0;
|
|
107
|
+
virtual int Truncate(sqlite3_int64 size) = 0;
|
|
108
|
+
virtual int Sync(int flags) = 0;
|
|
109
|
+
virtual int FileSize(sqlite3_int64 *pSize) = 0;
|
|
110
|
+
virtual int Lock(int eLock) = 0;
|
|
111
|
+
virtual int Unlock(int eLock) = 0;
|
|
112
|
+
virtual int CheckReservedLock(int *pResOut) = 0;
|
|
113
|
+
virtual int FileControl(int op, void *pArg) = 0;
|
|
114
|
+
virtual int SectorSize() = 0;
|
|
115
|
+
virtual int DeviceCharacteristics() = 0;
|
|
116
|
+
|
|
117
|
+
virtual int ShmMap(int iPg, int pgsz, int isWrite, void volatile **pp) = 0;
|
|
118
|
+
virtual int ShmLock(int offset, int n, int flags) = 0;
|
|
119
|
+
virtual void ShmBarrier() = 0;
|
|
120
|
+
virtual int ShmUnmap(int deleteFlag) = 0;
|
|
121
|
+
|
|
122
|
+
virtual int Fetch(sqlite3_int64 iOfst, int iAmt, void **pp) = 0;
|
|
123
|
+
virtual int Unfetch(sqlite3_int64 iOfst, void *p) = 0;
|
|
124
|
+
|
|
125
|
+
public:
|
|
126
|
+
/**
|
|
127
|
+
* sqlite3_file "handle" which VFS xOpen() is responsible for filling in by calling
|
|
128
|
+
* InitHandle()
|
|
129
|
+
*/
|
|
130
|
+
struct Handle {
|
|
131
|
+
sqlite3_file base;
|
|
132
|
+
File *this_;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
File(const char *zName) : log_(zName) {
|
|
136
|
+
memset(&methods_, 0, sizeof(methods_));
|
|
137
|
+
methods_.iVersion = 3; // subclasses may override to 2 or 1
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
virtual ~File() noexcept = default;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Initialize the Handle, assuming pFile points to a Handle.
|
|
144
|
+
*/
|
|
145
|
+
virtual void InitHandle(sqlite3_file *pFile) noexcept {
|
|
146
|
+
Handle *handle = (Handle *)pFile;
|
|
147
|
+
assert(methods_.iVersion && !methods_.xClose);
|
|
148
|
+
#define __SQLITEVFS_FILE_DISPATCH(Method, pFile, ...) \
|
|
149
|
+
try { \
|
|
150
|
+
return reinterpret_cast<Handle *>(pFile)->this_->Method(__VA_ARGS__); \
|
|
151
|
+
} catch (std::bad_alloc &) { \
|
|
152
|
+
return SQLITE_NOMEM; \
|
|
153
|
+
} catch (...) { \
|
|
154
|
+
return SQLITE_ERROR; \
|
|
155
|
+
}
|
|
156
|
+
methods_.xClose = [](sqlite3_file *pFile) noexcept {
|
|
157
|
+
__SQLITEVFS_FILE_DISPATCH(Close, pFile)
|
|
158
|
+
};
|
|
159
|
+
methods_.xRead = [](sqlite3_file *pFile, void *zBuf, int iAmt, sqlite3_int64 iOfst) {
|
|
160
|
+
__SQLITEVFS_FILE_DISPATCH(Read, pFile, zBuf, iAmt, iOfst);
|
|
161
|
+
};
|
|
162
|
+
methods_.xWrite = [](sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite3_int64 iOfst) {
|
|
163
|
+
__SQLITEVFS_FILE_DISPATCH(Write, pFile, zBuf, iAmt, iOfst);
|
|
164
|
+
};
|
|
165
|
+
methods_.xTruncate = [](sqlite3_file *pFile, sqlite3_int64 size) {
|
|
166
|
+
__SQLITEVFS_FILE_DISPATCH(Truncate, pFile, size);
|
|
167
|
+
};
|
|
168
|
+
methods_.xSync = [](sqlite3_file *pFile, int flags) {
|
|
169
|
+
__SQLITEVFS_FILE_DISPATCH(Sync, pFile, flags);
|
|
170
|
+
};
|
|
171
|
+
methods_.xFileSize = [](sqlite3_file *pFile, sqlite3_int64 *pSize) {
|
|
172
|
+
__SQLITEVFS_FILE_DISPATCH(FileSize, pFile, pSize);
|
|
173
|
+
};
|
|
174
|
+
methods_.xLock = [](sqlite3_file *pFile, int eLock) {
|
|
175
|
+
__SQLITEVFS_FILE_DISPATCH(Lock, pFile, eLock);
|
|
176
|
+
};
|
|
177
|
+
methods_.xUnlock = [](sqlite3_file *pFile, int eLock) {
|
|
178
|
+
__SQLITEVFS_FILE_DISPATCH(Unlock, pFile, eLock);
|
|
179
|
+
};
|
|
180
|
+
methods_.xCheckReservedLock = [](sqlite3_file *pFile, int *pResOut) {
|
|
181
|
+
__SQLITEVFS_FILE_DISPATCH(CheckReservedLock, pFile, pResOut);
|
|
182
|
+
};
|
|
183
|
+
methods_.xFileControl = [](sqlite3_file *pFile, int op, void *pArg) {
|
|
184
|
+
__SQLITEVFS_FILE_DISPATCH(FileControl, pFile, op, pArg);
|
|
185
|
+
};
|
|
186
|
+
methods_.xSectorSize = [](sqlite3_file *pFile) {
|
|
187
|
+
__SQLITEVFS_FILE_DISPATCH(SectorSize, pFile);
|
|
188
|
+
};
|
|
189
|
+
methods_.xDeviceCharacteristics = [](sqlite3_file *pFile) {
|
|
190
|
+
__SQLITEVFS_FILE_DISPATCH(DeviceCharacteristics, pFile);
|
|
191
|
+
};
|
|
192
|
+
if (methods_.iVersion >= 2) {
|
|
193
|
+
methods_.xShmMap = [](sqlite3_file *pFile, int iPg, int pgsz, int isWrite,
|
|
194
|
+
void volatile **pp) {
|
|
195
|
+
__SQLITEVFS_FILE_DISPATCH(ShmMap, pFile, iPg, pgsz, isWrite, pp);
|
|
196
|
+
};
|
|
197
|
+
methods_.xShmLock = [](sqlite3_file *pFile, int offset, int n, int flags) {
|
|
198
|
+
__SQLITEVFS_FILE_DISPATCH(ShmLock, pFile, offset, n, flags);
|
|
199
|
+
};
|
|
200
|
+
methods_.xShmBarrier = [](sqlite3_file *pFile) {
|
|
201
|
+
try {
|
|
202
|
+
reinterpret_cast<Handle *>(pFile)->this_->ShmBarrier();
|
|
203
|
+
} catch (...) {
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
methods_.xShmUnmap = [](sqlite3_file *pFile, int deleteFlag) {
|
|
207
|
+
__SQLITEVFS_FILE_DISPATCH(ShmUnmap, pFile, deleteFlag);
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
if (methods_.iVersion >= 3) {
|
|
211
|
+
methods_.xFetch = [](sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp) {
|
|
212
|
+
__SQLITEVFS_FILE_DISPATCH(Fetch, pFile, iOfst, iAmt, pp);
|
|
213
|
+
};
|
|
214
|
+
methods_.xUnfetch = [](sqlite3_file *pFile, sqlite3_int64 iOfst, void *p) {
|
|
215
|
+
__SQLITEVFS_FILE_DISPATCH(Unfetch, pFile, iOfst, p);
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
#undef __SQLITEVFS_FILE_DISPATCH
|
|
219
|
+
handle->this_ = this;
|
|
220
|
+
handle->base.pMethods = &methods_;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Implements File by wrapping some other sqlite3_file*. This accomplishes nothing useful itself,
|
|
226
|
+
* but lets subclasses override individual methods.
|
|
227
|
+
*/
|
|
228
|
+
class FileWrapper : public File {
|
|
229
|
+
protected:
|
|
230
|
+
std::shared_ptr<sqlite3_file> wrapped_;
|
|
231
|
+
|
|
232
|
+
int Close() override {
|
|
233
|
+
int rc = wrapped_->pMethods ? wrapped_->pMethods->xClose(wrapped_.get()) : SQLITE_OK;
|
|
234
|
+
wrapped_.reset(); // deletes this!
|
|
235
|
+
int rc2 = File::Close();
|
|
236
|
+
return rc != SQLITE_OK ? rc : rc2;
|
|
237
|
+
}
|
|
238
|
+
int Read(void *zBuf, int iAmt, sqlite3_int64 iOfst) override {
|
|
239
|
+
return wrapped_->pMethods->xRead(wrapped_.get(), zBuf, iAmt, iOfst);
|
|
240
|
+
}
|
|
241
|
+
int Write(const void *zBuf, int iAmt, sqlite3_int64 iOfst) override {
|
|
242
|
+
return wrapped_->pMethods->xWrite(wrapped_.get(), zBuf, iAmt, iOfst);
|
|
243
|
+
}
|
|
244
|
+
int Truncate(sqlite3_int64 size) override {
|
|
245
|
+
return wrapped_->pMethods->xTruncate(wrapped_.get(), size);
|
|
246
|
+
}
|
|
247
|
+
int Sync(int flags) override { return wrapped_->pMethods->xSync(wrapped_.get(), flags); }
|
|
248
|
+
int FileSize(sqlite3_int64 *pSize) override {
|
|
249
|
+
return wrapped_->pMethods->xFileSize(wrapped_.get(), pSize);
|
|
250
|
+
}
|
|
251
|
+
int Lock(int eLock) override { return wrapped_->pMethods->xLock(wrapped_.get(), eLock); }
|
|
252
|
+
int Unlock(int eLock) override { return wrapped_->pMethods->xUnlock(wrapped_.get(), eLock); }
|
|
253
|
+
int CheckReservedLock(int *pResOut) override {
|
|
254
|
+
return wrapped_->pMethods->xCheckReservedLock(wrapped_.get(), pResOut);
|
|
255
|
+
}
|
|
256
|
+
int FileControl(int op, void *pArg) override {
|
|
257
|
+
return wrapped_->pMethods->xFileControl(wrapped_.get(), op, pArg);
|
|
258
|
+
}
|
|
259
|
+
int SectorSize() override { return wrapped_->pMethods->xSectorSize(wrapped_.get()); }
|
|
260
|
+
int DeviceCharacteristics() override {
|
|
261
|
+
return wrapped_->pMethods->xDeviceCharacteristics(wrapped_.get());
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
int ShmMap(int iPg, int pgsz, int isWrite, void volatile **pp) override {
|
|
265
|
+
return wrapped_->pMethods->xShmMap(wrapped_.get(), iPg, pgsz, isWrite, pp);
|
|
266
|
+
}
|
|
267
|
+
int ShmLock(int offset, int n, int flags) override {
|
|
268
|
+
return wrapped_->pMethods->xShmLock(wrapped_.get(), offset, n, flags);
|
|
269
|
+
}
|
|
270
|
+
void ShmBarrier() override { return wrapped_->pMethods->xShmBarrier(wrapped_.get()); }
|
|
271
|
+
int ShmUnmap(int deleteFlag) override {
|
|
272
|
+
return wrapped_->pMethods->xShmUnmap(wrapped_.get(), deleteFlag);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
int Fetch(sqlite3_int64 iOfst, int iAmt, void **pp) override {
|
|
276
|
+
return wrapped_->pMethods->xFetch(wrapped_.get(), iOfst, iAmt, pp);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
int Unfetch(sqlite3_int64 iOfst, void *p) override {
|
|
280
|
+
return wrapped_->pMethods->xUnfetch(wrapped_.get(), iOfst, p);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
public:
|
|
284
|
+
// inner will be freed after xClose()
|
|
285
|
+
FileWrapper(const char *zName, int flags, const std::shared_ptr<sqlite3_file> &inner)
|
|
286
|
+
: File(zName), wrapped_(inner) {}
|
|
287
|
+
virtual ~FileWrapper() noexcept = default;
|
|
288
|
+
|
|
289
|
+
void InitHandle(sqlite3_file *pFile) noexcept override {
|
|
290
|
+
methods_.iVersion = std::min(methods_.iVersion, wrapped_->pMethods->iVersion);
|
|
291
|
+
File::InitHandle(pFile);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Abstract base class for SQLite VFS implementations. A subclass may implement the methods, then
|
|
297
|
+
* something can instantiate and call Register(vfs_name) to make it available via sqlite3_open_v2.
|
|
298
|
+
*/
|
|
299
|
+
class Base {
|
|
300
|
+
protected:
|
|
301
|
+
sqlite3_vfs vfs_;
|
|
302
|
+
std::string name_;
|
|
303
|
+
Logger log_;
|
|
304
|
+
|
|
305
|
+
// subclass may increase if it needs a large Handle for some reason
|
|
306
|
+
virtual size_t szOsFile() { return sizeof(File::Handle); }
|
|
307
|
+
|
|
308
|
+
virtual int Open(const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags) = 0;
|
|
309
|
+
virtual int Delete(const char *zPath, int syncDir) = 0;
|
|
310
|
+
virtual int Access(const char *zPath, int flags, int *pResOut) = 0;
|
|
311
|
+
virtual int FullPathname(const char *zName, int nPathOut, char *zPathOut) = 0;
|
|
312
|
+
|
|
313
|
+
virtual void *DlOpen(const char *zFilename) = 0;
|
|
314
|
+
virtual void DlError(int nByte, char *zErrMsg) = 0;
|
|
315
|
+
virtual void (*DlSym(void *pHandle, const char *zSymbol))() = 0;
|
|
316
|
+
virtual void DlClose(void *pHandle) = 0;
|
|
317
|
+
|
|
318
|
+
virtual int Randomness(int nByte, char *zOut) = 0;
|
|
319
|
+
virtual int Sleep(int nMicro) = 0;
|
|
320
|
+
virtual int CurrentTime(double *pTime) = 0;
|
|
321
|
+
virtual int GetLastError(int nByte, char *zErrMsg) = 0;
|
|
322
|
+
virtual int CurrentTimeInt64(sqlite3_int64 *pTime) = 0;
|
|
323
|
+
|
|
324
|
+
virtual int SetSystemCall(const char *zName, sqlite3_syscall_ptr fn) = 0;
|
|
325
|
+
virtual sqlite3_syscall_ptr GetSystemCall(const char *zName) = 0;
|
|
326
|
+
virtual const char *NextSystemCall(const char *zName) = 0;
|
|
327
|
+
|
|
328
|
+
public:
|
|
329
|
+
Base() {
|
|
330
|
+
memset(&vfs_, 0, sizeof(vfs_));
|
|
331
|
+
vfs_.iVersion = 3; // subclass may override to 2 or 1
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
virtual int Register(const char *name) noexcept {
|
|
335
|
+
assert(vfs_.iVersion && !vfs_.zName);
|
|
336
|
+
name_ = name;
|
|
337
|
+
vfs_.szOsFile = szOsFile();
|
|
338
|
+
vfs_.mxPathname = 1024;
|
|
339
|
+
vfs_.pNext = nullptr;
|
|
340
|
+
vfs_.zName = name_.c_str();
|
|
341
|
+
vfs_.pAppData = this;
|
|
342
|
+
|
|
343
|
+
#define __SQLITE_VFS_DISPATCH(Method, pVfs, ...) \
|
|
344
|
+
try { \
|
|
345
|
+
return reinterpret_cast<Base *>(pVfs->pAppData)->Method(__VA_ARGS__); \
|
|
346
|
+
} catch (std::bad_alloc &) { \
|
|
347
|
+
return SQLITE_NOMEM; \
|
|
348
|
+
} catch (...) { \
|
|
349
|
+
return SQLITE_ERROR; \
|
|
350
|
+
}
|
|
351
|
+
vfs_.xOpen = [](sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, int flags,
|
|
352
|
+
int *pOutFlags) noexcept {
|
|
353
|
+
__SQLITE_VFS_DISPATCH(Open, pVfs, zName, pFile, flags, pOutFlags)
|
|
354
|
+
};
|
|
355
|
+
vfs_.xDelete = [](sqlite3_vfs *pVfs, const char *zPath, int syncDir) noexcept {
|
|
356
|
+
__SQLITE_VFS_DISPATCH(Delete, pVfs, zPath, syncDir)
|
|
357
|
+
};
|
|
358
|
+
vfs_.xAccess = [](sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut) noexcept {
|
|
359
|
+
__SQLITE_VFS_DISPATCH(Access, pVfs, zPath, flags, pResOut)
|
|
360
|
+
};
|
|
361
|
+
vfs_.xFullPathname = [](sqlite3_vfs *pVfs, const char *zName, int nPathOut,
|
|
362
|
+
char *zPathOut) noexcept {
|
|
363
|
+
__SQLITE_VFS_DISPATCH(FullPathname, pVfs, zName, nPathOut, zPathOut)
|
|
364
|
+
};
|
|
365
|
+
vfs_.xDlOpen = [](sqlite3_vfs *pVfs, const char *zFilename) noexcept {
|
|
366
|
+
try {
|
|
367
|
+
return reinterpret_cast<Base *>(pVfs->pAppData)->DlOpen(zFilename);
|
|
368
|
+
} catch (...) {
|
|
369
|
+
return (void *)nullptr;
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
vfs_.xDlError = [](sqlite3_vfs *pVfs, int nByte, char *zErrMsg) noexcept {
|
|
373
|
+
try {
|
|
374
|
+
return reinterpret_cast<Base *>(pVfs->pAppData)->DlError(nByte, zErrMsg);
|
|
375
|
+
} catch (...) {
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
vfs_.xDlSym = [](sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol) noexcept {
|
|
379
|
+
try {
|
|
380
|
+
return reinterpret_cast<Base *>(pVfs->pAppData)->DlSym(pHandle, zSymbol);
|
|
381
|
+
} catch (...) {
|
|
382
|
+
return (void (*)()) nullptr;
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
vfs_.xDlClose = [](sqlite3_vfs *pVfs, void *pHandle) noexcept {
|
|
386
|
+
try {
|
|
387
|
+
return reinterpret_cast<Base *>(pVfs->pAppData)->DlClose(pHandle);
|
|
388
|
+
} catch (...) {
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
vfs_.xRandomness = [](sqlite3_vfs *pVfs, int nByte, char *zOut) noexcept {
|
|
392
|
+
__SQLITE_VFS_DISPATCH(Randomness, pVfs, nByte, zOut)
|
|
393
|
+
};
|
|
394
|
+
vfs_.xSleep = [](sqlite3_vfs *pVfs, int nMicro) noexcept {
|
|
395
|
+
__SQLITE_VFS_DISPATCH(Sleep, pVfs, nMicro)
|
|
396
|
+
};
|
|
397
|
+
vfs_.xCurrentTime = [](sqlite3_vfs *pVfs, double *pTime) noexcept {
|
|
398
|
+
__SQLITE_VFS_DISPATCH(CurrentTime, pVfs, pTime)
|
|
399
|
+
};
|
|
400
|
+
vfs_.xGetLastError = [](sqlite3_vfs *pVfs, int nByte, char *zErrMsg) noexcept {
|
|
401
|
+
__SQLITE_VFS_DISPATCH(GetLastError, pVfs, nByte, zErrMsg)
|
|
402
|
+
};
|
|
403
|
+
if (vfs_.iVersion >= 2) {
|
|
404
|
+
vfs_.xCurrentTimeInt64 = [](sqlite3_vfs *pVfs, sqlite3_int64 *pTime) noexcept {
|
|
405
|
+
__SQLITE_VFS_DISPATCH(CurrentTimeInt64, pVfs, pTime)
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
if (vfs_.iVersion >= 3) {
|
|
409
|
+
vfs_.xSetSystemCall = [](sqlite3_vfs *pVfs, const char *zName,
|
|
410
|
+
sqlite3_syscall_ptr fn) noexcept {
|
|
411
|
+
__SQLITE_VFS_DISPATCH(SetSystemCall, pVfs, zName, fn);
|
|
412
|
+
};
|
|
413
|
+
vfs_.xGetSystemCall = [](sqlite3_vfs *pVfs, const char *zName) noexcept {
|
|
414
|
+
try {
|
|
415
|
+
return reinterpret_cast<Base *>(pVfs->pAppData)->GetSystemCall(zName);
|
|
416
|
+
} catch (...) {
|
|
417
|
+
return (sqlite3_syscall_ptr) nullptr;
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
vfs_.xNextSystemCall = [](sqlite3_vfs *pVfs, const char *zName) noexcept {
|
|
421
|
+
try {
|
|
422
|
+
return reinterpret_cast<Base *>(pVfs->pAppData)->NextSystemCall(zName);
|
|
423
|
+
} catch (...) {
|
|
424
|
+
return (const char *)nullptr;
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
#undef __SQLITE_VFS_DISPATCH
|
|
429
|
+
return sqlite3_vfs_register(&vfs_, 0);
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Implements VFS by wrapping some other existing VFS (perhaps the default one). This accomplishes
|
|
435
|
+
* nothing useful itself, but lets subclasses override individual methods.
|
|
436
|
+
*/
|
|
437
|
+
class Wrapper : public Base {
|
|
438
|
+
protected:
|
|
439
|
+
sqlite3_vfs *wrapped_ = nullptr;
|
|
440
|
+
|
|
441
|
+
size_t szOsFile() override {
|
|
442
|
+
return std::max(SQLiteVFS::Base::szOsFile(), (size_t)wrapped_->szOsFile);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// instantiate FileWrapper; subclasses may override to instantiate an associated subclass of
|
|
446
|
+
// FileWrapper. zName may be used to access sqlite_uri_*.
|
|
447
|
+
virtual std::unique_ptr<FileWrapper>
|
|
448
|
+
NewFileWrapper(const char *zName, int flags,
|
|
449
|
+
const std::shared_ptr<sqlite3_file> &wrapped_file) {
|
|
450
|
+
return std::unique_ptr<FileWrapper>(new FileWrapper(zName, flags, wrapped_file));
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// xOpen a FileWrapper
|
|
454
|
+
int Open(const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags) override {
|
|
455
|
+
assert(!pFile->pMethods);
|
|
456
|
+
std::shared_ptr<sqlite3_file> wrapped_file(
|
|
457
|
+
(sqlite3_file *)sqlite3_malloc(wrapped_->szOsFile), sqlite3_free);
|
|
458
|
+
if (!wrapped_file) {
|
|
459
|
+
return SQLITE_NOMEM;
|
|
460
|
+
}
|
|
461
|
+
memset(wrapped_file.get(), 0, wrapped_->szOsFile);
|
|
462
|
+
|
|
463
|
+
int rc = wrapped_->xOpen(wrapped_, zName, wrapped_file.get(), flags, pOutFlags);
|
|
464
|
+
if (rc != SQLITE_OK) {
|
|
465
|
+
if (wrapped_file->pMethods) {
|
|
466
|
+
wrapped_file->pMethods->xClose(wrapped_file.get());
|
|
467
|
+
}
|
|
468
|
+
return rc;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
auto fw = NewFileWrapper(zName, flags, wrapped_file);
|
|
472
|
+
fw->InitHandle(pFile);
|
|
473
|
+
assert(pFile->pMethods);
|
|
474
|
+
// Since pFile->pMethods is now set, caller is required to invoke xClose(), which in turn
|
|
475
|
+
// closes+frees the wrapped_file and deletes the FileWrapper.
|
|
476
|
+
fw.release();
|
|
477
|
+
return SQLITE_OK;
|
|
478
|
+
}
|
|
479
|
+
int Delete(const char *zPath, int syncDir) override {
|
|
480
|
+
return wrapped_->xDelete(wrapped_, zPath, syncDir);
|
|
481
|
+
}
|
|
482
|
+
int Access(const char *zPath, int flags, int *pResOut) override {
|
|
483
|
+
return wrapped_->xAccess(wrapped_, zPath, flags, pResOut);
|
|
484
|
+
}
|
|
485
|
+
int FullPathname(const char *zName, int nPathOut, char *zPathOut) override {
|
|
486
|
+
return wrapped_->xFullPathname(wrapped_, zName, nPathOut, zPathOut);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
void *DlOpen(const char *zFilename) override { return wrapped_->xDlOpen(wrapped_, zFilename); }
|
|
490
|
+
void DlError(int nByte, char *zErrMsg) override {
|
|
491
|
+
wrapped_->xDlError(wrapped_, nByte, zErrMsg);
|
|
492
|
+
}
|
|
493
|
+
void (*DlSym(void *pHandle, const char *zSymbol))() override {
|
|
494
|
+
return wrapped_->xDlSym(wrapped_, pHandle, zSymbol);
|
|
495
|
+
}
|
|
496
|
+
void DlClose(void *pHandle) override { wrapped_->xDlClose(wrapped_, pHandle); }
|
|
497
|
+
|
|
498
|
+
int Randomness(int nByte, char *zOut) override {
|
|
499
|
+
return wrapped_->xRandomness(wrapped_, nByte, zOut);
|
|
500
|
+
}
|
|
501
|
+
int Sleep(int nMicro) override { return wrapped_->xSleep(wrapped_, nMicro); }
|
|
502
|
+
int CurrentTime(double *pTime) override { return wrapped_->xCurrentTime(wrapped_, pTime); }
|
|
503
|
+
int GetLastError(int nByte, char *zErrMsg) override {
|
|
504
|
+
return wrapped_->xGetLastError(wrapped_, nByte, zErrMsg);
|
|
505
|
+
}
|
|
506
|
+
int CurrentTimeInt64(sqlite3_int64 *pTime) override {
|
|
507
|
+
return wrapped_->xCurrentTimeInt64(wrapped_, pTime);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
int SetSystemCall(const char *zName, sqlite3_syscall_ptr fn) override {
|
|
511
|
+
return wrapped_->xSetSystemCall(wrapped_, zName, fn);
|
|
512
|
+
}
|
|
513
|
+
sqlite3_syscall_ptr GetSystemCall(const char *zName) override {
|
|
514
|
+
return wrapped_->xGetSystemCall(wrapped_, zName);
|
|
515
|
+
}
|
|
516
|
+
const char *NextSystemCall(const char *zName) override {
|
|
517
|
+
return wrapped_->xNextSystemCall(wrapped_, zName);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
public:
|
|
521
|
+
int Register(const char *name, const char *wrapped_vfs_name) noexcept {
|
|
522
|
+
wrapped_ = sqlite3_vfs_find(wrapped_vfs_name);
|
|
523
|
+
vfs_.iVersion = std::min(vfs_.iVersion, wrapped_->iVersion);
|
|
524
|
+
return Base::Register(name);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
int Register(const char *name) noexcept override { return Register(name, nullptr); }
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
} // namespace SQLiteVFS
|