@op-engineering/op-sqlite 15.0.7 → 15.1.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.
Files changed (45) hide show
  1. package/android/CMakeLists.txt +1 -1
  2. package/android/build.gradle +1 -1
  3. package/android/cpp-adapter.cpp +1 -1
  4. package/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt +7 -9
  5. package/cpp/DBHostObject.cpp +469 -677
  6. package/cpp/DBHostObject.h +56 -58
  7. package/cpp/DumbHostObject.cpp +1 -1
  8. package/cpp/DumbHostObject.h +12 -13
  9. package/cpp/OPSqlite.cpp +207 -0
  10. package/cpp/OPThreadPool.cpp +79 -79
  11. package/cpp/OPThreadPool.h +28 -28
  12. package/cpp/PreparedStatementHostObject.cpp +87 -136
  13. package/cpp/PreparedStatementHostObject.h +16 -28
  14. package/cpp/SmartHostObject.cpp +1 -1
  15. package/cpp/SmartHostObject.h +6 -7
  16. package/cpp/bridge.cpp +639 -633
  17. package/cpp/bridge.h +2 -2
  18. package/cpp/libsql/LICENSE.txt +9 -0
  19. package/cpp/libsql/bridge.cpp +2 -2
  20. package/cpp/libsql/{bridge.h → bridge.hpp} +4 -4
  21. package/cpp/macros.hpp +21 -0
  22. package/cpp/sqlcipher/LICENSE.txt +24 -0
  23. package/cpp/types.hpp +42 -0
  24. package/cpp/utils.cpp +320 -255
  25. package/cpp/{utils.h → utils.hpp} +9 -1
  26. package/ios/OPSQLite.mm +104 -106
  27. package/lib/module/functions.js +52 -44
  28. package/lib/module/functions.js.map +1 -1
  29. package/lib/module/index.js +1 -1
  30. package/lib/module/index.js.map +1 -1
  31. package/lib/typescript/src/functions.d.ts +5 -1
  32. package/lib/typescript/src/functions.d.ts.map +1 -1
  33. package/lib/typescript/src/index.d.ts +1 -1
  34. package/lib/typescript/src/index.d.ts.map +1 -1
  35. package/lib/typescript/src/types.d.ts +12 -1
  36. package/lib/typescript/src/types.d.ts.map +1 -1
  37. package/op-sqlite.podspec +1 -1
  38. package/package.json +10 -8
  39. package/src/functions.ts +64 -54
  40. package/src/index.ts +1 -12
  41. package/src/types.ts +9 -1
  42. package/cpp/bindings.cpp +0 -202
  43. package/cpp/macros.h +0 -15
  44. package/cpp/types.h +0 -33
  45. /package/cpp/{bindings.h → OPSqlite.hpp} +0 -0
package/cpp/bridge.cpp CHANGED
@@ -7,7 +7,7 @@
7
7
  #include "DumbHostObject.h"
8
8
  #include "SmartHostObject.h"
9
9
  #include "logs.h"
10
- #include "utils.h"
10
+ #include "utils.hpp"
11
11
  #include <filesystem>
12
12
  #include <iostream>
13
13
  #include <sstream>
