@op-engineering/op-sqlite 11.2.5 → 11.2.7

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/cpp/bridge.cpp CHANGED
@@ -1,10 +1,16 @@
1
+ // This file contains pure sqlite operations without JSI interaction
2
+ // Allows a clear defined boundary between the JSI and the SQLite operations
3
+ // so that threading operations are safe and contained within DBHostObject
4
+
1
5
  #include "bridge.h"
6
+ #include "DBHostObject.h"
2
7
  #include "DumbHostObject.h"
3
8
  #include "SmartHostObject.h"
4
9
  #include "logs.h"
5
10
  #include "utils.h"
6
11
  #include <iostream>
7
12
  #include <sstream>
13
+ #include <stdexcept>
8
14
  #include <unordered_map>
9
15
  #include <variant>
10
16
 
@@ -16,33 +22,42 @@
16
22
 
17
23
  namespace opsqlite {
18
24
 
19
- /// Maps to hold the different objects
20
- std::unordered_map<std::string, sqlite3 *> dbMap =
21
- std::unordered_map<std::string, sqlite3 *>();
22
-
23
- std::unordered_map<std::string, UpdateCallback> updateCallbackMap =
24
- std::unordered_map<std::string, UpdateCallback>();
25
+ inline void opsqlite_bind_statement(sqlite3_stmt *statement,
26
+ const std::vector<JSVariant> *values) {
27
+ sqlite3_clear_bindings(statement);
25
28
 
26
- std::unordered_map<std::string, CommitCallback> commitCallbackMap =
27
- std::unordered_map<std::string, CommitCallback>();
29
+ size_t size = values->size();
28
30
 
29
- std::unordered_map<std::string, RollbackCallback> rollbackCallbackMap =
30
- std::unordered_map<std::string, RollbackCallback>();
31
+ for (int ii = 0; ii < size; ii++) {
32
+ int stmt_index = ii + 1;
33
+ JSVariant value = values->at(ii);
31
34
 
32
- inline void check_db_open(std::string const &db_name) {
33
- if (dbMap.count(db_name) == 0) {
34
- throw std::runtime_error("[OP-SQLite] Database: " + db_name +
35
- " is not open");
35
+ std::visit(
36
+ [&](auto &&v) {
37
+ using T = std::decay_t<decltype(v)>;
38
+
39
+ if constexpr (std::is_same_v<T, bool>) {
40
+ sqlite3_bind_int(statement, stmt_index, static_cast<int>(v));
41
+ } else if constexpr (std::is_same_v<T, int>) {
42
+ sqlite3_bind_int(statement, stmt_index, v);
43
+ } else if constexpr (std::is_same_v<T, long long>) {
44
+ sqlite3_bind_double(statement, stmt_index, static_cast<double>(v));
45
+ } else if constexpr (std::is_same_v<T, double>) {
46
+ sqlite3_bind_double(statement, stmt_index, v);
47
+ } else if constexpr (std::is_same_v<T, std::string>) {
48
+ sqlite3_bind_text(statement, stmt_index, v.c_str(),
49
+ static_cast<int>(v.length()), SQLITE_TRANSIENT);
50
+ } else if constexpr (std::is_same_v<T, ArrayBuffer>) {
51
+ sqlite3_bind_blob(statement, stmt_index, v.data.get(),
52
+ static_cast<int>(v.size), SQLITE_TRANSIENT);
53
+ } else {
54
+ sqlite3_bind_null(statement, stmt_index);
55
+ }
56
+ },
57
+ value);
36
58
  }
37
59
  }
38
60
 
39
- // _____ _____
40
- // /\ | __ \_ _|
41
- // / \ | |__) || |
42
- // / /\ \ | ___/ | |
43
- // / ____ \| | _| |_
44
- // /_/ \_\_| |_____|
45
-
46
61
  /// Returns the completely formed db path, but it also creates any sub-folders
47
62
  /// along the way
48
63
  std::string opsqlite_get_db_path(std::string const &db_name,
@@ -57,47 +72,35 @@ std::string opsqlite_get_db_path(std::string const &db_name,
57
72
  }
58
73
 
59
74
  #ifdef OP_SQLITE_USE_SQLCIPHER
60
- BridgeResult opsqlite_open(std::string const &name,
61
- std::string const &last_path,
75
+ sqlite3 *opsqlite_open(std::string const &name, std::string const &path,
62
76
  std::string const &crsqlite_path,
63
77
  std::string const &sqlite_vec_path,
64
- std::string const &encryptionKey) {
78
+ std::string const &encryption_key) {
65
79
  #else
66
- BridgeResult opsqlite_open(std::string const &name,
67
- std::string const &last_path,
68
- [[maybe_unused]] std::string const &crsqlite_path,
69
- std::string const &sqlite_vec_path) {
70
-
71
- if (dbMap.count(name) != 0) {
72
- throw std::runtime_error(
73
- "[OP-SQLITE] Only one connection per database is allowed, db name: " +
74
- name);
75
- }
80
+ sqlite3 *opsqlite_open(std::string const &name, std::string const &path,
81
+ [[maybe_unused]] std::string const &crsqlite_path,
82
+ [[maybe_unused]] std::string const &sqlite_vec_path) {
76
83
  #endif
77
- std::string dbPath = opsqlite_get_db_path(name, last_path);
84
+ std::string final_path = opsqlite_get_db_path(name, path);
85
+ char *errMsg;
86
+ sqlite3 *db;
78
87
 
79
- int sqlOpenFlags =
88
+ int flags =
80
89
  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
81
90
 
82
- sqlite3 *db;
83
-
84
- int status = sqlite3_open_v2(dbPath.c_str(), &db, sqlOpenFlags, nullptr);
91
+ int status = sqlite3_open_v2(final_path.c_str(), &db, flags, nullptr);
85
92
 
86
93
  if (status != SQLITE_OK) {
87
- return {.type = SQLiteError, .message = sqlite3_errmsg(db)};
94
+ throw std::runtime_error(sqlite3_errmsg(db));
88
95
  }
89
96
 
90
- dbMap[name] = db;
91
-
92
97
  #ifdef OP_SQLITE_USE_SQLCIPHER
93
- opsqlite_execute(name, "PRAGMA key = '" + encryptionKey + "'", nullptr);
98
+ opsqlite_execute(db, "PRAGMA key = '" + encryption_key + "'", nullptr);
94
99
  #endif
95
100
 
96
101
  #ifndef OP_SQLITE_USE_PHONE_VERSION
97
102
  sqlite3_enable_load_extension(db, 1);
98
103
  #endif
99
-
100
- char *errMsg;
101
104
 
102
105
  #ifdef OP_SQLITE_USE_CRSQLITE
103
106
  const char *crsqliteEntryPoint = "sqlite3_crsqlite_init";
@@ -106,7 +109,7 @@ BridgeResult opsqlite_open(std::string const &name,
106
109
  &errMsg);
107
110
 
108
111
  if (errMsg != nullptr) {
109
- return {.type = SQLiteError, .message = errMsg};
112
+ throw std::runtime_error(errMsg);
110
113
  }
111
114
  #endif
112
115
 
@@ -116,138 +119,57 @@ BridgeResult opsqlite_open(std::string const &name,
116
119
  sqlite3_load_extension(db, sqlite_vec_path.c_str(), vec_entry_point, &errMsg);
117
120
 
118
121
  if (errMsg != nullptr) {
119
- return {.type = SQLiteError, .message = errMsg};
122
+ throw std::runtime_error(errMsg);
120
123
  }
121
124
  #endif
122
125
 
123
126
  TOKENIZER_LIST
124
127
 
125
- return {.type = SQLiteOk, .affectedRows = 0};
128
+ return db;
126
129
  }
127
130
 
128
- BridgeResult opsqlite_close(std::string const &name) {
129
-
130
- check_db_open(name);
131
-
132
- sqlite3 *db = dbMap[name];
131
+ void opsqlite_close(sqlite3 *db) {
133
132
 
134
133
  #ifdef OP_SQLITE_USE_CRSQLITE
135
134
  opsqlite_execute(name, "select crsql_finalize();", nullptr);
136
135
  #endif
137
136
 
138
137
  sqlite3_close_v2(db);
139
-
140
- dbMap.erase(name);
141
-
142
- return BridgeResult{
143
- .type = SQLiteOk,
144
- };
145
138
  }
146
139
 
147
- BridgeResult opsqlite_attach(std::string const &mainDBName,
148
- std::string const &docPath,
149
- std::string const &databaseToAttach,
150
- std::string const &alias) {
151
- std::string dbPath = opsqlite_get_db_path(databaseToAttach, docPath);
152
- std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
153
-
154
- BridgeResult result = opsqlite_execute(mainDBName, statement, nullptr);
155
-
156
- if (result.type == SQLiteError) {
157
- return {
158
- .type = SQLiteError,
159
- .message = mainDBName + " was unable to attach another database: " +
160
- std::string(result.message),
161
- };
162
- }
163
- return {
164
- .type = SQLiteOk,
165
- };
140
+ void opsqlite_attach(sqlite3 *db, std::string const &main_db_name,
141
+ std::string const &doc_path,
142
+ std::string const &secondary_db_name,
143
+ std::string const &alias) {
144
+ auto secondary_db_path = opsqlite_get_db_path(secondary_db_name, doc_path);
145
+ auto statement = "ATTACH DATABASE '" + secondary_db_path + "' AS " + alias;
146
+
147
+ opsqlite_execute(db, statement, nullptr);
166
148
  }
167
149
 
168
- BridgeResult opsqlite_detach(std::string const &mainDBName,
169
- std::string const &alias) {
150
+ void opsqlite_detach(sqlite3 *db, std::string const &main_db_name,
151
+ std::string const &alias) {
170
152
  std::string statement = "DETACH DATABASE " + alias;
171
- BridgeResult result = opsqlite_execute(mainDBName, statement, nullptr);
172
- if (result.type == SQLiteError) {
173
- return BridgeResult{
174
- .type = SQLiteError,
175
- .message = mainDBName + "was unable to detach database: " +
176
- std::string(result.message),
177
- };
178
- }
179
- return BridgeResult{
180
- .type = SQLiteOk,
181
- };
153
+ opsqlite_execute(db, statement, nullptr);
182
154
  }
183
155
 
184
- BridgeResult opsqlite_remove(std::string const &dbName,
185
- std::string const &docPath) {
186
- if (dbMap.count(dbName) == 1) {
187
- BridgeResult closeResult = opsqlite_close(dbName);
188
- if (closeResult.type == SQLiteError) {
189
- return closeResult;
190
- }
191
- }
156
+ void opsqlite_remove(sqlite3 *db, std::string const &name,
157
+ std::string const &doc_path) {
158
+ opsqlite_close(db);
192
159
 
193
- std::string dbPath = opsqlite_get_db_path(dbName, docPath);
160
+ std::string db_path = opsqlite_get_db_path(name, doc_path);
194
161
 
195
- if (!file_exists(dbPath)) {
196
- return {.type = SQLiteError,
197
- .message = "[op-sqlite]: Database file not found" + dbPath};
162
+ if (!file_exists(db_path)) {
163
+ throw std::runtime_error("op-sqlite: db file not found:" + db_path);
198
164
  }
199
165
 
200
- remove(dbPath.c_str());
201
-
202
- return {
203
- .type = SQLiteOk,
204
- };
205
- }
206
-
207
- inline void opsqlite_bind_statement(sqlite3_stmt *statement,
208
- const std::vector<JSVariant> *values) {
209
- // reset any existing bound values
210
- sqlite3_clear_bindings(statement);
211
-
212
- size_t size = values->size();
213
-
214
- for (int ii = 0; ii < size; ii++) {
215
- int sqIndex = ii + 1;
216
- JSVariant value = values->at(ii);
217
-
218
- if (std::holds_alternative<bool>(value)) {
219
- sqlite3_bind_int(statement, sqIndex,
220
- static_cast<int>(std::get<bool>(value)));
221
- } else if (std::holds_alternative<int>(value)) {
222
- sqlite3_bind_int(statement, sqIndex, std::get<int>(value));
223
- } else if (std::holds_alternative<long long>(value)) {
224
- sqlite3_bind_double(statement, sqIndex,
225
- static_cast<double>(std::get<long long>(value)));
226
- } else if (std::holds_alternative<double>(value)) {
227
- sqlite3_bind_double(statement, sqIndex, std::get<double>(value));
228
- } else if (std::holds_alternative<std::string>(value)) {
229
- std::string str = std::get<std::string>(value);
230
- sqlite3_bind_text(statement, sqIndex, str.c_str(),
231
- static_cast<int>(str.length()), SQLITE_TRANSIENT);
232
- } else if (std::holds_alternative<ArrayBuffer>(value)) {
233
- ArrayBuffer buffer = std::get<ArrayBuffer>(value);
234
- sqlite3_bind_blob(statement, sqIndex, buffer.data.get(),
235
- static_cast<int>(buffer.size), SQLITE_TRANSIENT);
236
- } else {
237
- sqlite3_bind_null(statement, sqIndex);
238
- }
239
- }
166
+ remove(db_path.c_str());
240
167
  }
241
168
 
242
169
  BridgeResult opsqlite_execute_prepared_statement(
243
- std::string const &dbName, sqlite3_stmt *statement,
244
- std::vector<DumbHostObject> *results,
170
+ sqlite3 *db, sqlite3_stmt *statement, std::vector<DumbHostObject> *results,
245
171
  std::shared_ptr<std::vector<SmartHostObject>> &metadatas) {
246
172
 
247
- check_db_open(dbName);
248
-
249
- sqlite3 *db = dbMap[dbName];
250
-
251
173
  const char *errorMessage;
252
174
 
253
175
  bool isConsuming = true;
@@ -356,25 +278,20 @@ BridgeResult opsqlite_execute_prepared_statement(
356
278
  sqlite3_reset(statement);
357
279
 
358
280
  if (isFailed) {
359
- return {.type = SQLiteError,
360
- .message = "[op-sqlite] SQLite code: " + std::to_string(result) +
361
- " execution error: " + std::string(errorMessage)};
281
+ throw std::runtime_error(
282
+ "[op-sqlite] SQLite code: " + std::to_string(result) +
283
+ " execution error: " + std::string(errorMessage));
362
284
  }
363
285
 
364
286
  int changedRowCount = sqlite3_changes(db);
365
287
  long long latestInsertRowId = sqlite3_last_insert_rowid(db);
366
288
 
367
- return {.type = SQLiteOk,
368
- .affectedRows = changedRowCount,
289
+ return {.affectedRows = changedRowCount,
369
290
  .insertId = static_cast<double>(latestInsertRowId)};
370
291
  }
371
292
 
372
- sqlite3_stmt *opsqlite_prepare_statement(std::string const &dbName,
293
+ sqlite3_stmt *opsqlite_prepare_statement(sqlite3 *db,
373
294
  std::string const &query) {
374
- check_db_open(dbName);
375
-
376
- sqlite3 *db = dbMap[dbName];
377
-
378
295
  sqlite3_stmt *statement;
379
296
 
380
297
  const char *queryStr = query.c_str();
@@ -391,12 +308,8 @@ sqlite3_stmt *opsqlite_prepare_statement(std::string const &dbName,
391
308
  return statement;
392
309
  }
393
310
 
394
- BridgeResult opsqlite_execute(std::string const &name, std::string const &query,
311
+ BridgeResult opsqlite_execute(sqlite3 *db, std::string const &query,
395
312
  const std::vector<JSVariant> *params) {
396
- check_db_open(name);
397
-
398
- sqlite3 *db = dbMap[name];
399
-
400
313
  sqlite3_stmt *statement;
401
314
  const char *errorMessage = nullptr;
402
315
  const char *remainingStatement = nullptr;
@@ -417,10 +330,8 @@ BridgeResult opsqlite_execute(std::string const &name, std::string const &query,
417
330
 
418
331
  if (status != SQLITE_OK) {
419
332
  errorMessage = sqlite3_errmsg(db);
420
- return {.type = SQLiteError,
421
- .message =
422
- "[op-sqlite] SQL prepare error: " + std::string(errorMessage),
423
- .affectedRows = 0};
333
+ throw std::runtime_error("[op-sqlite] SQL prepare error: " +
334
+ std::string(errorMessage));
424
335
  }
425
336
 
426
337
  // The statement did not fail to parse but there is nothing to do, just
@@ -516,32 +427,23 @@ BridgeResult opsqlite_execute(std::string const &name, std::string const &query,
516
427
 
517
428
  if (has_failed) {
518
429
  const char *message = sqlite3_errmsg(db);
519
- return {.type = SQLiteError,
520
- .message =
521
- "[op-sqlite] SQL execution error: " + std::string(message),
522
- .affectedRows = 0,
523
- .insertId = 0};
430
+ throw std::runtime_error("[op-sqlite] statement execution error: " +
431
+ std::string(message));
524
432
  }
525
433
 
526
434
  int changedRowCount = sqlite3_changes(db);
527
435
  long long latestInsertRowId = sqlite3_last_insert_rowid(db);
528
- return {.type = SQLiteOk,
529
- .affectedRows = changedRowCount,
436
+ return {.affectedRows = changedRowCount,
530
437
  .insertId = static_cast<double>(latestInsertRowId),
531
438
  .rows = std::move(rows),
532
439
  .column_names = std::move(column_names)};
533
440
  }
534
441
 
535
- /// Base execution function, returns HostObjects to the JS environment
536
442
  BridgeResult opsqlite_execute_host_objects(
537
- std::string const &dbName, std::string const &query,
538
- const std::vector<JSVariant> *params, std::vector<DumbHostObject> *results,
443
+ sqlite3 *db, std::string const &query, const std::vector<JSVariant> *params,
444
+ std::vector<DumbHostObject> *results,
539
445
  std::shared_ptr<std::vector<SmartHostObject>> &metadatas) {
540
446
 
541
- check_db_open(dbName);
542
-
543
- sqlite3 *db = dbMap[dbName];
544
-
545
447
  sqlite3_stmt *statement;
546
448
  const char *errorMessage;
547
449
  const char *remainingStatement = nullptr;
@@ -560,11 +462,10 @@ BridgeResult opsqlite_execute_host_objects(
560
462
 
561
463
  if (statementStatus != SQLITE_OK) {
562
464
  const char *message = sqlite3_errmsg(db);
563
- return {.type = SQLiteError,
564
- .message =
565
- "[op-sqlite] SQL statement error on opsqlite_execute:\n" +
566
- std::to_string(statementStatus) + " description:\n" +
567
- std::string(message)};
465
+ throw std::runtime_error(
466
+ "[op-sqlite] SQL statement error on opsqlite_execute:\n" +
467
+ std::to_string(statementStatus) + " description:\n" +
468
+ std::string(message));
568
469
  }
569
470
 
570
471
  // The statement did not fail to parse but there is nothing to do, just
@@ -683,32 +584,24 @@ BridgeResult opsqlite_execute_host_objects(
683
584
  strcmp(remainingStatement, "") != 0 && !isFailed);
684
585
 
685
586
  if (isFailed) {
686
-
687
- return {.type = SQLiteError,
688
- .message =
689
- "[op-sqlite] SQLite error code: " + std::to_string(result) +
690
- ", description: " + std::string(errorMessage)};
587
+ throw std::runtime_error(
588
+ "[op-sqlite] SQLite error code: " + std::to_string(result) +
589
+ ", description: " + std::string(errorMessage));
691
590
  }
692
591
 
693
592
  int changedRowCount = sqlite3_changes(db);
694
593
  long long latestInsertRowId = sqlite3_last_insert_rowid(db);
695
594
 
696
- return {.type = SQLiteOk,
697
- .affectedRows = changedRowCount,
595
+ return {.affectedRows = changedRowCount,
698
596
  .insertId = static_cast<double>(latestInsertRowId)};
699
597
  }
700
598
 
701
599
  /// Executes returning data in raw arrays, a small performance optimization
702
600
  /// for certain use cases
703
601
  BridgeResult
704
- opsqlite_execute_raw(std::string const &dbName, std::string const &query,
602
+ opsqlite_execute_raw(sqlite3 *db, std::string const &query,
705
603
  const std::vector<JSVariant> *params,
706
604
  std::vector<std::vector<JSVariant>> *results) {
707
-
708
- check_db_open(dbName);
709
-
710
- sqlite3 *db = dbMap[dbName];
711
-
712
605
  sqlite3_stmt *statement;
713
606
  const char *errorMessage;
714
607
  const char *remainingStatement = nullptr;
@@ -727,12 +620,9 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
727
620
 
728
621
  if (statementStatus != SQLITE_OK) {
729
622
  const char *message = sqlite3_errmsg(db);
730
- return {
731
- .type = SQLiteError,
732
- .message = "[op-sqlite] SQL statement error:" +
733
- std::to_string(statementStatus) +
734
- " description:" + std::string(message),
735
- };
623
+ throw std::runtime_error(
624
+ "[op-sqlite] SQL statement error:" + std::to_string(statementStatus) +
625
+ " description:" + std::string(message));
736
626
  }
737
627
 
738
628
  // The statement did not fail to parse but there is nothing to do, just
@@ -825,35 +715,18 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
825
715
  strcmp(remainingStatement, "") != 0 && !isFailed);
826
716
 
827
717
  if (isFailed) {
828
-
829
- return {.type = SQLiteError,
830
- .message =
831
- "[op-sqlite] SQLite error code: " + std::to_string(step) +
832
- ", description: " + std::string(errorMessage)};
718
+ throw std::runtime_error(
719
+ "[op-sqlite] SQLite error code: " + std::to_string(step) +
720
+ ", description: " + std::string(errorMessage));
833
721
  }
834
722
 
835
723
  int changedRowCount = sqlite3_changes(db);
836
724
  long long latestInsertRowId = sqlite3_last_insert_rowid(db);
837
725
 
838
- return {.type = SQLiteOk,
839
- .affectedRows = changedRowCount,
726
+ return {.affectedRows = changedRowCount,
840
727
  .insertId = static_cast<double>(latestInsertRowId)};
841
728
  }
842
729
 
843
- void opsqlite_close_all() {
844
- for (auto const &x : dbMap) {
845
- // Interrupt will make all pending operations to fail with
846
- // SQLITE_INTERRUPT The ongoing work from threads will then fail ASAP
847
- sqlite3_interrupt(x.second);
848
- // Each DB connection can then be safely interrupted
849
- sqlite3_close_v2(x.second);
850
- }
851
- dbMap.clear();
852
- updateCallbackMap.clear();
853
- rollbackCallbackMap.clear();
854
- commitCallbackMap.clear();
855
- }
856
-
857
730
  std::string operation_to_string(int operation_type) {
858
731
  switch (operation_type) {
859
732
  case SQLITE_INSERT:
@@ -866,139 +739,64 @@ std::string operation_to_string(int operation_type) {
866
739
  return "UPDATE";
867
740
 
868
741
  default:
869
- throw std::invalid_argument("Unknown SQLite operation on hook");
742
+ throw std::runtime_error("Unknown SQLite operation on hook");
870
743
  }
871
744
  }
872
745
 
873
- void update_callback(void *dbName, int operation_type,
746
+ void update_callback(void *db_host_object_ptr, int operation_type,
874
747
  [[maybe_unused]] char const *database, char const *table,
875
748
  sqlite3_int64 row_id) {
876
- std::string &strDbName = *(static_cast<std::string *>(dbName));
877
- auto callback = updateCallbackMap[strDbName];
878
- callback(strDbName, std::string(table), operation_to_string(operation_type),
879
- static_cast<int>(row_id));
749
+ auto db_host_object = reinterpret_cast<DBHostObject *>(db_host_object_ptr);
750
+ db_host_object->on_update(std::string(table),
751
+ operation_to_string(operation_type), row_id);
880
752
  }
881
753
 
882
- BridgeResult opsqlite_register_update_hook(std::string const &dbName,
883
- UpdateCallback const &callback) {
884
- check_db_open(dbName);
885
-
886
- sqlite3 *db = dbMap[dbName];
887
- updateCallbackMap[dbName] = callback;
888
- const std::string *key = nullptr;
889
-
890
- // TODO find a more elegant way to retrieve a reference to the key
891
- for (auto const &element : dbMap) {
892
- if (element.first == dbName) {
893
- key = &element.first;
894
- }
895
- }
896
-
897
- sqlite3_update_hook(db, &update_callback, (void *)key);
898
-
899
- return {SQLiteOk};
754
+ void opsqlite_register_update_hook(sqlite3 *db, void *db_host_object) {
755
+ sqlite3_update_hook(db, &update_callback, (void *)db_host_object);
900
756
  }
901
757
 
902
- BridgeResult opsqlite_deregister_update_hook(std::string const &dbName) {
903
- check_db_open(dbName);
904
-
905
- sqlite3 *db = dbMap[dbName];
906
- updateCallbackMap.erase(dbName);
907
-
758
+ void opsqlite_deregister_update_hook(sqlite3 *db) {
908
759
  sqlite3_update_hook(db, nullptr, nullptr);
909
-
910
- return {SQLiteOk};
911
760
  }
912
761
 
913
- int commit_callback(void *dbName) {
914
- std::string &strDbName = *(static_cast<std::string *>(dbName));
915
- auto callback = commitCallbackMap[strDbName];
916
- callback(strDbName);
917
- // You need to return 0 to allow commits to continue
762
+ int commit_callback(void *db_host_object_ptr) {
763
+ auto db_host_object = reinterpret_cast<DBHostObject *>(db_host_object_ptr);
764
+ db_host_object->on_commit();
918
765
  return 0;
919
766
  }
920
767
 
921
- BridgeResult opsqlite_register_commit_hook(std::string const &dbName,
922
- CommitCallback const &callback) {
923
- check_db_open(dbName);
924
-
925
- sqlite3 *db = dbMap[dbName];
926
- commitCallbackMap[dbName] = callback;
927
- const std::string *key = nullptr;
928
-
929
- // TODO find a more elegant way to retrieve a reference to the key
930
- for (auto const &element : dbMap) {
931
- if (element.first == dbName) {
932
- key = &element.first;
933
- }
934
- }
935
-
936
- sqlite3_commit_hook(db, &commit_callback, (void *)key);
937
-
938
- return {SQLiteOk};
768
+ void opsqlite_register_commit_hook(sqlite3 *db, void *db_host_object_ptr) {
769
+ sqlite3_commit_hook(db, &commit_callback, db_host_object_ptr);
939
770
  }
940
771
 
941
- BridgeResult opsqlite_deregister_commit_hook(std::string const &dbName) {
942
- check_db_open(dbName);
943
-
944
- sqlite3 *db = dbMap[dbName];
945
- commitCallbackMap.erase(dbName);
772
+ void opsqlite_deregister_commit_hook(sqlite3 *db) {
946
773
  sqlite3_commit_hook(db, nullptr, nullptr);
947
-
948
- return {SQLiteOk};
949
774
  }
950
775
 
951
- void rollback_callback(void *dbName) {
952
- std::string &strDbName = *(static_cast<std::string *>(dbName));
953
- auto callback = rollbackCallbackMap[strDbName];
954
- callback(strDbName);
776
+ void rollback_callback(void *db_host_object_ptr) {
777
+ auto db_host_object = reinterpret_cast<DBHostObject *>(db_host_object_ptr);
778
+ db_host_object->on_rollback();
955
779
  }
956
780
 
957
- BridgeResult opsqlite_register_rollback_hook(std::string const &dbName,
958
- RollbackCallback const &callback) {
959
- check_db_open(dbName);
960
-
961
- sqlite3 *db = dbMap[dbName];
962
- rollbackCallbackMap[dbName] = callback;
963
- const std::string *key = nullptr;
964
-
965
- // TODO find a more elegant way to retrieve a reference to the key
966
- for (auto const &element : dbMap) {
967
- if (element.first == dbName) {
968
- key = &element.first;
969
- }
970
- }
971
-
972
- sqlite3_rollback_hook(db, &rollback_callback, (void *)key);
973
-
974
- return {SQLiteOk};
781
+ void opsqlite_register_rollback_hook(sqlite3 *db, void *db_host_object_ptr) {
782
+ sqlite3_rollback_hook(db, &rollback_callback, db_host_object_ptr);
975
783
  }
976
784
 
977
- BridgeResult opsqlite_deregister_rollback_hook(std::string const &dbName) {
978
- check_db_open(dbName);
979
-
980
- sqlite3 *db = dbMap[dbName];
981
- rollbackCallbackMap.erase(dbName);
982
-
785
+ void opsqlite_deregister_rollback_hook(sqlite3 *db) {
983
786
  sqlite3_rollback_hook(db, nullptr, nullptr);
984
-
985
- return {SQLiteOk};
986
787
  }
987
788
 
988
- BridgeResult opsqlite_load_extension(std::string const &db_name,
989
- std::string &path,
990
- std::string &entry_point) {
789
+ void opsqlite_load_extension(sqlite3 *db, std::string &path,
790
+ std::string &entry_point) {
991
791
  #ifdef OP_SQLITE_USE_PHONE_VERSION
992
- throw std::runtime_error(
993
- "[op-sqlite] Embedded version of SQLite does not support loading extensions");
792
+ throw std::runtime_error("[op-sqlite] Embedded version of SQLite does not "
793
+ "support loading extensions");
994
794
  #else
995
- check_db_open(db_name);
996
-
997
- sqlite3 *db = dbMap[db_name];
998
795
  int status = 0;
999
796
  status = sqlite3_enable_load_extension(db, 1);
797
+
1000
798
  if (status != SQLITE_OK) {
1001
- return {SQLiteError, "[op-sqlite] could not enable extension loading"};
799
+ throw std::runtime_error("Could not enable extension loading");
1002
800
  }
1003
801
 
1004
802
  const char *entry_point_cstr = nullptr;
@@ -1011,54 +809,37 @@ BridgeResult opsqlite_load_extension(std::string const &db_name,
1011
809
  status = sqlite3_load_extension(db, path.c_str(), entry_point_cstr,
1012
810
  &error_message);
1013
811
  if (status != SQLITE_OK) {
1014
- return {SQLiteError, std::string(error_message)};
812
+ throw std::runtime_error(error_message);
1015
813
  }
1016
-
1017
- return {SQLiteOk};
1018
814
  #endif
1019
815
  }
1020
816
 
1021
- BatchResult opsqlite_execute_batch(std::string &name,
817
+ BatchResult opsqlite_execute_batch(sqlite3 *db,
1022
818
  std::vector<BatchArguments> *commands) {
1023
819
  size_t commandCount = commands->size();
1024
820
  if (commandCount <= 0) {
1025
- return BatchResult{
1026
- .type = SQLiteError,
1027
- .message = "No SQL commands provided",
1028
- };
821
+ throw std::runtime_error("No SQL commands provided");
1029
822
  }
1030
823
 
1031
- try {
1032
- int affectedRows = 0;
1033
- opsqlite_execute(name, "BEGIN EXCLUSIVE TRANSACTION", nullptr);
1034
- for (int i = 0; i < commandCount; i++) {
1035
- const auto &command = commands->at(i);
1036
- // We do not provide a datastructure to receive query data because we
1037
- // don't need/want to handle this results in a batch execution
1038
- auto result = opsqlite_execute(name, command.sql, command.params.get());
1039
- if (result.type == SQLiteError) {
1040
- opsqlite_execute(name, "ROLLBACK", nullptr);
1041
- return BatchResult{
1042
- .type = SQLiteError,
1043
- .message = result.message,
1044
- };
1045
- } else {
1046
- affectedRows += result.affectedRows;
1047
- }
824
+ int affectedRows = 0;
825
+ opsqlite_execute(db, "BEGIN EXCLUSIVE TRANSACTION", nullptr);
826
+ for (int i = 0; i < commandCount; i++) {
827
+ const auto &command = commands->at(i);
828
+ // We do not provide a datastructure to receive query data because we
829
+ // don't need/want to handle this results in a batch execution
830
+ try {
831
+ auto result = opsqlite_execute(db, command.sql, command.params.get());
832
+ affectedRows += result.affectedRows;
833
+ } catch (std::exception &exc) {
834
+ opsqlite_execute(db, "ROLLBACK", nullptr);
835
+ throw exc;
1048
836
  }
1049
- opsqlite_execute(name, "COMMIT", nullptr);
1050
- return BatchResult{
1051
- .type = SQLiteOk,
1052
- .affectedRows = affectedRows,
1053
- .commands = static_cast<int>(commandCount),
1054
- };
1055
- } catch (std::exception &exc) {
1056
- opsqlite_execute(name, "ROLLBACK", nullptr);
1057
- return BatchResult{
1058
- .type = SQLiteError,
1059
- .message = exc.what(),
1060
- };
1061
837
  }
838
+ opsqlite_execute(db, "COMMIT", nullptr);
839
+ return BatchResult{
840
+ .affectedRows = affectedRows,
841
+ .commands = static_cast<int>(commandCount),
842
+ };
1062
843
  }
1063
844
 
1064
845
  } // namespace opsqlite