@op-engineering/op-sqlite 2.0.20 → 3.0.0
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 +2 -567
- package/android/CMakeLists.txt +25 -5
- package/android/build.gradle +14 -6
- package/cpp/PreparedStatementHostObject.cpp +4 -11
- package/cpp/bindings.cpp +34 -17
- package/cpp/bridge.cpp +38 -85
- package/cpp/bridge.h +5 -3
- package/cpp/sqlbatchexecutor.cpp +5 -4
- package/cpp/sqlcipher/sqlite3.c +253047 -0
- package/cpp/sqlcipher/sqlite3.h +13029 -0
- package/cpp/types.h +17 -0
- package/cpp/utils.cpp +21 -24
- package/cpp/utils.h +0 -16
- package/lib/commonjs/index.js +4 -4
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +4 -4
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/index.d.ts +6 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/op-sqlite.podspec +20 -8
- package/package.json +2 -2
- package/src/index.ts +14 -5
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
//
|
|
2
|
-
// PreparedStatementHostObject.cpp
|
|
3
|
-
// op-sqlite
|
|
4
|
-
//
|
|
5
|
-
// Created by Oscar Franco on 5/12/23.
|
|
6
|
-
//
|
|
7
|
-
|
|
8
1
|
#include "PreparedStatementHostObject.h"
|
|
9
2
|
#include "bridge.h"
|
|
10
3
|
#include "macros.h"
|
|
@@ -31,7 +24,7 @@ jsi::Value PreparedStatementHostObject::get(jsi::Runtime &rt,
|
|
|
31
24
|
|
|
32
25
|
if (name == "bind") {
|
|
33
26
|
return HOSTFN("bind", 1) {
|
|
34
|
-
if (_statement ==
|
|
27
|
+
if (_statement == nullptr) {
|
|
35
28
|
throw std::runtime_error("statement has been freed");
|
|
36
29
|
}
|
|
37
30
|
|
|
@@ -46,7 +39,7 @@ jsi::Value PreparedStatementHostObject::get(jsi::Runtime &rt,
|
|
|
46
39
|
|
|
47
40
|
if (name == "execute") {
|
|
48
41
|
return HOSTFN("execute", 1) {
|
|
49
|
-
if (_statement ==
|
|
42
|
+
if (_statement == nullptr) {
|
|
50
43
|
throw std::runtime_error("statement has been freed");
|
|
51
44
|
}
|
|
52
45
|
std::vector<DumbHostObject> results;
|
|
@@ -69,9 +62,9 @@ jsi::Value PreparedStatementHostObject::get(jsi::Runtime &rt,
|
|
|
69
62
|
}
|
|
70
63
|
|
|
71
64
|
PreparedStatementHostObject::~PreparedStatementHostObject() {
|
|
72
|
-
if (_statement !=
|
|
65
|
+
if (_statement != nullptr) {
|
|
73
66
|
sqlite3_finalize(_statement);
|
|
74
|
-
_statement =
|
|
67
|
+
_statement = nullptr;
|
|
75
68
|
}
|
|
76
69
|
}
|
|
77
70
|
|
package/cpp/bindings.cpp
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
#include "sqlbatchexecutor.h"
|
|
9
9
|
#include "utils.h"
|
|
10
10
|
#include <iostream>
|
|
11
|
-
#include <sqlite3.h>
|
|
12
11
|
#include <string>
|
|
13
12
|
#include <unordered_map>
|
|
14
13
|
#include <vector>
|
|
@@ -55,32 +54,50 @@ void install(jsi::Runtime &rt,
|
|
|
55
54
|
throw std::runtime_error("[op-sqlite][open] database name is required");
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"[op-sqlite][open] database name must be a string");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
std::string dbName = args[0].asString(rt).utf8(rt);
|
|
57
|
+
jsi::Object options = args[0].asObject(rt);
|
|
58
|
+
std::string dbName = options.getProperty(rt, "name").asString(rt).utf8(rt);
|
|
64
59
|
std::string path = std::string(basePath);
|
|
60
|
+
std::string location;
|
|
61
|
+
std::string encryptionKey;
|
|
65
62
|
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"[op-sqlite][open] database location must be a string");
|
|
70
|
-
}
|
|
63
|
+
if (options.hasProperty(rt, "location")) {
|
|
64
|
+
location = options.getProperty(rt, "location").asString(rt).utf8(rt);
|
|
65
|
+
}
|
|
71
66
|
|
|
72
|
-
|
|
67
|
+
if (options.hasProperty(rt, "encryptionKey")) {
|
|
68
|
+
encryptionKey =
|
|
69
|
+
options.getProperty(rt, "encryptionKey").asString(rt).utf8(rt);
|
|
70
|
+
}
|
|
73
71
|
|
|
74
|
-
|
|
72
|
+
#ifdef OP_SQLITE_USE_SQLCIPHER
|
|
73
|
+
if (encryptionKey.empty()) {
|
|
74
|
+
throw std::runtime_error(
|
|
75
|
+
"[OP SQLite] using SQLCipher encryption key is required");
|
|
76
|
+
}
|
|
77
|
+
// TODO(osp) find a way to display the yellow box from c++
|
|
78
|
+
#else
|
|
79
|
+
// if (!encryptionKey.empty()) {
|
|
80
|
+
// // RCTLogWarn(@"Your message")
|
|
81
|
+
// throw std::runtime_error("[OP SQLite] SQLCipher is not enabled, "
|
|
82
|
+
// "encryption key is not allowed");
|
|
83
|
+
// }
|
|
84
|
+
#endif
|
|
85
|
+
|
|
86
|
+
if (!location.empty()) {
|
|
87
|
+
if (location == ":memory:") {
|
|
75
88
|
path = ":memory:";
|
|
76
|
-
} else if (
|
|
77
|
-
path =
|
|
89
|
+
} else if (location.rfind("/", 0) == 0) {
|
|
90
|
+
path = location;
|
|
78
91
|
} else {
|
|
79
|
-
path = path + "/" +
|
|
92
|
+
path = path + "/" + location;
|
|
80
93
|
}
|
|
81
94
|
}
|
|
82
95
|
|
|
96
|
+
#ifdef OP_SQLITE_USE_SQLCIPHER
|
|
97
|
+
BridgeResult result = opsqlite_open(dbName, path, encryptionKey);
|
|
98
|
+
#else
|
|
83
99
|
BridgeResult result = opsqlite_open(dbName, path);
|
|
100
|
+
#endif
|
|
84
101
|
|
|
85
102
|
if (result.type == SQLiteError) {
|
|
86
103
|
throw std::runtime_error(result.message);
|
package/cpp/bridge.cpp
CHANGED
|
@@ -41,9 +41,15 @@ std::string get_db_path(std::string const &db_name,
|
|
|
41
41
|
return location + "/" + db_name;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
#ifdef OP_SQLITE_USE_SQLCIPHER
|
|
44
45
|
BridgeResult opsqlite_open(std::string const &dbName,
|
|
45
|
-
std::string const &
|
|
46
|
-
|
|
46
|
+
std::string const &last_path,
|
|
47
|
+
std::string const &encryptionKey) {
|
|
48
|
+
#else
|
|
49
|
+
BridgeResult opsqlite_open(std::string const &dbName,
|
|
50
|
+
std::string const &last_path) {
|
|
51
|
+
#endif
|
|
52
|
+
std::string dbPath = get_db_path(dbName, last_path);
|
|
47
53
|
|
|
48
54
|
int sqlOpenFlags =
|
|
49
55
|
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
|
|
@@ -57,7 +63,12 @@ BridgeResult opsqlite_open(std::string const &dbName,
|
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
dbMap[dbName] = db;
|
|
60
|
-
|
|
66
|
+
#ifdef OP_SQLITE_USE_SQLCIPHER
|
|
67
|
+
auto encryptionResult =
|
|
68
|
+
opsqlite_execute(dbName, "PRAGMA key = '" + encryptionKey + "'", nullptr,
|
|
69
|
+
nullptr, nullptr);
|
|
70
|
+
LOGD("Encrypting database");
|
|
71
|
+
#endif
|
|
61
72
|
return BridgeResult{.type = SQLiteOk, .affectedRows = 0};
|
|
62
73
|
}
|
|
63
74
|
|
|
@@ -80,14 +91,11 @@ BridgeResult opsqlite_attach(std::string const &mainDBName,
|
|
|
80
91
|
std::string const &docPath,
|
|
81
92
|
std::string const &databaseToAttach,
|
|
82
93
|
std::string const &alias) {
|
|
83
|
-
/**
|
|
84
|
-
* There is no need to check if mainDBName is opened because
|
|
85
|
-
* sqliteExecuteLiteral will do that.
|
|
86
|
-
* */
|
|
87
94
|
std::string dbPath = get_db_path(databaseToAttach, docPath);
|
|
88
95
|
std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
|
|
89
96
|
|
|
90
|
-
BridgeResult result =
|
|
97
|
+
BridgeResult result =
|
|
98
|
+
opsqlite_execute(mainDBName, statement, nullptr, nullptr, nullptr);
|
|
91
99
|
|
|
92
100
|
if (result.type == SQLiteError) {
|
|
93
101
|
return {
|
|
@@ -103,12 +111,9 @@ BridgeResult opsqlite_attach(std::string const &mainDBName,
|
|
|
103
111
|
|
|
104
112
|
BridgeResult opsqlite_detach(std::string const &mainDBName,
|
|
105
113
|
std::string const &alias) {
|
|
106
|
-
/**
|
|
107
|
-
* There is no need to check if mainDBName is opened because
|
|
108
|
-
* sqliteExecuteLiteral will do that.
|
|
109
|
-
* */
|
|
110
114
|
std::string statement = "DETACH DATABASE " + alias;
|
|
111
|
-
BridgeResult result =
|
|
115
|
+
BridgeResult result =
|
|
116
|
+
opsqlite_execute(mainDBName, statement, nullptr, nullptr, nullptr);
|
|
112
117
|
if (result.type == SQLiteError) {
|
|
113
118
|
return BridgeResult{
|
|
114
119
|
.type = SQLiteError,
|
|
@@ -327,7 +332,7 @@ sqlite3_stmt *opsqlite_prepare_statement(std::string const &dbName,
|
|
|
327
332
|
|
|
328
333
|
if (statementStatus == SQLITE_ERROR) {
|
|
329
334
|
const char *message = sqlite3_errmsg(db);
|
|
330
|
-
throw std::runtime_error("[op-sqlite] SQL statement error: " +
|
|
335
|
+
throw std::runtime_error("[op-sqlite] SQL prepare statement error: " +
|
|
331
336
|
std::string(message));
|
|
332
337
|
}
|
|
333
338
|
|
|
@@ -365,15 +370,15 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
|
|
|
365
370
|
const char *message = sqlite3_errmsg(db);
|
|
366
371
|
return {
|
|
367
372
|
.type = SQLiteError,
|
|
368
|
-
.message = "[op-sqlite] SQL statement error
|
|
369
|
-
std::to_string(statementStatus) +
|
|
370
|
-
|
|
373
|
+
.message = "[op-sqlite] SQL statement error on opsqlite_execute:\n" +
|
|
374
|
+
std::to_string(statementStatus) + " description:\n" +
|
|
375
|
+
std::string(message) +
|
|
371
376
|
". See error codes: https://www.sqlite.org/rescode.html",
|
|
372
377
|
};
|
|
373
378
|
}
|
|
374
379
|
|
|
375
|
-
// The statement did not fail to parse but there is nothing to do, just
|
|
376
|
-
// to the end
|
|
380
|
+
// The statement did not fail to parse but there is nothing to do, just
|
|
381
|
+
// skip to the end
|
|
377
382
|
if (statement == NULL) {
|
|
378
383
|
continue;
|
|
379
384
|
}
|
|
@@ -508,8 +513,8 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
|
|
|
508
513
|
.insertId = static_cast<double>(latestInsertRowId)};
|
|
509
514
|
}
|
|
510
515
|
|
|
511
|
-
/// Executes returning data in raw arrays, a small performance optimization
|
|
512
|
-
/// certain use cases
|
|
516
|
+
/// Executes returning data in raw arrays, a small performance optimization
|
|
517
|
+
/// for certain use cases
|
|
513
518
|
BridgeResult
|
|
514
519
|
opsqlite_execute_raw(std::string const &dbName, std::string const &query,
|
|
515
520
|
const std::vector<JSVariant> *params,
|
|
@@ -526,7 +531,7 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
|
|
|
526
531
|
bool isConsuming = true;
|
|
527
532
|
bool isFailed = false;
|
|
528
533
|
|
|
529
|
-
int
|
|
534
|
+
int step = SQLITE_OK;
|
|
530
535
|
|
|
531
536
|
do {
|
|
532
537
|
const char *queryStr =
|
|
@@ -546,8 +551,8 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
|
|
|
546
551
|
};
|
|
547
552
|
}
|
|
548
553
|
|
|
549
|
-
// The statement did not fail to parse but there is nothing to do, just
|
|
550
|
-
// to the end
|
|
554
|
+
// The statement did not fail to parse but there is nothing to do, just
|
|
555
|
+
// skip to the end
|
|
551
556
|
if (statement == NULL) {
|
|
552
557
|
continue;
|
|
553
558
|
}
|
|
@@ -562,13 +567,14 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
|
|
|
562
567
|
std::string column_name, column_declared_type;
|
|
563
568
|
|
|
564
569
|
while (isConsuming) {
|
|
565
|
-
|
|
570
|
+
step = sqlite3_step(statement);
|
|
566
571
|
|
|
567
|
-
switch (
|
|
572
|
+
switch (step) {
|
|
568
573
|
case SQLITE_ROW: {
|
|
569
|
-
if (results ==
|
|
574
|
+
if (results == nullptr) {
|
|
570
575
|
break;
|
|
571
576
|
}
|
|
577
|
+
|
|
572
578
|
std::vector<JSVariant> row;
|
|
573
579
|
|
|
574
580
|
i = 0;
|
|
@@ -616,7 +622,8 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
|
|
|
616
622
|
}
|
|
617
623
|
|
|
618
624
|
case SQLITE_NULL:
|
|
619
|
-
|
|
625
|
+
row.push_back(JSVariant(nullptr));
|
|
626
|
+
break;
|
|
620
627
|
|
|
621
628
|
default:
|
|
622
629
|
row.push_back(JSVariant(nullptr));
|
|
@@ -649,7 +656,7 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
|
|
|
649
656
|
|
|
650
657
|
return {.type = SQLiteError,
|
|
651
658
|
.message =
|
|
652
|
-
"[op-sqlite] SQLite error code: " + std::to_string(
|
|
659
|
+
"[op-sqlite] SQLite error code: " + std::to_string(step) +
|
|
653
660
|
", description: " + std::string(errorMessage) +
|
|
654
661
|
".\nSee SQLite error codes reference: "
|
|
655
662
|
"https://www.sqlite.org/rescode.html"};
|
|
@@ -663,64 +670,10 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
|
|
|
663
670
|
.insertId = static_cast<double>(latestInsertRowId)};
|
|
664
671
|
}
|
|
665
672
|
|
|
666
|
-
/// Executes without returning any results, Useful for performance critical
|
|
667
|
-
/// operations
|
|
668
|
-
BridgeResult opsqlite_execute_literal(std::string const &dbName,
|
|
669
|
-
std::string const &query) {
|
|
670
|
-
check_db_open(dbName);
|
|
671
|
-
|
|
672
|
-
sqlite3 *db = dbMap[dbName];
|
|
673
|
-
sqlite3_stmt *statement;
|
|
674
|
-
|
|
675
|
-
int statementStatus =
|
|
676
|
-
sqlite3_prepare_v2(db, query.c_str(), -1, &statement, NULL);
|
|
677
|
-
|
|
678
|
-
if (statementStatus != SQLITE_OK) {
|
|
679
|
-
const char *message = sqlite3_errmsg(db);
|
|
680
|
-
return {SQLiteError,
|
|
681
|
-
"[op-sqlite] SQL statement error: " + std::string(message), 0};
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
bool isConsuming = true;
|
|
685
|
-
bool isFailed = false;
|
|
686
|
-
|
|
687
|
-
int result;
|
|
688
|
-
std::string column_name;
|
|
689
|
-
|
|
690
|
-
while (isConsuming) {
|
|
691
|
-
result = sqlite3_step(statement);
|
|
692
|
-
|
|
693
|
-
switch (result) {
|
|
694
|
-
case SQLITE_ROW:
|
|
695
|
-
isConsuming = true;
|
|
696
|
-
break;
|
|
697
|
-
|
|
698
|
-
case SQLITE_DONE:
|
|
699
|
-
isConsuming = false;
|
|
700
|
-
break;
|
|
701
|
-
|
|
702
|
-
default:
|
|
703
|
-
isFailed = true;
|
|
704
|
-
isConsuming = false;
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
sqlite3_finalize(statement);
|
|
709
|
-
|
|
710
|
-
if (isFailed) {
|
|
711
|
-
const char *message = sqlite3_errmsg(db);
|
|
712
|
-
return {SQLiteError,
|
|
713
|
-
"[op-sqlite] SQL execution error: " + std::string(message), 0};
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
int changedRowCount = sqlite3_changes(db);
|
|
717
|
-
return {SQLiteOk, "", changedRowCount};
|
|
718
|
-
}
|
|
719
|
-
|
|
720
673
|
void opsqlite_close_all() {
|
|
721
674
|
for (auto const &x : dbMap) {
|
|
722
|
-
// Interrupt will make all pending operations to fail with
|
|
723
|
-
// The ongoing work from threads will then fail ASAP
|
|
675
|
+
// Interrupt will make all pending operations to fail with
|
|
676
|
+
// SQLITE_INTERRUPT The ongoing work from threads will then fail ASAP
|
|
724
677
|
sqlite3_interrupt(x.second);
|
|
725
678
|
// Each DB connection can then be safely interrupted
|
|
726
679
|
sqlite3_close_v2(x.second);
|
package/cpp/bridge.h
CHANGED
|
@@ -19,8 +19,13 @@ typedef std::function<void(std::string dbName, std::string tableName,
|
|
|
19
19
|
typedef std::function<void(std::string dbName)> CommitCallback;
|
|
20
20
|
typedef std::function<void(std::string dbName)> RollbackCallback;
|
|
21
21
|
|
|
22
|
+
#ifdef OP_SQLITE_USE_SQLCIPHER
|
|
23
|
+
BridgeResult opsqlite_open(std::string const &dbName, std::string const &dbPath,
|
|
24
|
+
std::string const &encryptionKey);
|
|
25
|
+
#else
|
|
22
26
|
BridgeResult opsqlite_open(std::string const &dbName,
|
|
23
27
|
std::string const &dbPath);
|
|
28
|
+
#endif
|
|
24
29
|
|
|
25
30
|
BridgeResult opsqlite_close(std::string const &dbName);
|
|
26
31
|
|
|
@@ -46,9 +51,6 @@ BridgeResult opsqlite_execute_raw(std::string const &dbName,
|
|
|
46
51
|
const std::vector<JSVariant> *params,
|
|
47
52
|
std::vector<std::vector<JSVariant>> *results);
|
|
48
53
|
|
|
49
|
-
BridgeResult opsqlite_execute_literal(std::string const &dbName,
|
|
50
|
-
std::string const &query);
|
|
51
|
-
|
|
52
54
|
void opsqlite_close_all();
|
|
53
55
|
|
|
54
56
|
BridgeResult opsqlite_register_update_hook(std::string const &dbName,
|
package/cpp/sqlbatchexecutor.cpp
CHANGED
|
@@ -57,7 +57,8 @@ BatchResult sqliteExecuteBatch(std::string dbName,
|
|
|
57
57
|
|
|
58
58
|
try {
|
|
59
59
|
int affectedRows = 0;
|
|
60
|
-
|
|
60
|
+
opsqlite_execute(dbName, "BEGIN EXCLUSIVE TRANSACTION", nullptr, nullptr,
|
|
61
|
+
nullptr);
|
|
61
62
|
for (int i = 0; i < commandCount; i++) {
|
|
62
63
|
auto command = commands->at(i);
|
|
63
64
|
// We do not provide a datastructure to receive query data because we
|
|
@@ -65,7 +66,7 @@ BatchResult sqliteExecuteBatch(std::string dbName,
|
|
|
65
66
|
auto result = opsqlite_execute(dbName, command.sql, command.params.get(),
|
|
66
67
|
nullptr, nullptr);
|
|
67
68
|
if (result.type == SQLiteError) {
|
|
68
|
-
|
|
69
|
+
opsqlite_execute(dbName, "ROLLBACK", nullptr, nullptr, nullptr);
|
|
69
70
|
return BatchResult{
|
|
70
71
|
.type = SQLiteError,
|
|
71
72
|
.message = result.message,
|
|
@@ -74,14 +75,14 @@ BatchResult sqliteExecuteBatch(std::string dbName,
|
|
|
74
75
|
affectedRows += result.affectedRows;
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
|
-
|
|
78
|
+
opsqlite_execute(dbName, "COMMIT", nullptr, nullptr, nullptr);
|
|
78
79
|
return BatchResult{
|
|
79
80
|
.type = SQLiteOk,
|
|
80
81
|
.affectedRows = affectedRows,
|
|
81
82
|
.commands = static_cast<int>(commandCount),
|
|
82
83
|
};
|
|
83
84
|
} catch (std::exception &exc) {
|
|
84
|
-
|
|
85
|
+
opsqlite_execute(dbName, "ROLLBACK", nullptr, nullptr, nullptr);
|
|
85
86
|
return BatchResult{
|
|
86
87
|
.type = SQLiteError,
|
|
87
88
|
.message = exc.what(),
|