@@ -25,42 +25,38 @@ namespace opsqlite {
25
25
 
26
26
  inline void opsqlite_bind_statement(sqlite3_stmt *statement,
27
27
  const std::vector<JSVariant> *values) {
28
- sqlite3_clear_bindings(statement);
29
-
30
- size_t size = values->size();
31
-
32
- for (int ii = 0; ii < size; ii++) {
33
- int stmt_index = ii + 1;
34
- JSVariant value = values->at(ii);
35
-
36
- std::visit(
37
- [&](auto &&v) {
38
- using T = std::decay_t<decltype(v)>;
39
-
40
- if constexpr (std::is_same_v<T, bool>) {
41
- sqlite3_bind_int(statement, stmt_index,
42
- static_cast<int>(v));
43
- } else if constexpr (std::is_same_v<T, int>) {
44
- sqlite3_bind_int(statement, stmt_index, v);
45
- } else if constexpr (std::is_same_v<T, long long>) {
46
- sqlite3_bind_double(statement, stmt_index,
47
- static_cast<double>(v));
48
- } else if constexpr (std::is_same_v<T, double>) {
49
- sqlite3_bind_double(statement, stmt_index, v);
50
- } else if constexpr (std::is_same_v<T, std::string>) {
51
- sqlite3_bind_text(statement, stmt_index, v.c_str(),
52
- static_cast<int>(v.length()),
53
- SQLITE_TRANSIENT);
54
- } else if constexpr (std::is_same_v<T, ArrayBuffer>) {
55
- sqlite3_bind_blob(statement, stmt_index, v.data.get(),
56
- static_cast<int>(v.size),
57
- SQLITE_TRANSIENT);
58
- } else {
59
- sqlite3_bind_null(statement, stmt_index);
60
- }
61
- },
62
- value);
63
- }
28
+ sqlite3_clear_bindings(statement);
29
+
30
+ size_t size = values->size();
31
+
32
+ for (int ii = 0; ii < size; ii++) {
33
+ int stmt_index = ii + 1;
34
+ JSVariant value = values->at(ii);
35
+
36
+ std::visit(
37
+ [&](auto &&v) {
38
+ using T = std::decay_t<decltype(v)>;
39
+
40
+ if constexpr (std::is_same_v<T, bool>) {
41
+ sqlite3_bind_int(statement, stmt_index, static_cast<int>(v));
42
+ } else if constexpr (std::is_same_v<T, int>) {
43
+ sqlite3_bind_int(statement, stmt_index, v);
44
+ } else if constexpr (std::is_same_v<T, long long>) {
45
+ sqlite3_bind_double(statement, stmt_index, static_cast<double>(v));
46
+ } else if constexpr (std::is_same_v<T, double>) {
47
+ sqlite3_bind_double(statement, stmt_index, v);
48
+ } else if constexpr (std::is_same_v<T, std::string>) {
49
+ sqlite3_bind_text(statement, stmt_index, v.c_str(),
50
+ static_cast<int>(v.length()), SQLITE_TRANSIENT);
51
+ } else if constexpr (std::is_same_v<T, ArrayBuffer>) {
52
+ sqlite3_bind_blob(statement, stmt_index, v.data.get(),
53
+ static_cast<int>(v.size), SQLITE_TRANSIENT);
54
+ } else {
55
+ sqlite3_bind_null(statement, stmt_index);
56
+ }
57
+ },
58
+ value);
59
+ }
64
60
  }
65
61
 
66
62
  /// Returns the completely formed db path, but it also creates any sub-folders
@@ -68,18 +64,18 @@ inline void opsqlite_bind_statement(sqlite3_stmt *statement,
68
64
  std::string opsqlite_get_db_path(std::string const &db_name,
69
65
  std::string const &location) {
70
66
 
71
- if (location == ":memory:") {
72
- return location;
73
- }
67
+ if (location == ":memory:") {
68
+ return location;
69
+ }
74
70
 
75
- // Will return false if the directory already exists, no need to check
76
- std::filesystem::create_directories(location);
71
+ // Will return false if the directory already exists, no need to check
72
+ std::filesystem::create_directories(location);
77
73
 
78
- if (!location.empty() && location.back() != '/') {
79
- return location + "/" + db_name;
80
- }
74
+ if (!location.empty() && location.back() != '/') {
75
+ return location + "/" + db_name;
76
+ }
81
77
 
82
- return location + db_name;
78
+ return location + db_name;
83
79
  }
84
80
 
85
81
  #ifdef OP_SQLITE_USE_SQLCIPHER
@@ -92,369 +88,386 @@ sqlite3 *opsqlite_open(std::string const &name, std::string const &path,
92
88
  [[maybe_unused]] std::string const &crsqlite_path,
93
89
  [[maybe_unused]] std::string const &sqlite_vec_path) {
94
90
  #endif
95
- std::string final_path = opsqlite_get_db_path(name, path);
96
- char *errMsg;
97
- sqlite3 *db;
91
+ std::string final_path = opsqlite_get_db_path(name, path);
92
+ char *errMsg;
93
+ sqlite3 *db;
98
94
 
99
- int flags =
100
- SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
95
+ int flags =
96
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
101
97
 
102
- int status = sqlite3_open_v2(final_path.c_str(), &db, flags, nullptr);
98
+ int status = sqlite3_open_v2(final_path.c_str(), &db, flags, nullptr);
103
99
 
104
- if (status != SQLITE_OK) {
105
- throw std::runtime_error(sqlite3_errmsg(db));
106
- }
100
+ if (status != SQLITE_OK) {
101
+ throw std::runtime_error(sqlite3_errmsg(db));
102
+ }
107
103
 
108
104
  #ifdef OP_SQLITE_USE_SQLCIPHER
109
- if (!encryption_key.empty()) {
110
- opsqlite_execute(db, "PRAGMA key = '" + encryption_key + "'", nullptr);
111
- }
105
+ if (!encryption_key.empty()) {
106
+ opsqlite_execute(db, "PRAGMA key = '" + encryption_key + "'", nullptr);
107
+ }
112
108
  #endif
113
109
 
114
110
  #ifndef OP_SQLITE_USE_PHONE_VERSION
115
- sqlite3_enable_load_extension(db, 1);
111
+ sqlite3_enable_load_extension(db, 1);
116
112
  #endif
117
113
 
118
114
  #ifdef OP_SQLITE_USE_CRSQLITE
119
- const char *crsqliteEntryPoint = "sqlite3_crsqlite_init";
115
+ const char *crsqliteEntryPoint = "sqlite3_crsqlite_init";
120
116
 
121
- sqlite3_load_extension(db, crsqlite_path.c_str(), crsqliteEntryPoint,
122
- &errMsg);
117
+ sqlite3_load_extension(db, crsqlite_path.c_str(), crsqliteEntryPoint,
118
+ &errMsg);
123
119
 
124
- if (errMsg != nullptr) {
125
- throw std::runtime_error(errMsg);
126
- }
120
+ if (errMsg != nullptr) {
121
+ throw std::runtime_error(errMsg);
122
+ }
127
123
  #endif
128
124
 
129
125
  #ifdef OP_SQLITE_USE_SQLITE_VEC
130
- const char *vec_entry_point = "sqlite3_vec_init";
126
+ const char *vec_entry_point = "sqlite3_vec_init";
131
127
 
132
- sqlite3_load_extension(db, sqlite_vec_path.c_str(), vec_entry_point,
133
- &errMsg);
128
+ sqlite3_load_extension(db, sqlite_vec_path.c_str(), vec_entry_point, &errMsg);
134
129
 
135
- if (errMsg != nullptr) {
136
- throw std::runtime_error(errMsg);
137
- }
130
+ if (errMsg != nullptr) {
131
+ throw std::runtime_error(errMsg);
132
+ }
138
133
  #endif
139
134
 
140
- TOKENIZER_LIST
135
+ TOKENIZER_LIST
141
136
 
142
- return db;
137
+ return db;
138
+ }
139
+
140
+ void create_dirs_if_needed(const std::string &path) {
141
+ if (path == ":memory:") {
142
+ return;
143
+ }
144
+
145
+ // Extract directory part from path (exclude filename)
146
+ std::filesystem::path fs_path(path);
147
+ auto dir = fs_path.parent_path();
148
+ if (!dir.empty()) {
149
+ std::filesystem::create_directories(dir);
150
+ }
143
151
  }
144
152
 
145
153
  void opsqlite_close(sqlite3 *db) {
146
154
  #ifdef OP_SQLITE_USE_CRSQLITE
147
- opsqlite_execute(db, "select crsql_finalize();", nullptr);
155
+ opsqlite_execute(db, "select crsql_finalize();", nullptr);
148
156
  #endif
149
157
 
150
- sqlite3_close_v2(db);
158
+ sqlite3_close_v2(db);
151
159
  }
152
160
 
153
161
  void opsqlite_attach(sqlite3 *db, std::string const &doc_path,
154
162
  std::string const &secondary_db_name,
155
163
  std::string const &alias) {
156
- auto secondary_db_path = opsqlite_get_db_path(secondary_db_name, doc_path);
157
- auto statement = "ATTACH DATABASE '" + secondary_db_path + "' AS " + alias;
164
+ auto secondary_db_path = opsqlite_get_db_path(secondary_db_name, doc_path);
165
+ auto statement = "ATTACH DATABASE '" + secondary_db_path + "' AS " + alias;
158
166
 
159
- opsqlite_execute(db, statement, nullptr);
167
+ opsqlite_execute(db, statement, nullptr);
160
168
  }
161
169
 
162
170
  void opsqlite_detach(sqlite3 *db, std::string const &alias) {
163
- std::string statement = "DETACH DATABASE " + alias;
164
- opsqlite_execute(db, statement, nullptr);
171
+ std::string statement = "DETACH DATABASE " + alias;
172
+ opsqlite_execute(db, statement, nullptr);
165
173
  }
166
174
 
167
175
  void opsqlite_remove(sqlite3 *db, std::string const &name,
168
176
  std::string const &doc_path) {
169
- opsqlite_close(db);
177
+ opsqlite_close(db);
170
178
 
171
- std::string db_path = opsqlite_get_db_path(name, doc_path);
179
+ std::string db_path = opsqlite_get_db_path(name, doc_path);
172
180
 
173
- if (!file_exists(db_path)) {
174
- throw std::runtime_error("op-sqlite: db file not found:" + db_path);
175
- }
181
+ if (!file_exists(db_path)) {
182
+ throw std::runtime_error("op-sqlite: db file not found:" + db_path);
183
+ }
184
+
185
+ remove(db_path.c_str());
186
+ }
187
+
188
+ void opsqlite_remove_v2(sqlite3 *db, std::string const &path) {
189
+ opsqlite_close(db);
176
190
 
177
- remove(db_path.c_str());
191
+ if (!file_exists(path)) {
192
+ throw std::runtime_error("[op-sqlite] db file not found: " + path);
193
+ }
194
+
195
+ remove(path.c_str());
178
196
  }
179
197
 
180
198
  BridgeResult opsqlite_execute_prepared_statement(
181
199
  sqlite3 *db, sqlite3_stmt *statement, std::vector<DumbHostObject> *results,
182
200
  std::shared_ptr<std::vector<SmartHostObject>> &metadatas) {
183
201
 
184
- const char *errorMessage;
202
+ const char *errorMessage;
185
203
 
186
- bool isConsuming = true;
187
- bool isFailed = false;
204
+ bool isConsuming = true;
205
+ bool isFailed = false;
188
206
 
189
- int result = SQLITE_OK;
207
+ int result = SQLITE_OK;
190
208
 
191
- int i, count, column_type;
192
- std::string column_name, column_declared_type;
209
+ int i, count, column_type;
210
+ std::string column_name, column_declared_type;
193
211
 
194
- while (isConsuming) {
195
- result = sqlite3_step(statement);
196
-
197
- switch (result) {
198
- case SQLITE_ROW: {
199
- i = 0;
200
- DumbHostObject row = DumbHostObject(metadatas);
201
-
202
- count = sqlite3_column_count(statement);
203
-
204
- while (i < count) {
205
- column_type = sqlite3_column_type(statement, i);
206
-
207
- switch (column_type) {
208
- case SQLITE_INTEGER: {
209
- /**
210
- * Warning this will loose precision because JS can
211
- * only represent Integers up to 53 bits
212
- */
213
- double column_value = sqlite3_column_double(statement, i);
214
- row.values.emplace_back(column_value);
215
- break;
216
- }
217
-
218
- case SQLITE_FLOAT: {
219
- double column_value = sqlite3_column_double(statement, i);
220
- row.values.emplace_back(column_value);
221
- break;
222
- }
223
-
224
- case SQLITE_TEXT: {
225
- const char *column_value = reinterpret_cast<const char *>(
226
- sqlite3_column_text(statement, i));
227
- int byteLen = sqlite3_column_bytes(statement, i);
228
- // Specify length too; in case string contains NULL in the
229
- // middle
230
- row.values.emplace_back(std::string(column_value, byteLen));
231
- break;
232
- }
233
-
234
- case SQLITE_BLOB: {
235
- int blob_size = sqlite3_column_bytes(statement, i);
236
- const void *blob = sqlite3_column_blob(statement, i);
237
- auto *data = new uint8_t[blob_size];
238
- // You cannot share raw memory between native and JS
239
- // always copy the data
240
- memcpy(data, blob, blob_size);
241
- row.values.emplace_back(
242
- ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
243
- .size = static_cast<size_t>(blob_size)});
244
- break;
245
- }
246
-
247
- case SQLITE_NULL:
248
- // Intentionally left blank
249
-
250
- default:
251
- row.values.emplace_back(nullptr);
252
- break;
253
- }
254
- i++;
255
- }
256
-
257
- results->emplace_back(row);
212
+ while (isConsuming) {
213
+ result = sqlite3_step(statement);
258
214
 
259
- break;
215
+ switch (result) {
216
+ case SQLITE_ROW: {
217
+ i = 0;
218
+ DumbHostObject row = DumbHostObject(metadatas);
219
+
220
+ count = sqlite3_column_count(statement);
221
+
222
+ while (i < count) {
223
+ column_type = sqlite3_column_type(statement, i);
224
+
225
+ switch (column_type) {
226
+ case SQLITE_INTEGER: {
227
+ /**
228
+ * Warning this will loose precision because JS can
229
+ * only represent Integers up to 53 bits
230
+ */
231
+ double column_value = sqlite3_column_double(statement, i);
232
+ row.values.emplace_back(column_value);
233
+ break;
260
234
  }
261
235
 
262
- case SQLITE_DONE:
263
- if (metadatas != nullptr) {
264
- i = 0;
265
- count = sqlite3_column_count(statement);
266
-
267
- while (i < count) {
268
- column_name = sqlite3_column_name(statement, i);
269
- const char *type = sqlite3_column_decltype(statement, i);
270
- auto metadata = SmartHostObject();
271
- metadata.fields.emplace_back("name", column_name);
272
- metadata.fields.emplace_back("index", i);
273
- metadata.fields.emplace_back(
274
- "type", type == nullptr ? "UNKNOWN" : type);
275
-
276
- metadatas->emplace_back(metadata);
277
- i++;
278
- }
279
- }
280
- isConsuming = false;
281
- break;
236
+ case SQLITE_FLOAT: {
237
+ double column_value = sqlite3_column_double(statement, i);
238
+ row.values.emplace_back(column_value);
239
+ break;
240
+ }
241
+
242
+ case SQLITE_TEXT: {
243
+ const char *column_value =
244
+ reinterpret_cast<const char *>(sqlite3_column_text(statement, i));
245
+ int byteLen = sqlite3_column_bytes(statement, i);
246
+ // Specify length too; in case string contains NULL in the
247
+ // middle
248
+ row.values.emplace_back(std::string(column_value, byteLen));
249
+ break;
250
+ }
251
+
252
+ case SQLITE_BLOB: {
253
+ int blob_size = sqlite3_column_bytes(statement, i);
254
+ const void *blob = sqlite3_column_blob(statement, i);
255
+ auto *data = new uint8_t[blob_size];
256
+ // You cannot share raw memory between native and JS
257
+ // always copy the data
258
+ memcpy(data, blob, blob_size);
259
+ row.values.emplace_back(
260
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
261
+ .size = static_cast<size_t>(blob_size)});
262
+ break;
263
+ }
264
+
265
+ case SQLITE_NULL:
266
+ // Intentionally left blank
282
267
 
283
268
  default:
284
- errorMessage = sqlite3_errmsg(db);
285
- isFailed = true;
286
- isConsuming = false;
269
+ row.values.emplace_back(nullptr);
270
+ break;
287
271
  }
272
+ i++;
273
+ }
274
+
275
+ results->emplace_back(row);
276
+
277
+ break;
288
278
  }
289
279
 
290
- sqlite3_reset(statement);
280
+ case SQLITE_DONE:
281
+ if (metadatas != nullptr) {
282
+ i = 0;
283
+ count = sqlite3_column_count(statement);
284
+
285
+ while (i < count) {
286
+ column_name = sqlite3_column_name(statement, i);
287
+ const char *type = sqlite3_column_decltype(statement, i);
288
+ auto metadata = SmartHostObject();
289
+ metadata.fields.emplace_back("name", column_name);
290
+ metadata.fields.emplace_back("index", i);
291
+ metadata.fields.emplace_back("type",
292
+ type == nullptr ? "UNKNOWN" : type);
293
+
294
+ metadatas->emplace_back(metadata);
295
+ i++;
296
+ }
297
+ }
298
+ isConsuming = false;
299
+ break;
291
300
 
292
- if (isFailed) {
293
- throw std::runtime_error(
294
- "[op-sqlite] SQLite code: " + std::to_string(result) +
295
- " execution error: " + std::string(errorMessage));
301
+ default:
302
+ errorMessage = sqlite3_errmsg(db);
303
+ isFailed = true;
304
+ isConsuming = false;
296
305
  }
306
+ }
307
+
308
+ sqlite3_reset(statement);
309
+
310
+ if (isFailed) {
311
+ throw std::runtime_error(
312
+ "[op-sqlite] SQLite code: " + std::to_string(result) +
313
+ " execution error: " + std::string(errorMessage));
314
+ }
297
315
 
298
- int changedRowCount = sqlite3_changes(db);
299
- long long latestInsertRowId = sqlite3_last_insert_rowid(db);
316
+ int changedRowCount = sqlite3_changes(db);
317
+ long long latestInsertRowId = sqlite3_last_insert_rowid(db);
300
318
 
301
- return {.affectedRows = changedRowCount,
302
- .insertId = static_cast<double>(latestInsertRowId)};
319
+ return {.affectedRows = changedRowCount,
320
+ .insertId = static_cast<double>(latestInsertRowId)};
303
321
  }
304
322
 
305
323
  sqlite3_stmt *opsqlite_prepare_statement(sqlite3 *db,
306
324
  std::string const &query) {
307
- sqlite3_stmt *statement;
325
+ sqlite3_stmt *statement;
308
326
 
309
- const char *queryStr = query.c_str();
327
+ const char *queryStr = query.c_str();
310
328
 
311
- int statementStatus =
312
- sqlite3_prepare_v2(db, queryStr, -1, &statement, nullptr);
329
+ int statementStatus =
330
+ sqlite3_prepare_v2(db, queryStr, -1, &statement, nullptr);
313
331
 
314
- if (statementStatus == SQLITE_ERROR) {
315
- const char *message = sqlite3_errmsg(db);
316
- throw std::runtime_error("[op-sqlite] SQL prepare statement error: " +
317
- std::string(message));
318
- }
332
+ if (statementStatus == SQLITE_ERROR) {
333
+ const char *message = sqlite3_errmsg(db);
334
+ throw std::runtime_error("[op-sqlite] SQL prepare statement error: " +
335
+ std::string(message));
336
+ }
319
337
 
320
- return statement;
338
+ return statement;
321
339
  }
322
340
 
323
341
  BridgeResult opsqlite_execute(sqlite3 *db, std::string const &query,
324
342
  const std::vector<JSVariant> *params) {
325
- sqlite3_stmt *statement;
326
- const char *errorMessage = nullptr;
327
- const char *remainingStatement = nullptr;
328
- bool has_failed = false;
329
- int status, current_column, column_count, column_type;
330
- std::string column_name, column_declared_type;
331
- std::vector<std::string> column_names;
332
- std::vector<std::vector<JSVariant>> rows;
333
- rows.reserve(20);
334
- std::vector<JSVariant> row;
335
-
336
- do {
337
- const char *query_str =
338
- remainingStatement == nullptr ? query.c_str() : remainingStatement;
339
-
340
- status = sqlite3_prepare_v2(db, query_str, -1, &statement,
341
- &remainingStatement);
342
-
343
- if (status != SQLITE_OK) {
344
- errorMessage = sqlite3_errmsg(db);
345
- throw std::runtime_error("[op-sqlite] sqlite query error: " +
346
- std::string(errorMessage));
347
- }
343
+ sqlite3_stmt *statement;
344
+ const char *errorMessage = nullptr;
345
+ const char *remainingStatement = nullptr;
346
+ bool has_failed = false;
347
+ int status, current_column, column_count, column_type;
348
+ std::string column_name, column_declared_type;
349
+ std::vector<std::string> column_names;
350
+ std::vector<std::vector<JSVariant>> rows;
351
+ rows.reserve(20);
352
+ std::vector<JSVariant> row;
353
+
354
+ do {
355
+ const char *query_str =
356
+ remainingStatement == nullptr ? query.c_str() : remainingStatement;
357
+
358
+ status =
359
+ sqlite3_prepare_v2(db, query_str, -1, &statement, &remainingStatement);
348
360
 
349
- // The statement did not fail to parse but there is nothing to do, just
350
- // skip to the end
351
- if (statement == nullptr) {
352
- continue;
353
- }
361
+ if (status != SQLITE_OK) {
362
+ errorMessage = sqlite3_errmsg(db);
363
+ throw std::runtime_error("[op-sqlite] sqlite query error: " +
364
+ std::string(errorMessage));
365
+ }
354
366
 
355
- if (params != nullptr && !params->empty()) {
356
- opsqlite_bind_statement(statement, params);
357
- }
367
+ // The statement did not fail to parse but there is nothing to do, just
368
+ // skip to the end
369
+ if (statement == nullptr) {
370
+ continue;
371
+ }
358
372
 
359
- column_count = sqlite3_column_count(statement);
360
- column_names.reserve(column_count);
361
- bool is_consuming_rows = true;
362
- double double_value;
363
- const char *string_value;
373
+ if (params != nullptr && !params->empty()) {
374
+ opsqlite_bind_statement(statement, params);
375
+ }
364
376
 
365
- // Do a first pass to get the column names
366
- for (int i = 0; i < column_count; i++) {
367
- column_name = sqlite3_column_name(statement, i);
368
- column_names.emplace_back(column_name);
369
- }
377
+ column_count = sqlite3_column_count(statement);
378
+ column_names.reserve(column_count);
379
+ bool is_consuming_rows = true;
380
+ double double_value;
381
+ const char *string_value;
382
+
383
+ // Do a first pass to get the column names
384
+ for (int i = 0; i < column_count; i++) {
385
+ column_name = sqlite3_column_name(statement, i);
386
+ column_names.emplace_back(column_name);
387
+ }
388
+
389
+ while (is_consuming_rows) {
390
+ status = sqlite3_step(statement);
370
391
 
371
- while (is_consuming_rows) {
372
- status = sqlite3_step(statement);
373
-
374
- switch (status) {
375
- case SQLITE_ROW:
376
- current_column = 0;
377
- row = std::vector<JSVariant>();
378
- row.reserve(column_count);
379
-
380
- while (current_column < column_count) {
381
- column_type =
382
- sqlite3_column_type(statement, current_column);
383
-
384
- switch (column_type) {
385
-
386
- case SQLITE_INTEGER:
387
- // intentional fallthrough
388
- case SQLITE_FLOAT: {
389
- double_value =
390
- sqlite3_column_double(statement, current_column);
391
- row.emplace_back(double_value);
392
- break;
393
- }
394
-
395
- case SQLITE_TEXT: {
396
- string_value = reinterpret_cast<const char *>(
397
- sqlite3_column_text(statement, current_column));
398
- int len =
399
- sqlite3_column_bytes(statement, current_column);
400
- // Specify length too; in case string contains NULL in
401
- // the middle
402
- row.emplace_back(std::string(string_value, len));
403
- break;
404
- }
405
-
406
- case SQLITE_BLOB: {
407
- int blob_size =
408
- sqlite3_column_bytes(statement, current_column);
409
- const void *blob =
410
- sqlite3_column_blob(statement, current_column);
411
- auto *data = new uint8_t[blob_size];
412
- memcpy(data, blob, blob_size);
413
- row.emplace_back(ArrayBuffer{
414
- .data = std::shared_ptr<uint8_t>{data},
392
+ switch (status) {
393
+ case SQLITE_ROW:
394
+ current_column = 0;
395
+ row = std::vector<JSVariant>();
396
+ row.reserve(column_count);
397
+
398
+ while (current_column < column_count) {
399
+ column_type = sqlite3_column_type(statement, current_column);
400
+
401
+ switch (column_type) {
402
+
403
+ case SQLITE_INTEGER:
404
+ // intentional fallthrough
405
+ case SQLITE_FLOAT: {
406
+ double_value = sqlite3_column_double(statement, current_column);
407
+ row.emplace_back(double_value);
408
+ break;
409
+ }
410
+
411
+ case SQLITE_TEXT: {
412
+ string_value = reinterpret_cast<const char *>(
413
+ sqlite3_column_text(statement, current_column));
414
+ int len = sqlite3_column_bytes(statement, current_column);
415
+ // Specify length too; in case string contains NULL in
416
+ // the middle
417
+ row.emplace_back(std::string(string_value, len));
418
+ break;
419
+ }
420
+
421
+ case SQLITE_BLOB: {
422
+ int blob_size = sqlite3_column_bytes(statement, current_column);
423
+ const void *blob = sqlite3_column_blob(statement, current_column);
424
+ auto *data = new uint8_t[blob_size];
425
+ memcpy(data, blob, blob_size);
426
+ row.emplace_back(
427
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
415
428
  .size = static_cast<size_t>(blob_size)});
416
- break;
417
- }
418
-
419
- case SQLITE_NULL:
420
- // Intentionally left blank to switch to default case
421
- default:
422
- row.emplace_back(nullptr);
423
- break;
424
- }
425
-
426
- current_column++;
427
- }
428
-
429
- rows.emplace_back(std::move(row));
430
- break;
431
-
432
- case SQLITE_DONE:
433
- is_consuming_rows = false;
434
- break;
435
-
436
- default:
437
- has_failed = true;
438
- is_consuming_rows = false;
439
- }
429
+ break;
430
+ }
431
+
432
+ case SQLITE_NULL:
433
+ // Intentionally left blank to switch to default case
434
+ default:
435
+ row.emplace_back(nullptr);
436
+ break;
437
+ }
438
+
439
+ current_column++;
440
440
  }
441
441
 
442
- sqlite3_finalize(statement);
443
- } while (remainingStatement != nullptr &&
444
- strcmp(remainingStatement, "") != 0 && !has_failed);
442
+ rows.emplace_back(std::move(row));
443
+ break;
444
+
445
+ case SQLITE_DONE:
446
+ is_consuming_rows = false;
447
+ break;
445
448
 
446
- if (has_failed) {
447
- const char *message = sqlite3_errmsg(db);
448
- throw std::runtime_error("[op-sqlite] statement execution error: " +
449
- std::string(message));
449
+ default:
450
+ has_failed = true;
451
+ is_consuming_rows = false;
452
+ }
450
453
  }
451
454
 
452
- int changedRowCount = sqlite3_changes(db);
453
- long long latestInsertRowId = sqlite3_last_insert_rowid(db);
454
- return {.affectedRows = changedRowCount,
455
- .insertId = static_cast<double>(latestInsertRowId),
456
- .rows = std::move(rows),
457
- .column_names = std::move(column_names)};
455
+ sqlite3_finalize(statement);
456
+ } while (remainingStatement != nullptr &&
457
+ strcmp(remainingStatement, "") != 0 && !has_failed);
458
+
459
+ if (has_failed) {
460
+ const char *message = sqlite3_errmsg(db);
461
+ throw std::runtime_error("[op-sqlite] statement execution error: " +
462
+ std::string(message));
463
+ }
464
+
465
+ int changedRowCount = sqlite3_changes(db);
466
+ long long latestInsertRowId = sqlite3_last_insert_rowid(db);
467
+ return {.affectedRows = changedRowCount,
468
+ .insertId = static_cast<double>(latestInsertRowId),
469
+ .rows = std::move(rows),
470
+ .column_names = std::move(column_names)};
458
471
  }
459
472
 
460
473
  BridgeResult opsqlite_execute_host_objects(
@@ -462,162 +475,157 @@ BridgeResult opsqlite_execute_host_objects(
462
475
  std::vector<DumbHostObject> *results,
463
476
  std::shared_ptr<std::vector<SmartHostObject>> &metadatas) {
464
477
 
465
- sqlite3_stmt *statement;
466
- const char *errorMessage;
467
- const char *remainingStatement = nullptr;
478
+ sqlite3_stmt *statement;
479
+ const char *errorMessage;
480
+ const char *remainingStatement = nullptr;
481
+
482
+ bool isConsuming = true;
483
+ bool isFailed = false;
468
484
 
469
- bool isConsuming = true;
470
- bool isFailed = false;
485
+ int result = SQLITE_OK;
471
486
 
472
- int result = SQLITE_OK;
487
+ do {
488
+ const char *queryStr =
489
+ remainingStatement == nullptr ? query.c_str() : remainingStatement;
473
490
 
474
- do {
475
- const char *queryStr =
476
- remainingStatement == nullptr ? query.c_str() : remainingStatement;
491
+ int statementStatus =
492
+ sqlite3_prepare_v2(db, queryStr, -1, &statement, &remainingStatement);
493
+
494
+ if (statementStatus != SQLITE_OK) {
495
+ const char *message = sqlite3_errmsg(db);
496
+ throw std::runtime_error(
497
+ "[op-sqlite] SQL statement error on opsqlite_execute:\n" +
498
+ std::to_string(statementStatus) + " description:\n" +
499
+ std::string(message));
500
+ }
477
501
 
478
- int statementStatus = sqlite3_prepare_v2(db, queryStr, -1, &statement,
479
- &remainingStatement);
502
+ // The statement did not fail to parse but there is nothing to do, just
503
+ // skip to the end
504
+ if (statement == nullptr) {
505
+ continue;
506
+ }
480
507
 
481
- if (statementStatus != SQLITE_OK) {
482
- const char *message = sqlite3_errmsg(db);
483
- throw std::runtime_error(
484
- "[op-sqlite] SQL statement error on opsqlite_execute:\n" +
485
- std::to_string(statementStatus) + " description:\n" +
486
- std::string(message));
487
- }
508
+ if (params != nullptr && !params->empty()) {
509
+ opsqlite_bind_statement(statement, params);
510
+ }
488
511
 
489
- // The statement did not fail to parse but there is nothing to do, just
490
- // skip to the end
491
- if (statement == nullptr) {
492
- continue;
493
- }
512
+ int i, count, column_type;
513
+ std::string column_name, column_declared_type;
494
514
 
495
- if (params != nullptr && !params->empty()) {
496
- opsqlite_bind_statement(statement, params);
515
+ while (isConsuming) {
516
+ result = sqlite3_step(statement);
517
+
518
+ switch (result) {
519
+ case SQLITE_ROW: {
520
+ if (results == nullptr) {
521
+ break;
497
522
  }
498
523
 
499
- int i, count, column_type;
500
- std::string column_name, column_declared_type;
501
-
502
- while (isConsuming) {
503
- result = sqlite3_step(statement);
504
-
505
- switch (result) {
506
- case SQLITE_ROW: {
507
- if (results == nullptr) {
508
- break;
509
- }
510
-
511
- i = 0;
512
- DumbHostObject row = DumbHostObject(metadatas);
513
-
514
- count = sqlite3_column_count(statement);
515
-
516
- while (i < count) {
517
- column_type = sqlite3_column_type(statement, i);
518
-
519
- switch (column_type) {
520
- case SQLITE_INTEGER: {
521
- /**
522
- * Warning this will loose precision because JS can
523
- * only represent Integers up to 53 bits
524
- */
525
- double column_value =
526
- sqlite3_column_double(statement, i);
527
- row.values.emplace_back(column_value);
528
- break;
529
- }
530
-
531
- case SQLITE_FLOAT: {
532
- double column_value =
533
- sqlite3_column_double(statement, i);
534
- row.values.emplace_back(column_value);
535
- break;
536
- }
537
-
538
- case SQLITE_TEXT: {
539
- const char *column_value =
540
- reinterpret_cast<const char *>(
541
- sqlite3_column_text(statement, i));
542
- int byteLen = sqlite3_column_bytes(statement, i);
543
- // Specify length too; in case string contains NULL in
544
- // the middle
545
- row.values.emplace_back(
546
- std::string(column_value, byteLen));
547
- break;
548
- }
549
-
550
- case SQLITE_BLOB: {
551
- int blob_size = sqlite3_column_bytes(statement, i);
552
- const void *blob = sqlite3_column_blob(statement, i);
553
- auto *data = new uint8_t[blob_size];
554
- // You cannot share raw memory between native and JS
555
- // always copy the data
556
- memcpy(data, blob, blob_size);
557
- row.values.emplace_back(ArrayBuffer{
558
- .data = std::shared_ptr<uint8_t>{data},
524
+ i = 0;
525
+ DumbHostObject row = DumbHostObject(metadatas);
526
+
527
+ count = sqlite3_column_count(statement);
528
+
529
+ while (i < count) {
530
+ column_type = sqlite3_column_type(statement, i);
531
+
532
+ switch (column_type) {
533
+ case SQLITE_INTEGER: {
534
+ /**
535
+ * Warning this will loose precision because JS can
536
+ * only represent Integers up to 53 bits
537
+ */
538
+ double column_value = sqlite3_column_double(statement, i);
539
+ row.values.emplace_back(column_value);
540
+ break;
541
+ }
542
+
543
+ case SQLITE_FLOAT: {
544
+ double column_value = sqlite3_column_double(statement, i);
545
+ row.values.emplace_back(column_value);
546
+ break;
547
+ }
548
+
549
+ case SQLITE_TEXT: {
550
+ const char *column_value = reinterpret_cast<const char *>(
551
+ sqlite3_column_text(statement, i));
552
+ int byteLen = sqlite3_column_bytes(statement, i);
553
+ // Specify length too; in case string contains NULL in
554
+ // the middle
555
+ row.values.emplace_back(std::string(column_value, byteLen));
556
+ break;
557
+ }
558
+
559
+ case SQLITE_BLOB: {
560
+ int blob_size = sqlite3_column_bytes(statement, i);
561
+ const void *blob = sqlite3_column_blob(statement, i);
562
+ auto *data = new uint8_t[blob_size];
563
+ // You cannot share raw memory between native and JS
564
+ // always copy the data
565
+ memcpy(data, blob, blob_size);
566
+ row.values.emplace_back(
567
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
559
568
  .size = static_cast<size_t>(blob_size)});
560
- break;
561
- }
562
-
563
- case SQLITE_NULL:
564
- // Intentionally left blank
565
-
566
- default:
567
- row.values.emplace_back(nullptr);
568
- break;
569
- }
570
- i++;
571
- }
572
-
573
- results->emplace_back(row);
574
- break;
575
- }
576
-
577
- case SQLITE_DONE:
578
- if (metadatas != nullptr) {
579
- i = 0;
580
- count = sqlite3_column_count(statement);
581
-
582
- while (i < count) {
583
- column_name = sqlite3_column_name(statement, i);
584
- const char *type =
585
- sqlite3_column_decltype(statement, i);
586
- auto metadata = SmartHostObject();
587
- metadata.fields.emplace_back("name", column_name);
588
- metadata.fields.emplace_back("index", i);
589
- metadata.fields.emplace_back(
590
- "type", type == nullptr ? "UNKNOWN" : type);
591
-
592
- metadatas->push_back(metadata);
593
- i++;
594
- }
595
- }
596
- isConsuming = false;
597
- break;
598
-
599
- default:
600
- errorMessage = sqlite3_errmsg(db);
601
- isFailed = true;
602
- isConsuming = false;
603
- }
569
+ break;
570
+ }
571
+
572
+ case SQLITE_NULL:
573
+ // Intentionally left blank
574
+
575
+ default:
576
+ row.values.emplace_back(nullptr);
577
+ break;
578
+ }
579
+ i++;
604
580
  }
605
581
 
606
- sqlite3_finalize(statement);
607
- } while (remainingStatement != nullptr &&
608
- strcmp(remainingStatement, "") != 0 && !isFailed);
582
+ results->emplace_back(row);
583
+ break;
584
+ }
585
+
586
+ case SQLITE_DONE:
587
+ if (metadatas != nullptr) {
588
+ i = 0;
589
+ count = sqlite3_column_count(statement);
609
590
 
610
- if (isFailed) {
611
- throw std::runtime_error(
612
- "[op-sqlite] SQLite error code: " + std::to_string(result) +
613
- ", description: " + std::string(errorMessage));
591
+ while (i < count) {
592
+ column_name = sqlite3_column_name(statement, i);
593
+ const char *type = sqlite3_column_decltype(statement, i);
594
+ auto metadata = SmartHostObject();
595
+ metadata.fields.emplace_back("name", column_name);
596
+ metadata.fields.emplace_back("index", i);
597
+ metadata.fields.emplace_back("type",
598
+ type == nullptr ? "UNKNOWN" : type);
599
+
600
+ metadatas->push_back(metadata);
601
+ i++;
602
+ }
603
+ }
604
+ isConsuming = false;
605
+ break;
606
+
607
+ default:
608
+ errorMessage = sqlite3_errmsg(db);
609
+ isFailed = true;
610
+ isConsuming = false;
611
+ }
614
612
  }
615
613
 
616
- int changedRowCount = sqlite3_changes(db);
617
- long long latestInsertRowId = sqlite3_last_insert_rowid(db);
614
+ sqlite3_finalize(statement);
615
+ } while (remainingStatement != nullptr &&
616
+ strcmp(remainingStatement, "") != 0 && !isFailed);
618
617
 
619
- return {.affectedRows = changedRowCount,
620
- .insertId = static_cast<double>(latestInsertRowId)};
618
+ if (isFailed) {
619
+ throw std::runtime_error(
620
+ "[op-sqlite] SQLite error code: " + std::to_string(result) +
621
+ ", description: " + std::string(errorMessage));
622
+ }
623
+
624
+ int changedRowCount = sqlite3_changes(db);
625
+ long long latestInsertRowId = sqlite3_last_insert_rowid(db);
626
+
627
+ return {.affectedRows = changedRowCount,
628
+ .insertId = static_cast<double>(latestInsertRowId)};
621
629
  }
622
630
 
623
631
  /// Executes returning data in raw arrays, a small performance optimization
@@ -626,245 +634,243 @@ BridgeResult
626
634
  opsqlite_execute_raw(sqlite3 *db, std::string const &query,
627
635
  const std::vector<JSVariant> *params,
628
636
  std::vector<std::vector<JSVariant>> *results) {
629
- sqlite3_stmt *statement;
630
- const char *errorMessage;
631
- const char *remainingStatement = nullptr;
637
+ sqlite3_stmt *statement;
638
+ const char *errorMessage;
639
+ const char *remainingStatement = nullptr;
632
640
 
633
- bool isConsuming = true;
634
- bool isFailed = false;
641
+ bool isConsuming = true;
642
+ bool isFailed = false;
635
643
 
636
- int step = SQLITE_OK;
644
+ int step = SQLITE_OK;
637
645
 
638
- do {
639
- const char *queryStr =
640
- remainingStatement == nullptr ? query.c_str() : remainingStatement;
646
+ do {
647
+ const char *queryStr =
648
+ remainingStatement == nullptr ? query.c_str() : remainingStatement;
641
649
 
642
- int statementStatus = sqlite3_prepare_v2(db, queryStr, -1, &statement,
643
- &remainingStatement);
650
+ int statementStatus =
651
+ sqlite3_prepare_v2(db, queryStr, -1, &statement, &remainingStatement);
644
652
 
645
- if (statementStatus != SQLITE_OK) {
646
- const char *message = sqlite3_errmsg(db);
647
- throw std::runtime_error("[op-sqlite] SQL statement error:" +
648
- std::to_string(statementStatus) +
649
- " description:" + std::string(message));
650
- }
653
+ if (statementStatus != SQLITE_OK) {
654
+ const char *message = sqlite3_errmsg(db);
655
+ throw std::runtime_error(
656
+ "[op-sqlite] SQL statement error:" + std::to_string(statementStatus) +
657
+ " description:" + std::string(message));
658
+ }
651
659
 
652
- // The statement did not fail to parse but there is nothing to do, just
653
- // skip to the end
654
- if (statement == nullptr) {
655
- continue;
656
- }
660
+ // The statement did not fail to parse but there is nothing to do, just
661
+ // skip to the end
662
+ if (statement == nullptr) {
663
+ continue;
664
+ }
657
665
 
658
- if (params != nullptr && !params->empty()) {
659
- opsqlite_bind_statement(statement, params);
666
+ if (params != nullptr && !params->empty()) {
667
+ opsqlite_bind_statement(statement, params);
668
+ }
669
+
670
+ int i, column_type;
671
+ std::string column_name, column_declared_type;
672
+
673
+ int column_count = sqlite3_column_count(statement);
674
+
675
+ while (isConsuming) {
676
+ step = sqlite3_step(statement);
677
+
678
+ switch (step) {
679
+ case SQLITE_ROW: {
680
+ if (results == nullptr) {
681
+ break;
660
682
  }
661
683
 
662
- int i, column_type;
663
- std::string column_name, column_declared_type;
664
-
665
- int column_count = sqlite3_column_count(statement);
666
-
667
- while (isConsuming) {
668
- step = sqlite3_step(statement);
669
-
670
- switch (step) {
671
- case SQLITE_ROW: {
672
- if (results == nullptr) {
673
- break;
674
- }
675
-
676
- std::vector<JSVariant> row;
677
- row.reserve(column_count);
678
-
679
- i = 0;
680
-
681
- while (i < column_count) {
682
- column_type = sqlite3_column_type(statement, i);
683
-
684
- switch (column_type) {
685
- case SQLITE_INTEGER:
686
- case SQLITE_FLOAT: {
687
- double column_value =
688
- sqlite3_column_double(statement, i);
689
- row.emplace_back(column_value);
690
- break;
691
- }
692
-
693
- case SQLITE_TEXT: {
694
- const char *column_value =
695
- reinterpret_cast<const char *>(
696
- sqlite3_column_text(statement, i));
697
- int byteLen = sqlite3_column_bytes(statement, i);
698
- // Specify length too; in case string contains NULL in
699
- // the middle
700
- row.emplace_back(std::string(column_value, byteLen));
701
- break;
702
- }
703
-
704
- case SQLITE_BLOB: {
705
- int blob_size = sqlite3_column_bytes(statement, i);
706
- const void *blob = sqlite3_column_blob(statement, i);
707
- auto *data = new uint8_t[blob_size];
708
- memcpy(data, blob, blob_size);
709
- row.emplace_back(ArrayBuffer{
710
- .data = std::shared_ptr<uint8_t>{data},
684
+ std::vector<JSVariant> row;
685
+ row.reserve(column_count);
686
+
687
+ i = 0;
688
+
689
+ while (i < column_count) {
690
+ column_type = sqlite3_column_type(statement, i);
691
+
692
+ switch (column_type) {
693
+ case SQLITE_INTEGER:
694
+ case SQLITE_FLOAT: {
695
+ double column_value = sqlite3_column_double(statement, i);
696
+ row.emplace_back(column_value);
697
+ break;
698
+ }
699
+
700
+ case SQLITE_TEXT: {
701
+ const char *column_value = reinterpret_cast<const char *>(
702
+ sqlite3_column_text(statement, i));
703
+ int byteLen = sqlite3_column_bytes(statement, i);
704
+ // Specify length too; in case string contains NULL in
705
+ // the middle
706
+ row.emplace_back(std::string(column_value, byteLen));
707
+ break;
708
+ }
709
+
710
+ case SQLITE_BLOB: {
711
+ int blob_size = sqlite3_column_bytes(statement, i);
712
+ const void *blob = sqlite3_column_blob(statement, i);
713
+ auto *data = new uint8_t[blob_size];
714
+ memcpy(data, blob, blob_size);
715
+ row.emplace_back(
716
+ ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
711
717
  .size = static_cast<size_t>(blob_size)});
712
- break;
713
- }
714
-
715
- case SQLITE_NULL:
716
- // intentional fallthrough
717
- default:
718
- row.emplace_back(nullptr);
719
- break;
720
- }
721
- i++;
722
- }
723
-
724
- results->emplace_back(row);
725
-
726
- break;
727
- }
728
-
729
- case SQLITE_DONE:
730
- isConsuming = false;
731
- break;
732
-
733
- default:
734
- errorMessage = sqlite3_errmsg(db);
735
- isFailed = true;
736
- isConsuming = false;
737
- }
718
+ break;
719
+ }
720
+
721
+ case SQLITE_NULL:
722
+ // intentional fallthrough
723
+ default:
724
+ row.emplace_back(nullptr);
725
+ break;
726
+ }
727
+ i++;
738
728
  }
739
729
 
740
- sqlite3_finalize(statement);
741
- } while (remainingStatement != nullptr &&
742
- strcmp(remainingStatement, "") != 0 && !isFailed);
730
+ results->emplace_back(row);
743
731
 
744
- if (isFailed) {
745
- throw std::runtime_error(
746
- "[op-sqlite] SQLite error code: " + std::to_string(step) +
747
- ", description: " + std::string(errorMessage));
732
+ break;
733
+ }
734
+
735
+ case SQLITE_DONE:
736
+ isConsuming = false;
737
+ break;
738
+
739
+ default:
740
+ errorMessage = sqlite3_errmsg(db);
741
+ isFailed = true;
742
+ isConsuming = false;
743
+ }
748
744
  }
749
745
 
750
- int changedRowCount = sqlite3_changes(db);
751
- long long latestInsertRowId = sqlite3_last_insert_rowid(db);
746
+ sqlite3_finalize(statement);
747
+ } while (remainingStatement != nullptr &&
748
+ strcmp(remainingStatement, "") != 0 && !isFailed);
749
+
750
+ if (isFailed) {
751
+ throw std::runtime_error(
752
+ "[op-sqlite] SQLite error code: " + std::to_string(step) +
753
+ ", description: " + std::string(errorMessage));
754
+ }
755
+
756
+ int changedRowCount = sqlite3_changes(db);
757
+ long long latestInsertRowId = sqlite3_last_insert_rowid(db);
752
758
 
753
- return {.affectedRows = changedRowCount,
754
- .insertId = static_cast<double>(latestInsertRowId)};
759
+ return {.affectedRows = changedRowCount,
760
+ .insertId = static_cast<double>(latestInsertRowId)};
755
761
  }
756
762
 
757
763
  std::string operation_to_string(int operation_type) {
758
- switch (operation_type) {
759
- case SQLITE_INSERT:
760
- return "INSERT";
764
+ switch (operation_type) {
765
+ case SQLITE_INSERT:
766
+ return "INSERT";
761
767
 
762
- case SQLITE_DELETE:
763
- return "DELETE";
768
+ case SQLITE_DELETE:
769
+ return "DELETE";
764
770
 
765
- case SQLITE_UPDATE:
766
- return "UPDATE";
771
+ case SQLITE_UPDATE:
772
+ return "UPDATE";
767
773
 
768
- default:
769
- throw std::runtime_error("Unknown SQLite operation on hook");
770
- }
774
+ default:
775
+ throw std::runtime_error("Unknown SQLite operation on hook");
776
+ }
771
777
  }
772
778
 
773
779
  void update_callback(void *db_host_object_ptr, int operation_type,
774
780
  [[maybe_unused]] char const *database, char const *table,
775
781
  sqlite3_int64 row_id) {
776
- auto db_host_object = reinterpret_cast<DBHostObject *>(db_host_object_ptr);
777
- db_host_object->on_update(std::string(table),
778
- operation_to_string(operation_type), row_id);
782
+ auto db_host_object = reinterpret_cast<DBHostObject *>(db_host_object_ptr);
783
+ db_host_object->on_update(std::string(table),
784
+ operation_to_string(operation_type), row_id);
779
785
  }
780
786
 
781
787
  void opsqlite_register_update_hook(sqlite3 *db, void *db_host_object) {
782
- sqlite3_update_hook(db, &update_callback, (void *)db_host_object);
788
+ sqlite3_update_hook(db, &update_callback, (void *)db_host_object);
783
789
  }
784
790
 
785
791
  void opsqlite_deregister_update_hook(sqlite3 *db) {
786
- sqlite3_update_hook(db, nullptr, nullptr);
792
+ sqlite3_update_hook(db, nullptr, nullptr);
787
793
  }
788
794
 
789
795
  int commit_callback(void *db_host_object_ptr) {
790
- auto db_host_object = reinterpret_cast<DBHostObject *>(db_host_object_ptr);
791
- db_host_object->on_commit();
792
- return 0;
796
+ auto db_host_object = reinterpret_cast<DBHostObject *>(db_host_object_ptr);
797
+ db_host_object->on_commit();
798
+ return 0;
793
799
  }
794
800
 
795
801
  void opsqlite_register_commit_hook(sqlite3 *db, void *db_host_object_ptr) {
796
- sqlite3_commit_hook(db, &commit_callback, db_host_object_ptr);
802
+ sqlite3_commit_hook(db, &commit_callback, db_host_object_ptr);
797
803
  }
798
804
 
799
805
  void opsqlite_deregister_commit_hook(sqlite3 *db) {
800
- sqlite3_commit_hook(db, nullptr, nullptr);
806
+ sqlite3_commit_hook(db, nullptr, nullptr);
801
807
  }
802
808
 
803
809
  void rollback_callback(void *db_host_object_ptr) {
804
- auto db_host_object = reinterpret_cast<DBHostObject *>(db_host_object_ptr);
805
- db_host_object->on_rollback();
810
+ auto db_host_object = reinterpret_cast<DBHostObject *>(db_host_object_ptr);
811
+ db_host_object->on_rollback();
806
812
  }
807
813
 
808
814
  void opsqlite_register_rollback_hook(sqlite3 *db, void *db_host_object_ptr) {
809
- sqlite3_rollback_hook(db, &rollback_callback, db_host_object_ptr);
815
+ sqlite3_rollback_hook(db, &rollback_callback, db_host_object_ptr);
810
816
  }
811
817
 
812
818
  void opsqlite_deregister_rollback_hook(sqlite3 *db) {
813
- sqlite3_rollback_hook(db, nullptr, nullptr);
819
+ sqlite3_rollback_hook(db, nullptr, nullptr);
814
820
  }
815
821
 
816
822
  void opsqlite_load_extension(sqlite3 *db, std::string &path,
817
823
  std::string &entry_point) {
818
824
  #ifdef OP_SQLITE_USE_PHONE_VERSION
819
- throw std::runtime_error("[op-sqlite] Embedded version of SQLite does not "
820
- "support loading extensions");
825
+ throw std::runtime_error("[op-sqlite] Embedded version of SQLite does not "
826
+ "support loading extensions");
821
827
  #else
822
- int status = 0;
823
- status = sqlite3_enable_load_extension(db, 1);
828
+ int status = 0;
829
+ status = sqlite3_enable_load_extension(db, 1);
824
830
 
825
- if (status != SQLITE_OK) {
826
- throw std::runtime_error("Could not enable extension loading");
827
- }
831
+ if (status != SQLITE_OK) {
832
+ throw std::runtime_error("Could not enable extension loading");
833
+ }
828
834
 
829
- const char *entry_point_cstr = nullptr;
830
- if (!entry_point.empty()) {
831
- entry_point_cstr = entry_point.c_str();
832
- }
835
+ const char *entry_point_cstr = nullptr;
836
+ if (!entry_point.empty()) {
837
+ entry_point_cstr = entry_point.c_str();
838
+ }
833
839
 
834
- char *error_message;
840
+ char *error_message;
835
841
 
836
- status = sqlite3_load_extension(db, path.c_str(), entry_point_cstr,
837
- &error_message);
838
- if (status != SQLITE_OK) {
839
- throw std::runtime_error(error_message);
840
- }
842
+ status = sqlite3_load_extension(db, path.c_str(), entry_point_cstr,
843
+ &error_message);
844
+ if (status != SQLITE_OK) {
845
+ throw std::runtime_error(error_message);
846
+ }
841
847
  #endif
842
848
  }
843
849
 
844
850
  BatchResult
845
851
  opsqlite_execute_batch(sqlite3 *db,
846
852
  const std::vector<BatchArguments> *commands) {
847
- size_t commandCount = commands->size();
848
- if (commandCount <= 0) {
849
- throw std::runtime_error("No SQL commands provided");
850
- }
851
-
852
- int affectedRows = 0;
853
- // opsqlite_execute(db, "BEGIN EXCLUSIVE TRANSACTION", nullptr);
854
- for (int i = 0; i < commandCount; i++) {
855
- const auto &command = commands->at(i);
856
- // We do not provide a datastructure to receive query data because we
857
- // don't need/want to handle this results in a batch execution
858
- // There is also no need to commit/catch this transaction, this is done
859
- // in the JS code
860
- auto result = opsqlite_execute(db, command.sql, &command.params);
861
- affectedRows += result.affectedRows;
862
- }
863
-
864
- return BatchResult{
865
- .affectedRows = affectedRows,
866
- .commands = static_cast<int>(commandCount),
867
- };
853
+ size_t commandCount = commands->size();
854
+ if (commandCount <= 0) {
855
+ throw std::runtime_error("No SQL commands provided");
856
+ }
857
+
858
+ int affectedRows = 0;
859
+ // opsqlite_execute(db, "BEGIN EXCLUSIVE TRANSACTION", nullptr);
860
+ for (int i = 0; i < commandCount; i++) {
861
+ const auto &command = commands->at(i);
862
+ // We do not provide a datastructure to receive query data because we
863
+ // don't need/want to handle this results in a batch execution
864
+ // There is also no need to commit/catch this transaction, this is done
865
+ // in the JS code
866
+ auto result = opsqlite_execute(db, command.sql, &command.params);
867
+ affectedRows += result.affectedRows;
868
+ }
869
+
870
+ return BatchResult{
871
+ .affectedRows = affectedRows,
872
+ .commands = static_cast<int>(commandCount),
873
+ };
868
874
  }
869
875
 
870
876
  } // namespace opsqlite