@op-engineering/op-sqlite 2.0.8 → 2.0.11
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.
- package/README.md +10 -2
- package/cpp/bindings.cpp +20 -23
- package/cpp/bridge.cpp +42 -88
- package/cpp/bridge.h +31 -31
- package/cpp/sqlbatchexecutor.cpp +6 -6
- package/cpp/utils.cpp +23 -5
- package/cpp/utils.h +6 -0
- package/op-sqlite.podspec +6 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Created by [@ospfranco](https://twitter.com/ospfranco). **Please consider Sponso
|
|
|
16
16
|
|
|
17
17
|
## Benchmarks
|
|
18
18
|
|
|
19
|
-
You can find the [benchmarking code in the example app](https://github.com/OP-Engineering/op-sqlite/blob/main/example/src/Database.ts#L44).
|
|
19
|
+
You can find the [benchmarking code in the example app](https://github.com/OP-Engineering/op-sqlite/blob/main/example/src/Database.ts#L44). This is run using the `OP_SQLITE_PERF` flag which in turns disables some old and unused features of sqlite to squeeze the last drop of performance.
|
|
20
20
|
|
|
21
21
|

|
|
22
22
|
|
|
@@ -104,7 +104,7 @@ const largeDb = open({
|
|
|
104
104
|
});
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
#
|
|
107
|
+
# Performance
|
|
108
108
|
|
|
109
109
|
op-sqlite is already the fastest solution it can be, but it doesn't mean you cannot tweak SQLite to be faster (at the cost of some disadvantages). One possible tweak is turning on [Memory Mapping](https://www.sqlite.org/mmap.html). It allows to read/write to/from the disk without going through the kernel. However, if your queries throw an error your application might crash.
|
|
110
110
|
|
|
@@ -129,6 +129,14 @@ If you use [prepared statements](#prepared-statements) plus memory mapping and s
|
|
|
129
129
|
|
|
130
130
|

|
|
131
131
|
|
|
132
|
+
# Perf flag
|
|
133
|
+
|
|
134
|
+
You can turn on the performance flag to tweak all possible performance enhancing compilation flags, this greatly affects performance of sqlite itself
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
OP_SQLITE_PERF=1 npx pod-install
|
|
138
|
+
```
|
|
139
|
+
|
|
132
140
|
# SQLite Gotchas
|
|
133
141
|
|
|
134
142
|
## Strictness
|
package/cpp/bindings.cpp
CHANGED
|
@@ -35,10 +35,9 @@ bool invalidated = false;
|
|
|
35
35
|
void clearState() {
|
|
36
36
|
invalidated = true;
|
|
37
37
|
// Will terminate all operations and database connections
|
|
38
|
-
|
|
38
|
+
sqlite_close_all();
|
|
39
39
|
// We then join all the threads before the context gets invalidated
|
|
40
40
|
pool.restartPool();
|
|
41
|
-
|
|
42
41
|
updateHooks.clear();
|
|
43
42
|
commitHooks.clear();
|
|
44
43
|
rollbackHooks.clear();
|
|
@@ -81,7 +80,7 @@ void install(jsi::Runtime &rt,
|
|
|
81
80
|
}
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
BridgeResult result =
|
|
83
|
+
BridgeResult result = sqlite_open(dbName, path);
|
|
85
84
|
|
|
86
85
|
if (result.type == SQLiteError) {
|
|
87
86
|
throw std::runtime_error(result.message);
|
|
@@ -115,7 +114,7 @@ void install(jsi::Runtime &rt,
|
|
|
115
114
|
std::string databaseToAttach = args[1].asString(rt).utf8(rt);
|
|
116
115
|
std::string alias = args[2].asString(rt).utf8(rt);
|
|
117
116
|
BridgeResult result =
|
|
118
|
-
|
|
117
|
+
sqlite_attach(dbName, tempDocPath, databaseToAttach, alias);
|
|
119
118
|
|
|
120
119
|
if (result.type == SQLiteError) {
|
|
121
120
|
throw std::runtime_error(result.message);
|
|
@@ -137,7 +136,7 @@ void install(jsi::Runtime &rt,
|
|
|
137
136
|
|
|
138
137
|
std::string dbName = args[0].asString(rt).utf8(rt);
|
|
139
138
|
std::string alias = args[1].asString(rt).utf8(rt);
|
|
140
|
-
BridgeResult result =
|
|
139
|
+
BridgeResult result = sqlite_detach(dbName, alias);
|
|
141
140
|
|
|
142
141
|
if (result.type == SQLiteError) {
|
|
143
142
|
throw jsi::JSError(rt, result.message.c_str());
|
|
@@ -158,7 +157,7 @@ void install(jsi::Runtime &rt,
|
|
|
158
157
|
|
|
159
158
|
std::string dbName = args[0].asString(rt).utf8(rt);
|
|
160
159
|
|
|
161
|
-
BridgeResult result =
|
|
160
|
+
BridgeResult result = sqlite_close(dbName);
|
|
162
161
|
|
|
163
162
|
if (result.type == SQLiteError) {
|
|
164
163
|
throw jsi::JSError(rt, result.message.c_str());
|
|
@@ -190,7 +189,7 @@ void install(jsi::Runtime &rt,
|
|
|
190
189
|
tempDocPath = tempDocPath + "/" + args[1].asString(rt).utf8(rt);
|
|
191
190
|
}
|
|
192
191
|
|
|
193
|
-
BridgeResult result =
|
|
192
|
+
BridgeResult result = sqlite_remove(dbName, tempDocPath);
|
|
194
193
|
|
|
195
194
|
if (result.type == SQLiteError) {
|
|
196
195
|
throw std::runtime_error(result.message);
|
|
@@ -213,7 +212,7 @@ void install(jsi::Runtime &rt,
|
|
|
213
212
|
std::shared_ptr<std::vector<SmartHostObject>> metadata =
|
|
214
213
|
std::make_shared<std::vector<SmartHostObject>>();
|
|
215
214
|
|
|
216
|
-
auto status =
|
|
215
|
+
auto status = sqlite_execute(dbName, query, ¶ms, &results, metadata);
|
|
217
216
|
|
|
218
217
|
if (status.type == SQLiteError) {
|
|
219
218
|
throw std::runtime_error(status.message);
|
|
@@ -249,7 +248,7 @@ void install(jsi::Runtime &rt,
|
|
|
249
248
|
std::make_shared<std::vector<SmartHostObject>>();
|
|
250
249
|
|
|
251
250
|
auto status =
|
|
252
|
-
|
|
251
|
+
sqlite_execute(dbName, query, ¶ms, &results, metadata);
|
|
253
252
|
|
|
254
253
|
if (invalidated) {
|
|
255
254
|
return;
|
|
@@ -422,9 +421,8 @@ void install(jsi::Runtime &rt,
|
|
|
422
421
|
|
|
423
422
|
auto updateHook = HOSTFN("updateHook", 2) {
|
|
424
423
|
if (sizeof(args) < 2) {
|
|
425
|
-
throw std::runtime_error(
|
|
426
|
-
|
|
427
|
-
"dbName and callback needed");
|
|
424
|
+
throw std::runtime_error("[op-sqlite][updateHook] Incorrect parameters: "
|
|
425
|
+
"dbName and callback needed");
|
|
428
426
|
return {};
|
|
429
427
|
}
|
|
430
428
|
|
|
@@ -432,7 +430,7 @@ void install(jsi::Runtime &rt,
|
|
|
432
430
|
auto callback = std::make_shared<jsi::Value>(rt, args[1]);
|
|
433
431
|
|
|
434
432
|
if (callback->isUndefined() || callback->isNull()) {
|
|
435
|
-
|
|
433
|
+
sqlite_deregister_update_hook(dbName);
|
|
436
434
|
return {};
|
|
437
435
|
}
|
|
438
436
|
|
|
@@ -449,7 +447,7 @@ void install(jsi::Runtime &rt,
|
|
|
449
447
|
if (operation != "DELETE") {
|
|
450
448
|
std::string query = "SELECT * FROM " + tableName +
|
|
451
449
|
" where rowid = " + std::to_string(rowId) + ";";
|
|
452
|
-
|
|
450
|
+
sqlite_execute(dbName, query, ¶ms, &results, metadata);
|
|
453
451
|
}
|
|
454
452
|
|
|
455
453
|
invoker->invokeAsync(
|
|
@@ -474,23 +472,22 @@ void install(jsi::Runtime &rt,
|
|
|
474
472
|
});
|
|
475
473
|
};
|
|
476
474
|
|
|
477
|
-
|
|
475
|
+
sqlite_register_update_hook(dbName, std::move(hook));
|
|
478
476
|
|
|
479
477
|
return {};
|
|
480
478
|
});
|
|
481
479
|
|
|
482
480
|
auto commitHook = HOSTFN("commitHook", 2) {
|
|
483
481
|
if (sizeof(args) < 2) {
|
|
484
|
-
throw std::runtime_error(
|
|
485
|
-
|
|
486
|
-
"dbName and callback needed");
|
|
482
|
+
throw std::runtime_error("[op-sqlite][commitHook] Incorrect parameters: "
|
|
483
|
+
"dbName and callback needed");
|
|
487
484
|
return {};
|
|
488
485
|
}
|
|
489
486
|
|
|
490
487
|
auto dbName = args[0].asString(rt).utf8(rt);
|
|
491
488
|
auto callback = std::make_shared<jsi::Value>(rt, args[1]);
|
|
492
489
|
if (callback->isUndefined() || callback->isNull()) {
|
|
493
|
-
|
|
490
|
+
sqlite_deregister_commit_hook(dbName);
|
|
494
491
|
return {};
|
|
495
492
|
}
|
|
496
493
|
commitHooks[dbName] = callback;
|
|
@@ -500,7 +497,7 @@ void install(jsi::Runtime &rt,
|
|
|
500
497
|
[&rt, callback] { callback->asObject(rt).asFunction(rt).call(rt); });
|
|
501
498
|
};
|
|
502
499
|
|
|
503
|
-
|
|
500
|
+
sqlite_register_commit_hook(dbName, std::move(hook));
|
|
504
501
|
|
|
505
502
|
return {};
|
|
506
503
|
});
|
|
@@ -508,7 +505,7 @@ void install(jsi::Runtime &rt,
|
|
|
508
505
|
auto rollbackHook = HOSTFN("rollbackHook", 2) {
|
|
509
506
|
if (sizeof(args) < 2) {
|
|
510
507
|
throw std::runtime_error(
|
|
511
|
-
"[op-sqlite][
|
|
508
|
+
"[op-sqlite][rollbackHook] Incorrect parameters: "
|
|
512
509
|
"dbName and callback needed");
|
|
513
510
|
return {};
|
|
514
511
|
}
|
|
@@ -517,7 +514,7 @@ void install(jsi::Runtime &rt,
|
|
|
517
514
|
auto callback = std::make_shared<jsi::Value>(rt, args[1]);
|
|
518
515
|
|
|
519
516
|
if (callback->isUndefined() || callback->isNull()) {
|
|
520
|
-
|
|
517
|
+
sqlite_deregister_rollback_hook(dbName);
|
|
521
518
|
return {};
|
|
522
519
|
}
|
|
523
520
|
rollbackHooks[dbName] = callback;
|
|
@@ -527,7 +524,7 @@ void install(jsi::Runtime &rt,
|
|
|
527
524
|
[&rt, callback] { callback->asObject(rt).asFunction(rt).call(rt); });
|
|
528
525
|
};
|
|
529
526
|
|
|
530
|
-
|
|
527
|
+
sqlite_register_rollback_hook(dbName, std::move(hook));
|
|
531
528
|
return {};
|
|
532
529
|
});
|
|
533
530
|
|
package/cpp/bridge.cpp
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
#include "DumbHostObject.h"
|
|
3
3
|
#include "SmartHostObject.h"
|
|
4
4
|
#include "logs.h"
|
|
5
|
+
#include "utils.h"
|
|
5
6
|
#include <ctime>
|
|
6
|
-
#include <sstream>
|
|
7
|
-
#include <sys/stat.h>
|
|
8
|
-
#include <unistd.h>
|
|
9
7
|
#include <unordered_map>
|
|
10
8
|
#include <variant>
|
|
11
9
|
|
|
@@ -31,63 +29,16 @@ std::unordered_map<std::string, std::function<void(std::string dbName)>>
|
|
|
31
29
|
std::unordered_map<std::string,
|
|
32
30
|
std::function<void(std::string dbName)>>();
|
|
33
31
|
|
|
34
|
-
bool folder_exists(const std::string &foldername) {
|
|
35
|
-
struct stat buffer;
|
|
36
|
-
return (stat(foldername.c_str(), &buffer) == 0);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Portable wrapper for mkdir. Internally used by mkdir()
|
|
41
|
-
* @param[in] path the full path of the directory to create.
|
|
42
|
-
* @return zero on success, otherwise -1.
|
|
43
|
-
*/
|
|
44
|
-
int _mkdir(const char *path) {
|
|
45
|
-
#if _POSIX_C_SOURCE
|
|
46
|
-
return mkdir(path);
|
|
47
|
-
#else
|
|
48
|
-
return mkdir(path, 0755); // not sure if this works on mac
|
|
49
|
-
#endif
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Recursive, portable wrapper for mkdir.
|
|
54
|
-
* @param[in] path the full path of the directory to create.
|
|
55
|
-
* @return zero on success, otherwise -1.
|
|
56
|
-
*/
|
|
57
|
-
int mkdir(const char *path) {
|
|
58
|
-
std::string current_level = "/";
|
|
59
|
-
std::string level;
|
|
60
|
-
std::stringstream ss(path);
|
|
61
|
-
// First line is empty because it starts with /User
|
|
62
|
-
getline(ss, level, '/');
|
|
63
|
-
// split path using slash as a separator
|
|
64
|
-
while (getline(ss, level, '/')) {
|
|
65
|
-
current_level += level; // append folder to the current level
|
|
66
|
-
// create current level
|
|
67
|
-
if (!folder_exists(current_level) && _mkdir(current_level.c_str()) != 0)
|
|
68
|
-
return -1;
|
|
69
|
-
|
|
70
|
-
current_level += "/"; // don't forget to append a slash
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return 0;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
inline bool file_exists(const std::string &path) {
|
|
77
|
-
struct stat buffer;
|
|
78
|
-
return (stat(path.c_str(), &buffer) == 0);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
32
|
std::string get_db_path(std::string const dbName, std::string const lastPath) {
|
|
82
33
|
if (lastPath == ":memory:") {
|
|
83
34
|
return lastPath;
|
|
84
35
|
}
|
|
85
|
-
mkdir(lastPath
|
|
36
|
+
mkdir(lastPath);
|
|
86
37
|
return lastPath + "/" + dbName;
|
|
87
38
|
}
|
|
88
39
|
|
|
89
|
-
BridgeResult
|
|
90
|
-
|
|
40
|
+
BridgeResult sqlite_open(std::string const &dbName,
|
|
41
|
+
std::string const &lastPath) {
|
|
91
42
|
std::string dbPath = get_db_path(dbName, lastPath);
|
|
92
43
|
|
|
93
44
|
int sqlOpenFlags =
|
|
@@ -106,7 +57,7 @@ BridgeResult sqliteOpenDb(std::string const dbName,
|
|
|
106
57
|
return BridgeResult{.type = SQLiteOk, .affectedRows = 0};
|
|
107
58
|
}
|
|
108
59
|
|
|
109
|
-
BridgeResult
|
|
60
|
+
BridgeResult sqlite_close(std::string const &dbName) {
|
|
110
61
|
|
|
111
62
|
if (dbMap.count(dbName) == 0) {
|
|
112
63
|
return {
|
|
@@ -126,10 +77,10 @@ BridgeResult sqliteCloseDb(std::string const dbName) {
|
|
|
126
77
|
};
|
|
127
78
|
}
|
|
128
79
|
|
|
129
|
-
BridgeResult
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
80
|
+
BridgeResult sqlite_attach(std::string const &mainDBName,
|
|
81
|
+
std::string const &docPath,
|
|
82
|
+
std::string const &databaseToAttach,
|
|
83
|
+
std::string const &alias) {
|
|
133
84
|
/**
|
|
134
85
|
* There is no need to check if mainDBName is opened because
|
|
135
86
|
* sqliteExecuteLiteral will do that.
|
|
@@ -137,7 +88,7 @@ BridgeResult sqliteAttachDb(std::string const mainDBName,
|
|
|
137
88
|
std::string dbPath = get_db_path(databaseToAttach, docPath);
|
|
138
89
|
std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
|
|
139
90
|
|
|
140
|
-
BridgeResult result =
|
|
91
|
+
BridgeResult result = sqlite_execute_literal(mainDBName, statement);
|
|
141
92
|
|
|
142
93
|
if (result.type == SQLiteError) {
|
|
143
94
|
return {
|
|
@@ -151,14 +102,14 @@ BridgeResult sqliteAttachDb(std::string const mainDBName,
|
|
|
151
102
|
};
|
|
152
103
|
}
|
|
153
104
|
|
|
154
|
-
BridgeResult
|
|
155
|
-
|
|
105
|
+
BridgeResult sqlite_detach(std::string const &mainDBName,
|
|
106
|
+
std::string const &alias) {
|
|
156
107
|
/**
|
|
157
108
|
* There is no need to check if mainDBName is opened because
|
|
158
109
|
* sqliteExecuteLiteral will do that.
|
|
159
110
|
* */
|
|
160
111
|
std::string statement = "DETACH DATABASE " + alias;
|
|
161
|
-
BridgeResult result =
|
|
112
|
+
BridgeResult result = sqlite_execute_literal(mainDBName, statement);
|
|
162
113
|
if (result.type == SQLiteError) {
|
|
163
114
|
return BridgeResult{
|
|
164
115
|
.type = SQLiteError,
|
|
@@ -171,10 +122,10 @@ BridgeResult sqliteDetachDb(std::string const mainDBName,
|
|
|
171
122
|
};
|
|
172
123
|
}
|
|
173
124
|
|
|
174
|
-
BridgeResult
|
|
175
|
-
|
|
125
|
+
BridgeResult sqlite_remove(std::string const &dbName,
|
|
126
|
+
std::string const &docPath) {
|
|
176
127
|
if (dbMap.count(dbName) == 1) {
|
|
177
|
-
BridgeResult closeResult =
|
|
128
|
+
BridgeResult closeResult = sqlite_close(dbName);
|
|
178
129
|
if (closeResult.type == SQLiteError) {
|
|
179
130
|
return closeResult;
|
|
180
131
|
}
|
|
@@ -230,7 +181,7 @@ void sqlite_bind_statement(sqlite3_stmt *statement,
|
|
|
230
181
|
}
|
|
231
182
|
|
|
232
183
|
BridgeResult sqlite_execute_prepared_statement(
|
|
233
|
-
std::string const dbName, sqlite3_stmt *statement,
|
|
184
|
+
std::string const &dbName, sqlite3_stmt *statement,
|
|
234
185
|
std::vector<DumbHostObject> *results,
|
|
235
186
|
std::shared_ptr<std::vector<SmartHostObject>> metadatas) {
|
|
236
187
|
if (dbMap.find(dbName) == dbMap.end()) {
|
|
@@ -368,7 +319,7 @@ BridgeResult sqlite_execute_prepared_statement(
|
|
|
368
319
|
.insertId = static_cast<double>(latestInsertRowId)};
|
|
369
320
|
}
|
|
370
321
|
|
|
371
|
-
sqlite3_stmt *sqlite_prepare_statement(std::string const dbName,
|
|
322
|
+
sqlite3_stmt *sqlite_prepare_statement(std::string const &dbName,
|
|
372
323
|
std::string const &query) {
|
|
373
324
|
if (dbMap.find(dbName) == dbMap.end()) {
|
|
374
325
|
throw std::runtime_error("Database not opened");
|
|
@@ -392,10 +343,10 @@ sqlite3_stmt *sqlite_prepare_statement(std::string const dbName,
|
|
|
392
343
|
}
|
|
393
344
|
|
|
394
345
|
BridgeResult
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
346
|
+
sqlite_execute(std::string const &dbName, std::string const &query,
|
|
347
|
+
const std::vector<JSVariant> *params,
|
|
348
|
+
std::vector<DumbHostObject> *results,
|
|
349
|
+
std::shared_ptr<std::vector<SmartHostObject>> metadatas) {
|
|
399
350
|
|
|
400
351
|
if (dbMap.find(dbName) == dbMap.end()) {
|
|
401
352
|
return {.type = SQLiteError,
|
|
@@ -427,7 +378,7 @@ sqliteExecute(std::string const dbName, std::string const &query,
|
|
|
427
378
|
.message = "[op-sqlite] SQL statement error:" +
|
|
428
379
|
std::to_string(statementStatus) +
|
|
429
380
|
" description:" + std::string(message) +
|
|
430
|
-
"
|
|
381
|
+
". See error codes: https://www.sqlite.org/rescode.html",
|
|
431
382
|
};
|
|
432
383
|
}
|
|
433
384
|
|
|
@@ -567,8 +518,8 @@ sqliteExecute(std::string const dbName, std::string const &query,
|
|
|
567
518
|
.insertId = static_cast<double>(latestInsertRowId)};
|
|
568
519
|
}
|
|
569
520
|
|
|
570
|
-
BridgeResult
|
|
571
|
-
|
|
521
|
+
BridgeResult sqlite_execute_literal(std::string const &dbName,
|
|
522
|
+
std::string const &query) {
|
|
572
523
|
if (dbMap.count(dbName) == 0) {
|
|
573
524
|
return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
|
|
574
525
|
}
|
|
@@ -621,7 +572,7 @@ BridgeResult sqliteExecuteLiteral(std::string const dbName,
|
|
|
621
572
|
return {SQLiteOk, "", changedRowCount};
|
|
622
573
|
}
|
|
623
574
|
|
|
624
|
-
void
|
|
575
|
+
void sqlite_close_all() {
|
|
625
576
|
for (auto const &x : dbMap) {
|
|
626
577
|
// Interrupt will make all pending operations to fail with SQLITE_INTERRUPT
|
|
627
578
|
// The ongoing work from threads will then fail ASAP
|
|
@@ -630,9 +581,12 @@ void sqliteCloseAll() {
|
|
|
630
581
|
sqlite3_close_v2(x.second);
|
|
631
582
|
}
|
|
632
583
|
dbMap.clear();
|
|
584
|
+
updateCallbackMap.clear();
|
|
585
|
+
rollbackCallbackMap.clear();
|
|
586
|
+
commitCallbackMap.clear();
|
|
633
587
|
}
|
|
634
588
|
|
|
635
|
-
std::string
|
|
589
|
+
std::string operation_to_string(int operation_type) {
|
|
636
590
|
switch (operation_type) {
|
|
637
591
|
case SQLITE_INSERT:
|
|
638
592
|
return "INSERT";
|
|
@@ -652,12 +606,12 @@ void update_callback(void *dbName, int operation_type, char const *database,
|
|
|
652
606
|
char const *table, sqlite3_int64 rowid) {
|
|
653
607
|
std::string &strDbName = *(static_cast<std::string *>(dbName));
|
|
654
608
|
auto callback = updateCallbackMap[strDbName];
|
|
655
|
-
callback(strDbName, std::string(table),
|
|
609
|
+
callback(strDbName, std::string(table), operation_to_string(operation_type),
|
|
656
610
|
static_cast<int>(rowid));
|
|
657
611
|
}
|
|
658
612
|
|
|
659
|
-
BridgeResult
|
|
660
|
-
std::string const dbName,
|
|
613
|
+
BridgeResult sqlite_register_update_hook(
|
|
614
|
+
std::string const &dbName,
|
|
661
615
|
std::function<void(std::string dbName, std::string tableName,
|
|
662
616
|
std::string operation, int rowId)> const callback) {
|
|
663
617
|
if (dbMap.count(dbName) == 0) {
|
|
@@ -680,7 +634,7 @@ BridgeResult registerUpdateHook(
|
|
|
680
634
|
return {SQLiteOk};
|
|
681
635
|
}
|
|
682
636
|
|
|
683
|
-
BridgeResult
|
|
637
|
+
BridgeResult sqlite_deregister_update_hook(std::string const &dbName) {
|
|
684
638
|
if (dbMap.count(dbName) == 0) {
|
|
685
639
|
return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
|
|
686
640
|
}
|
|
@@ -701,9 +655,9 @@ int commit_callback(void *dbName) {
|
|
|
701
655
|
return 0;
|
|
702
656
|
}
|
|
703
657
|
|
|
704
|
-
BridgeResult
|
|
705
|
-
|
|
706
|
-
|
|
658
|
+
BridgeResult sqlite_register_commit_hook(
|
|
659
|
+
std::string const &dbName,
|
|
660
|
+
std::function<void(std::string dbName)> const callback) {
|
|
707
661
|
if (dbMap.count(dbName) == 0) {
|
|
708
662
|
return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
|
|
709
663
|
}
|
|
@@ -724,7 +678,7 @@ registerCommitHook(std::string const dbName,
|
|
|
724
678
|
return {SQLiteOk};
|
|
725
679
|
}
|
|
726
680
|
|
|
727
|
-
BridgeResult
|
|
681
|
+
BridgeResult sqlite_deregister_commit_hook(std::string const &dbName) {
|
|
728
682
|
if (dbMap.count(dbName) == 0) {
|
|
729
683
|
return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
|
|
730
684
|
}
|
|
@@ -742,9 +696,9 @@ void rollback_callback(void *dbName) {
|
|
|
742
696
|
callback(strDbName);
|
|
743
697
|
}
|
|
744
698
|
|
|
745
|
-
BridgeResult
|
|
746
|
-
|
|
747
|
-
|
|
699
|
+
BridgeResult sqlite_register_rollback_hook(
|
|
700
|
+
std::string const &dbName,
|
|
701
|
+
std::function<void(std::string dbName)> const callback) {
|
|
748
702
|
if (dbMap.count(dbName) == 0) {
|
|
749
703
|
return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
|
|
750
704
|
}
|
|
@@ -765,7 +719,7 @@ registerRollbackHook(std::string const dbName,
|
|
|
765
719
|
return {SQLiteOk};
|
|
766
720
|
}
|
|
767
721
|
|
|
768
|
-
BridgeResult
|
|
722
|
+
BridgeResult sqlite_deregister_rollback_hook(std::string const &dbName) {
|
|
769
723
|
if (dbMap.count(dbName) == 0) {
|
|
770
724
|
return {SQLiteError, "[op-sqlite] Database not opened: " + dbName};
|
|
771
725
|
}
|
package/cpp/bridge.h
CHANGED
|
@@ -12,54 +12,54 @@ namespace opsqlite {
|
|
|
12
12
|
|
|
13
13
|
namespace jsi = facebook::jsi;
|
|
14
14
|
|
|
15
|
-
BridgeResult
|
|
15
|
+
BridgeResult sqlite_open(std::string const &dbName, std::string const &dbPath);
|
|
16
16
|
|
|
17
|
-
BridgeResult
|
|
17
|
+
BridgeResult sqlite_close(std::string const &dbName);
|
|
18
18
|
|
|
19
|
-
BridgeResult
|
|
20
|
-
|
|
19
|
+
BridgeResult sqlite_remove(std::string const &dbName,
|
|
20
|
+
std::string const &docPath);
|
|
21
21
|
|
|
22
|
-
BridgeResult
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
BridgeResult sqlite_attach(std::string const &mainDBName,
|
|
23
|
+
std::string const &docPath,
|
|
24
|
+
std::string const &databaseToAttach,
|
|
25
|
+
std::string const &alias);
|
|
26
26
|
|
|
27
|
-
BridgeResult
|
|
28
|
-
|
|
27
|
+
BridgeResult sqlite_detach(std::string const &mainDBName,
|
|
28
|
+
std::string const &alias);
|
|
29
29
|
|
|
30
30
|
BridgeResult
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
sqlite_execute(std::string const &dbName, std::string const &query,
|
|
32
|
+
const std::vector<JSVariant> *params,
|
|
33
|
+
std::vector<DumbHostObject> *results,
|
|
34
|
+
std::shared_ptr<std::vector<SmartHostObject>> metadatas);
|
|
35
35
|
|
|
36
|
-
BridgeResult
|
|
37
|
-
|
|
36
|
+
BridgeResult sqlite_execute_literal(std::string const &dbName,
|
|
37
|
+
std::string const &query);
|
|
38
38
|
|
|
39
|
-
void
|
|
39
|
+
void sqlite_close_all();
|
|
40
40
|
|
|
41
|
-
BridgeResult
|
|
42
|
-
std::string const dbName,
|
|
41
|
+
BridgeResult sqlite_register_update_hook(
|
|
42
|
+
std::string const &dbName,
|
|
43
43
|
std::function<void(std::string dbName, std::string tableName,
|
|
44
44
|
std::string operation, int rowId)> const callback);
|
|
45
|
-
BridgeResult
|
|
46
|
-
BridgeResult
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
BridgeResult
|
|
50
|
-
BridgeResult
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
BridgeResult
|
|
54
|
-
|
|
55
|
-
sqlite3_stmt *sqlite_prepare_statement(std::string const dbName,
|
|
45
|
+
BridgeResult sqlite_deregister_update_hook(std::string const &dbName);
|
|
46
|
+
BridgeResult sqlite_register_commit_hook(
|
|
47
|
+
std::string const &dbName,
|
|
48
|
+
std::function<void(std::string dbName)> const callback);
|
|
49
|
+
BridgeResult sqlite_deregister_commit_hook(std::string const &dbName);
|
|
50
|
+
BridgeResult sqlite_register_rollback_hook(
|
|
51
|
+
std::string const &dbName,
|
|
52
|
+
std::function<void(std::string dbName)> const callback);
|
|
53
|
+
BridgeResult sqlite_deregister_rollback_hook(std::string const &dbName);
|
|
54
|
+
|
|
55
|
+
sqlite3_stmt *sqlite_prepare_statement(std::string const &dbName,
|
|
56
56
|
std::string const &query);
|
|
57
57
|
|
|
58
58
|
void sqlite_bind_statement(sqlite3_stmt *statement,
|
|
59
59
|
const std::vector<JSVariant> *params);
|
|
60
60
|
|
|
61
61
|
BridgeResult sqlite_execute_prepared_statement(
|
|
62
|
-
std::string const dbName, sqlite3_stmt *statement,
|
|
62
|
+
std::string const &dbName, sqlite3_stmt *statement,
|
|
63
63
|
std::vector<DumbHostObject> *results,
|
|
64
64
|
std::shared_ptr<std::vector<SmartHostObject>> metadatas);
|
|
65
65
|
} // namespace opsqlite
|
package/cpp/sqlbatchexecutor.cpp
CHANGED
|
@@ -57,15 +57,15 @@ BatchResult sqliteExecuteBatch(std::string dbName,
|
|
|
57
57
|
|
|
58
58
|
try {
|
|
59
59
|
int affectedRows = 0;
|
|
60
|
-
|
|
60
|
+
sqlite_execute_literal(dbName, "BEGIN EXCLUSIVE TRANSACTION");
|
|
61
61
|
for (int i = 0; i < commandCount; i++) {
|
|
62
62
|
auto command = commands->at(i);
|
|
63
63
|
// We do not provide a datastructure to receive query data because we
|
|
64
64
|
// don't need/want to handle this results in a batch execution
|
|
65
|
-
auto result =
|
|
66
|
-
|
|
65
|
+
auto result = sqlite_execute(dbName, command.sql, command.params.get(),
|
|
66
|
+
nullptr, nullptr);
|
|
67
67
|
if (result.type == SQLiteError) {
|
|
68
|
-
|
|
68
|
+
sqlite_execute_literal(dbName, "ROLLBACK");
|
|
69
69
|
return BatchResult{
|
|
70
70
|
.type = SQLiteError,
|
|
71
71
|
.message = result.message,
|
|
@@ -74,14 +74,14 @@ BatchResult sqliteExecuteBatch(std::string dbName,
|
|
|
74
74
|
affectedRows += result.affectedRows;
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
sqlite_execute_literal(dbName, "COMMIT");
|
|
78
78
|
return BatchResult{
|
|
79
79
|
.type = SQLiteOk,
|
|
80
80
|
.affectedRows = affectedRows,
|
|
81
81
|
.commands = static_cast<int>(commandCount),
|
|
82
82
|
};
|
|
83
83
|
} catch (std::exception &exc) {
|
|
84
|
-
|
|
84
|
+
sqlite_execute_literal(dbName, "ROLLBACK");
|
|
85
85
|
return BatchResult{
|
|
86
86
|
.type = SQLiteError,
|
|
87
87
|
.message = exc.what(),
|
package/cpp/utils.cpp
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
#include "bridge.h"
|
|
4
4
|
#include <fstream>
|
|
5
5
|
#include <iostream>
|
|
6
|
+
#include <sstream>
|
|
7
|
+
#include <sys/stat.h>
|
|
8
|
+
#include <unistd.h>
|
|
6
9
|
|
|
7
10
|
namespace opsqlite {
|
|
8
11
|
|
|
@@ -191,12 +194,12 @@ BatchResult importSQLFile(std::string dbName, std::string fileLocation) {
|
|
|
191
194
|
try {
|
|
192
195
|
int affectedRows = 0;
|
|
193
196
|
int commands = 0;
|
|
194
|
-
|
|
197
|
+
sqlite_execute_literal(dbName, "BEGIN EXCLUSIVE TRANSACTION");
|
|
195
198
|
while (std::getline(sqFile, line, '\n')) {
|
|
196
199
|
if (!line.empty()) {
|
|
197
|
-
BridgeResult result =
|
|
200
|
+
BridgeResult result = sqlite_execute_literal(dbName, line);
|
|
198
201
|
if (result.type == SQLiteError) {
|
|
199
|
-
|
|
202
|
+
sqlite_execute_literal(dbName, "ROLLBACK");
|
|
200
203
|
sqFile.close();
|
|
201
204
|
return {SQLiteError, result.message, 0, commands};
|
|
202
205
|
} else {
|
|
@@ -206,11 +209,11 @@ BatchResult importSQLFile(std::string dbName, std::string fileLocation) {
|
|
|
206
209
|
}
|
|
207
210
|
}
|
|
208
211
|
sqFile.close();
|
|
209
|
-
|
|
212
|
+
sqlite_execute_literal(dbName, "COMMIT");
|
|
210
213
|
return {SQLiteOk, "", affectedRows, commands};
|
|
211
214
|
} catch (...) {
|
|
212
215
|
sqFile.close();
|
|
213
|
-
|
|
216
|
+
sqlite_execute_literal(dbName, "ROLLBACK");
|
|
214
217
|
return {SQLiteError,
|
|
215
218
|
"[op-sqlite][loadSQLFile] Unexpected error, transaction was "
|
|
216
219
|
"rolledback",
|
|
@@ -221,4 +224,19 @@ BatchResult importSQLFile(std::string dbName, std::string fileLocation) {
|
|
|
221
224
|
}
|
|
222
225
|
}
|
|
223
226
|
|
|
227
|
+
bool folder_exists(const std::string &foldername) {
|
|
228
|
+
struct stat buffer;
|
|
229
|
+
return (stat(foldername.c_str(), &buffer) == 0);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
bool file_exists(const std::string &path) {
|
|
233
|
+
struct stat buffer;
|
|
234
|
+
return (stat(path.c_str(), &buffer) == 0);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
int mkdir(std::string const &path) {
|
|
238
|
+
std::filesystem::create_directories(path);
|
|
239
|
+
return 0;
|
|
240
|
+
}
|
|
241
|
+
|
|
224
242
|
} // namespace opsqlite
|
package/cpp/utils.h
CHANGED
|
@@ -43,6 +43,12 @@ jsi::Value createResult(jsi::Runtime &rt, BridgeResult status,
|
|
|
43
43
|
|
|
44
44
|
BatchResult importSQLFile(std::string dbName, std::string fileLocation);
|
|
45
45
|
|
|
46
|
+
int mkdir(const std::string &path);
|
|
47
|
+
|
|
48
|
+
bool folder_exists(const std::string &foldername);
|
|
49
|
+
|
|
50
|
+
bool file_exists(const std::string &path);
|
|
51
|
+
|
|
46
52
|
} // namespace opsqlite
|
|
47
53
|
|
|
48
54
|
#endif /* utils_h */
|
package/op-sqlite.podspec
CHANGED
|
@@ -12,14 +12,14 @@ Pod::Spec.new do |s|
|
|
|
12
12
|
s.license = package["license"]
|
|
13
13
|
s.authors = package["author"]
|
|
14
14
|
|
|
15
|
-
s.platforms = { :ios => "
|
|
15
|
+
s.platforms = { :ios => "13.0", :osx => "10.15" }
|
|
16
16
|
s.source = { :git => "https://github.com/op-engineering/op-sqlite.git", :tag => "#{s.version}" }
|
|
17
17
|
|
|
18
18
|
s.pod_target_xcconfig = {
|
|
19
19
|
:GCC_PREPROCESSOR_DEFINITIONS => "HAVE_FULLFSYNC=1",
|
|
20
20
|
:WARNING_CFLAGS => "-Wno-shorten-64-to-32 -Wno-comma -Wno-unreachable-code -Wno-conditional-uninitialized -Wno-deprecated-declarations",
|
|
21
21
|
:USE_HEADERMAP => "No",
|
|
22
|
-
:CLANG_CXX_LANGUAGE_STANDARD => "c++17"
|
|
22
|
+
:CLANG_CXX_LANGUAGE_STANDARD => "c++17",
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
s.header_mappings_dir = "cpp"
|
|
@@ -37,5 +37,9 @@ Pod::Spec.new do |s|
|
|
|
37
37
|
s.exclude_files = "cpp/sqlite3.c", "cpp/sqlite3.h"
|
|
38
38
|
s.library = "sqlite3"
|
|
39
39
|
end
|
|
40
|
+
|
|
41
|
+
if ENV['OP_SQLITE_PERF'] == '1' then
|
|
42
|
+
:OTHER_CFLAGS => '$(inherited) -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_OMIT_DEPRECATED=1 -DSQLITE_OMIT_PROGRESS_CALLBACK=1 -DSQLITE_OMIT_SHARED_CACHE=1 -DSQLITE_USE_ALLOCA=1'
|
|
43
|
+
end
|
|
40
44
|
|
|
41
45
|
end
|