@photostructure/sqlite 0.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/LICENSE +21 -0
  3. package/README.md +522 -0
  4. package/SECURITY.md +114 -0
  5. package/binding.gyp +94 -0
  6. package/dist/index.cjs +134 -0
  7. package/dist/index.cjs.map +1 -0
  8. package/dist/index.d.cts +408 -0
  9. package/dist/index.d.mts +408 -0
  10. package/dist/index.d.ts +408 -0
  11. package/dist/index.mjs +103 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/package.json +144 -0
  14. package/prebuilds/darwin-arm64/@photostructure+sqlite.glibc.node +0 -0
  15. package/prebuilds/linux-arm64/@photostructure+sqlite.glibc.node +0 -0
  16. package/prebuilds/linux-arm64/@photostructure+sqlite.musl.node +0 -0
  17. package/prebuilds/linux-x64/@photostructure+sqlite.glibc.node +0 -0
  18. package/prebuilds/linux-x64/@photostructure+sqlite.musl.node +0 -0
  19. package/prebuilds/win32-x64/@photostructure+sqlite.glibc.node +0 -0
  20. package/scripts/post-build.mjs +21 -0
  21. package/scripts/prebuild-linux-glibc.sh +108 -0
  22. package/src/aggregate_function.cpp +417 -0
  23. package/src/aggregate_function.h +116 -0
  24. package/src/binding.cpp +160 -0
  25. package/src/dirname.ts +13 -0
  26. package/src/index.ts +465 -0
  27. package/src/shims/base_object-inl.h +8 -0
  28. package/src/shims/base_object.h +50 -0
  29. package/src/shims/debug_utils-inl.h +23 -0
  30. package/src/shims/env-inl.h +19 -0
  31. package/src/shims/memory_tracker-inl.h +17 -0
  32. package/src/shims/napi_extensions.h +73 -0
  33. package/src/shims/node.h +16 -0
  34. package/src/shims/node_errors.h +66 -0
  35. package/src/shims/node_mem-inl.h +8 -0
  36. package/src/shims/node_mem.h +31 -0
  37. package/src/shims/node_url.h +23 -0
  38. package/src/shims/promise_resolver.h +31 -0
  39. package/src/shims/util-inl.h +18 -0
  40. package/src/shims/util.h +101 -0
  41. package/src/sqlite_impl.cpp +2440 -0
  42. package/src/sqlite_impl.h +314 -0
  43. package/src/stack_path.ts +64 -0
  44. package/src/types/node-gyp-build.d.ts +4 -0
  45. package/src/upstream/node_sqlite.cc +2706 -0
  46. package/src/upstream/node_sqlite.h +234 -0
  47. package/src/upstream/sqlite.gyp +38 -0
  48. package/src/upstream/sqlite.js +19 -0
  49. package/src/upstream/sqlite3.c +262809 -0
  50. package/src/upstream/sqlite3.h +13773 -0
  51. package/src/upstream/sqlite3ext.h +723 -0
  52. package/src/user_function.cpp +225 -0
  53. package/src/user_function.h +40 -0
