@op-engineering/op-sqlite 2.0.22 → 3.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.
@@ -6,9 +6,10 @@ set (CMAKE_VERBOSE_MAKEFILE ON)
6
6
  set (CMAKE_CXX_STANDARD 17)
7
7
  set (BUILD_DIR ${CMAKE_SOURCE_DIR}/build)
8
8
 
9
- include_directories(
10
- ../cpp
11
- )
9
+ include_directories(
10
+ ../cpp
11
+ ../cpp/sqlcipher
12
+ )
12
13
 
13
14
  add_definitions(
14
15
  ${SQLITE_FLAGS}
@@ -21,8 +22,6 @@ add_library(
21
22
  ../cpp/bridge.h
22
23
  ../cpp/bindings.cpp
23
24
  ../cpp/bindings.h
24
- ../cpp/sqlite3.h
25
- ../cpp/sqlite3.c
26
25
  ../cpp/utils.h
27
26
  ../cpp/utils.cpp
28
27
  ../cpp/ThreadPool.h
@@ -40,6 +39,20 @@ add_library(
40
39
  cpp-adapter.cpp
41
40
  )
42
41
 
42
+ if (OP_SQLITE_USE_SQLCIPHER)
43
+ target_sources(${PACKAGE_NAME} PRIVATE ../cpp/sqlcipher/sqlite3.h ../cpp/sqlcipher/sqlite3.c)
44
+
45
+ add_definitions(
46
+ -DOP_SQLITE_USE_SQLCIPHER
47
+ -DSQLITE_HAS_CODEC
48
+ -DSQLITE_TEMP_STORE=2
49
+ )
50
+
51
+ find_package(openssl REQUIRED CONFIG)
52
+ else()
53
+ target_sources(${PACKAGE_NAME} PRIVATE ../cpp/sqlite3.h ../cpp/sqlite3.c)
54
+ endif()
55
+
43
56
  set_target_properties(
44
57
  ${PACKAGE_NAME} PROPERTIES
45
58
  CXX_STANDARD 17
@@ -49,12 +62,19 @@ set_target_properties(
49
62
 
50
63
  find_package(ReactAndroid REQUIRED CONFIG)
51
64
  find_package(fbjni REQUIRED CONFIG)
65
+ find_library(LOG_LIB log)
66
+
52
67
 
53
68
  target_link_libraries(
54
69
  ${PACKAGE_NAME}
70
+ ${LOG_LIB}
55
71
  fbjni::fbjni
56
72
  ReactAndroid::jsi
57
73
  ReactAndroid::turbomodulejsijni
58
74
  ReactAndroid::react_nativemodule_core
59
75
  android
60
76
  )
77
+
78
+ if (OP_SQLITE_USE_SQLCIPHER)
79
+ target_link_libraries(${PACKAGE_NAME} PRIVATE openssl::crypto)
80
+ endif()
@@ -78,17 +78,23 @@ android {
78
78
  cmake {
79
79
  if(System.getenv("OP_SQLITE_PERF") == '1') {
80
80
  println "OP-SQLITE performance mode enabled! 🚀"
81
- cFlags "-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"
81
+ cFlags += ["-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"]
82
82
  }
83
83
  if(System.getenv("OP_SQLITE_PERF") == '2') {
84
84
  println "OP-SQLITE (thread safe) performance mode enabled! 🚀"
85
- cFlags "-DSQLITE_DQS=0", "-DSQLITE_THREADSAFE=1", "-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"
85
+ cFlags += ["-DSQLITE_DQS=0", "-DSQLITE_THREADSAFE=1", "-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"]
86
86
  }
87
+
88
+ if(System.getenv("OP_SQLITE_USE_SQLCIPHER") == '1') {
89
+ println "OP-SQLITE using SQLCipher! 🔒"
90
+ cFlags += "-DOP_SQLITE_USE_SQLCIPHER=1"
91
+ }
92
+
87
93
  cppFlags "-O2", "-fexceptions", "-frtti", "-std=c++1y", "-DONANDROID"
88
94
  abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
89
- arguments '-DANDROID_STL=c++_shared',
90
- "-DSQLITE_FLAGS='${SQLITE_FLAGS ? SQLITE_FLAGS : ''}'",
91
- "-DUSE_HERMES=${USE_HERMES}"
95
+ arguments "-DANDROID_STL=c++_shared",
96
+ "-DSQLITE_FLAGS='${SQLITE_FLAGS ? SQLITE_FLAGS : ''}'"
97
+ "-DOP_SQLITE_USE_SQLCIPHER='${System.getenv("OP_SQLITE_USE_SQLCIPHER") == '1'? 1 : 0}'"
92
98
  abiFilters (*reactNativeArchitectures())
93
99
  }
94
100
  }
@@ -134,10 +140,12 @@ repositories {
134
140
  }
135
141
 
136
142
  def kotlin_version = getExtOrDefault("kotlinVersion")
137
-
138
143
  dependencies {
139
144
  implementation 'com.facebook.react:react-native'
140
145
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
146
+ if (System.getenv("OP_SQLITE_USE_SQLCIPHER") == '1') {
147
+ implementation('com.android.ndk.thirdparty:openssl:1.1.1q-beta-1')
148
+ }
141
149
  }
142
150
 
143
151
  // Resolves "LOCAL_SRC_FILES points to a missing file, Check that libfb.so exists or that its path is correct".
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
- if (!args[0].isString()) {
59
- throw std::runtime_error(
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 (count > 1 && !args[1].isUndefined() && !args[1].isNull()) {
67
- if (!args[1].isString()) {
68
- throw std::runtime_error(
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
- std::string lastPath = args[1].asString(rt).utf8(rt);
67
+ if (options.hasProperty(rt, "encryptionKey")) {
68
+ encryptionKey =
69
+ options.getProperty(rt, "encryptionKey").asString(rt).utf8(rt);
70
+ }
73
71
 
74
- if (lastPath == ":memory:") {
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 (lastPath.rfind("/", 0) == 0) {
77
- path = lastPath;
89
+ } else if (location.rfind("/", 0) == 0) {
90
+ path = location;
78
91
  } else {
79
- path = path + "/" + lastPath;
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);
@@ -618,6 +635,30 @@ void install(jsi::Runtime &rt,
618
635
  return {};
619
636
  });
620
637
 
638
+ auto get_db_path = HOSTFN("getDbPath", 2) {
639
+ std::string db_name = args[0].asString(rt).utf8(rt);
640
+ std::string path = std::string(basePath);
641
+ if (count > 1 && !args[1].isUndefined() && !args[1].isNull()) {
642
+ if (!args[1].isString()) {
643
+ throw std::runtime_error(
644
+ "[op-sqlite][open] database location must be a string");
645
+ }
646
+
647
+ std::string lastPath = args[1].asString(rt).utf8(rt);
648
+
649
+ if (lastPath == ":memory:") {
650
+ path = ":memory:";
651
+ } else if (lastPath.rfind("/", 0) == 0) {
652
+ path = lastPath;
653
+ } else {
654
+ path = path + "/" + lastPath;
655
+ }
656
+ }
657
+
658
+ auto result = opsqlite_get_db_path(db_name, path);
659
+ return jsi::String::createFromUtf8(rt, result);
660
+ });
661
+
621
662
  jsi::Object module = jsi::Object(rt);
622
663
 
623
664
  module.setProperty(rt, "open", std::move(open));
@@ -636,6 +677,7 @@ void install(jsi::Runtime &rt,
636
677
  module.setProperty(rt, "prepareStatement", std::move(prepare_statement));
637
678
  module.setProperty(rt, "loadExtension", std::move(load_extension));
638
679
  module.setProperty(rt, "executeRawAsync", std::move(execute_raw_async));
680
+ module.setProperty(rt, "getDbPath", std::move(get_db_path));
639
681
 
640
682
  rt.global().setProperty(rt, "__OPSQLiteProxy", std::move(module));
641
683
  }
package/cpp/bridge.cpp CHANGED
@@ -30,8 +30,8 @@ inline void check_db_open(std::string const &db_name) {
30
30
 
31
31
  /// Returns the completely formed db path, but it also creates any sub-folders
32
32
  /// along the way
33
- std::string get_db_path(std::string const &db_name,
34
- std::string const &location) {
33
+ std::string opsqlite_get_db_path(std::string const &db_name,
34
+ std::string const &location) {
35
35
 
36
36
  if (location == ":memory:") {
37
37
  return location;
@@ -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 &lastPath) {
46
- std::string dbPath = get_db_path(dbName, lastPath);
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 = opsqlite_get_db_path(dbName, last_path);
47
53
 
48
54
  int sqlOpenFlags =
49
55
  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
@@ -58,6 +64,11 @@ BridgeResult opsqlite_open(std::string const &dbName,
58
64
 
59
65
  dbMap[dbName] = db;
60
66
 
67
+ #ifdef OP_SQLITE_USE_SQLCIPHER
68
+ opsqlite_execute(dbName, "PRAGMA key = '" + encryptionKey + "'", nullptr,
69
+ nullptr, nullptr);
70
+ #endif
71
+
61
72
  return BridgeResult{.type = SQLiteOk, .affectedRows = 0};
62
73
  }
63
74
 
@@ -80,7 +91,7 @@ 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
- std::string dbPath = get_db_path(databaseToAttach, docPath);
94
+ std::string dbPath = opsqlite_get_db_path(databaseToAttach, docPath);
84
95
  std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
85
96
 
86
97
  BridgeResult result =
@@ -124,7 +135,7 @@ BridgeResult opsqlite_remove(std::string const &dbName,
124
135
  }
125
136
  }
126
137
 
127
- std::string dbPath = get_db_path(dbName, docPath);
138
+ std::string dbPath = opsqlite_get_db_path(dbName, docPath);
128
139
 
129
140
  if (!file_exists(dbPath)) {
130
141
  return {.type = SQLiteError,
@@ -321,7 +332,7 @@ sqlite3_stmt *opsqlite_prepare_statement(std::string const &dbName,
321
332
 
322
333
  if (statementStatus == SQLITE_ERROR) {
323
334
  const char *message = sqlite3_errmsg(db);
324
- throw std::runtime_error("[op-sqlite] SQL statement error: " +
335
+ throw std::runtime_error("[op-sqlite] SQL prepare statement error: " +
325
336
  std::string(message));
326
337
  }
327
338
 
@@ -359,15 +370,15 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
359
370
  const char *message = sqlite3_errmsg(db);
360
371
  return {
361
372
  .type = SQLiteError,
362
- .message = "[op-sqlite] SQL statement error:" +
363
- std::to_string(statementStatus) +
364
- " description:" + std::string(message) +
373
+ .message = "[op-sqlite] SQL statement error on opsqlite_execute:\n" +
374
+ std::to_string(statementStatus) + " description:\n" +
375
+ std::string(message) +
365
376
  ". See error codes: https://www.sqlite.org/rescode.html",
366
377
  };
367
378
  }
368
379
 
369
- // The statement did not fail to parse but there is nothing to do, just skip
370
- // to the end
380
+ // The statement did not fail to parse but there is nothing to do, just
381
+ // skip to the end
371
382
  if (statement == NULL) {
372
383
  continue;
373
384
  }
@@ -502,8 +513,8 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
502
513
  .insertId = static_cast<double>(latestInsertRowId)};
503
514
  }
504
515
 
505
- /// Executes returning data in raw arrays, a small performance optimization for
506
- /// certain use cases
516
+ /// Executes returning data in raw arrays, a small performance optimization
517
+ /// for certain use cases
507
518
  BridgeResult
508
519
  opsqlite_execute_raw(std::string const &dbName, std::string const &query,
509
520
  const std::vector<JSVariant> *params,
@@ -540,8 +551,8 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
540
551
  };
541
552
  }
542
553
 
543
- // The statement did not fail to parse but there is nothing to do, just skip
544
- // to the end
554
+ // The statement did not fail to parse but there is nothing to do, just
555
+ // skip to the end
545
556
  if (statement == NULL) {
546
557
  continue;
547
558
  }
@@ -661,8 +672,8 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
661
672
 
662
673
  void opsqlite_close_all() {
663
674
  for (auto const &x : dbMap) {
664
- // Interrupt will make all pending operations to fail with SQLITE_INTERRUPT
665
- // 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
666
677
  sqlite3_interrupt(x.second);
667
678
  // Each DB connection can then be safely interrupted
668
679
  sqlite3_close_v2(x.second);
package/cpp/bridge.h CHANGED
@@ -19,8 +19,16 @@ 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
+ std::string opsqlite_get_db_path(std::string const &db_name,
23
+ std::string const &location);
24
+
25
+ #ifdef OP_SQLITE_USE_SQLCIPHER
26
+ BridgeResult opsqlite_open(std::string const &dbName, std::string const &dbPath,
27
+ std::string const &encryptionKey);
28
+ #else
22
29
  BridgeResult opsqlite_open(std::string const &dbName,
23
30
  std::string const &dbPath);
31
+ #endif
24
32
 
25
33
  BridgeResult opsqlite_close(std::string const &dbName);
26
34