@op-engineering/op-sqlite 7.4.3 → 8.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.
- package/README.md +11 -3
- package/android/build.gradle +8 -0
- package/cpp/DBHostObject.cpp +118 -112
- package/cpp/PreparedStatementHostObject.cpp +39 -14
- package/cpp/PreparedStatementHostObject.h +17 -4
- package/cpp/bindings.cpp +5 -5
- package/cpp/bridge.cpp +221 -98
- package/cpp/bridge.h +11 -9
- package/cpp/libsql/bridge.cpp +212 -92
- package/cpp/libsql/bridge.h +7 -3
- package/cpp/macros.h +2 -2
- package/cpp/types.h +11 -8
- package/cpp/utils.cpp +43 -7
- package/cpp/utils.h +2 -0
- package/lib/commonjs/index.js +53 -30
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +53 -29
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +11 -11
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +80 -46
package/cpp/bridge.cpp
CHANGED
|
@@ -24,7 +24,8 @@ std::unordered_map<std::string, RollbackCallback> rollbackCallbackMap =
|
|
|
24
24
|
|
|
25
25
|
inline void check_db_open(std::string const &db_name) {
|
|
26
26
|
if (dbMap.count(db_name) == 0) {
|
|
27
|
-
throw std::runtime_error("[OP-SQLite]
|
|
27
|
+
throw std::runtime_error("[OP-SQLite] Database: " + db_name +
|
|
28
|
+
" is not open");
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -49,18 +50,23 @@ std::string opsqlite_get_db_path(std::string const &db_name,
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
#ifdef OP_SQLITE_USE_SQLCIPHER
|
|
52
|
-
BridgeResult opsqlite_open(std::string const &
|
|
53
|
+
BridgeResult opsqlite_open(std::string const &name,
|
|
53
54
|
std::string const &last_path,
|
|
54
55
|
std::string const &crsqlite_path,
|
|
55
56
|
std::string const &sqlite_vec_path,
|
|
56
57
|
std::string const &encryptionKey) {
|
|
57
58
|
#else
|
|
58
|
-
BridgeResult opsqlite_open(std::string const &
|
|
59
|
+
BridgeResult opsqlite_open(std::string const &name,
|
|
59
60
|
std::string const &last_path,
|
|
60
61
|
std::string const &crsqlite_path,
|
|
61
62
|
std::string const &sqlite_vec_path) {
|
|
63
|
+
|
|
64
|
+
if (dbMap.count(name) != 0) {
|
|
65
|
+
throw std::runtime_error(
|
|
66
|
+
"You can only have one JS connection per database");
|
|
67
|
+
}
|
|
62
68
|
#endif
|
|
63
|
-
std::string dbPath = opsqlite_get_db_path(
|
|
69
|
+
std::string dbPath = opsqlite_get_db_path(name, last_path);
|
|
64
70
|
|
|
65
71
|
int sqlOpenFlags =
|
|
66
72
|
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
|
|
@@ -73,11 +79,10 @@ BridgeResult opsqlite_open(std::string const &dbName,
|
|
|
73
79
|
return {.type = SQLiteError, .message = sqlite3_errmsg(db)};
|
|
74
80
|
}
|
|
75
81
|
|
|
76
|
-
dbMap[
|
|
82
|
+
dbMap[name] = db;
|
|
77
83
|
|
|
78
84
|
#ifdef OP_SQLITE_USE_SQLCIPHER
|
|
79
|
-
opsqlite_execute(
|
|
80
|
-
nullptr, nullptr);
|
|
85
|
+
opsqlite_execute(name, "PRAGMA key = '" + encryptionKey + "'", nullptr);
|
|
81
86
|
#endif
|
|
82
87
|
|
|
83
88
|
sqlite3_enable_load_extension(db, 1);
|
|
@@ -92,8 +97,6 @@ BridgeResult opsqlite_open(std::string const &dbName,
|
|
|
92
97
|
|
|
93
98
|
if (errMsg != nullptr) {
|
|
94
99
|
return {.type = SQLiteError, .message = errMsg};
|
|
95
|
-
} else {
|
|
96
|
-
LOGI("Loaded CRSQlite successfully");
|
|
97
100
|
}
|
|
98
101
|
#endif
|
|
99
102
|
|
|
@@ -104,8 +107,6 @@ BridgeResult opsqlite_open(std::string const &dbName,
|
|
|
104
107
|
|
|
105
108
|
if (errMsg != nullptr) {
|
|
106
109
|
return {.type = SQLiteError, .message = errMsg};
|
|
107
|
-
} else {
|
|
108
|
-
LOGI("Loaded sqlite-vec successfully");
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
#endif
|
|
@@ -113,20 +114,19 @@ BridgeResult opsqlite_open(std::string const &dbName,
|
|
|
113
114
|
return {.type = SQLiteOk, .affectedRows = 0};
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
BridgeResult opsqlite_close(std::string const &
|
|
117
|
+
BridgeResult opsqlite_close(std::string const &name) {
|
|
117
118
|
|
|
118
|
-
check_db_open(
|
|
119
|
+
check_db_open(name);
|
|
119
120
|
|
|
120
|
-
sqlite3 *db = dbMap[
|
|
121
|
+
sqlite3 *db = dbMap[name];
|
|
121
122
|
|
|
122
123
|
#ifdef OP_SQLITE_USE_CRSQLITE
|
|
123
|
-
opsqlite_execute(
|
|
124
|
-
nullptr);
|
|
124
|
+
opsqlite_execute(name, "select crsql_finalize();", nullptr);
|
|
125
125
|
#endif
|
|
126
126
|
|
|
127
127
|
sqlite3_close_v2(db);
|
|
128
128
|
|
|
129
|
-
dbMap.erase(
|
|
129
|
+
dbMap.erase(name);
|
|
130
130
|
|
|
131
131
|
return BridgeResult{
|
|
132
132
|
.type = SQLiteOk,
|
|
@@ -140,8 +140,7 @@ BridgeResult opsqlite_attach(std::string const &mainDBName,
|
|
|
140
140
|
std::string dbPath = opsqlite_get_db_path(databaseToAttach, docPath);
|
|
141
141
|
std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
|
|
142
142
|
|
|
143
|
-
BridgeResult result =
|
|
144
|
-
opsqlite_execute(mainDBName, statement, nullptr, nullptr, nullptr);
|
|
143
|
+
BridgeResult result = opsqlite_execute(mainDBName, statement, nullptr);
|
|
145
144
|
|
|
146
145
|
if (result.type == SQLiteError) {
|
|
147
146
|
return {
|
|
@@ -158,8 +157,7 @@ BridgeResult opsqlite_attach(std::string const &mainDBName,
|
|
|
158
157
|
BridgeResult opsqlite_detach(std::string const &mainDBName,
|
|
159
158
|
std::string const &alias) {
|
|
160
159
|
std::string statement = "DETACH DATABASE " + alias;
|
|
161
|
-
BridgeResult result =
|
|
162
|
-
opsqlite_execute(mainDBName, statement, nullptr, nullptr, nullptr);
|
|
160
|
+
BridgeResult result = opsqlite_execute(mainDBName, statement, nullptr);
|
|
163
161
|
if (result.type == SQLiteError) {
|
|
164
162
|
return BridgeResult{
|
|
165
163
|
.type = SQLiteError,
|
|
@@ -206,22 +204,22 @@ inline void opsqlite_bind_statement(sqlite3_stmt *statement,
|
|
|
206
204
|
int sqIndex = ii + 1;
|
|
207
205
|
JSVariant value = values->at(ii);
|
|
208
206
|
|
|
209
|
-
if (std::holds_alternative<bool>(value)
|
|
210
|
-
|
|
211
|
-
} else if (std::holds_alternative<int>(value)) {
|
|
207
|
+
if (std::holds_alternative<bool>(value) ||
|
|
208
|
+
std::holds_alternative<int>(value)) {
|
|
212
209
|
sqlite3_bind_int(statement, sqIndex, std::get<int>(value));
|
|
213
210
|
} else if (std::holds_alternative<long long>(value)) {
|
|
214
|
-
sqlite3_bind_double(statement, sqIndex,
|
|
211
|
+
sqlite3_bind_double(statement, sqIndex,
|
|
212
|
+
static_cast<double>(std::get<long long>(value)));
|
|
215
213
|
} else if (std::holds_alternative<double>(value)) {
|
|
216
214
|
sqlite3_bind_double(statement, sqIndex, std::get<double>(value));
|
|
217
215
|
} else if (std::holds_alternative<std::string>(value)) {
|
|
218
216
|
std::string str = std::get<std::string>(value);
|
|
219
|
-
sqlite3_bind_text(statement, sqIndex, str.c_str(),
|
|
220
|
-
SQLITE_TRANSIENT);
|
|
217
|
+
sqlite3_bind_text(statement, sqIndex, str.c_str(),
|
|
218
|
+
static_cast<int>(str.length()), SQLITE_TRANSIENT);
|
|
221
219
|
} else if (std::holds_alternative<ArrayBuffer>(value)) {
|
|
222
220
|
ArrayBuffer buffer = std::get<ArrayBuffer>(value);
|
|
223
|
-
sqlite3_bind_blob(statement, sqIndex, buffer.data.get(),
|
|
224
|
-
SQLITE_TRANSIENT);
|
|
221
|
+
sqlite3_bind_blob(statement, sqIndex, buffer.data.get(),
|
|
222
|
+
static_cast<int>(buffer.size), SQLITE_TRANSIENT);
|
|
225
223
|
} else {
|
|
226
224
|
sqlite3_bind_null(statement, sqIndex);
|
|
227
225
|
}
|
|
@@ -231,7 +229,7 @@ inline void opsqlite_bind_statement(sqlite3_stmt *statement,
|
|
|
231
229
|
BridgeResult opsqlite_execute_prepared_statement(
|
|
232
230
|
std::string const &dbName, sqlite3_stmt *statement,
|
|
233
231
|
std::vector<DumbHostObject> *results,
|
|
234
|
-
std::shared_ptr<std::vector<SmartHostObject>> metadatas) {
|
|
232
|
+
std::shared_ptr<std::vector<SmartHostObject>> &metadatas) {
|
|
235
233
|
|
|
236
234
|
check_db_open(dbName);
|
|
237
235
|
|
|
@@ -244,8 +242,6 @@ BridgeResult opsqlite_execute_prepared_statement(
|
|
|
244
242
|
|
|
245
243
|
int result = SQLITE_OK;
|
|
246
244
|
|
|
247
|
-
isConsuming = true;
|
|
248
|
-
|
|
249
245
|
int i, count, column_type;
|
|
250
246
|
std::string column_name, column_declared_type;
|
|
251
247
|
|
|
@@ -254,7 +250,7 @@ BridgeResult opsqlite_execute_prepared_statement(
|
|
|
254
250
|
|
|
255
251
|
switch (result) {
|
|
256
252
|
case SQLITE_ROW: {
|
|
257
|
-
if (results ==
|
|
253
|
+
if (results == nullptr) {
|
|
258
254
|
break;
|
|
259
255
|
}
|
|
260
256
|
|
|
@@ -273,13 +269,13 @@ BridgeResult opsqlite_execute_prepared_statement(
|
|
|
273
269
|
* only represent Integers up to 53 bits
|
|
274
270
|
*/
|
|
275
271
|
double column_value = sqlite3_column_double(statement, i);
|
|
276
|
-
row.values.
|
|
272
|
+
row.values.emplace_back(column_value);
|
|
277
273
|
break;
|
|
278
274
|
}
|
|
279
275
|
|
|
280
276
|
case SQLITE_FLOAT: {
|
|
281
277
|
double column_value = sqlite3_column_double(statement, i);
|
|
282
|
-
row.values.
|
|
278
|
+
row.values.emplace_back(column_value);
|
|
283
279
|
break;
|
|
284
280
|
}
|
|
285
281
|
|
|
@@ -288,20 +284,20 @@ BridgeResult opsqlite_execute_prepared_statement(
|
|
|
288
284
|
reinterpret_cast<const char *>(sqlite3_column_text(statement, i));
|
|
289
285
|
int byteLen = sqlite3_column_bytes(statement, i);
|
|
290
286
|
// Specify length too; in case string contains NULL in the middle
|
|
291
|
-
row.values.
|
|
287
|
+
row.values.emplace_back(std::string(column_value, byteLen));
|
|
292
288
|
break;
|
|
293
289
|
}
|
|
294
290
|
|
|
295
291
|
case SQLITE_BLOB: {
|
|
296
292
|
int blob_size = sqlite3_column_bytes(statement, i);
|
|
297
293
|
const void *blob = sqlite3_column_blob(statement, i);
|
|
298
|
-
|
|
294
|
+
auto *data = new uint8_t[blob_size];
|
|
299
295
|
// You cannot share raw memory between native and JS
|
|
300
296
|
// always copy the data
|
|
301
297
|
memcpy(data, blob, blob_size);
|
|
302
|
-
row.values.
|
|
303
|
-
|
|
304
|
-
|
|
298
|
+
row.values.emplace_back(
|
|
299
|
+
ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
|
|
300
|
+
.size = static_cast<size_t>(blob_size)});
|
|
305
301
|
break;
|
|
306
302
|
}
|
|
307
303
|
|
|
@@ -309,14 +305,16 @@ BridgeResult opsqlite_execute_prepared_statement(
|
|
|
309
305
|
// Intentionally left blank
|
|
310
306
|
|
|
311
307
|
default:
|
|
312
|
-
row.values.
|
|
308
|
+
row.values.emplace_back(nullptr);
|
|
313
309
|
break;
|
|
314
310
|
}
|
|
315
311
|
i++;
|
|
316
312
|
}
|
|
313
|
+
|
|
317
314
|
if (results != nullptr) {
|
|
318
315
|
results->push_back(row);
|
|
319
316
|
}
|
|
317
|
+
|
|
320
318
|
break;
|
|
321
319
|
}
|
|
322
320
|
|
|
@@ -329,10 +327,10 @@ BridgeResult opsqlite_execute_prepared_statement(
|
|
|
329
327
|
column_name = sqlite3_column_name(statement, i);
|
|
330
328
|
const char *type = sqlite3_column_decltype(statement, i);
|
|
331
329
|
auto metadata = SmartHostObject();
|
|
332
|
-
metadata.fields.
|
|
333
|
-
metadata.fields.
|
|
334
|
-
metadata.fields.
|
|
335
|
-
|
|
330
|
+
metadata.fields.emplace_back("name", column_name);
|
|
331
|
+
metadata.fields.emplace_back("index", i);
|
|
332
|
+
metadata.fields.emplace_back("type",
|
|
333
|
+
type == nullptr ? "UNKNOWN" : type);
|
|
336
334
|
|
|
337
335
|
metadatas->push_back(metadata);
|
|
338
336
|
i++;
|
|
@@ -374,7 +372,8 @@ sqlite3_stmt *opsqlite_prepare_statement(std::string const &dbName,
|
|
|
374
372
|
|
|
375
373
|
const char *queryStr = query.c_str();
|
|
376
374
|
|
|
377
|
-
int statementStatus =
|
|
375
|
+
int statementStatus =
|
|
376
|
+
sqlite3_prepare_v2(db, queryStr, -1, &statement, nullptr);
|
|
378
377
|
|
|
379
378
|
if (statementStatus == SQLITE_ERROR) {
|
|
380
379
|
const char *message = sqlite3_errmsg(db);
|
|
@@ -385,12 +384,144 @@ sqlite3_stmt *opsqlite_prepare_statement(std::string const &dbName,
|
|
|
385
384
|
return statement;
|
|
386
385
|
}
|
|
387
386
|
|
|
387
|
+
BridgeResult opsqlite_execute(std::string const &name, std::string const &query,
|
|
388
|
+
const std::vector<JSVariant> *params) {
|
|
389
|
+
check_db_open(name);
|
|
390
|
+
|
|
391
|
+
sqlite3 *db = dbMap[name];
|
|
392
|
+
|
|
393
|
+
sqlite3_stmt *statement;
|
|
394
|
+
const char *errorMessage;
|
|
395
|
+
const char *remainingStatement = nullptr;
|
|
396
|
+
|
|
397
|
+
bool isFailed = false;
|
|
398
|
+
int step_result, current_column, column_count, column_type;
|
|
399
|
+
std::string column_name, column_declared_type;
|
|
400
|
+
std::vector<std::string> column_names;
|
|
401
|
+
std::vector<std::vector<JSVariant>> rows;
|
|
402
|
+
std::vector<JSVariant> row;
|
|
403
|
+
|
|
404
|
+
do {
|
|
405
|
+
const char *queryStr =
|
|
406
|
+
remainingStatement == nullptr ? query.c_str() : remainingStatement;
|
|
407
|
+
|
|
408
|
+
int statementStatus =
|
|
409
|
+
sqlite3_prepare_v2(db, queryStr, -1, &statement, &remainingStatement);
|
|
410
|
+
|
|
411
|
+
if (statementStatus != SQLITE_OK) {
|
|
412
|
+
errorMessage = sqlite3_errmsg(db);
|
|
413
|
+
return {.type = SQLiteError,
|
|
414
|
+
.message =
|
|
415
|
+
"[op-sqlite] SQL prepare error: " + std::string(errorMessage),
|
|
416
|
+
.affectedRows = 0};
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (params != nullptr && !params->empty()) {
|
|
420
|
+
opsqlite_bind_statement(statement, params);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
column_count = sqlite3_column_count(statement);
|
|
424
|
+
bool is_consuming = true;
|
|
425
|
+
// Do a first pass to get the column names
|
|
426
|
+
for (int i = 0; i < column_count; i++) {
|
|
427
|
+
column_name = sqlite3_column_name(statement, i);
|
|
428
|
+
column_names.push_back(column_name);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
double double_value;
|
|
432
|
+
const char *string_value;
|
|
433
|
+
while (is_consuming) {
|
|
434
|
+
step_result = sqlite3_step(statement);
|
|
435
|
+
|
|
436
|
+
switch (step_result) {
|
|
437
|
+
case SQLITE_ROW:
|
|
438
|
+
current_column = 0;
|
|
439
|
+
row = std::vector<JSVariant>();
|
|
440
|
+
column_count = sqlite3_column_count(statement);
|
|
441
|
+
|
|
442
|
+
while (current_column < column_count) {
|
|
443
|
+
column_type = sqlite3_column_type(statement, current_column);
|
|
444
|
+
|
|
445
|
+
switch (column_type) {
|
|
446
|
+
|
|
447
|
+
case SQLITE_INTEGER:
|
|
448
|
+
// intentional fallthrough
|
|
449
|
+
case SQLITE_FLOAT: {
|
|
450
|
+
double_value = sqlite3_column_double(statement, current_column);
|
|
451
|
+
row.emplace_back(double_value);
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
case SQLITE_TEXT: {
|
|
456
|
+
string_value = reinterpret_cast<const char *>(
|
|
457
|
+
sqlite3_column_text(statement, current_column));
|
|
458
|
+
int byteLen = sqlite3_column_bytes(statement, current_column);
|
|
459
|
+
// Specify length too; in case string contains NULL in the middle
|
|
460
|
+
row.emplace_back(std::string(string_value, byteLen));
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
case SQLITE_BLOB: {
|
|
465
|
+
int blob_size = sqlite3_column_bytes(statement, current_column);
|
|
466
|
+
const void *blob = sqlite3_column_blob(statement, current_column);
|
|
467
|
+
auto *data = new uint8_t[blob_size];
|
|
468
|
+
memcpy(data, blob, blob_size);
|
|
469
|
+
row.emplace_back(
|
|
470
|
+
ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
|
|
471
|
+
.size = static_cast<size_t>(blob_size)});
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
case SQLITE_NULL:
|
|
476
|
+
// Intentionally left blank to switch to default case
|
|
477
|
+
default:
|
|
478
|
+
row.emplace_back(nullptr);
|
|
479
|
+
break;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
current_column++;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
rows.push_back(row);
|
|
486
|
+
break;
|
|
487
|
+
|
|
488
|
+
case SQLITE_DONE:
|
|
489
|
+
is_consuming = false;
|
|
490
|
+
break;
|
|
491
|
+
|
|
492
|
+
default:
|
|
493
|
+
isFailed = true;
|
|
494
|
+
is_consuming = false;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
sqlite3_finalize(statement);
|
|
499
|
+
} while (remainingStatement != nullptr &&
|
|
500
|
+
strcmp(remainingStatement, "") != 0 && !isFailed);
|
|
501
|
+
|
|
502
|
+
if (isFailed) {
|
|
503
|
+
const char *message = sqlite3_errmsg(db);
|
|
504
|
+
return {.type = SQLiteError,
|
|
505
|
+
.message =
|
|
506
|
+
"[op-sqlite] SQL execution error: " + std::string(message),
|
|
507
|
+
.affectedRows = 0,
|
|
508
|
+
.insertId = 0};
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
int changedRowCount = sqlite3_changes(db);
|
|
512
|
+
long long latestInsertRowId = sqlite3_last_insert_rowid(db);
|
|
513
|
+
return {.type = SQLiteOk,
|
|
514
|
+
.affectedRows = changedRowCount,
|
|
515
|
+
.insertId = static_cast<double>(latestInsertRowId),
|
|
516
|
+
.rows = std::move(rows),
|
|
517
|
+
.column_names = std::move(column_names)};
|
|
518
|
+
}
|
|
519
|
+
|
|
388
520
|
/// Base execution function, returns HostObjects to the JS environment
|
|
389
|
-
BridgeResult
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
std::shared_ptr<std::vector<SmartHostObject>> metadatas) {
|
|
521
|
+
BridgeResult opsqlite_execute_host_objects(
|
|
522
|
+
std::string const &dbName, std::string const &query,
|
|
523
|
+
const std::vector<JSVariant> *params, std::vector<DumbHostObject> *results,
|
|
524
|
+
std::shared_ptr<std::vector<SmartHostObject>> &metadatas) {
|
|
394
525
|
|
|
395
526
|
check_db_open(dbName);
|
|
396
527
|
|
|
@@ -423,16 +554,14 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
|
|
|
423
554
|
|
|
424
555
|
// The statement did not fail to parse but there is nothing to do, just
|
|
425
556
|
// skip to the end
|
|
426
|
-
if (statement ==
|
|
557
|
+
if (statement == nullptr) {
|
|
427
558
|
continue;
|
|
428
559
|
}
|
|
429
560
|
|
|
430
|
-
if (params != nullptr && params->
|
|
561
|
+
if (params != nullptr && !params->empty()) {
|
|
431
562
|
opsqlite_bind_statement(statement, params);
|
|
432
563
|
}
|
|
433
564
|
|
|
434
|
-
isConsuming = true;
|
|
435
|
-
|
|
436
565
|
int i, count, column_type;
|
|
437
566
|
std::string column_name, column_declared_type;
|
|
438
567
|
|
|
@@ -441,7 +570,7 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
|
|
|
441
570
|
|
|
442
571
|
switch (result) {
|
|
443
572
|
case SQLITE_ROW: {
|
|
444
|
-
if (results ==
|
|
573
|
+
if (results == nullptr) {
|
|
445
574
|
break;
|
|
446
575
|
}
|
|
447
576
|
|
|
@@ -460,13 +589,13 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
|
|
|
460
589
|
* only represent Integers up to 53 bits
|
|
461
590
|
*/
|
|
462
591
|
double column_value = sqlite3_column_double(statement, i);
|
|
463
|
-
row.values.
|
|
592
|
+
row.values.emplace_back(column_value);
|
|
464
593
|
break;
|
|
465
594
|
}
|
|
466
595
|
|
|
467
596
|
case SQLITE_FLOAT: {
|
|
468
597
|
double column_value = sqlite3_column_double(statement, i);
|
|
469
|
-
row.values.
|
|
598
|
+
row.values.emplace_back(column_value);
|
|
470
599
|
break;
|
|
471
600
|
}
|
|
472
601
|
|
|
@@ -475,20 +604,20 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
|
|
|
475
604
|
sqlite3_column_text(statement, i));
|
|
476
605
|
int byteLen = sqlite3_column_bytes(statement, i);
|
|
477
606
|
// Specify length too; in case string contains NULL in the middle
|
|
478
|
-
row.values.
|
|
607
|
+
row.values.emplace_back(std::string(column_value, byteLen));
|
|
479
608
|
break;
|
|
480
609
|
}
|
|
481
610
|
|
|
482
611
|
case SQLITE_BLOB: {
|
|
483
612
|
int blob_size = sqlite3_column_bytes(statement, i);
|
|
484
613
|
const void *blob = sqlite3_column_blob(statement, i);
|
|
485
|
-
|
|
614
|
+
auto *data = new uint8_t[blob_size];
|
|
486
615
|
// You cannot share raw memory between native and JS
|
|
487
616
|
// always copy the data
|
|
488
617
|
memcpy(data, blob, blob_size);
|
|
489
|
-
row.values.
|
|
490
|
-
|
|
491
|
-
|
|
618
|
+
row.values.emplace_back(
|
|
619
|
+
ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
|
|
620
|
+
.size = static_cast<size_t>(blob_size)});
|
|
492
621
|
break;
|
|
493
622
|
}
|
|
494
623
|
|
|
@@ -496,7 +625,7 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
|
|
|
496
625
|
// Intentionally left blank
|
|
497
626
|
|
|
498
627
|
default:
|
|
499
|
-
row.values.
|
|
628
|
+
row.values.emplace_back(nullptr);
|
|
500
629
|
break;
|
|
501
630
|
}
|
|
502
631
|
i++;
|
|
@@ -516,10 +645,10 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
|
|
|
516
645
|
column_name = sqlite3_column_name(statement, i);
|
|
517
646
|
const char *type = sqlite3_column_decltype(statement, i);
|
|
518
647
|
auto metadata = SmartHostObject();
|
|
519
|
-
metadata.fields.
|
|
520
|
-
metadata.fields.
|
|
521
|
-
metadata.fields.
|
|
522
|
-
|
|
648
|
+
metadata.fields.emplace_back("name", column_name);
|
|
649
|
+
metadata.fields.emplace_back("index", i);
|
|
650
|
+
metadata.fields.emplace_back("type",
|
|
651
|
+
type == nullptr ? "UNKNOWN" : type);
|
|
523
652
|
|
|
524
653
|
metadatas->push_back(metadata);
|
|
525
654
|
i++;
|
|
@@ -536,8 +665,8 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
|
|
|
536
665
|
}
|
|
537
666
|
|
|
538
667
|
sqlite3_finalize(statement);
|
|
539
|
-
} while (remainingStatement !=
|
|
540
|
-
!isFailed);
|
|
668
|
+
} while (remainingStatement != nullptr &&
|
|
669
|
+
strcmp(remainingStatement, "") != 0 && !isFailed);
|
|
541
670
|
|
|
542
671
|
if (isFailed) {
|
|
543
672
|
|
|
@@ -594,16 +723,14 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
|
|
|
594
723
|
|
|
595
724
|
// The statement did not fail to parse but there is nothing to do, just
|
|
596
725
|
// skip to the end
|
|
597
|
-
if (statement ==
|
|
726
|
+
if (statement == nullptr) {
|
|
598
727
|
continue;
|
|
599
728
|
}
|
|
600
729
|
|
|
601
|
-
if (params != nullptr && params->
|
|
730
|
+
if (params != nullptr && !params->empty()) {
|
|
602
731
|
opsqlite_bind_statement(statement, params);
|
|
603
732
|
}
|
|
604
733
|
|
|
605
|
-
isConsuming = true;
|
|
606
|
-
|
|
607
734
|
int i, count, column_type;
|
|
608
735
|
std::string column_name, column_declared_type;
|
|
609
736
|
|
|
@@ -632,13 +759,13 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
|
|
|
632
759
|
* only represent Integers up to 53 bits
|
|
633
760
|
*/
|
|
634
761
|
double column_value = sqlite3_column_double(statement, i);
|
|
635
|
-
row.
|
|
762
|
+
row.emplace_back(column_value);
|
|
636
763
|
break;
|
|
637
764
|
}
|
|
638
765
|
|
|
639
766
|
case SQLITE_FLOAT: {
|
|
640
767
|
double column_value = sqlite3_column_double(statement, i);
|
|
641
|
-
row.
|
|
768
|
+
row.emplace_back(column_value);
|
|
642
769
|
break;
|
|
643
770
|
}
|
|
644
771
|
|
|
@@ -647,27 +774,25 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
|
|
|
647
774
|
sqlite3_column_text(statement, i));
|
|
648
775
|
int byteLen = sqlite3_column_bytes(statement, i);
|
|
649
776
|
// Specify length too; in case string contains NULL in the middle
|
|
650
|
-
row.
|
|
777
|
+
row.emplace_back(std::string(column_value, byteLen));
|
|
651
778
|
break;
|
|
652
779
|
}
|
|
653
780
|
|
|
654
781
|
case SQLITE_BLOB: {
|
|
655
782
|
int blob_size = sqlite3_column_bytes(statement, i);
|
|
656
783
|
const void *blob = sqlite3_column_blob(statement, i);
|
|
657
|
-
|
|
784
|
+
auto *data = new uint8_t[blob_size];
|
|
658
785
|
memcpy(data, blob, blob_size);
|
|
659
|
-
row.
|
|
660
|
-
|
|
661
|
-
|
|
786
|
+
row.emplace_back(
|
|
787
|
+
ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
|
|
788
|
+
.size = static_cast<size_t>(blob_size)});
|
|
662
789
|
break;
|
|
663
790
|
}
|
|
664
791
|
|
|
665
792
|
case SQLITE_NULL:
|
|
666
|
-
|
|
667
|
-
break;
|
|
668
|
-
|
|
793
|
+
// intentional fallthrough
|
|
669
794
|
default:
|
|
670
|
-
row.
|
|
795
|
+
row.emplace_back(nullptr);
|
|
671
796
|
break;
|
|
672
797
|
}
|
|
673
798
|
i++;
|
|
@@ -690,8 +815,8 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
|
|
|
690
815
|
}
|
|
691
816
|
|
|
692
817
|
sqlite3_finalize(statement);
|
|
693
|
-
} while (remainingStatement !=
|
|
694
|
-
!isFailed);
|
|
818
|
+
} while (remainingStatement != nullptr &&
|
|
819
|
+
strcmp(remainingStatement, "") != 0 && !isFailed);
|
|
695
820
|
|
|
696
821
|
if (isFailed) {
|
|
697
822
|
|
|
@@ -773,7 +898,7 @@ BridgeResult opsqlite_deregister_update_hook(std::string const &dbName) {
|
|
|
773
898
|
sqlite3 *db = dbMap[dbName];
|
|
774
899
|
updateCallbackMap.erase(dbName);
|
|
775
900
|
|
|
776
|
-
sqlite3_update_hook(db,
|
|
901
|
+
sqlite3_update_hook(db, nullptr, nullptr);
|
|
777
902
|
|
|
778
903
|
return {SQLiteOk};
|
|
779
904
|
}
|
|
@@ -811,7 +936,7 @@ BridgeResult opsqlite_deregister_commit_hook(std::string const &dbName) {
|
|
|
811
936
|
|
|
812
937
|
sqlite3 *db = dbMap[dbName];
|
|
813
938
|
commitCallbackMap.erase(dbName);
|
|
814
|
-
sqlite3_commit_hook(db,
|
|
939
|
+
sqlite3_commit_hook(db, nullptr, nullptr);
|
|
815
940
|
|
|
816
941
|
return {SQLiteOk};
|
|
817
942
|
}
|
|
@@ -848,7 +973,7 @@ BridgeResult opsqlite_deregister_rollback_hook(std::string const &dbName) {
|
|
|
848
973
|
sqlite3 *db = dbMap[dbName];
|
|
849
974
|
rollbackCallbackMap.erase(dbName);
|
|
850
975
|
|
|
851
|
-
sqlite3_rollback_hook(db,
|
|
976
|
+
sqlite3_rollback_hook(db, nullptr, nullptr);
|
|
852
977
|
|
|
853
978
|
return {SQLiteOk};
|
|
854
979
|
}
|
|
@@ -884,7 +1009,7 @@ BridgeResult opsqlite_load_extension(std::string const &db_name,
|
|
|
884
1009
|
#endif
|
|
885
1010
|
}
|
|
886
1011
|
|
|
887
|
-
BatchResult opsqlite_execute_batch(std::string
|
|
1012
|
+
BatchResult opsqlite_execute_batch(std::string &name,
|
|
888
1013
|
std::vector<BatchArguments> *commands) {
|
|
889
1014
|
size_t commandCount = commands->size();
|
|
890
1015
|
if (commandCount <= 0) {
|
|
@@ -896,16 +1021,14 @@ BatchResult opsqlite_execute_batch(std::string dbName,
|
|
|
896
1021
|
|
|
897
1022
|
try {
|
|
898
1023
|
int affectedRows = 0;
|
|
899
|
-
opsqlite_execute(
|
|
900
|
-
nullptr);
|
|
1024
|
+
opsqlite_execute(name, "BEGIN EXCLUSIVE TRANSACTION", nullptr);
|
|
901
1025
|
for (int i = 0; i < commandCount; i++) {
|
|
902
1026
|
auto command = commands->at(i);
|
|
903
1027
|
// We do not provide a datastructure to receive query data because we
|
|
904
1028
|
// don't need/want to handle this results in a batch execution
|
|
905
|
-
auto result = opsqlite_execute(
|
|
906
|
-
nullptr, nullptr);
|
|
1029
|
+
auto result = opsqlite_execute(name, command.sql, command.params.get());
|
|
907
1030
|
if (result.type == SQLiteError) {
|
|
908
|
-
opsqlite_execute(
|
|
1031
|
+
opsqlite_execute(name, "ROLLBACK", nullptr);
|
|
909
1032
|
return BatchResult{
|
|
910
1033
|
.type = SQLiteError,
|
|
911
1034
|
.message = result.message,
|
|
@@ -914,14 +1037,14 @@ BatchResult opsqlite_execute_batch(std::string dbName,
|
|
|
914
1037
|
affectedRows += result.affectedRows;
|
|
915
1038
|
}
|
|
916
1039
|
}
|
|
917
|
-
opsqlite_execute(
|
|
1040
|
+
opsqlite_execute(name, "COMMIT", nullptr);
|
|
918
1041
|
return BatchResult{
|
|
919
1042
|
.type = SQLiteOk,
|
|
920
1043
|
.affectedRows = affectedRows,
|
|
921
1044
|
.commands = static_cast<int>(commandCount),
|
|
922
1045
|
};
|
|
923
1046
|
} catch (std::exception &exc) {
|
|
924
|
-
opsqlite_execute(
|
|
1047
|
+
opsqlite_execute(name, "ROLLBACK", nullptr);
|
|
925
1048
|
return BatchResult{
|
|
926
1049
|
.type = SQLiteError,
|
|
927
1050
|
.message = exc.what(),
|