@@ -0,0 +1,2706 @@
1
+ #include "node_sqlite.h"
2
+ #include <path.h>
3
+ #include "base_object-inl.h"
4
+ #include "debug_utils-inl.h"
5
+ #include "env-inl.h"
6
+ #include "memory_tracker-inl.h"
7
+ #include "node.h"
8
+ #include "node_errors.h"
9
+ #include "node_mem-inl.h"
10
+ #include "node_url.h"
11
+ #include "sqlite3.h"
12
+ #include "threadpoolwork-inl.h"
13
+ #include "util-inl.h"
14
+
15
+ #include <cinttypes>
16
+
17
+ namespace node {
18
+ namespace sqlite {
19
+
20
+ using v8::Array;
21
+ using v8::ArrayBuffer;
22
+ using v8::BackingStoreInitializationMode;
23
+ using v8::BigInt;
24
+ using v8::Boolean;
25
+ using v8::ConstructorBehavior;
26
+ using v8::Context;
27
+ using v8::DontDelete;
28
+ using v8::Exception;
29
+ using v8::Function;
30
+ using v8::FunctionCallback;
31
+ using v8::FunctionCallbackInfo;
32
+ using v8::FunctionTemplate;
33
+ using v8::Global;
34
+ using v8::HandleScope;
35
+ using v8::Int32;
36
+ using v8::Integer;
37
+ using v8::Isolate;
38
+ using v8::Local;
39
+ using v8::LocalVector;
40
+ using v8::MaybeLocal;
41
+ using v8::Name;
42
+ using v8::NewStringType;
43
+ using v8::Null;
44
+ using v8::Number;
45
+ using v8::Object;
46
+ using v8::Promise;
47
+ using v8::SideEffectType;
48
+ using v8::String;
49
+ using v8::TryCatch;
50
+ using v8::Uint8Array;
51
+ using v8::Value;
52
+
53
+ #define CHECK_ERROR_OR_THROW(isolate, db, expr, expected, ret) \
54
+ do { \
55
+ int r_ = (expr); \
56
+ if (r_ != (expected)) { \
57
+ THROW_ERR_SQLITE_ERROR((isolate), (db)); \
58
+ return (ret); \
59
+ } \
60
+ } while (0)
61
+
62
+ #define THROW_AND_RETURN_ON_BAD_STATE(env, condition, msg) \
63
+ do { \
64
+ if ((condition)) { \
65
+ THROW_ERR_INVALID_STATE((env), (msg)); \
66
+ return; \
67
+ } \
68
+ } while (0)
69
+
70
+ #define SQLITE_VALUE_TO_JS(from, isolate, use_big_int_args, result, ...) \
71
+ do { \
72
+ switch (sqlite3_##from##_type(__VA_ARGS__)) { \
73
+ case SQLITE_INTEGER: { \
74
+ sqlite3_int64 val = sqlite3_##from##_int64(__VA_ARGS__); \
75
+ if ((use_big_int_args)) { \
76
+ (result) = BigInt::New((isolate), val); \
77
+ } else if (std::abs(val) <= kMaxSafeJsInteger) { \
78
+ (result) = Number::New((isolate), val); \
79
+ } else { \
80
+ THROW_ERR_OUT_OF_RANGE((isolate), \
81
+ "Value is too large to be represented as a " \
82
+ "JavaScript number: %" PRId64, \
83
+ val); \
84
+ } \
85
+ break; \
86
+ } \
87
+ case SQLITE_FLOAT: { \
88
+ (result) = \
89
+ Number::New((isolate), sqlite3_##from##_double(__VA_ARGS__)); \
90
+ break; \
91
+ } \
92
+ case SQLITE_TEXT: { \
93
+ const char* v = \
94
+ reinterpret_cast<const char*>(sqlite3_##from##_text(__VA_ARGS__)); \
95
+ (result) = String::NewFromUtf8((isolate), v).As<Value>(); \
96
+ break; \
97
+ } \
98
+ case SQLITE_NULL: { \
99
+ (result) = Null((isolate)); \
100
+ break; \
101
+ } \
102
+ case SQLITE_BLOB: { \
103
+ size_t size = \
104
+ static_cast<size_t>(sqlite3_##from##_bytes(__VA_ARGS__)); \
105
+ auto data = reinterpret_cast<const uint8_t*>( \
106
+ sqlite3_##from##_blob(__VA_ARGS__)); \
107
+ auto store = ArrayBuffer::NewBackingStore( \
108
+ (isolate), size, BackingStoreInitializationMode::kUninitialized); \
109
+ memcpy(store->Data(), data, size); \
110
+ auto ab = ArrayBuffer::New((isolate), std::move(store)); \
111
+ (result) = Uint8Array::New(ab, 0, size); \
112
+ break; \
113
+ } \
114
+ default: \
115
+ UNREACHABLE("Bad SQLite value"); \
116
+ } \
117
+ } while (0)
118
+
119
+ inline MaybeLocal<Object> CreateSQLiteError(Isolate* isolate,
120
+ const char* message) {
121
+ Local<String> js_msg;
122
+ Local<Object> e;
123
+ Environment* env = Environment::GetCurrent(isolate);
124
+ if (!String::NewFromUtf8(isolate, message).ToLocal(&js_msg) ||
125
+ !Exception::Error(js_msg)
126
+ ->ToObject(isolate->GetCurrentContext())
127
+ .ToLocal(&e) ||
128
+ e->Set(isolate->GetCurrentContext(),
129
+ env->code_string(),
130
+ env->err_sqlite_error_string())
131
+ .IsNothing()) {
132
+ return MaybeLocal<Object>();
133
+ }
134
+ return e;
135
+ }
136
+
137
+ inline MaybeLocal<Object> CreateSQLiteError(Isolate* isolate, int errcode) {
138
+ const char* errstr = sqlite3_errstr(errcode);
139
+ Local<String> js_errmsg;
140
+ Local<Object> e;
141
+ Environment* env = Environment::GetCurrent(isolate);
142
+ if (!String::NewFromUtf8(isolate, errstr).ToLocal(&js_errmsg) ||
143
+ !CreateSQLiteError(isolate, errstr).ToLocal(&e) ||
144
+ e->Set(env->context(),
145
+ env->errcode_string(),
146
+ Integer::New(isolate, errcode))
147
+ .IsNothing() ||
148
+ e->Set(env->context(), env->errstr_string(), js_errmsg).IsNothing()) {
149
+ return MaybeLocal<Object>();
150
+ }
151
+ return e;
152
+ }
153
+
154
+ inline MaybeLocal<Object> CreateSQLiteError(Isolate* isolate, sqlite3* db) {
155
+ int errcode = sqlite3_extended_errcode(db);
156
+ const char* errstr = sqlite3_errstr(errcode);
157
+ const char* errmsg = sqlite3_errmsg(db);
158
+ Local<String> js_errmsg;
159
+ Local<Object> e;
160
+ Environment* env = Environment::GetCurrent(isolate);
161
+ if (!String::NewFromUtf8(isolate, errstr).ToLocal(&js_errmsg) ||
162
+ !CreateSQLiteError(isolate, errmsg).ToLocal(&e) ||
163
+ e->Set(isolate->GetCurrentContext(),
164
+ env->errcode_string(),
165
+ Integer::New(isolate, errcode))
166
+ .IsNothing() ||
167
+ e->Set(isolate->GetCurrentContext(), env->errstr_string(), js_errmsg)
168
+ .IsNothing()) {
169
+ return MaybeLocal<Object>();
170
+ }
171
+ return e;
172
+ }
173
+
174
+ void JSValueToSQLiteResult(Isolate* isolate,
175
+ sqlite3_context* ctx,
176
+ Local<Value> value) {
177
+ if (value->IsNullOrUndefined()) {
178
+ sqlite3_result_null(ctx);
179
+ } else if (value->IsNumber()) {
180
+ sqlite3_result_double(ctx, value.As<Number>()->Value());
181
+ } else if (value->IsString()) {
182
+ Utf8Value val(isolate, value.As<String>());
183
+ sqlite3_result_text(ctx, *val, val.length(), SQLITE_TRANSIENT);
184
+ } else if (value->IsArrayBufferView()) {
185
+ ArrayBufferViewContents<uint8_t> buf(value);
186
+ sqlite3_result_blob(ctx, buf.data(), buf.length(), SQLITE_TRANSIENT);
187
+ } else if (value->IsBigInt()) {
188
+ bool lossless;
189
+ int64_t as_int = value.As<BigInt>()->Int64Value(&lossless);
190
+ if (!lossless) {
191
+ sqlite3_result_error(ctx, "BigInt value is too large for SQLite", -1);
192
+ return;
193
+ }
194
+ sqlite3_result_int64(ctx, as_int);
195
+ } else if (value->IsPromise()) {
196
+ sqlite3_result_error(
197
+ ctx, "Asynchronous user-defined functions are not supported", -1);
198
+ } else {
199
+ sqlite3_result_error(
200
+ ctx,
201
+ "Returned JavaScript value cannot be converted to a SQLite value",
202
+ -1);
203
+ }
204
+ }
205
+
206
+ class DatabaseSync;
207
+
208
+ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, DatabaseSync* db) {
209
+ if (db->ShouldIgnoreSQLiteError()) {
210
+ db->SetIgnoreNextSQLiteError(false);
211
+ return;
212
+ }
213
+
214
+ Local<Object> e;
215
+ if (CreateSQLiteError(isolate, db->Connection()).ToLocal(&e)) {
216
+ isolate->ThrowException(e);
217
+ }
218
+ }
219
+
220
+ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, const char* message) {
221
+ Local<Object> e;
222
+ if (CreateSQLiteError(isolate, message).ToLocal(&e)) {
223
+ isolate->ThrowException(e);
224
+ }
225
+ }
226
+
227
+ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, int errcode) {
228
+ const char* errstr = sqlite3_errstr(errcode);
229
+
230
+ Environment* env = Environment::GetCurrent(isolate);
231
+ Local<Object> error;
232
+ if (CreateSQLiteError(isolate, errstr).ToLocal(&error) &&
233
+ error
234
+ ->Set(isolate->GetCurrentContext(),
235
+ env->errcode_string(),
236
+ Integer::New(isolate, errcode))
237
+ .IsJust()) {
238
+ isolate->ThrowException(error);
239
+ }
240
+ }
241
+
242
+ inline MaybeLocal<Value> NullableSQLiteStringToValue(Isolate* isolate,
243
+ const char* str) {
244
+ if (str == nullptr) {
245
+ return Null(isolate);
246
+ }
247
+
248
+ return String::NewFromUtf8(isolate, str, NewStringType::kInternalized)
249
+ .As<Value>();
250
+ }
251
+
252
+ class CustomAggregate {
253
+ public:
254
+ explicit CustomAggregate(Environment* env,
255
+ DatabaseSync* db,
256
+ bool use_bigint_args,
257
+ Local<Value> start,
258
+ Local<Function> step_fn,
259
+ Local<Function> inverse_fn,
260
+ Local<Function> result_fn)
261
+ : env_(env),
262
+ db_(db),
263
+ use_bigint_args_(use_bigint_args),
264
+ start_(env->isolate(), start),
265
+ step_fn_(env->isolate(), step_fn),
266
+ inverse_fn_(env->isolate(), inverse_fn),
267
+ result_fn_(env->isolate(), result_fn) {}
268
+
269
+ static void xStep(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
270
+ xStepBase(ctx, argc, argv, &CustomAggregate::step_fn_);
271
+ }
272
+
273
+ static void xInverse(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
274
+ xStepBase(ctx, argc, argv, &CustomAggregate::inverse_fn_);
275
+ }
276
+
277
+ static void xFinal(sqlite3_context* ctx) { xValueBase(ctx, true); }
278
+
279
+ static void xValue(sqlite3_context* ctx) { xValueBase(ctx, false); }
280
+
281
+ static void xDestroy(void* self) {
282
+ delete static_cast<CustomAggregate*>(self);
283
+ }
284
+
285
+ private:
286
+ struct aggregate_data {
287
+ Global<Value> value;
288
+ bool initialized;
289
+ bool is_window;
290
+ };
291
+
292
+ static inline void xStepBase(sqlite3_context* ctx,
293
+ int argc,
294
+ sqlite3_value** argv,
295
+ Global<Function> CustomAggregate::*mptr) {
296
+ CustomAggregate* self =
297
+ static_cast<CustomAggregate*>(sqlite3_user_data(ctx));
298
+ Environment* env = self->env_;
299
+ Isolate* isolate = env->isolate();
300
+ auto agg = self->GetAggregate(ctx);
301
+
302
+ if (!agg) {
303
+ return;
304
+ }
305
+
306
+ auto recv = Undefined(isolate);
307
+ LocalVector<Value> js_argv(isolate);
308
+ js_argv.emplace_back(Local<Value>::New(isolate, agg->value));
309
+
310
+ for (int i = 0; i < argc; ++i) {
311
+ sqlite3_value* value = argv[i];
312
+ MaybeLocal<Value> js_val;
313
+ SQLITE_VALUE_TO_JS(value, isolate, self->use_bigint_args_, js_val, value);
314
+ if (js_val.IsEmpty()) {
315
+ // Ignore the SQLite error because a JavaScript exception is pending.
316
+ self->db_->SetIgnoreNextSQLiteError(true);
317
+ sqlite3_result_error(ctx, "", 0);
318
+ return;
319
+ }
320
+
321
+ Local<Value> local;
322
+ if (!js_val.ToLocal(&local)) {
323
+ // Ignore the SQLite error because a JavaScript exception is pending.
324
+ self->db_->SetIgnoreNextSQLiteError(true);
325
+ sqlite3_result_error(ctx, "", 0);
326
+ return;
327
+ }
328
+
329
+ js_argv.emplace_back(local);
330
+ }
331
+
332
+ Local<Value> ret;
333
+ if (!(self->*mptr)
334
+ .Get(isolate)
335
+ ->Call(env->context(), recv, argc + 1, js_argv.data())
336
+ .ToLocal(&ret)) {
337
+ self->db_->SetIgnoreNextSQLiteError(true);
338
+ sqlite3_result_error(ctx, "", 0);
339
+ return;
340
+ }
341
+
342
+ agg->value.Reset(isolate, ret);
343
+ }
344
+
345
+ static inline void xValueBase(sqlite3_context* ctx, bool is_final) {
346
+ CustomAggregate* self =
347
+ static_cast<CustomAggregate*>(sqlite3_user_data(ctx));
348
+ Environment* env = self->env_;
349
+ Isolate* isolate = env->isolate();
350
+ auto agg = self->GetAggregate(ctx);
351
+
352
+ if (!agg) {
353
+ return;
354
+ }
355
+
356
+ if (!is_final) {
357
+ agg->is_window = true;
358
+ } else if (agg->is_window) {
359
+ DestroyAggregateData(ctx);
360
+ return;
361
+ }
362
+
363
+ Local<Value> result;
364
+ if (!self->result_fn_.IsEmpty()) {
365
+ Local<Function> fn =
366
+ Local<Function>::New(env->isolate(), self->result_fn_);
367
+ Local<Value> js_arg[] = {Local<Value>::New(isolate, agg->value)};
368
+
369
+ if (!fn->Call(env->context(), Null(isolate), 1, js_arg)
370
+ .ToLocal(&result)) {
371
+ self->db_->SetIgnoreNextSQLiteError(true);
372
+ sqlite3_result_error(ctx, "", 0);
373
+ }
374
+ } else {
375
+ result = Local<Value>::New(isolate, agg->value);
376
+ }
377
+
378
+ if (!result.IsEmpty()) {
379
+ JSValueToSQLiteResult(isolate, ctx, result);
380
+ }
381
+
382
+ if (is_final) {
383
+ DestroyAggregateData(ctx);
384
+ }
385
+ }
386
+
387
+ static void DestroyAggregateData(sqlite3_context* ctx) {
388
+ aggregate_data* agg = static_cast<aggregate_data*>(
389
+ sqlite3_aggregate_context(ctx, sizeof(aggregate_data)));
390
+ CHECK(agg->initialized);
391
+ agg->value.Reset();
392
+ }
393
+
394
+ aggregate_data* GetAggregate(sqlite3_context* ctx) {
395
+ aggregate_data* agg = static_cast<aggregate_data*>(
396
+ sqlite3_aggregate_context(ctx, sizeof(aggregate_data)));
397
+ if (!agg->initialized) {
398
+ Isolate* isolate = env_->isolate();
399
+ Local<Value> start_v = Local<Value>::New(isolate, start_);
400
+ if (start_v->IsFunction()) {
401
+ auto fn = start_v.As<Function>();
402
+ MaybeLocal<Value> retval =
403
+ fn->Call(env_->context(), Null(isolate), 0, nullptr);
404
+ if (!retval.ToLocal(&start_v)) {
405
+ db_->SetIgnoreNextSQLiteError(true);
406
+ sqlite3_result_error(ctx, "", 0);
407
+ return nullptr;
408
+ }
409
+ }
410
+
411
+ agg->value.Reset(env_->isolate(), start_v);
412
+ agg->initialized = true;
413
+ }
414
+
415
+ return agg;
416
+ }
417
+
418
+ Environment* env_;
419
+ DatabaseSync* db_;
420
+ bool use_bigint_args_;
421
+ Global<Value> start_;
422
+ Global<Function> step_fn_;
423
+ Global<Function> inverse_fn_;
424
+ Global<Function> result_fn_;
425
+ };
426
+
427
+ class BackupJob : public ThreadPoolWork {
428
+ public:
429
+ explicit BackupJob(Environment* env,
430
+ DatabaseSync* source,
431
+ Local<Promise::Resolver> resolver,
432
+ std::string source_db,
433
+ std::string destination_name,
434
+ std::string dest_db,
435
+ int pages,
436
+ Local<Function> progressFunc)
437
+ : ThreadPoolWork(env, "node_sqlite3.BackupJob"),
438
+ env_(env),
439
+ source_(source),
440
+ pages_(pages),
441
+ source_db_(std::move(source_db)),
442
+ destination_name_(std::move(destination_name)),
443
+ dest_db_(std::move(dest_db)) {
444
+ resolver_.Reset(env->isolate(), resolver);
445
+ progressFunc_.Reset(env->isolate(), progressFunc);
446
+ }
447
+
448
+ void ScheduleBackup() {
449
+ Isolate* isolate = env()->isolate();
450
+ HandleScope handle_scope(isolate);
451
+ backup_status_ = sqlite3_open_v2(
452
+ destination_name_.c_str(),
453
+ &dest_,
454
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI,
455
+ nullptr);
456
+ Local<Promise::Resolver> resolver =
457
+ Local<Promise::Resolver>::New(env()->isolate(), resolver_);
458
+ if (backup_status_ != SQLITE_OK) {
459
+ HandleBackupError(resolver);
460
+ return;
461
+ }
462
+
463
+ backup_ = sqlite3_backup_init(
464
+ dest_, dest_db_.c_str(), source_->Connection(), source_db_.c_str());
465
+ if (backup_ == nullptr) {
466
+ HandleBackupError(resolver);
467
+ return;
468
+ }
469
+
470
+ this->ScheduleWork();
471
+ }
472
+
473
+ void DoThreadPoolWork() override {
474
+ backup_status_ = sqlite3_backup_step(backup_, pages_);
475
+ }
476
+
477
+ void AfterThreadPoolWork(int status) override {
478
+ HandleScope handle_scope(env()->isolate());
479
+ Local<Promise::Resolver> resolver =
480
+ Local<Promise::Resolver>::New(env()->isolate(), resolver_);
481
+
482
+ if (!(backup_status_ == SQLITE_OK || backup_status_ == SQLITE_DONE ||
483
+ backup_status_ == SQLITE_BUSY || backup_status_ == SQLITE_LOCKED)) {
484
+ HandleBackupError(resolver, backup_status_);
485
+ return;
486
+ }
487
+
488
+ int total_pages = sqlite3_backup_pagecount(backup_);
489
+ int remaining_pages = sqlite3_backup_remaining(backup_);
490
+ if (remaining_pages != 0) {
491
+ Local<Function> fn =
492
+ Local<Function>::New(env()->isolate(), progressFunc_);
493
+ if (!fn.IsEmpty()) {
494
+ Local<Object> progress_info = Object::New(env()->isolate());
495
+ if (progress_info
496
+ ->Set(env()->context(),
497
+ env()->total_pages_string(),
498
+ Integer::New(env()->isolate(), total_pages))
499
+ .IsNothing() ||
500
+ progress_info
501
+ ->Set(env()->context(),
502
+ env()->remaining_pages_string(),
503
+ Integer::New(env()->isolate(), remaining_pages))
504
+ .IsNothing()) {
505
+ return;
506
+ }
507
+
508
+ Local<Value> argv[] = {progress_info};
509
+ TryCatch try_catch(env()->isolate());
510
+ fn->Call(env()->context(), Null(env()->isolate()), 1, argv)
511
+ .FromMaybe(Local<Value>());
512
+ if (try_catch.HasCaught()) {
513
+ Finalize();
514
+ resolver->Reject(env()->context(), try_catch.Exception()).ToChecked();
515
+ return;
516
+ }
517
+ }
518
+
519
+ // There's still work to do
520
+ this->ScheduleWork();
521
+ return;
522
+ }
523
+
524
+ if (backup_status_ != SQLITE_DONE) {
525
+ HandleBackupError(resolver);
526
+ return;
527
+ }
528
+
529
+ Finalize();
530
+ resolver
531
+ ->Resolve(env()->context(), Integer::New(env()->isolate(), total_pages))
532
+ .ToChecked();
533
+ }
534
+
535
+ void Finalize() {
536
+ Cleanup();
537
+ source_->RemoveBackup(this);
538
+ }
539
+
540
+ void Cleanup() {
541
+ if (backup_) {
542
+ sqlite3_backup_finish(backup_);
543
+ backup_ = nullptr;
544
+ }
545
+
546
+ if (dest_) {
547
+ backup_status_ = sqlite3_errcode(dest_);
548
+ sqlite3_close_v2(dest_);
549
+ dest_ = nullptr;
550
+ }
551
+ }
552
+
553
+ private:
554
+ void HandleBackupError(Local<Promise::Resolver> resolver) {
555
+ Local<Object> e;
556
+ if (!CreateSQLiteError(env()->isolate(), dest_).ToLocal(&e)) {
557
+ Finalize();
558
+ return;
559
+ }
560
+
561
+ Finalize();
562
+ resolver->Reject(env()->context(), e).ToChecked();
563
+ }
564
+
565
+ void HandleBackupError(Local<Promise::Resolver> resolver, int errcode) {
566
+ Local<Object> e;
567
+ if (!CreateSQLiteError(env()->isolate(), errcode).ToLocal(&e)) {
568
+ Finalize();
569
+ return;
570
+ }
571
+
572
+ Finalize();
573
+ resolver->Reject(env()->context(), e).ToChecked();
574
+ }
575
+
576
+ Environment* env() const { return env_; }
577
+
578
+ Environment* env_;
579
+ DatabaseSync* source_;
580
+ Global<Promise::Resolver> resolver_;
581
+ Global<Function> progressFunc_;
582
+ sqlite3* dest_ = nullptr;
583
+ sqlite3_backup* backup_ = nullptr;
584
+ int pages_;
585
+ int backup_status_ = SQLITE_OK;
586
+ std::string source_db_;
587
+ std::string destination_name_;
588
+ std::string dest_db_;
589
+ };
590
+
591
+ UserDefinedFunction::UserDefinedFunction(Environment* env,
592
+ Local<Function> fn,
593
+ DatabaseSync* db,
594
+ bool use_bigint_args)
595
+ : env_(env),
596
+ fn_(env->isolate(), fn),
597
+ db_(db),
598
+ use_bigint_args_(use_bigint_args) {}
599
+
600
+ UserDefinedFunction::~UserDefinedFunction() {}
601
+
602
+ void UserDefinedFunction::xFunc(sqlite3_context* ctx,
603
+ int argc,
604
+ sqlite3_value** argv) {
605
+ UserDefinedFunction* self =
606
+ static_cast<UserDefinedFunction*>(sqlite3_user_data(ctx));
607
+ Environment* env = self->env_;
608
+ Isolate* isolate = env->isolate();
609
+ auto recv = Undefined(isolate);
610
+ auto fn = self->fn_.Get(isolate);
611
+ LocalVector<Value> js_argv(isolate);
612
+
613
+ for (int i = 0; i < argc; ++i) {
614
+ sqlite3_value* value = argv[i];
615
+ MaybeLocal<Value> js_val = MaybeLocal<Value>();
616
+ SQLITE_VALUE_TO_JS(value, isolate, self->use_bigint_args_, js_val, value);
617
+ if (js_val.IsEmpty()) {
618
+ // Ignore the SQLite error because a JavaScript exception is pending.
619
+ self->db_->SetIgnoreNextSQLiteError(true);
620
+ sqlite3_result_error(ctx, "", 0);
621
+ return;
622
+ }
623
+
624
+ Local<Value> local;
625
+ if (!js_val.ToLocal(&local)) {
626
+ // Ignore the SQLite error because a JavaScript exception is pending.
627
+ self->db_->SetIgnoreNextSQLiteError(true);
628
+ sqlite3_result_error(ctx, "", 0);
629
+ return;
630
+ }
631
+
632
+ js_argv.emplace_back(local);
633
+ }
634
+
635
+ MaybeLocal<Value> retval =
636
+ fn->Call(env->context(), recv, argc, js_argv.data());
637
+ Local<Value> result;
638
+ if (!retval.ToLocal(&result)) {
639
+ // Ignore the SQLite error because a JavaScript exception is pending.
640
+ self->db_->SetIgnoreNextSQLiteError(true);
641
+ sqlite3_result_error(ctx, "", 0);
642
+ return;
643
+ }
644
+
645
+ JSValueToSQLiteResult(isolate, ctx, result);
646
+ }
647
+
648
+ void UserDefinedFunction::xDestroy(void* self) {
649
+ delete static_cast<UserDefinedFunction*>(self);
650
+ }
651
+
652
+ DatabaseSync::DatabaseSync(Environment* env,
653
+ Local<Object> object,
654
+ DatabaseOpenConfiguration&& open_config,
655
+ bool open,
656
+ bool allow_load_extension)
657
+ : BaseObject(env, object), open_config_(std::move(open_config)) {
658
+ MakeWeak();
659
+ connection_ = nullptr;
660
+ allow_load_extension_ = allow_load_extension;
661
+ enable_load_extension_ = allow_load_extension;
662
+ ignore_next_sqlite_error_ = false;
663
+
664
+ if (open) {
665
+ Open();
666
+ }
667
+ }
668
+
669
+ void DatabaseSync::AddBackup(BackupJob* job) {
670
+ backups_.insert(job);
671
+ }
672
+
673
+ void DatabaseSync::RemoveBackup(BackupJob* job) {
674
+ backups_.erase(job);
675
+ }
676
+
677
+ void DatabaseSync::DeleteSessions() {
678
+ // all attached sessions need to be deleted before the database is closed
679
+ // https://www.sqlite.org/session/sqlite3session_create.html
680
+ for (auto* session : sessions_) {
681
+ sqlite3session_delete(session);
682
+ }
683
+ sessions_.clear();
684
+ }
685
+
686
+ DatabaseSync::~DatabaseSync() {
687
+ FinalizeBackups();
688
+
689
+ if (IsOpen()) {
690
+ FinalizeStatements();
691
+ DeleteSessions();
692
+ sqlite3_close_v2(connection_);
693
+ connection_ = nullptr;
694
+ }
695
+ }
696
+
697
+ void DatabaseSync::MemoryInfo(MemoryTracker* tracker) const {
698
+ // TODO(tniessen): more accurately track the size of all fields
699
+ tracker->TrackFieldWithSize(
700
+ "open_config", sizeof(open_config_), "DatabaseOpenConfiguration");
701
+ }
702
+
703
+ bool DatabaseSync::Open() {
704
+ if (IsOpen()) {
705
+ THROW_ERR_INVALID_STATE(env(), "database is already open");
706
+ return false;
707
+ }
708
+
709
+ // TODO(cjihrig): Support additional flags.
710
+ int default_flags = SQLITE_OPEN_URI;
711
+ int flags = open_config_.get_read_only()
712
+ ? SQLITE_OPEN_READONLY
713
+ : SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
714
+ int r = sqlite3_open_v2(open_config_.location().c_str(),
715
+ &connection_,
716
+ flags | default_flags,
717
+ nullptr);
718
+ CHECK_ERROR_OR_THROW(env()->isolate(), this, r, SQLITE_OK, false);
719
+
720
+ r = sqlite3_db_config(connection_,
721
+ SQLITE_DBCONFIG_DQS_DML,
722
+ static_cast<int>(open_config_.get_enable_dqs()),
723
+ nullptr);
724
+ CHECK_ERROR_OR_THROW(env()->isolate(), this, r, SQLITE_OK, false);
725
+ r = sqlite3_db_config(connection_,
726
+ SQLITE_DBCONFIG_DQS_DDL,
727
+ static_cast<int>(open_config_.get_enable_dqs()),
728
+ nullptr);
729
+ CHECK_ERROR_OR_THROW(env()->isolate(), this, r, SQLITE_OK, false);
730
+
731
+ int foreign_keys_enabled;
732
+ r = sqlite3_db_config(
733
+ connection_,
734
+ SQLITE_DBCONFIG_ENABLE_FKEY,
735
+ static_cast<int>(open_config_.get_enable_foreign_keys()),
736
+ &foreign_keys_enabled);
737
+ CHECK_ERROR_OR_THROW(env()->isolate(), this, r, SQLITE_OK, false);
738
+ CHECK_EQ(foreign_keys_enabled, open_config_.get_enable_foreign_keys());
739
+
740
+ sqlite3_busy_timeout(connection_, open_config_.get_timeout());
741
+
742
+ if (allow_load_extension_) {
743
+ if (env()->permission()->enabled()) [[unlikely]] {
744
+ THROW_ERR_LOAD_SQLITE_EXTENSION(env(),
745
+ "Cannot load SQLite extensions when the "
746
+ "permission model is enabled.");
747
+ return false;
748
+ }
749
+ const int load_extension_ret = sqlite3_db_config(
750
+ connection_, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, nullptr);
751
+ CHECK_ERROR_OR_THROW(
752
+ env()->isolate(), this, load_extension_ret, SQLITE_OK, false);
753
+ }
754
+
755
+ return true;
756
+ }
757
+
758
+ void DatabaseSync::FinalizeBackups() {
759
+ for (auto backup : backups_) {
760
+ backup->Cleanup();
761
+ }
762
+
763
+ backups_.clear();
764
+ }
765
+
766
+ void DatabaseSync::FinalizeStatements() {
767
+ for (auto stmt : statements_) {
768
+ stmt->Finalize();
769
+ }
770
+
771
+ statements_.clear();
772
+ }
773
+
774
+ void DatabaseSync::UntrackStatement(StatementSync* statement) {
775
+ auto it = statements_.find(statement);
776
+ if (it != statements_.end()) {
777
+ statements_.erase(it);
778
+ }
779
+ }
780
+
781
+ inline bool DatabaseSync::IsOpen() {
782
+ return connection_ != nullptr;
783
+ }
784
+
785
+ inline sqlite3* DatabaseSync::Connection() {
786
+ return connection_;
787
+ }
788
+
789
+ void DatabaseSync::SetIgnoreNextSQLiteError(bool ignore) {
790
+ ignore_next_sqlite_error_ = ignore;
791
+ }
792
+
793
+ bool DatabaseSync::ShouldIgnoreSQLiteError() {
794
+ return ignore_next_sqlite_error_;
795
+ }
796
+
797
+ std::optional<std::string> ValidateDatabasePath(Environment* env,
798
+ Local<Value> path,
799
+ const std::string& field_name) {
800
+ constexpr auto has_null_bytes = [](std::string_view str) {
801
+ return str.find('\0') != std::string_view::npos;
802
+ };
803
+ if (path->IsString()) {
804
+ Utf8Value location(env->isolate(), path.As<String>());
805
+ if (!has_null_bytes(location.ToStringView())) {
806
+ return location.ToString();
807
+ }
808
+ } else if (path->IsUint8Array()) {
809
+ Local<Uint8Array> buffer = path.As<Uint8Array>();
810
+ size_t byteOffset = buffer->ByteOffset();
811
+ size_t byteLength = buffer->ByteLength();
812
+ auto data =
813
+ static_cast<const uint8_t*>(buffer->Buffer()->Data()) + byteOffset;
814
+ if (std::find(data, data + byteLength, 0) == data + byteLength) {
815
+ return std::string(reinterpret_cast<const char*>(data), byteLength);
816
+ }
817
+ } else if (path->IsObject()) { // When is URL
818
+ auto url = path.As<Object>();
819
+ Local<Value> href;
820
+ if (url->Get(env->context(), env->href_string()).ToLocal(&href) &&
821
+ href->IsString()) {
822
+ Utf8Value location_value(env->isolate(), href.As<String>());
823
+ auto location = location_value.ToStringView();
824
+ if (!has_null_bytes(location)) {
825
+ CHECK(ada::can_parse(location));
826
+ if (!location.starts_with("file:")) {
827
+ THROW_ERR_INVALID_URL_SCHEME(env->isolate());
828
+ return std::nullopt;
829
+ }
830
+
831
+ return location_value.ToString();
832
+ }
833
+ }
834
+ }
835
+
836
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
837
+ "The \"%s\" argument must be a string, "
838
+ "Uint8Array, or URL without null bytes.",
839
+ field_name.c_str());
840
+
841
+ return std::nullopt;
842
+ }
843
+
844
+ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
845
+ Environment* env = Environment::GetCurrent(args);
846
+ if (!args.IsConstructCall()) {
847
+ THROW_ERR_CONSTRUCT_CALL_REQUIRED(env);
848
+ return;
849
+ }
850
+
851
+ std::optional<std::string> location =
852
+ ValidateDatabasePath(env, args[0], "path");
853
+ if (!location.has_value()) {
854
+ return;
855
+ }
856
+
857
+ DatabaseOpenConfiguration open_config(std::move(location.value()));
858
+ bool open = true;
859
+ bool allow_load_extension = false;
860
+ if (args.Length() > 1) {
861
+ if (!args[1]->IsObject()) {
862
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
863
+ "The \"options\" argument must be an object.");
864
+ return;
865
+ }
866
+
867
+ Local<Object> options = args[1].As<Object>();
868
+ Local<String> open_string = FIXED_ONE_BYTE_STRING(env->isolate(), "open");
869
+ Local<Value> open_v;
870
+ if (!options->Get(env->context(), open_string).ToLocal(&open_v)) {
871
+ return;
872
+ }
873
+ if (!open_v->IsUndefined()) {
874
+ if (!open_v->IsBoolean()) {
875
+ THROW_ERR_INVALID_ARG_TYPE(
876
+ env->isolate(), "The \"options.open\" argument must be a boolean.");
877
+ return;
878
+ }
879
+ open = open_v.As<Boolean>()->Value();
880
+ }
881
+
882
+ Local<String> read_only_string =
883
+ FIXED_ONE_BYTE_STRING(env->isolate(), "readOnly");
884
+ Local<Value> read_only_v;
885
+ if (!options->Get(env->context(), read_only_string).ToLocal(&read_only_v)) {
886
+ return;
887
+ }
888
+ if (!read_only_v->IsUndefined()) {
889
+ if (!read_only_v->IsBoolean()) {
890
+ THROW_ERR_INVALID_ARG_TYPE(
891
+ env->isolate(),
892
+ "The \"options.readOnly\" argument must be a boolean.");
893
+ return;
894
+ }
895
+ open_config.set_read_only(read_only_v.As<Boolean>()->Value());
896
+ }
897
+
898
+ Local<String> enable_foreign_keys_string =
899
+ FIXED_ONE_BYTE_STRING(env->isolate(), "enableForeignKeyConstraints");
900
+ Local<Value> enable_foreign_keys_v;
901
+ if (!options->Get(env->context(), enable_foreign_keys_string)
902
+ .ToLocal(&enable_foreign_keys_v)) {
903
+ return;
904
+ }
905
+ if (!enable_foreign_keys_v->IsUndefined()) {
906
+ if (!enable_foreign_keys_v->IsBoolean()) {
907
+ THROW_ERR_INVALID_ARG_TYPE(
908
+ env->isolate(),
909
+ "The \"options.enableForeignKeyConstraints\" argument must be a "
910
+ "boolean.");
911
+ return;
912
+ }
913
+ open_config.set_enable_foreign_keys(
914
+ enable_foreign_keys_v.As<Boolean>()->Value());
915
+ }
916
+
917
+ Local<String> enable_dqs_string = FIXED_ONE_BYTE_STRING(
918
+ env->isolate(), "enableDoubleQuotedStringLiterals");
919
+ Local<Value> enable_dqs_v;
920
+ if (!options->Get(env->context(), enable_dqs_string)
921
+ .ToLocal(&enable_dqs_v)) {
922
+ return;
923
+ }
924
+ if (!enable_dqs_v->IsUndefined()) {
925
+ if (!enable_dqs_v->IsBoolean()) {
926
+ THROW_ERR_INVALID_ARG_TYPE(
927
+ env->isolate(),
928
+ "The \"options.enableDoubleQuotedStringLiterals\" argument must be "
929
+ "a boolean.");
930
+ return;
931
+ }
932
+ open_config.set_enable_dqs(enable_dqs_v.As<Boolean>()->Value());
933
+ }
934
+
935
+ Local<String> allow_extension_string =
936
+ FIXED_ONE_BYTE_STRING(env->isolate(), "allowExtension");
937
+ Local<Value> allow_extension_v;
938
+ if (!options->Get(env->context(), allow_extension_string)
939
+ .ToLocal(&allow_extension_v)) {
940
+ return;
941
+ }
942
+
943
+ if (!allow_extension_v->IsUndefined()) {
944
+ if (!allow_extension_v->IsBoolean()) {
945
+ THROW_ERR_INVALID_ARG_TYPE(
946
+ env->isolate(),
947
+ "The \"options.allowExtension\" argument must be a boolean.");
948
+ return;
949
+ }
950
+ allow_load_extension = allow_extension_v.As<Boolean>()->Value();
951
+ }
952
+
953
+ Local<Value> timeout_v;
954
+ if (!options->Get(env->context(), env->timeout_string())
955
+ .ToLocal(&timeout_v)) {
956
+ return;
957
+ }
958
+
959
+ if (!timeout_v->IsUndefined()) {
960
+ if (!timeout_v->IsInt32()) {
961
+ THROW_ERR_INVALID_ARG_TYPE(
962
+ env->isolate(),
963
+ "The \"options.timeout\" argument must be an integer.");
964
+ return;
965
+ }
966
+
967
+ open_config.set_timeout(timeout_v.As<Int32>()->Value());
968
+ }
969
+ }
970
+
971
+ new DatabaseSync(
972
+ env, args.This(), std::move(open_config), open, allow_load_extension);
973
+ }
974
+
975
+ void DatabaseSync::Open(const FunctionCallbackInfo<Value>& args) {
976
+ DatabaseSync* db;
977
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
978
+ db->Open();
979
+ }
980
+
981
+ void DatabaseSync::IsOpenGetter(const FunctionCallbackInfo<Value>& args) {
982
+ DatabaseSync* db;
983
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
984
+ args.GetReturnValue().Set(db->IsOpen());
985
+ }
986
+
987
+ void DatabaseSync::IsTransactionGetter(
988
+ const FunctionCallbackInfo<Value>& args) {
989
+ DatabaseSync* db;
990
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
991
+ Environment* env = Environment::GetCurrent(args);
992
+ THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
993
+ args.GetReturnValue().Set(sqlite3_get_autocommit(db->connection_) == 0);
994
+ }
995
+
996
+ void DatabaseSync::Close(const FunctionCallbackInfo<Value>& args) {
997
+ DatabaseSync* db;
998
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
999
+ Environment* env = Environment::GetCurrent(args);
1000
+ THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1001
+ db->FinalizeStatements();
1002
+ db->DeleteSessions();
1003
+ int r = sqlite3_close_v2(db->connection_);
1004
+ CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
1005
+ db->connection_ = nullptr;
1006
+ }
1007
+
1008
+ void DatabaseSync::Prepare(const FunctionCallbackInfo<Value>& args) {
1009
+ DatabaseSync* db;
1010
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1011
+ Environment* env = Environment::GetCurrent(args);
1012
+ THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1013
+
1014
+ if (!args[0]->IsString()) {
1015
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1016
+ "The \"sql\" argument must be a string.");
1017
+ return;
1018
+ }
1019
+
1020
+ Utf8Value sql(env->isolate(), args[0].As<String>());
1021
+ sqlite3_stmt* s = nullptr;
1022
+ int r = sqlite3_prepare_v2(db->connection_, *sql, -1, &s, 0);
1023
+ CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
1024
+ BaseObjectPtr<StatementSync> stmt =
1025
+ StatementSync::Create(env, BaseObjectPtr<DatabaseSync>(db), s);
1026
+ db->statements_.insert(stmt.get());
1027
+ args.GetReturnValue().Set(stmt->object());
1028
+ }
1029
+
1030
+ void DatabaseSync::Exec(const FunctionCallbackInfo<Value>& args) {
1031
+ DatabaseSync* db;
1032
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1033
+ Environment* env = Environment::GetCurrent(args);
1034
+ THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1035
+
1036
+ if (!args[0]->IsString()) {
1037
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1038
+ "The \"sql\" argument must be a string.");
1039
+ return;
1040
+ }
1041
+
1042
+ Utf8Value sql(env->isolate(), args[0].As<String>());
1043
+ int r = sqlite3_exec(db->connection_, *sql, nullptr, nullptr, nullptr);
1044
+ CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
1045
+ }
1046
+
1047
+ void DatabaseSync::CustomFunction(const FunctionCallbackInfo<Value>& args) {
1048
+ DatabaseSync* db;
1049
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1050
+ Environment* env = Environment::GetCurrent(args);
1051
+ THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1052
+
1053
+ if (!args[0]->IsString()) {
1054
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1055
+ "The \"name\" argument must be a string.");
1056
+ return;
1057
+ }
1058
+
1059
+ int fn_index = args.Length() < 3 ? 1 : 2;
1060
+ bool use_bigint_args = false;
1061
+ bool varargs = false;
1062
+ bool deterministic = false;
1063
+ bool direct_only = false;
1064
+
1065
+ if (fn_index > 1) {
1066
+ if (!args[1]->IsObject()) {
1067
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1068
+ "The \"options\" argument must be an object.");
1069
+ return;
1070
+ }
1071
+
1072
+ Local<Object> options = args[1].As<Object>();
1073
+ Local<Value> use_bigint_args_v;
1074
+ if (!options
1075
+ ->Get(env->context(),
1076
+ FIXED_ONE_BYTE_STRING(env->isolate(), "useBigIntArguments"))
1077
+ .ToLocal(&use_bigint_args_v)) {
1078
+ return;
1079
+ }
1080
+
1081
+ if (!use_bigint_args_v->IsUndefined()) {
1082
+ if (!use_bigint_args_v->IsBoolean()) {
1083
+ THROW_ERR_INVALID_ARG_TYPE(
1084
+ env->isolate(),
1085
+ "The \"options.useBigIntArguments\" argument must be a boolean.");
1086
+ return;
1087
+ }
1088
+ use_bigint_args = use_bigint_args_v.As<Boolean>()->Value();
1089
+ }
1090
+
1091
+ Local<Value> varargs_v;
1092
+ if (!options
1093
+ ->Get(env->context(),
1094
+ FIXED_ONE_BYTE_STRING(env->isolate(), "varargs"))
1095
+ .ToLocal(&varargs_v)) {
1096
+ return;
1097
+ }
1098
+
1099
+ if (!varargs_v->IsUndefined()) {
1100
+ if (!varargs_v->IsBoolean()) {
1101
+ THROW_ERR_INVALID_ARG_TYPE(
1102
+ env->isolate(),
1103
+ "The \"options.varargs\" argument must be a boolean.");
1104
+ return;
1105
+ }
1106
+ varargs = varargs_v.As<Boolean>()->Value();
1107
+ }
1108
+
1109
+ Local<Value> deterministic_v;
1110
+ if (!options
1111
+ ->Get(env->context(),
1112
+ FIXED_ONE_BYTE_STRING(env->isolate(), "deterministic"))
1113
+ .ToLocal(&deterministic_v)) {
1114
+ return;
1115
+ }
1116
+
1117
+ if (!deterministic_v->IsUndefined()) {
1118
+ if (!deterministic_v->IsBoolean()) {
1119
+ THROW_ERR_INVALID_ARG_TYPE(
1120
+ env->isolate(),
1121
+ "The \"options.deterministic\" argument must be a boolean.");
1122
+ return;
1123
+ }
1124
+ deterministic = deterministic_v.As<Boolean>()->Value();
1125
+ }
1126
+
1127
+ Local<Value> direct_only_v;
1128
+ if (!options
1129
+ ->Get(env->context(),
1130
+ FIXED_ONE_BYTE_STRING(env->isolate(), "directOnly"))
1131
+ .ToLocal(&direct_only_v)) {
1132
+ return;
1133
+ }
1134
+
1135
+ if (!direct_only_v->IsUndefined()) {
1136
+ if (!direct_only_v->IsBoolean()) {
1137
+ THROW_ERR_INVALID_ARG_TYPE(
1138
+ env->isolate(),
1139
+ "The \"options.directOnly\" argument must be a boolean.");
1140
+ return;
1141
+ }
1142
+ direct_only = direct_only_v.As<Boolean>()->Value();
1143
+ }
1144
+ }
1145
+
1146
+ if (!args[fn_index]->IsFunction()) {
1147
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1148
+ "The \"function\" argument must be a function.");
1149
+ return;
1150
+ }
1151
+
1152
+ Utf8Value name(env->isolate(), args[0].As<String>());
1153
+ Local<Function> fn = args[fn_index].As<Function>();
1154
+
1155
+ int argc = 0;
1156
+ if (varargs) {
1157
+ argc = -1;
1158
+ } else {
1159
+ Local<Value> js_len;
1160
+ if (!fn->Get(env->context(),
1161
+ FIXED_ONE_BYTE_STRING(env->isolate(), "length"))
1162
+ .ToLocal(&js_len)) {
1163
+ return;
1164
+ }
1165
+ argc = js_len.As<Int32>()->Value();
1166
+ }
1167
+
1168
+ UserDefinedFunction* user_data =
1169
+ new UserDefinedFunction(env, fn, db, use_bigint_args);
1170
+ int text_rep = SQLITE_UTF8;
1171
+
1172
+ if (deterministic) {
1173
+ text_rep |= SQLITE_DETERMINISTIC;
1174
+ }
1175
+
1176
+ if (direct_only) {
1177
+ text_rep |= SQLITE_DIRECTONLY;
1178
+ }
1179
+
1180
+ int r = sqlite3_create_function_v2(db->connection_,
1181
+ *name,
1182
+ argc,
1183
+ text_rep,
1184
+ user_data,
1185
+ UserDefinedFunction::xFunc,
1186
+ nullptr,
1187
+ nullptr,
1188
+ UserDefinedFunction::xDestroy);
1189
+ CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
1190
+ }
1191
+
1192
+ void DatabaseSync::Location(const FunctionCallbackInfo<Value>& args) {
1193
+ DatabaseSync* db;
1194
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1195
+ Environment* env = Environment::GetCurrent(args);
1196
+ THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1197
+
1198
+ std::string db_name = "main";
1199
+ if (!args[0]->IsUndefined()) {
1200
+ if (!args[0]->IsString()) {
1201
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1202
+ "The \"dbName\" argument must be a string.");
1203
+ return;
1204
+ }
1205
+
1206
+ db_name = Utf8Value(env->isolate(), args[0].As<String>()).ToString();
1207
+ }
1208
+
1209
+ const char* db_filename =
1210
+ sqlite3_db_filename(db->connection_, db_name.c_str());
1211
+ if (!db_filename || db_filename[0] == '\0') {
1212
+ args.GetReturnValue().Set(Null(env->isolate()));
1213
+ return;
1214
+ }
1215
+
1216
+ Local<String> ret;
1217
+ if (String::NewFromUtf8(env->isolate(), db_filename).ToLocal(&ret)) {
1218
+ args.GetReturnValue().Set(ret);
1219
+ }
1220
+ }
1221
+
1222
+ void DatabaseSync::AggregateFunction(const FunctionCallbackInfo<Value>& args) {
1223
+ DatabaseSync* db;
1224
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1225
+ Environment* env = Environment::GetCurrent(args);
1226
+ THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1227
+ Utf8Value name(env->isolate(), args[0].As<String>());
1228
+ Local<Object> options = args[1].As<Object>();
1229
+ Local<Value> start_v;
1230
+ if (!options->Get(env->context(), env->start_string()).ToLocal(&start_v)) {
1231
+ return;
1232
+ }
1233
+
1234
+ if (start_v->IsUndefined()) {
1235
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1236
+ "The \"options.start\" argument must be a "
1237
+ "function or a primitive value.");
1238
+ return;
1239
+ }
1240
+
1241
+ Local<Value> step_v;
1242
+ if (!options->Get(env->context(), env->step_string()).ToLocal(&step_v)) {
1243
+ return;
1244
+ }
1245
+
1246
+ if (!step_v->IsFunction()) {
1247
+ THROW_ERR_INVALID_ARG_TYPE(
1248
+ env->isolate(), "The \"options.step\" argument must be a function.");
1249
+ return;
1250
+ }
1251
+
1252
+ Local<Value> result_v;
1253
+ if (!options->Get(env->context(), env->result_string()).ToLocal(&result_v)) {
1254
+ return;
1255
+ }
1256
+
1257
+ bool use_bigint_args = false;
1258
+ bool varargs = false;
1259
+ bool direct_only = false;
1260
+ Local<Value> use_bigint_args_v;
1261
+ Local<Function> inverseFunc = Local<Function>();
1262
+ if (!options
1263
+ ->Get(env->context(),
1264
+ FIXED_ONE_BYTE_STRING(env->isolate(), "useBigIntArguments"))
1265
+ .ToLocal(&use_bigint_args_v)) {
1266
+ return;
1267
+ }
1268
+
1269
+ if (!use_bigint_args_v->IsUndefined()) {
1270
+ if (!use_bigint_args_v->IsBoolean()) {
1271
+ THROW_ERR_INVALID_ARG_TYPE(
1272
+ env->isolate(),
1273
+ "The \"options.useBigIntArguments\" argument must be a boolean.");
1274
+ return;
1275
+ }
1276
+ use_bigint_args = use_bigint_args_v.As<Boolean>()->Value();
1277
+ }
1278
+
1279
+ Local<Value> varargs_v;
1280
+ if (!options
1281
+ ->Get(env->context(),
1282
+ FIXED_ONE_BYTE_STRING(env->isolate(), "varargs"))
1283
+ .ToLocal(&varargs_v)) {
1284
+ return;
1285
+ }
1286
+
1287
+ if (!varargs_v->IsUndefined()) {
1288
+ if (!varargs_v->IsBoolean()) {
1289
+ THROW_ERR_INVALID_ARG_TYPE(
1290
+ env->isolate(),
1291
+ "The \"options.varargs\" argument must be a boolean.");
1292
+ return;
1293
+ }
1294
+ varargs = varargs_v.As<Boolean>()->Value();
1295
+ }
1296
+
1297
+ Local<Value> direct_only_v;
1298
+ if (!options
1299
+ ->Get(env->context(),
1300
+ FIXED_ONE_BYTE_STRING(env->isolate(), "directOnly"))
1301
+ .ToLocal(&direct_only_v)) {
1302
+ return;
1303
+ }
1304
+
1305
+ if (!direct_only_v->IsUndefined()) {
1306
+ if (!direct_only_v->IsBoolean()) {
1307
+ THROW_ERR_INVALID_ARG_TYPE(
1308
+ env->isolate(),
1309
+ "The \"options.directOnly\" argument must be a boolean.");
1310
+ return;
1311
+ }
1312
+ direct_only = direct_only_v.As<Boolean>()->Value();
1313
+ }
1314
+
1315
+ Local<Value> inverse_v;
1316
+ if (!options->Get(env->context(), env->inverse_string())
1317
+ .ToLocal(&inverse_v)) {
1318
+ return;
1319
+ }
1320
+
1321
+ if (!inverse_v->IsUndefined()) {
1322
+ if (!inverse_v->IsFunction()) {
1323
+ THROW_ERR_INVALID_ARG_TYPE(
1324
+ env->isolate(),
1325
+ "The \"options.inverse\" argument must be a function.");
1326
+ return;
1327
+ }
1328
+ inverseFunc = inverse_v.As<Function>();
1329
+ }
1330
+
1331
+ Local<Function> stepFunction = step_v.As<Function>();
1332
+ Local<Function> resultFunction =
1333
+ result_v->IsFunction() ? result_v.As<Function>() : Local<Function>();
1334
+ int argc = -1;
1335
+ if (!varargs) {
1336
+ Local<Value> js_len;
1337
+ if (!stepFunction->Get(env->context(), env->length_string())
1338
+ .ToLocal(&js_len)) {
1339
+ return;
1340
+ }
1341
+
1342
+ // Subtract 1 because the first argument is the aggregate value.
1343
+ argc = js_len.As<Int32>()->Value() - 1;
1344
+ if (!inverseFunc.IsEmpty() &&
1345
+ !inverseFunc->Get(env->context(), env->length_string())
1346
+ .ToLocal(&js_len)) {
1347
+ return;
1348
+ }
1349
+
1350
+ argc = std::max({argc, js_len.As<Int32>()->Value() - 1, 0});
1351
+ }
1352
+
1353
+ int text_rep = SQLITE_UTF8;
1354
+ if (direct_only) {
1355
+ text_rep |= SQLITE_DIRECTONLY;
1356
+ }
1357
+
1358
+ auto xInverse = !inverseFunc.IsEmpty() ? CustomAggregate::xInverse : nullptr;
1359
+ auto xValue = xInverse ? CustomAggregate::xValue : nullptr;
1360
+ int r = sqlite3_create_window_function(db->connection_,
1361
+ *name,
1362
+ argc,
1363
+ text_rep,
1364
+ new CustomAggregate(env,
1365
+ db,
1366
+ use_bigint_args,
1367
+ start_v,
1368
+ stepFunction,
1369
+ inverseFunc,
1370
+ resultFunction),
1371
+ CustomAggregate::xStep,
1372
+ CustomAggregate::xFinal,
1373
+ xValue,
1374
+ xInverse,
1375
+ CustomAggregate::xDestroy);
1376
+ CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
1377
+ }
1378
+
1379
+ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
1380
+ std::string table;
1381
+ std::string db_name = "main";
1382
+
1383
+ Environment* env = Environment::GetCurrent(args);
1384
+ if (args.Length() > 0) {
1385
+ if (!args[0]->IsObject()) {
1386
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1387
+ "The \"options\" argument must be an object.");
1388
+ return;
1389
+ }
1390
+
1391
+ Local<Object> options = args[0].As<Object>();
1392
+
1393
+ Local<String> table_key = FIXED_ONE_BYTE_STRING(env->isolate(), "table");
1394
+ bool hasIt;
1395
+ if (!options->HasOwnProperty(env->context(), table_key).To(&hasIt)) {
1396
+ return;
1397
+ }
1398
+ if (hasIt) {
1399
+ Local<Value> table_value;
1400
+ if (!options->Get(env->context(), table_key).ToLocal(&table_value)) {
1401
+ return;
1402
+ }
1403
+
1404
+ if (table_value->IsString()) {
1405
+ String::Utf8Value str(env->isolate(), table_value);
1406
+ table = *str;
1407
+ } else {
1408
+ THROW_ERR_INVALID_ARG_TYPE(
1409
+ env->isolate(), "The \"options.table\" argument must be a string.");
1410
+ return;
1411
+ }
1412
+ }
1413
+
1414
+ Local<String> db_key = FIXED_ONE_BYTE_STRING(env->isolate(), "db");
1415
+
1416
+ if (!options->HasOwnProperty(env->context(), db_key).To(&hasIt)) {
1417
+ return;
1418
+ }
1419
+ if (hasIt) {
1420
+ Local<Value> db_value;
1421
+ if (!options->Get(env->context(), db_key).ToLocal(&db_value)) {
1422
+ // An error will have been scheduled.
1423
+ return;
1424
+ }
1425
+ if (db_value->IsString()) {
1426
+ String::Utf8Value str(env->isolate(), db_value);
1427
+ db_name = std::string(*str);
1428
+ } else {
1429
+ THROW_ERR_INVALID_ARG_TYPE(
1430
+ env->isolate(), "The \"options.db\" argument must be a string.");
1431
+ return;
1432
+ }
1433
+ }
1434
+ }
1435
+
1436
+ DatabaseSync* db;
1437
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1438
+ THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1439
+
1440
+ sqlite3_session* pSession;
1441
+ int r = sqlite3session_create(db->connection_, db_name.c_str(), &pSession);
1442
+ CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
1443
+ db->sessions_.insert(pSession);
1444
+
1445
+ r = sqlite3session_attach(pSession, table == "" ? nullptr : table.c_str());
1446
+ CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
1447
+
1448
+ BaseObjectPtr<Session> session =
1449
+ Session::Create(env, BaseObjectWeakPtr<DatabaseSync>(db), pSession);
1450
+ args.GetReturnValue().Set(session->object());
1451
+ }
1452
+
1453
+ void Backup(const FunctionCallbackInfo<Value>& args) {
1454
+ Environment* env = Environment::GetCurrent(args);
1455
+ if (args.Length() < 1 || !args[0]->IsObject()) {
1456
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1457
+ "The \"sourceDb\" argument must be an object.");
1458
+ return;
1459
+ }
1460
+
1461
+ DatabaseSync* db;
1462
+ ASSIGN_OR_RETURN_UNWRAP(&db, args[0].As<Object>());
1463
+ THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1464
+ std::optional<std::string> dest_path =
1465
+ ValidateDatabasePath(env, args[1], "path");
1466
+ if (!dest_path.has_value()) {
1467
+ return;
1468
+ }
1469
+
1470
+ int rate = 100;
1471
+ std::string source_db = "main";
1472
+ std::string dest_db = "main";
1473
+ Local<Function> progressFunc = Local<Function>();
1474
+
1475
+ if (args.Length() > 2) {
1476
+ if (!args[2]->IsObject()) {
1477
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1478
+ "The \"options\" argument must be an object.");
1479
+ return;
1480
+ }
1481
+
1482
+ Local<Object> options = args[2].As<Object>();
1483
+ Local<Value> rate_v;
1484
+ if (!options->Get(env->context(), env->rate_string()).ToLocal(&rate_v)) {
1485
+ return;
1486
+ }
1487
+
1488
+ if (!rate_v->IsUndefined()) {
1489
+ if (!rate_v->IsInt32()) {
1490
+ THROW_ERR_INVALID_ARG_TYPE(
1491
+ env->isolate(),
1492
+ "The \"options.rate\" argument must be an integer.");
1493
+ return;
1494
+ }
1495
+ rate = rate_v.As<Int32>()->Value();
1496
+ }
1497
+
1498
+ Local<Value> source_v;
1499
+ if (!options->Get(env->context(), env->source_string())
1500
+ .ToLocal(&source_v)) {
1501
+ return;
1502
+ }
1503
+
1504
+ if (!source_v->IsUndefined()) {
1505
+ if (!source_v->IsString()) {
1506
+ THROW_ERR_INVALID_ARG_TYPE(
1507
+ env->isolate(),
1508
+ "The \"options.source\" argument must be a string.");
1509
+ return;
1510
+ }
1511
+
1512
+ source_db = Utf8Value(env->isolate(), source_v.As<String>()).ToString();
1513
+ }
1514
+
1515
+ Local<Value> target_v;
1516
+ if (!options->Get(env->context(), env->target_string())
1517
+ .ToLocal(&target_v)) {
1518
+ return;
1519
+ }
1520
+
1521
+ if (!target_v->IsUndefined()) {
1522
+ if (!target_v->IsString()) {
1523
+ THROW_ERR_INVALID_ARG_TYPE(
1524
+ env->isolate(),
1525
+ "The \"options.target\" argument must be a string.");
1526
+ return;
1527
+ }
1528
+
1529
+ dest_db = Utf8Value(env->isolate(), target_v.As<String>()).ToString();
1530
+ }
1531
+
1532
+ Local<Value> progress_v;
1533
+ if (!options->Get(env->context(), env->progress_string())
1534
+ .ToLocal(&progress_v)) {
1535
+ return;
1536
+ }
1537
+
1538
+ if (!progress_v->IsUndefined()) {
1539
+ if (!progress_v->IsFunction()) {
1540
+ THROW_ERR_INVALID_ARG_TYPE(
1541
+ env->isolate(),
1542
+ "The \"options.progress\" argument must be a function.");
1543
+ return;
1544
+ }
1545
+ progressFunc = progress_v.As<Function>();
1546
+ }
1547
+ }
1548
+
1549
+ Local<Promise::Resolver> resolver;
1550
+ if (!Promise::Resolver::New(env->context()).ToLocal(&resolver)) {
1551
+ return;
1552
+ }
1553
+
1554
+ args.GetReturnValue().Set(resolver->GetPromise());
1555
+ BackupJob* job = new BackupJob(env,
1556
+ db,
1557
+ resolver,
1558
+ std::move(source_db),
1559
+ dest_path.value(),
1560
+ std::move(dest_db),
1561
+ rate,
1562
+ progressFunc);
1563
+ db->AddBackup(job);
1564
+ job->ScheduleBackup();
1565
+ }
1566
+
1567
+ // the reason for using static functions here is that SQLite needs a
1568
+ // function pointer
1569
+ static std::function<int(int)> conflictCallback;
1570
+
1571
+ static int xConflict(void* pCtx, int eConflict, sqlite3_changeset_iter* pIter) {
1572
+ if (!conflictCallback) return SQLITE_CHANGESET_ABORT;
1573
+ return conflictCallback(eConflict);
1574
+ }
1575
+
1576
+ static std::function<bool(std::string)> filterCallback;
1577
+
1578
+ static int xFilter(void* pCtx, const char* zTab) {
1579
+ if (!filterCallback) return 1;
1580
+
1581
+ return filterCallback(zTab) ? 1 : 0;
1582
+ }
1583
+
1584
+ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
1585
+ conflictCallback = nullptr;
1586
+ filterCallback = nullptr;
1587
+
1588
+ DatabaseSync* db;
1589
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1590
+ Environment* env = Environment::GetCurrent(args);
1591
+ THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1592
+
1593
+ if (!args[0]->IsUint8Array()) {
1594
+ THROW_ERR_INVALID_ARG_TYPE(
1595
+ env->isolate(), "The \"changeset\" argument must be a Uint8Array.");
1596
+ return;
1597
+ }
1598
+
1599
+ if (args.Length() > 1 && !args[1]->IsUndefined()) {
1600
+ if (!args[1]->IsObject()) {
1601
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1602
+ "The \"options\" argument must be an object.");
1603
+ return;
1604
+ }
1605
+
1606
+ Local<Object> options = args[1].As<Object>();
1607
+ Local<Value> conflictValue;
1608
+ if (!options->Get(env->context(), env->onconflict_string())
1609
+ .ToLocal(&conflictValue)) {
1610
+ // An error will have been scheduled.
1611
+ return;
1612
+ }
1613
+
1614
+ if (!conflictValue->IsUndefined()) {
1615
+ if (!conflictValue->IsFunction()) {
1616
+ THROW_ERR_INVALID_ARG_TYPE(
1617
+ env->isolate(),
1618
+ "The \"options.onConflict\" argument must be a function.");
1619
+ return;
1620
+ }
1621
+ Local<Function> conflictFunc = conflictValue.As<Function>();
1622
+ conflictCallback = [env, conflictFunc](int conflictType) -> int {
1623
+ Local<Value> argv[] = {Integer::New(env->isolate(), conflictType)};
1624
+ TryCatch try_catch(env->isolate());
1625
+ Local<Value> result =
1626
+ conflictFunc->Call(env->context(), Null(env->isolate()), 1, argv)
1627
+ .FromMaybe(Local<Value>());
1628
+ if (try_catch.HasCaught()) {
1629
+ try_catch.ReThrow();
1630
+ return SQLITE_CHANGESET_ABORT;
1631
+ }
1632
+ constexpr auto invalid_value = -1;
1633
+ if (!result->IsInt32()) return invalid_value;
1634
+ return result->Int32Value(env->context()).FromJust();
1635
+ };
1636
+ }
1637
+
1638
+ bool hasIt;
1639
+ if (!options->HasOwnProperty(env->context(), env->filter_string())
1640
+ .To(&hasIt)) {
1641
+ return;
1642
+ }
1643
+ if (hasIt) {
1644
+ Local<Value> filterValue;
1645
+ if (!options->Get(env->context(), env->filter_string())
1646
+ .ToLocal(&filterValue)) {
1647
+ // An error will have been scheduled.
1648
+ return;
1649
+ }
1650
+
1651
+ if (!filterValue->IsFunction()) {
1652
+ THROW_ERR_INVALID_ARG_TYPE(
1653
+ env->isolate(),
1654
+ "The \"options.filter\" argument must be a function.");
1655
+ return;
1656
+ }
1657
+
1658
+ Local<Function> filterFunc = filterValue.As<Function>();
1659
+
1660
+ filterCallback = [env, filterFunc](std::string item) -> bool {
1661
+ // TODO(@jasnell): The use of ToLocalChecked here means that if
1662
+ // the filter function throws an error the process will crash.
1663
+ // The filterCallback should be updated to avoid the check and
1664
+ // propagate the error correctly.
1665
+ Local<Value> argv[] = {String::NewFromUtf8(env->isolate(),
1666
+ item.c_str(),
1667
+ NewStringType::kNormal)
1668
+ .ToLocalChecked()};
1669
+ Local<Value> result =
1670
+ filterFunc->Call(env->context(), Null(env->isolate()), 1, argv)
1671
+ .ToLocalChecked();
1672
+ return result->BooleanValue(env->isolate());
1673
+ };
1674
+ }
1675
+ }
1676
+
1677
+ ArrayBufferViewContents<uint8_t> buf(args[0]);
1678
+ int r = sqlite3changeset_apply(
1679
+ db->connection_,
1680
+ buf.length(),
1681
+ const_cast<void*>(static_cast<const void*>(buf.data())),
1682
+ xFilter,
1683
+ xConflict,
1684
+ nullptr);
1685
+ if (r == SQLITE_OK) {
1686
+ args.GetReturnValue().Set(true);
1687
+ return;
1688
+ }
1689
+ if (r == SQLITE_ABORT) {
1690
+ // this is not an error, return false
1691
+ args.GetReturnValue().Set(false);
1692
+ return;
1693
+ }
1694
+ THROW_ERR_SQLITE_ERROR(env->isolate(), r);
1695
+ }
1696
+
1697
+ void DatabaseSync::EnableLoadExtension(
1698
+ const FunctionCallbackInfo<Value>& args) {
1699
+ DatabaseSync* db;
1700
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1701
+ Environment* env = Environment::GetCurrent(args);
1702
+ if (!args[0]->IsBoolean()) {
1703
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1704
+ "The \"allow\" argument must be a boolean.");
1705
+ return;
1706
+ }
1707
+
1708
+ const int enable = args[0].As<Boolean>()->Value();
1709
+ auto isolate = env->isolate();
1710
+
1711
+ if (db->allow_load_extension_ == false && enable == true) {
1712
+ THROW_ERR_INVALID_STATE(
1713
+ isolate,
1714
+ "Cannot enable extension loading because it was disabled at database "
1715
+ "creation.");
1716
+ return;
1717
+ }
1718
+ db->enable_load_extension_ = enable;
1719
+ const int load_extension_ret = sqlite3_db_config(
1720
+ db->connection_, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, enable, nullptr);
1721
+ CHECK_ERROR_OR_THROW(isolate, db, load_extension_ret, SQLITE_OK, void());
1722
+ }
1723
+
1724
+ void DatabaseSync::LoadExtension(const FunctionCallbackInfo<Value>& args) {
1725
+ DatabaseSync* db;
1726
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1727
+ Environment* env = Environment::GetCurrent(args);
1728
+ THROW_AND_RETURN_ON_BAD_STATE(
1729
+ env, db->connection_ == nullptr, "database is not open");
1730
+ THROW_AND_RETURN_ON_BAD_STATE(
1731
+ env, !db->allow_load_extension_, "extension loading is not allowed");
1732
+ THROW_AND_RETURN_ON_BAD_STATE(
1733
+ env, !db->enable_load_extension_, "extension loading is not allowed");
1734
+
1735
+ if (!args[0]->IsString()) {
1736
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1737
+ "The \"path\" argument must be a string.");
1738
+ return;
1739
+ }
1740
+
1741
+ auto isolate = env->isolate();
1742
+
1743
+ BufferValue path(isolate, args[0]);
1744
+ BufferValue entryPoint(isolate, args[1]);
1745
+ CHECK_NOT_NULL(*path);
1746
+ ToNamespacedPath(env, &path);
1747
+ if (*entryPoint == nullptr) {
1748
+ ToNamespacedPath(env, &entryPoint);
1749
+ }
1750
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
1751
+ env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
1752
+ char* errmsg = nullptr;
1753
+ const int r =
1754
+ sqlite3_load_extension(db->connection_, *path, *entryPoint, &errmsg);
1755
+ if (r != SQLITE_OK) {
1756
+ isolate->ThrowException(ERR_LOAD_SQLITE_EXTENSION(isolate, errmsg));
1757
+ }
1758
+ }
1759
+
1760
+ StatementSync::StatementSync(Environment* env,
1761
+ Local<Object> object,
1762
+ BaseObjectPtr<DatabaseSync> db,
1763
+ sqlite3_stmt* stmt)
1764
+ : BaseObject(env, object), db_(std::move(db)) {
1765
+ MakeWeak();
1766
+ statement_ = stmt;
1767
+ // In the future, some of these options could be set at the database
1768
+ // connection level and inherited by statements to reduce boilerplate.
1769
+ return_arrays_ = false;
1770
+ use_big_ints_ = false;
1771
+ allow_bare_named_params_ = true;
1772
+ allow_unknown_named_params_ = false;
1773
+ bare_named_params_ = std::nullopt;
1774
+ }
1775
+
1776
+ StatementSync::~StatementSync() {
1777
+ if (!IsFinalized()) {
1778
+ db_->UntrackStatement(this);
1779
+ Finalize();
1780
+ }
1781
+ }
1782
+
1783
+ void StatementSync::Finalize() {
1784
+ sqlite3_finalize(statement_);
1785
+ statement_ = nullptr;
1786
+ }
1787
+
1788
+ inline bool StatementSync::IsFinalized() {
1789
+ return statement_ == nullptr;
1790
+ }
1791
+
1792
+ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
1793
+ int r = sqlite3_clear_bindings(statement_);
1794
+ CHECK_ERROR_OR_THROW(env()->isolate(), db_.get(), r, SQLITE_OK, false);
1795
+
1796
+ int anon_idx = 1;
1797
+ int anon_start = 0;
1798
+
1799
+ if (args[0]->IsObject() && !args[0]->IsArrayBufferView()) {
1800
+ Local<Object> obj = args[0].As<Object>();
1801
+ Local<Context> context = obj->GetIsolate()->GetCurrentContext();
1802
+ Local<Array> keys;
1803
+ if (!obj->GetOwnPropertyNames(context).ToLocal(&keys)) {
1804
+ return false;
1805
+ }
1806
+
1807
+ if (allow_bare_named_params_ && !bare_named_params_.has_value()) {
1808
+ bare_named_params_.emplace();
1809
+ int param_count = sqlite3_bind_parameter_count(statement_);
1810
+ // Parameter indexing starts at one.
1811
+ for (int i = 1; i <= param_count; ++i) {
1812
+ const char* name = sqlite3_bind_parameter_name(statement_, i);
1813
+ if (name == nullptr) {
1814
+ continue;
1815
+ }
1816
+
1817
+ auto bare_name = std::string(name + 1);
1818
+ auto full_name = std::string(name);
1819
+ auto insertion = bare_named_params_->insert({bare_name, full_name});
1820
+ if (insertion.second == false) {
1821
+ auto existing_full_name = (*insertion.first).second;
1822
+ if (full_name != existing_full_name) {
1823
+ THROW_ERR_INVALID_STATE(
1824
+ env(),
1825
+ "Cannot create bare named parameter '%s' because of "
1826
+ "conflicting names '%s' and '%s'.",
1827
+ bare_name,
1828
+ existing_full_name,
1829
+ full_name);
1830
+ return false;
1831
+ }
1832
+ }
1833
+ }
1834
+ }
1835
+
1836
+ uint32_t len = keys->Length();
1837
+ for (uint32_t j = 0; j < len; j++) {
1838
+ Local<Value> key;
1839
+ if (!keys->Get(context, j).ToLocal(&key)) {
1840
+ return false;
1841
+ }
1842
+
1843
+ Utf8Value utf8_key(env()->isolate(), key);
1844
+ int r = sqlite3_bind_parameter_index(statement_, *utf8_key);
1845
+ if (r == 0) {
1846
+ if (allow_bare_named_params_) {
1847
+ auto lookup = bare_named_params_->find(std::string(*utf8_key));
1848
+ if (lookup != bare_named_params_->end()) {
1849
+ r = sqlite3_bind_parameter_index(statement_,
1850
+ lookup->second.c_str());
1851
+ }
1852
+ }
1853
+
1854
+ if (r == 0) {
1855
+ if (allow_unknown_named_params_) {
1856
+ continue;
1857
+ } else {
1858
+ THROW_ERR_INVALID_STATE(
1859
+ env(), "Unknown named parameter '%s'", *utf8_key);
1860
+ return false;
1861
+ }
1862
+ }
1863
+ }
1864
+
1865
+ Local<Value> value;
1866
+ if (!obj->Get(context, key).ToLocal(&value)) {
1867
+ return false;
1868
+ }
1869
+
1870
+ if (!BindValue(value, r)) {
1871
+ return false;
1872
+ }
1873
+ }
1874
+ anon_start++;
1875
+ }
1876
+
1877
+ for (int i = anon_start; i < args.Length(); ++i) {
1878
+ while (sqlite3_bind_parameter_name(statement_, anon_idx) != nullptr) {
1879
+ anon_idx++;
1880
+ }
1881
+
1882
+ if (!BindValue(args[i], anon_idx)) {
1883
+ return false;
1884
+ }
1885
+
1886
+ anon_idx++;
1887
+ }
1888
+
1889
+ return true;
1890
+ }
1891
+
1892
+ bool StatementSync::BindValue(const Local<Value>& value, const int index) {
1893
+ // SQLite only supports a subset of JavaScript types. Some JS types such as
1894
+ // functions don't make sense to support. Other JS types such as booleans and
1895
+ // Dates could be supported by converting them to numbers. However, there
1896
+ // would not be a good way to read the values back from SQLite with the
1897
+ // original type.
1898
+ int r;
1899
+ if (value->IsNumber()) {
1900
+ double val = value.As<Number>()->Value();
1901
+ r = sqlite3_bind_double(statement_, index, val);
1902
+ } else if (value->IsString()) {
1903
+ Utf8Value val(env()->isolate(), value.As<String>());
1904
+ r = sqlite3_bind_text(
1905
+ statement_, index, *val, val.length(), SQLITE_TRANSIENT);
1906
+ } else if (value->IsNull()) {
1907
+ r = sqlite3_bind_null(statement_, index);
1908
+ } else if (value->IsArrayBufferView()) {
1909
+ ArrayBufferViewContents<uint8_t> buf(value);
1910
+ r = sqlite3_bind_blob(
1911
+ statement_, index, buf.data(), buf.length(), SQLITE_TRANSIENT);
1912
+ } else if (value->IsBigInt()) {
1913
+ bool lossless;
1914
+ int64_t as_int = value.As<BigInt>()->Int64Value(&lossless);
1915
+ if (!lossless) {
1916
+ THROW_ERR_INVALID_ARG_VALUE(env(), "BigInt value is too large to bind.");
1917
+ return false;
1918
+ }
1919
+ r = sqlite3_bind_int64(statement_, index, as_int);
1920
+ } else {
1921
+ THROW_ERR_INVALID_ARG_TYPE(
1922
+ env()->isolate(),
1923
+ "Provided value cannot be bound to SQLite parameter %d.",
1924
+ index);
1925
+ return false;
1926
+ }
1927
+
1928
+ CHECK_ERROR_OR_THROW(env()->isolate(), db_.get(), r, SQLITE_OK, false);
1929
+ return true;
1930
+ }
1931
+
1932
+ MaybeLocal<Value> StatementSync::ColumnToValue(const int column) {
1933
+ Isolate* isolate = env()->isolate();
1934
+ MaybeLocal<Value> js_val = MaybeLocal<Value>();
1935
+ SQLITE_VALUE_TO_JS(
1936
+ column, isolate, use_big_ints_, js_val, statement_, column);
1937
+ return js_val;
1938
+ }
1939
+
1940
+ MaybeLocal<Name> StatementSync::ColumnNameToName(const int column) {
1941
+ const char* col_name = sqlite3_column_name(statement_, column);
1942
+ if (col_name == nullptr) {
1943
+ THROW_ERR_INVALID_STATE(env(), "Cannot get name of column %d", column);
1944
+ return MaybeLocal<Name>();
1945
+ }
1946
+
1947
+ return String::NewFromUtf8(env()->isolate(), col_name).As<Name>();
1948
+ }
1949
+
1950
+ void StatementSync::MemoryInfo(MemoryTracker* tracker) const {}
1951
+
1952
+ void StatementSync::All(const FunctionCallbackInfo<Value>& args) {
1953
+ StatementSync* stmt;
1954
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
1955
+ Environment* env = Environment::GetCurrent(args);
1956
+ THROW_AND_RETURN_ON_BAD_STATE(
1957
+ env, stmt->IsFinalized(), "statement has been finalized");
1958
+ Isolate* isolate = env->isolate();
1959
+ int r = sqlite3_reset(stmt->statement_);
1960
+ CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, void());
1961
+
1962
+ if (!stmt->BindParams(args)) {
1963
+ return;
1964
+ }
1965
+
1966
+ auto reset = OnScopeLeave([&]() { sqlite3_reset(stmt->statement_); });
1967
+ int num_cols = sqlite3_column_count(stmt->statement_);
1968
+ LocalVector<Value> rows(isolate);
1969
+
1970
+ if (stmt->return_arrays_) {
1971
+ while ((r = sqlite3_step(stmt->statement_)) == SQLITE_ROW) {
1972
+ LocalVector<Value> array_values(isolate);
1973
+ array_values.reserve(num_cols);
1974
+ for (int i = 0; i < num_cols; ++i) {
1975
+ Local<Value> val;
1976
+ if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1977
+ array_values.emplace_back(val);
1978
+ }
1979
+ Local<Array> row_array =
1980
+ Array::New(isolate, array_values.data(), array_values.size());
1981
+ rows.emplace_back(row_array);
1982
+ }
1983
+ } else {
1984
+ LocalVector<Name> row_keys(isolate);
1985
+
1986
+ while ((r = sqlite3_step(stmt->statement_)) == SQLITE_ROW) {
1987
+ if (row_keys.size() == 0) {
1988
+ row_keys.reserve(num_cols);
1989
+ for (int i = 0; i < num_cols; ++i) {
1990
+ Local<Name> key;
1991
+ if (!stmt->ColumnNameToName(i).ToLocal(&key)) return;
1992
+ row_keys.emplace_back(key);
1993
+ }
1994
+ }
1995
+
1996
+ LocalVector<Value> row_values(isolate);
1997
+ row_values.reserve(num_cols);
1998
+ for (int i = 0; i < num_cols; ++i) {
1999
+ Local<Value> val;
2000
+ if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
2001
+ row_values.emplace_back(val);
2002
+ }
2003
+
2004
+ DCHECK_EQ(row_keys.size(), row_values.size());
2005
+ Local<Object> row_obj = Object::New(
2006
+ isolate, Null(isolate), row_keys.data(), row_values.data(), num_cols);
2007
+ rows.emplace_back(row_obj);
2008
+ }
2009
+ }
2010
+
2011
+ CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_DONE, void());
2012
+ args.GetReturnValue().Set(Array::New(isolate, rows.data(), rows.size()));
2013
+ }
2014
+
2015
+ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
2016
+ StatementSync* stmt;
2017
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2018
+ Environment* env = Environment::GetCurrent(args);
2019
+ THROW_AND_RETURN_ON_BAD_STATE(
2020
+ env, stmt->IsFinalized(), "statement has been finalized");
2021
+ auto isolate = env->isolate();
2022
+ auto context = env->context();
2023
+ int r = sqlite3_reset(stmt->statement_);
2024
+ CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, void());
2025
+
2026
+ if (!stmt->BindParams(args)) {
2027
+ return;
2028
+ }
2029
+
2030
+ Local<Object> global = context->Global();
2031
+ Local<Value> js_iterator;
2032
+ Local<Value> js_iterator_prototype;
2033
+ if (!global->Get(context, env->iterator_string()).ToLocal(&js_iterator)) {
2034
+ return;
2035
+ }
2036
+ if (!js_iterator.As<Object>()
2037
+ ->Get(context, env->prototype_string())
2038
+ .ToLocal(&js_iterator_prototype)) {
2039
+ return;
2040
+ }
2041
+
2042
+ BaseObjectPtr<StatementSyncIterator> iter =
2043
+ StatementSyncIterator::Create(env, BaseObjectPtr<StatementSync>(stmt));
2044
+
2045
+ if (iter->object()
2046
+ ->GetPrototype()
2047
+ .As<Object>()
2048
+ ->SetPrototype(context, js_iterator_prototype)
2049
+ .IsNothing()) {
2050
+ return;
2051
+ }
2052
+
2053
+ args.GetReturnValue().Set(iter->object());
2054
+ }
2055
+
2056
+ void StatementSync::Get(const FunctionCallbackInfo<Value>& args) {
2057
+ StatementSync* stmt;
2058
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2059
+ Environment* env = Environment::GetCurrent(args);
2060
+ THROW_AND_RETURN_ON_BAD_STATE(
2061
+ env, stmt->IsFinalized(), "statement has been finalized");
2062
+ Isolate* isolate = env->isolate();
2063
+ int r = sqlite3_reset(stmt->statement_);
2064
+ CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, void());
2065
+
2066
+ if (!stmt->BindParams(args)) {
2067
+ return;
2068
+ }
2069
+
2070
+ auto reset = OnScopeLeave([&]() { sqlite3_reset(stmt->statement_); });
2071
+ r = sqlite3_step(stmt->statement_);
2072
+ if (r == SQLITE_DONE) return;
2073
+ if (r != SQLITE_ROW) {
2074
+ THROW_ERR_SQLITE_ERROR(isolate, stmt->db_.get());
2075
+ return;
2076
+ }
2077
+
2078
+ int num_cols = sqlite3_column_count(stmt->statement_);
2079
+ if (num_cols == 0) {
2080
+ return;
2081
+ }
2082
+
2083
+ if (stmt->return_arrays_) {
2084
+ LocalVector<Value> array_values(isolate);
2085
+ array_values.reserve(num_cols);
2086
+ for (int i = 0; i < num_cols; ++i) {
2087
+ Local<Value> val;
2088
+ if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
2089
+ array_values.emplace_back(val);
2090
+ }
2091
+ Local<Array> result =
2092
+ Array::New(isolate, array_values.data(), array_values.size());
2093
+ args.GetReturnValue().Set(result);
2094
+ } else {
2095
+ LocalVector<Name> keys(isolate);
2096
+ keys.reserve(num_cols);
2097
+ LocalVector<Value> values(isolate);
2098
+ values.reserve(num_cols);
2099
+
2100
+ for (int i = 0; i < num_cols; ++i) {
2101
+ Local<Name> key;
2102
+ if (!stmt->ColumnNameToName(i).ToLocal(&key)) return;
2103
+ Local<Value> val;
2104
+ if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
2105
+ keys.emplace_back(key);
2106
+ values.emplace_back(val);
2107
+ }
2108
+
2109
+ DCHECK_EQ(keys.size(), values.size());
2110
+ Local<Object> result = Object::New(
2111
+ isolate, Null(isolate), keys.data(), values.data(), num_cols);
2112
+
2113
+ args.GetReturnValue().Set(result);
2114
+ }
2115
+ }
2116
+
2117
+ void StatementSync::Run(const FunctionCallbackInfo<Value>& args) {
2118
+ StatementSync* stmt;
2119
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2120
+ Environment* env = Environment::GetCurrent(args);
2121
+ THROW_AND_RETURN_ON_BAD_STATE(
2122
+ env, stmt->IsFinalized(), "statement has been finalized");
2123
+ int r = sqlite3_reset(stmt->statement_);
2124
+ CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
2125
+
2126
+ if (!stmt->BindParams(args)) {
2127
+ return;
2128
+ }
2129
+
2130
+ sqlite3_step(stmt->statement_);
2131
+ r = sqlite3_reset(stmt->statement_);
2132
+ CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
2133
+ Local<Object> result = Object::New(env->isolate());
2134
+ sqlite3_int64 last_insert_rowid =
2135
+ sqlite3_last_insert_rowid(stmt->db_->Connection());
2136
+ sqlite3_int64 changes = sqlite3_changes64(stmt->db_->Connection());
2137
+ Local<Value> last_insert_rowid_val;
2138
+ Local<Value> changes_val;
2139
+
2140
+ if (stmt->use_big_ints_) {
2141
+ last_insert_rowid_val = BigInt::New(env->isolate(), last_insert_rowid);
2142
+ changes_val = BigInt::New(env->isolate(), changes);
2143
+ } else {
2144
+ last_insert_rowid_val = Number::New(env->isolate(), last_insert_rowid);
2145
+ changes_val = Number::New(env->isolate(), changes);
2146
+ }
2147
+
2148
+ if (result
2149
+ ->Set(env->context(),
2150
+ env->last_insert_rowid_string(),
2151
+ last_insert_rowid_val)
2152
+ .IsNothing() ||
2153
+ result->Set(env->context(), env->changes_string(), changes_val)
2154
+ .IsNothing()) {
2155
+ return;
2156
+ }
2157
+
2158
+ args.GetReturnValue().Set(result);
2159
+ }
2160
+
2161
+ void StatementSync::Columns(const FunctionCallbackInfo<Value>& args) {
2162
+ StatementSync* stmt;
2163
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2164
+ Environment* env = Environment::GetCurrent(args);
2165
+ THROW_AND_RETURN_ON_BAD_STATE(
2166
+ env, stmt->IsFinalized(), "statement has been finalized");
2167
+ int num_cols = sqlite3_column_count(stmt->statement_);
2168
+ Isolate* isolate = env->isolate();
2169
+ LocalVector<Value> cols(isolate);
2170
+ LocalVector<Name> col_keys(isolate,
2171
+ {env->column_string(),
2172
+ env->database_string(),
2173
+ env->name_string(),
2174
+ env->table_string(),
2175
+ env->type_string()});
2176
+ Local<Value> value;
2177
+
2178
+ cols.reserve(num_cols);
2179
+ for (int i = 0; i < num_cols; ++i) {
2180
+ LocalVector<Value> col_values(isolate);
2181
+ col_values.reserve(col_keys.size());
2182
+
2183
+ if (!NullableSQLiteStringToValue(
2184
+ isolate, sqlite3_column_origin_name(stmt->statement_, i))
2185
+ .ToLocal(&value)) {
2186
+ return;
2187
+ }
2188
+ col_values.emplace_back(value);
2189
+
2190
+ if (!NullableSQLiteStringToValue(
2191
+ isolate, sqlite3_column_database_name(stmt->statement_, i))
2192
+ .ToLocal(&value)) {
2193
+ return;
2194
+ }
2195
+ col_values.emplace_back(value);
2196
+
2197
+ if (!stmt->ColumnNameToName(i).ToLocal(&value)) {
2198
+ return;
2199
+ }
2200
+ col_values.emplace_back(value);
2201
+
2202
+ if (!NullableSQLiteStringToValue(
2203
+ isolate, sqlite3_column_table_name(stmt->statement_, i))
2204
+ .ToLocal(&value)) {
2205
+ return;
2206
+ }
2207
+ col_values.emplace_back(value);
2208
+
2209
+ if (!NullableSQLiteStringToValue(
2210
+ isolate, sqlite3_column_decltype(stmt->statement_, i))
2211
+ .ToLocal(&value)) {
2212
+ return;
2213
+ }
2214
+ col_values.emplace_back(value);
2215
+
2216
+ Local<Object> column = Object::New(isolate,
2217
+ Null(isolate),
2218
+ col_keys.data(),
2219
+ col_values.data(),
2220
+ col_keys.size());
2221
+ cols.emplace_back(column);
2222
+ }
2223
+
2224
+ args.GetReturnValue().Set(Array::New(isolate, cols.data(), cols.size()));
2225
+ }
2226
+
2227
+ void StatementSync::SourceSQLGetter(const FunctionCallbackInfo<Value>& args) {
2228
+ StatementSync* stmt;
2229
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2230
+ Environment* env = Environment::GetCurrent(args);
2231
+ THROW_AND_RETURN_ON_BAD_STATE(
2232
+ env, stmt->IsFinalized(), "statement has been finalized");
2233
+ Local<String> sql;
2234
+ if (!String::NewFromUtf8(env->isolate(), sqlite3_sql(stmt->statement_))
2235
+ .ToLocal(&sql)) {
2236
+ return;
2237
+ }
2238
+ args.GetReturnValue().Set(sql);
2239
+ }
2240
+
2241
+ void StatementSync::ExpandedSQLGetter(const FunctionCallbackInfo<Value>& args) {
2242
+ StatementSync* stmt;
2243
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2244
+ Environment* env = Environment::GetCurrent(args);
2245
+ THROW_AND_RETURN_ON_BAD_STATE(
2246
+ env, stmt->IsFinalized(), "statement has been finalized");
2247
+
2248
+ // sqlite3_expanded_sql may return nullptr without producing an error code.
2249
+ char* expanded = sqlite3_expanded_sql(stmt->statement_);
2250
+ if (expanded == nullptr) {
2251
+ return THROW_ERR_SQLITE_ERROR(
2252
+ env->isolate(), "Expanded SQL text would exceed configured limits");
2253
+ }
2254
+ auto maybe_expanded = String::NewFromUtf8(env->isolate(), expanded);
2255
+ sqlite3_free(expanded);
2256
+ Local<String> result;
2257
+ if (!maybe_expanded.ToLocal(&result)) {
2258
+ return;
2259
+ }
2260
+ args.GetReturnValue().Set(result);
2261
+ }
2262
+
2263
+ void StatementSync::SetAllowBareNamedParameters(
2264
+ const FunctionCallbackInfo<Value>& args) {
2265
+ StatementSync* stmt;
2266
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2267
+ Environment* env = Environment::GetCurrent(args);
2268
+ THROW_AND_RETURN_ON_BAD_STATE(
2269
+ env, stmt->IsFinalized(), "statement has been finalized");
2270
+
2271
+ if (!args[0]->IsBoolean()) {
2272
+ THROW_ERR_INVALID_ARG_TYPE(
2273
+ env->isolate(),
2274
+ "The \"allowBareNamedParameters\" argument must be a boolean.");
2275
+ return;
2276
+ }
2277
+
2278
+ stmt->allow_bare_named_params_ = args[0]->IsTrue();
2279
+ }
2280
+
2281
+ void StatementSync::SetAllowUnknownNamedParameters(
2282
+ const FunctionCallbackInfo<Value>& args) {
2283
+ StatementSync* stmt;
2284
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2285
+ Environment* env = Environment::GetCurrent(args);
2286
+ THROW_AND_RETURN_ON_BAD_STATE(
2287
+ env, stmt->IsFinalized(), "statement has been finalized");
2288
+
2289
+ if (!args[0]->IsBoolean()) {
2290
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
2291
+ "The \"enabled\" argument must be a boolean.");
2292
+ return;
2293
+ }
2294
+
2295
+ stmt->allow_unknown_named_params_ = args[0]->IsTrue();
2296
+ }
2297
+
2298
+ void StatementSync::SetReadBigInts(const FunctionCallbackInfo<Value>& args) {
2299
+ StatementSync* stmt;
2300
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2301
+ Environment* env = Environment::GetCurrent(args);
2302
+ THROW_AND_RETURN_ON_BAD_STATE(
2303
+ env, stmt->IsFinalized(), "statement has been finalized");
2304
+
2305
+ if (!args[0]->IsBoolean()) {
2306
+ THROW_ERR_INVALID_ARG_TYPE(
2307
+ env->isolate(), "The \"readBigInts\" argument must be a boolean.");
2308
+ return;
2309
+ }
2310
+
2311
+ stmt->use_big_ints_ = args[0]->IsTrue();
2312
+ }
2313
+
2314
+ void StatementSync::SetReturnArrays(const FunctionCallbackInfo<Value>& args) {
2315
+ StatementSync* stmt;
2316
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2317
+ Environment* env = Environment::GetCurrent(args);
2318
+ THROW_AND_RETURN_ON_BAD_STATE(
2319
+ env, stmt->IsFinalized(), "statement has been finalized");
2320
+
2321
+ if (!args[0]->IsBoolean()) {
2322
+ THROW_ERR_INVALID_ARG_TYPE(
2323
+ env->isolate(), "The \"returnArrays\" argument must be a boolean.");
2324
+ return;
2325
+ }
2326
+
2327
+ stmt->return_arrays_ = args[0]->IsTrue();
2328
+ }
2329
+
2330
+ void IllegalConstructor(const FunctionCallbackInfo<Value>& args) {
2331
+ THROW_ERR_ILLEGAL_CONSTRUCTOR(Environment::GetCurrent(args));
2332
+ }
2333
+
2334
+ static inline void SetSideEffectFreeGetter(
2335
+ Isolate* isolate,
2336
+ Local<FunctionTemplate> class_template,
2337
+ Local<String> name,
2338
+ FunctionCallback fn) {
2339
+ Local<FunctionTemplate> getter =
2340
+ FunctionTemplate::New(isolate,
2341
+ fn,
2342
+ Local<Value>(),
2343
+ v8::Signature::New(isolate, class_template),
2344
+ /* length */ 0,
2345
+ ConstructorBehavior::kThrow,
2346
+ SideEffectType::kHasNoSideEffect);
2347
+ class_template->InstanceTemplate()->SetAccessorProperty(
2348
+ name, getter, Local<FunctionTemplate>(), DontDelete);
2349
+ }
2350
+
2351
+ Local<FunctionTemplate> StatementSync::GetConstructorTemplate(
2352
+ Environment* env) {
2353
+ Local<FunctionTemplate> tmpl =
2354
+ env->sqlite_statement_sync_constructor_template();
2355
+ if (tmpl.IsEmpty()) {
2356
+ Isolate* isolate = env->isolate();
2357
+ tmpl = NewFunctionTemplate(isolate, IllegalConstructor);
2358
+ tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "StatementSync"));
2359
+ tmpl->InstanceTemplate()->SetInternalFieldCount(
2360
+ StatementSync::kInternalFieldCount);
2361
+ SetProtoMethod(isolate, tmpl, "iterate", StatementSync::Iterate);
2362
+ SetProtoMethod(isolate, tmpl, "all", StatementSync::All);
2363
+ SetProtoMethod(isolate, tmpl, "get", StatementSync::Get);
2364
+ SetProtoMethod(isolate, tmpl, "run", StatementSync::Run);
2365
+ SetProtoMethodNoSideEffect(
2366
+ isolate, tmpl, "columns", StatementSync::Columns);
2367
+ SetSideEffectFreeGetter(isolate,
2368
+ tmpl,
2369
+ FIXED_ONE_BYTE_STRING(isolate, "sourceSQL"),
2370
+ StatementSync::SourceSQLGetter);
2371
+ SetSideEffectFreeGetter(isolate,
2372
+ tmpl,
2373
+ FIXED_ONE_BYTE_STRING(isolate, "expandedSQL"),
2374
+ StatementSync::ExpandedSQLGetter);
2375
+ SetProtoMethod(isolate,
2376
+ tmpl,
2377
+ "setAllowBareNamedParameters",
2378
+ StatementSync::SetAllowBareNamedParameters);
2379
+ SetProtoMethod(isolate,
2380
+ tmpl,
2381
+ "setAllowUnknownNamedParameters",
2382
+ StatementSync::SetAllowUnknownNamedParameters);
2383
+ SetProtoMethod(
2384
+ isolate, tmpl, "setReadBigInts", StatementSync::SetReadBigInts);
2385
+ SetProtoMethod(
2386
+ isolate, tmpl, "setReturnArrays", StatementSync::SetReturnArrays);
2387
+ env->set_sqlite_statement_sync_constructor_template(tmpl);
2388
+ }
2389
+ return tmpl;
2390
+ }
2391
+
2392
+ BaseObjectPtr<StatementSync> StatementSync::Create(
2393
+ Environment* env, BaseObjectPtr<DatabaseSync> db, sqlite3_stmt* stmt) {
2394
+ Local<Object> obj;
2395
+ if (!GetConstructorTemplate(env)
2396
+ ->InstanceTemplate()
2397
+ ->NewInstance(env->context())
2398
+ .ToLocal(&obj)) {
2399
+ return nullptr;
2400
+ }
2401
+
2402
+ return MakeBaseObject<StatementSync>(env, obj, std::move(db), stmt);
2403
+ }
2404
+
2405
+ StatementSyncIterator::StatementSyncIterator(Environment* env,
2406
+ Local<Object> object,
2407
+ BaseObjectPtr<StatementSync> stmt)
2408
+ : BaseObject(env, object), stmt_(std::move(stmt)) {
2409
+ MakeWeak();
2410
+ done_ = false;
2411
+ }
2412
+
2413
+ StatementSyncIterator::~StatementSyncIterator() {}
2414
+ void StatementSyncIterator::MemoryInfo(MemoryTracker* tracker) const {}
2415
+
2416
+ Local<FunctionTemplate> StatementSyncIterator::GetConstructorTemplate(
2417
+ Environment* env) {
2418
+ Local<FunctionTemplate> tmpl =
2419
+ env->sqlite_statement_sync_iterator_constructor_template();
2420
+ if (tmpl.IsEmpty()) {
2421
+ Isolate* isolate = env->isolate();
2422
+ tmpl = NewFunctionTemplate(isolate, IllegalConstructor);
2423
+ tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "StatementSyncIterator"));
2424
+ tmpl->InstanceTemplate()->SetInternalFieldCount(
2425
+ StatementSync::kInternalFieldCount);
2426
+ SetProtoMethod(isolate, tmpl, "next", StatementSyncIterator::Next);
2427
+ SetProtoMethod(isolate, tmpl, "return", StatementSyncIterator::Return);
2428
+ env->set_sqlite_statement_sync_iterator_constructor_template(tmpl);
2429
+ }
2430
+ return tmpl;
2431
+ }
2432
+
2433
+ BaseObjectPtr<StatementSyncIterator> StatementSyncIterator::Create(
2434
+ Environment* env, BaseObjectPtr<StatementSync> stmt) {
2435
+ Local<Object> obj;
2436
+ if (!GetConstructorTemplate(env)
2437
+ ->InstanceTemplate()
2438
+ ->NewInstance(env->context())
2439
+ .ToLocal(&obj)) {
2440
+ return BaseObjectPtr<StatementSyncIterator>();
2441
+ }
2442
+
2443
+ return MakeBaseObject<StatementSyncIterator>(env, obj, std::move(stmt));
2444
+ }
2445
+
2446
+ void StatementSyncIterator::Next(const FunctionCallbackInfo<Value>& args) {
2447
+ StatementSyncIterator* iter;
2448
+ ASSIGN_OR_RETURN_UNWRAP(&iter, args.This());
2449
+ Environment* env = Environment::GetCurrent(args);
2450
+ THROW_AND_RETURN_ON_BAD_STATE(
2451
+ env, iter->stmt_->IsFinalized(), "statement has been finalized");
2452
+ Isolate* isolate = env->isolate();
2453
+ LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
2454
+
2455
+ if (iter->done_) {
2456
+ LocalVector<Value> values(isolate,
2457
+ {Boolean::New(isolate, true), Null(isolate)});
2458
+ DCHECK_EQ(values.size(), keys.size());
2459
+ Local<Object> result = Object::New(
2460
+ isolate, Null(isolate), keys.data(), values.data(), keys.size());
2461
+ args.GetReturnValue().Set(result);
2462
+ return;
2463
+ }
2464
+
2465
+ int r = sqlite3_step(iter->stmt_->statement_);
2466
+ if (r != SQLITE_ROW) {
2467
+ CHECK_ERROR_OR_THROW(
2468
+ env->isolate(), iter->stmt_->db_.get(), r, SQLITE_DONE, void());
2469
+ sqlite3_reset(iter->stmt_->statement_);
2470
+ LocalVector<Value> values(isolate,
2471
+ {Boolean::New(isolate, true), Null(isolate)});
2472
+ DCHECK_EQ(values.size(), keys.size());
2473
+ Local<Object> result = Object::New(
2474
+ isolate, Null(isolate), keys.data(), values.data(), keys.size());
2475
+ args.GetReturnValue().Set(result);
2476
+ return;
2477
+ }
2478
+
2479
+ int num_cols = sqlite3_column_count(iter->stmt_->statement_);
2480
+ Local<Value> row_value;
2481
+
2482
+ if (iter->stmt_->return_arrays_) {
2483
+ LocalVector<Value> array_values(isolate);
2484
+ array_values.reserve(num_cols);
2485
+ for (int i = 0; i < num_cols; ++i) {
2486
+ Local<Value> val;
2487
+ if (!iter->stmt_->ColumnToValue(i).ToLocal(&val)) return;
2488
+ array_values.emplace_back(val);
2489
+ }
2490
+ row_value = Array::New(isolate, array_values.data(), array_values.size());
2491
+ } else {
2492
+ LocalVector<Name> row_keys(isolate);
2493
+ LocalVector<Value> row_values(isolate);
2494
+ row_keys.reserve(num_cols);
2495
+ row_values.reserve(num_cols);
2496
+ for (int i = 0; i < num_cols; ++i) {
2497
+ Local<Name> key;
2498
+ if (!iter->stmt_->ColumnNameToName(i).ToLocal(&key)) return;
2499
+ Local<Value> val;
2500
+ if (!iter->stmt_->ColumnToValue(i).ToLocal(&val)) return;
2501
+ row_keys.emplace_back(key);
2502
+ row_values.emplace_back(val);
2503
+ }
2504
+
2505
+ DCHECK_EQ(row_keys.size(), row_values.size());
2506
+ row_value = Object::New(
2507
+ isolate, Null(isolate), row_keys.data(), row_values.data(), num_cols);
2508
+ }
2509
+
2510
+ LocalVector<Value> values(isolate, {Boolean::New(isolate, false), row_value});
2511
+ DCHECK_EQ(keys.size(), values.size());
2512
+ Local<Object> result = Object::New(
2513
+ isolate, Null(isolate), keys.data(), values.data(), keys.size());
2514
+ args.GetReturnValue().Set(result);
2515
+ }
2516
+
2517
+ void StatementSyncIterator::Return(const FunctionCallbackInfo<Value>& args) {
2518
+ StatementSyncIterator* iter;
2519
+ ASSIGN_OR_RETURN_UNWRAP(&iter, args.This());
2520
+ Environment* env = Environment::GetCurrent(args);
2521
+ THROW_AND_RETURN_ON_BAD_STATE(
2522
+ env, iter->stmt_->IsFinalized(), "statement has been finalized");
2523
+ Isolate* isolate = env->isolate();
2524
+
2525
+ sqlite3_reset(iter->stmt_->statement_);
2526
+ iter->done_ = true;
2527
+ LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
2528
+ LocalVector<Value> values(isolate,
2529
+ {Boolean::New(isolate, true), Null(isolate)});
2530
+
2531
+ DCHECK_EQ(keys.size(), values.size());
2532
+ Local<Object> result = Object::New(
2533
+ isolate, Null(isolate), keys.data(), values.data(), keys.size());
2534
+ args.GetReturnValue().Set(result);
2535
+ }
2536
+
2537
+ Session::Session(Environment* env,
2538
+ Local<Object> object,
2539
+ BaseObjectWeakPtr<DatabaseSync> database,
2540
+ sqlite3_session* session)
2541
+ : BaseObject(env, object),
2542
+ session_(session),
2543
+ database_(std::move(database)) {
2544
+ MakeWeak();
2545
+ }
2546
+
2547
+ Session::~Session() {
2548
+ Delete();
2549
+ }
2550
+
2551
+ BaseObjectPtr<Session> Session::Create(Environment* env,
2552
+ BaseObjectWeakPtr<DatabaseSync> database,
2553
+ sqlite3_session* session) {
2554
+ Local<Object> obj;
2555
+ if (!GetConstructorTemplate(env)
2556
+ ->InstanceTemplate()
2557
+ ->NewInstance(env->context())
2558
+ .ToLocal(&obj)) {
2559
+ return nullptr;
2560
+ }
2561
+
2562
+ return MakeBaseObject<Session>(env, obj, std::move(database), session);
2563
+ }
2564
+
2565
+ Local<FunctionTemplate> Session::GetConstructorTemplate(Environment* env) {
2566
+ Local<FunctionTemplate> tmpl = env->sqlite_session_constructor_template();
2567
+ if (tmpl.IsEmpty()) {
2568
+ Isolate* isolate = env->isolate();
2569
+ tmpl = NewFunctionTemplate(isolate, IllegalConstructor);
2570
+ tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Session"));
2571
+ tmpl->InstanceTemplate()->SetInternalFieldCount(
2572
+ Session::kInternalFieldCount);
2573
+ SetProtoMethod(isolate,
2574
+ tmpl,
2575
+ "changeset",
2576
+ Session::Changeset<sqlite3session_changeset>);
2577
+ SetProtoMethod(
2578
+ isolate, tmpl, "patchset", Session::Changeset<sqlite3session_patchset>);
2579
+ SetProtoMethod(isolate, tmpl, "close", Session::Close);
2580
+ env->set_sqlite_session_constructor_template(tmpl);
2581
+ }
2582
+ return tmpl;
2583
+ }
2584
+
2585
+ void Session::MemoryInfo(MemoryTracker* tracker) const {}
2586
+
2587
+ template <Sqlite3ChangesetGenFunc sqliteChangesetFunc>
2588
+ void Session::Changeset(const FunctionCallbackInfo<Value>& args) {
2589
+ Session* session;
2590
+ ASSIGN_OR_RETURN_UNWRAP(&session, args.This());
2591
+ Environment* env = Environment::GetCurrent(args);
2592
+ THROW_AND_RETURN_ON_BAD_STATE(
2593
+ env, !session->database_->IsOpen(), "database is not open");
2594
+ THROW_AND_RETURN_ON_BAD_STATE(
2595
+ env, session->session_ == nullptr, "session is not open");
2596
+
2597
+ int nChangeset;
2598
+ void* pChangeset;
2599
+ int r = sqliteChangesetFunc(session->session_, &nChangeset, &pChangeset);
2600
+ CHECK_ERROR_OR_THROW(
2601
+ env->isolate(), session->database_.get(), r, SQLITE_OK, void());
2602
+
2603
+ auto freeChangeset = OnScopeLeave([&] { sqlite3_free(pChangeset); });
2604
+
2605
+ Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), nChangeset);
2606
+ std::memcpy(buffer->GetBackingStore()->Data(), pChangeset, nChangeset);
2607
+ Local<Uint8Array> uint8Array = Uint8Array::New(buffer, 0, nChangeset);
2608
+
2609
+ args.GetReturnValue().Set(uint8Array);
2610
+ }
2611
+
2612
+ void Session::Close(const FunctionCallbackInfo<Value>& args) {
2613
+ Session* session;
2614
+ ASSIGN_OR_RETURN_UNWRAP(&session, args.This());
2615
+ Environment* env = Environment::GetCurrent(args);
2616
+ THROW_AND_RETURN_ON_BAD_STATE(
2617
+ env, !session->database_->IsOpen(), "database is not open");
2618
+ THROW_AND_RETURN_ON_BAD_STATE(
2619
+ env, session->session_ == nullptr, "session is not open");
2620
+
2621
+ session->Delete();
2622
+ }
2623
+
2624
+ void Session::Delete() {
2625
+ if (!database_ || !database_->connection_ || session_ == nullptr) return;
2626
+ sqlite3session_delete(session_);
2627
+ database_->sessions_.erase(session_);
2628
+ session_ = nullptr;
2629
+ }
2630
+
2631
+ void DefineConstants(Local<Object> target) {
2632
+ NODE_DEFINE_CONSTANT(target, SQLITE_CHANGESET_OMIT);
2633
+ NODE_DEFINE_CONSTANT(target, SQLITE_CHANGESET_REPLACE);
2634
+ NODE_DEFINE_CONSTANT(target, SQLITE_CHANGESET_ABORT);
2635
+
2636
+ NODE_DEFINE_CONSTANT(target, SQLITE_CHANGESET_DATA);
2637
+ NODE_DEFINE_CONSTANT(target, SQLITE_CHANGESET_NOTFOUND);
2638
+ NODE_DEFINE_CONSTANT(target, SQLITE_CHANGESET_CONFLICT);
2639
+ NODE_DEFINE_CONSTANT(target, SQLITE_CHANGESET_CONSTRAINT);
2640
+ NODE_DEFINE_CONSTANT(target, SQLITE_CHANGESET_FOREIGN_KEY);
2641
+ }
2642
+
2643
+ static void Initialize(Local<Object> target,
2644
+ Local<Value> unused,
2645
+ Local<Context> context,
2646
+ void* priv) {
2647
+ Environment* env = Environment::GetCurrent(context);
2648
+ Isolate* isolate = env->isolate();
2649
+ Local<FunctionTemplate> db_tmpl =
2650
+ NewFunctionTemplate(isolate, DatabaseSync::New);
2651
+ db_tmpl->InstanceTemplate()->SetInternalFieldCount(
2652
+ DatabaseSync::kInternalFieldCount);
2653
+ Local<Object> constants = Object::New(isolate);
2654
+
2655
+ DefineConstants(constants);
2656
+
2657
+ SetProtoMethod(isolate, db_tmpl, "open", DatabaseSync::Open);
2658
+ SetProtoMethod(isolate, db_tmpl, "close", DatabaseSync::Close);
2659
+ SetProtoMethod(isolate, db_tmpl, "prepare", DatabaseSync::Prepare);
2660
+ SetProtoMethod(isolate, db_tmpl, "exec", DatabaseSync::Exec);
2661
+ SetProtoMethod(isolate, db_tmpl, "function", DatabaseSync::CustomFunction);
2662
+ SetProtoMethodNoSideEffect(
2663
+ isolate, db_tmpl, "location", DatabaseSync::Location);
2664
+ SetProtoMethod(
2665
+ isolate, db_tmpl, "aggregate", DatabaseSync::AggregateFunction);
2666
+ SetProtoMethod(
2667
+ isolate, db_tmpl, "createSession", DatabaseSync::CreateSession);
2668
+ SetProtoMethod(
2669
+ isolate, db_tmpl, "applyChangeset", DatabaseSync::ApplyChangeset);
2670
+ SetProtoMethod(isolate,
2671
+ db_tmpl,
2672
+ "enableLoadExtension",
2673
+ DatabaseSync::EnableLoadExtension);
2674
+ SetProtoMethod(
2675
+ isolate, db_tmpl, "loadExtension", DatabaseSync::LoadExtension);
2676
+ SetSideEffectFreeGetter(isolate,
2677
+ db_tmpl,
2678
+ FIXED_ONE_BYTE_STRING(isolate, "isOpen"),
2679
+ DatabaseSync::IsOpenGetter);
2680
+ SetSideEffectFreeGetter(isolate,
2681
+ db_tmpl,
2682
+ FIXED_ONE_BYTE_STRING(isolate, "isTransaction"),
2683
+ DatabaseSync::IsTransactionGetter);
2684
+ SetConstructorFunction(context, target, "DatabaseSync", db_tmpl);
2685
+ SetConstructorFunction(context,
2686
+ target,
2687
+ "StatementSync",
2688
+ StatementSync::GetConstructorTemplate(env));
2689
+
2690
+ target->Set(context, env->constants_string(), constants).Check();
2691
+
2692
+ Local<Function> backup_function;
2693
+
2694
+ if (!Function::New(context, Backup, Local<Value>(), 2)
2695
+ .ToLocal(&backup_function)) {
2696
+ return;
2697
+ }
2698
+ backup_function->SetName(env->backup_string());
2699
+
2700
+ target->Set(context, env->backup_string(), backup_function).Check();
2701
+ }
2702
+
2703
+ } // namespace sqlite
2704
+ } // namespace node
2705
+
2706
+ NODE_BINDING_CONTEXT_AWARE_INTERNAL(sqlite, node::sqlite::Initialize)