@bullet./paraql 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/binding.c ADDED
@@ -0,0 +1,2646 @@
1
+ #include <assert.h>
2
+ #include <bare.h>
3
+ #include <js.h>
4
+ #include <sqlite3.h>
5
+ #include <stdbool.h>
6
+ #include <stdint.h>
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+ #include <utf.h>
10
+ #include <uv.h>
11
+
12
+ static const char *PARAVFS = "paravfs";
13
+
14
+ static const char *STMT_FINALIZED = "Statement has already been finalized";
15
+
16
+ typedef utf8_t paraql_path_t[4096];
17
+
18
+ typedef struct {
19
+ sqlite3_vfs handle;
20
+
21
+ js_env_t *env;
22
+ js_ref_t *ctx;
23
+
24
+ js_threadsafe_function_t *on_delete;
25
+ js_threadsafe_function_t *on_access;
26
+ js_threadsafe_function_t *on_read;
27
+ js_threadsafe_function_t *on_write;
28
+ js_threadsafe_function_t *on_truncate;
29
+ js_threadsafe_function_t *on_sync;
30
+ js_threadsafe_function_t *on_size;
31
+
32
+ uv_sem_t done;
33
+ } paravfs_t;
34
+
35
+ typedef struct {
36
+ sqlite3_file handle;
37
+
38
+ paraql_path_t name;
39
+ bool delete_on_close;
40
+
41
+ paravfs_t *vfs;
42
+ } paravfs_file_t;
43
+
44
+ typedef struct {
45
+ paravfs_file_t *file;
46
+
47
+ void *buf;
48
+ int len;
49
+ int64_t offset;
50
+
51
+ int status;
52
+ } paravfs_read_t;
53
+
54
+ typedef struct {
55
+ paravfs_file_t *file;
56
+
57
+ const void *buf;
58
+ int len;
59
+ int64_t offset;
60
+
61
+ int status;
62
+ } paravfs_write_t;
63
+
64
+ typedef struct {
65
+ paravfs_file_t *file;
66
+
67
+ int64_t size;
68
+
69
+ int status;
70
+ } paravfs_truncate_t;
71
+
72
+ typedef struct {
73
+ paravfs_file_t *file;
74
+
75
+ int status;
76
+ } paravfs_sync_t;
77
+
78
+ typedef struct {
79
+ paravfs_file_t *file;
80
+
81
+ int64_t size;
82
+
83
+ int status;
84
+ } paravfs_size_t;
85
+
86
+ typedef struct {
87
+ paravfs_t *vfs;
88
+
89
+ const char *name;
90
+ bool exists;
91
+
92
+ int status;
93
+ } paravfs_access_t;
94
+
95
+ typedef struct {
96
+ paravfs_t *vfs;
97
+
98
+ const char *name;
99
+
100
+ int status;
101
+ } paravfs_delete_t;
102
+
103
+ typedef struct paraql_statement_s paraql_statement_t;
104
+
105
+ typedef struct {
106
+ sqlite3 *handle;
107
+
108
+ js_env_t *env;
109
+
110
+ paraql_statement_t *statements;
111
+ } paraql_t;
112
+
113
+ struct paraql_statement_s {
114
+ sqlite3_stmt *handle;
115
+
116
+ paraql_t *db;
117
+ paraql_statement_t *prev;
118
+ paraql_statement_t *next;
119
+ };
120
+
121
+ typedef struct {
122
+ uv_work_t handle;
123
+
124
+ paraql_t *db;
125
+
126
+ js_deferred_t *deferred;
127
+
128
+ paraql_path_t name;
129
+
130
+ int errcode;
131
+ const char *errmsg;
132
+ } paraql_open_t;
133
+
134
+ typedef struct {
135
+ uv_work_t handle;
136
+
137
+ paraql_t *db;
138
+
139
+ js_deferred_t *deferred;
140
+
141
+ int errcode;
142
+ const char *errmsg;
143
+ } paraql_close_t;
144
+
145
+ typedef struct {
146
+ uv_work_t handle;
147
+
148
+ paraql_t *db;
149
+
150
+ js_deferred_t *deferred;
151
+
152
+ utf8_t *sql;
153
+
154
+ int errcode;
155
+ const char *errmsg;
156
+ } paraql_exec_t;
157
+
158
+ typedef struct {
159
+ uv_work_t handle;
160
+
161
+ paraql_t *db;
162
+
163
+ js_deferred_t *deferred;
164
+
165
+ utf8_t *sql;
166
+
167
+ paraql_statement_t *stmt;
168
+
169
+ int errcode;
170
+ const char *errmsg;
171
+ } paraql_prepare_t;
172
+
173
+ typedef struct {
174
+ uv_work_t handle;
175
+
176
+ js_env_t *env;
177
+
178
+ js_deferred_t *deferred;
179
+
180
+ paraql_statement_t *stmt;
181
+ } paraql_finalize_t;
182
+
183
+ typedef struct {
184
+ uv_work_t handle;
185
+
186
+ js_env_t *env;
187
+
188
+ js_deferred_t *deferred;
189
+
190
+ paraql_statement_t *stmt;
191
+
192
+ int errcode;
193
+ const char *errmsg;
194
+ } paraql_reset_t;
195
+
196
+ typedef struct {
197
+ js_value_type_t type;
198
+
199
+ bool is_double;
200
+
201
+ union {
202
+ struct {
203
+ size_t len;
204
+ void *data;
205
+ } buffer;
206
+ double d;
207
+ int64_t i;
208
+ } value;
209
+ } paraql_bind_value_t;
210
+
211
+ typedef struct {
212
+ uv_work_t handle;
213
+
214
+ js_env_t *env;
215
+
216
+ js_deferred_t *deferred;
217
+
218
+ js_ref_t *named;
219
+ js_ref_t *positional;
220
+
221
+ paraql_statement_t *stmt;
222
+
223
+ int param_count;
224
+ const char **param_names;
225
+ paraql_bind_value_t **values;
226
+
227
+ int errcode;
228
+ const char *errmsg;
229
+ } paraql_bind_t;
230
+
231
+ typedef struct {
232
+ int type;
233
+
234
+ const char *name;
235
+
236
+ union {
237
+ struct {
238
+ size_t len;
239
+ const void *data;
240
+ } buffer;
241
+ double d;
242
+ int64_t i;
243
+ } value;
244
+ } paraql_step_value_t;
245
+
246
+ typedef struct {
247
+ uv_work_t handle;
248
+
249
+ js_env_t *env;
250
+
251
+ js_deferred_t *deferred;
252
+
253
+ paraql_statement_t *stmt;
254
+
255
+ bool done;
256
+ int count;
257
+ paraql_step_value_t *values;
258
+
259
+ int errcode;
260
+ const char *errmsg;
261
+ } paraql_step_t;
262
+
263
+ typedef struct {
264
+ uv_work_t handle;
265
+
266
+ js_env_t *env;
267
+
268
+ js_deferred_t *deferred;
269
+
270
+ paraql_statement_t *stmt;
271
+
272
+ int64_t changes;
273
+ int64_t last_insert_rowid;
274
+
275
+ int errcode;
276
+ const char *errmsg;
277
+ } paraql_run_t;
278
+
279
+ static const size_t paraql__queue_limit = 64;
280
+
281
+ static int
282
+ paravfs__error_from(js_env_t *env, js_value_t *value, int code) {
283
+ int err;
284
+
285
+ js_value_type_t type;
286
+ err = js_typeof(env, value, &type);
287
+ assert(err == 0);
288
+
289
+ if (type == js_null || type == js_undefined) return SQLITE_OK;
290
+
291
+ return code;
292
+ }
293
+
294
+ static void
295
+ paravfs__temporary_name(char *out, size_t len) {
296
+ int err;
297
+
298
+ char *hex = out;
299
+ size_t buflen = len / 2;
300
+ uint8_t buffer[buflen];
301
+
302
+ err = uv_random(NULL, NULL, (void *) buffer, buflen, 0, NULL);
303
+ assert(err == 0);
304
+
305
+ for (int i = 0; i < buflen; i++) {
306
+ hex += sprintf(hex, "%02X", buffer[i]);
307
+ }
308
+ }
309
+
310
+ static int
311
+ paravfs__on_close(sqlite3_file *handle) {
312
+ paravfs_file_t *file = (paravfs_file_t *) handle;
313
+
314
+ if (file->delete_on_close) {
315
+ return file->vfs->handle.xDelete((sqlite3_vfs *) file->vfs, (const char *) file->name, 0);
316
+ }
317
+
318
+ return SQLITE_OK;
319
+ }
320
+
321
+ static js_value_t *
322
+ paravfs__on_read_done(js_env_t *env, js_callback_info_t *info) {
323
+ int err;
324
+
325
+ paravfs_read_t *data;
326
+
327
+ size_t argc = 1;
328
+ js_value_t *argv[1];
329
+
330
+ err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &data);
331
+ assert(err == 0);
332
+
333
+ assert(argc == 1);
334
+
335
+ data->status = paravfs__error_from(env, argv[0], SQLITE_IOERR_READ);
336
+
337
+ uv_sem_post(&data->file->vfs->done);
338
+
339
+ return NULL;
340
+ }
341
+
342
+ static void
343
+ paravfs__on_read_call(js_env_t *env, js_value_t *on_read, void *context, void *arg) {
344
+ int err;
345
+
346
+ paravfs_t *vfs = (paravfs_t *) context;
347
+
348
+ paravfs_read_t *data = (paravfs_read_t *) arg;
349
+
350
+ js_value_t *ctx;
351
+ err = js_get_reference_value(env, vfs->ctx, &ctx);
352
+ assert(err == 0);
353
+
354
+ js_value_t *args[4];
355
+
356
+ err = js_create_string_utf8(env, data->file->name, -1, &args[0]);
357
+ assert(err == 0);
358
+
359
+ err = js_create_external_arraybuffer(env, data->buf, data->len, NULL, NULL, &args[1]);
360
+ assert(err == 0);
361
+
362
+ err = js_create_int64(env, data->offset, &args[2]);
363
+ assert(err == 0);
364
+
365
+ err = js_create_function(env, "done", -1, paravfs__on_read_done, (void *) data, &args[3]);
366
+ assert(err == 0);
367
+
368
+ err = js_call_function(env, ctx, on_read, 4, args, NULL);
369
+ assert(err == 0);
370
+ }
371
+
372
+ static int
373
+ paravfs__on_read(sqlite3_file *handle, void *buf, int len, sqlite3_int64 offset) {
374
+ int err;
375
+
376
+ paravfs_file_t *file = (paravfs_file_t *) handle;
377
+
378
+ paravfs_t *vfs = file->vfs;
379
+
380
+ paravfs_read_t data = {
381
+ file,
382
+ buf,
383
+ len,
384
+ offset,
385
+ };
386
+
387
+ err = js_call_threadsafe_function(vfs->on_read, (void *) &data, js_threadsafe_function_blocking);
388
+ assert(err == 0);
389
+
390
+ uv_sem_wait(&vfs->done);
391
+
392
+ return data.status;
393
+ }
394
+
395
+ static js_value_t *
396
+ paravfs__on_write_done(js_env_t *env, js_callback_info_t *info) {
397
+ int err;
398
+
399
+ paravfs_write_t *data;
400
+
401
+ size_t argc = 1;
402
+ js_value_t *argv[1];
403
+
404
+ err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &data);
405
+ assert(err == 0);
406
+
407
+ assert(argc == 1);
408
+
409
+ data->status = paravfs__error_from(env, argv[0], SQLITE_IOERR_WRITE);
410
+
411
+ uv_sem_post(&data->file->vfs->done);
412
+
413
+ return NULL;
414
+ }
415
+
416
+ static void
417
+ paravfs__on_write_call(js_env_t *env, js_value_t *on_write, void *context, void *arg) {
418
+ int err;
419
+
420
+ paravfs_t *vfs = (paravfs_t *) context;
421
+
422
+ paravfs_write_t *data = (paravfs_write_t *) arg;
423
+
424
+ js_value_t *ctx;
425
+ err = js_get_reference_value(env, vfs->ctx, &ctx);
426
+ assert(err == 0);
427
+
428
+ js_value_t *args[4];
429
+
430
+ err = js_create_string_utf8(env, data->file->name, -1, &args[0]);
431
+ assert(err == 0);
432
+
433
+ err = js_create_external_arraybuffer(env, (void *) data->buf, data->len, NULL, NULL, &args[1]);
434
+ assert(err == 0);
435
+
436
+ err = js_create_int64(env, data->offset, &args[2]);
437
+ assert(err == 0);
438
+
439
+ err = js_create_function(env, "done", -1, paravfs__on_write_done, (void *) data, &args[3]);
440
+ assert(err == 0);
441
+
442
+ err = js_call_function(env, ctx, on_write, 4, args, NULL);
443
+ assert(err == 0);
444
+ }
445
+
446
+ static int
447
+ paravfs__on_write(sqlite3_file *handle, const void *buf, int len, sqlite3_int64 offset) {
448
+ int err;
449
+
450
+ paravfs_file_t *file = (paravfs_file_t *) handle;
451
+
452
+ paravfs_t *vfs = file->vfs;
453
+
454
+ paravfs_write_t data = {
455
+ file,
456
+ buf,
457
+ len,
458
+ offset,
459
+ };
460
+
461
+ err = js_call_threadsafe_function(vfs->on_write, (void *) &data, js_threadsafe_function_blocking);
462
+ assert(err == 0);
463
+
464
+ uv_sem_wait(&vfs->done);
465
+
466
+ return data.status;
467
+ }
468
+
469
+ static js_value_t *
470
+ paravfs__on_truncate_done(js_env_t *env, js_callback_info_t *info) {
471
+ int err;
472
+
473
+ paravfs_truncate_t *data;
474
+
475
+ size_t argc = 1;
476
+ js_value_t *argv[1];
477
+
478
+ err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &data);
479
+ assert(err == 0);
480
+
481
+ assert(argc == 1);
482
+
483
+ data->status = paravfs__error_from(env, argv[0], SQLITE_IOERR);
484
+
485
+ uv_sem_post(&data->file->vfs->done);
486
+
487
+ return NULL;
488
+ }
489
+
490
+ static void
491
+ paravfs__on_truncate_call(js_env_t *env, js_value_t *on_truncate, void *context, void *arg) {
492
+ int err;
493
+
494
+ paravfs_t *vfs = (paravfs_t *) context;
495
+
496
+ paravfs_truncate_t *data = (paravfs_truncate_t *) arg;
497
+
498
+ js_value_t *ctx;
499
+ err = js_get_reference_value(env, vfs->ctx, &ctx);
500
+ assert(err == 0);
501
+
502
+ js_value_t *args[3];
503
+
504
+ err = js_create_string_utf8(env, data->file->name, -1, &args[0]);
505
+ assert(err == 0);
506
+
507
+ err = js_create_int64(env, data->size, &args[1]);
508
+ assert(err == 0);
509
+
510
+ err = js_create_function(env, "done", -1, paravfs__on_truncate_done, (void *) data, &args[2]);
511
+ assert(err == 0);
512
+
513
+ err = js_call_function(env, ctx, on_truncate, 3, args, NULL);
514
+ assert(err == 0);
515
+ }
516
+
517
+ static int
518
+ paravfs__on_truncate(sqlite3_file *handle, sqlite3_int64 size) {
519
+ int err;
520
+
521
+ paravfs_file_t *file = (paravfs_file_t *) handle;
522
+
523
+ paravfs_t *vfs = file->vfs;
524
+
525
+ paravfs_truncate_t data = {
526
+ file,
527
+ size,
528
+ };
529
+
530
+ err = js_call_threadsafe_function(vfs->on_truncate, (void *) &data, js_threadsafe_function_blocking);
531
+ assert(err == 0);
532
+
533
+ uv_sem_wait(&vfs->done);
534
+
535
+ return data.status;
536
+ }
537
+
538
+ static js_value_t *
539
+ paravfs__on_sync_done(js_env_t *env, js_callback_info_t *info) {
540
+ int err;
541
+
542
+ paravfs_sync_t *data;
543
+
544
+ size_t argc = 1;
545
+ js_value_t *argv[1];
546
+
547
+ err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &data);
548
+ assert(err == 0);
549
+
550
+ assert(argc == 1);
551
+
552
+ data->status = paravfs__error_from(env, argv[0], SQLITE_IOERR);
553
+
554
+ uv_sem_post(&data->file->vfs->done);
555
+
556
+ return NULL;
557
+ }
558
+
559
+ static void
560
+ paravfs__on_sync_call(js_env_t *env, js_value_t *on_sync, void *context, void *arg) {
561
+ int err;
562
+
563
+ paravfs_t *vfs = (paravfs_t *) context;
564
+
565
+ paravfs_sync_t *data = (paravfs_sync_t *) arg;
566
+
567
+ js_value_t *ctx;
568
+ err = js_get_reference_value(env, vfs->ctx, &ctx);
569
+ assert(err == 0);
570
+
571
+ js_value_t *args[2];
572
+
573
+ err = js_create_string_utf8(env, data->file->name, -1, &args[0]);
574
+ assert(err == 0);
575
+
576
+ err = js_create_function(env, "done", -1, paravfs__on_sync_done, (void *) data, &args[1]);
577
+ assert(err == 0);
578
+
579
+ err = js_call_function(env, ctx, on_sync, 2, args, NULL);
580
+ assert(err == 0);
581
+ }
582
+
583
+ static int
584
+ paravfs__on_sync(sqlite3_file *handle, int flags) {
585
+ int err;
586
+
587
+ paravfs_file_t *file = (paravfs_file_t *) handle;
588
+
589
+ paravfs_t *vfs = file->vfs;
590
+
591
+ paravfs_sync_t data = {
592
+ file,
593
+ };
594
+
595
+ err = js_call_threadsafe_function(vfs->on_sync, (void *) &data, js_threadsafe_function_blocking);
596
+ assert(err == 0);
597
+
598
+ uv_sem_wait(&vfs->done);
599
+
600
+ return data.status;
601
+ }
602
+
603
+ static js_value_t *
604
+ paravfs__on_size_done(js_env_t *env, js_callback_info_t *info) {
605
+ int err;
606
+
607
+ paravfs_size_t *data;
608
+
609
+ size_t argc = 2;
610
+ js_value_t *argv[2];
611
+
612
+ err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &data);
613
+ assert(err == 0);
614
+
615
+ assert(argc >= 1);
616
+
617
+ data->status = paravfs__error_from(env, argv[0], SQLITE_IOERR_FSTAT);
618
+
619
+ if (data->status == SQLITE_OK) {
620
+ assert(argc == 2);
621
+
622
+ err = js_get_value_int64(env, argv[1], &data->size);
623
+ assert(err == 0);
624
+ }
625
+
626
+ uv_sem_post(&data->file->vfs->done);
627
+
628
+ return NULL;
629
+ }
630
+
631
+ static void
632
+ paravfs__on_size_call(js_env_t *env, js_value_t *on_size, void *context, void *arg) {
633
+ int err;
634
+
635
+ paravfs_t *vfs = (paravfs_t *) context;
636
+
637
+ paravfs_size_t *data = (paravfs_size_t *) arg;
638
+
639
+ js_value_t *ctx;
640
+ err = js_get_reference_value(env, vfs->ctx, &ctx);
641
+ assert(err == 0);
642
+
643
+ js_value_t *args[2];
644
+
645
+ err = js_create_string_utf8(env, data->file->name, -1, &args[0]);
646
+ assert(err == 0);
647
+
648
+ err = js_create_function(env, "done", -1, paravfs__on_size_done, (void *) data, &args[1]);
649
+ assert(err == 0);
650
+
651
+ err = js_call_function(env, ctx, on_size, 2, args, NULL);
652
+ assert(err == 0);
653
+ }
654
+
655
+ static int
656
+ paravfs__on_size(sqlite3_file *handle, sqlite3_int64 *size) {
657
+ int err;
658
+
659
+ paravfs_file_t *file = (paravfs_file_t *) handle;
660
+
661
+ paravfs_t *vfs = file->vfs;
662
+
663
+ paravfs_size_t data = {
664
+ file,
665
+ };
666
+
667
+ err = js_call_threadsafe_function(vfs->on_size, (void *) &data, js_threadsafe_function_blocking);
668
+ assert(err == 0);
669
+
670
+ uv_sem_wait(&vfs->done);
671
+
672
+ if (data.status != SQLITE_OK) return data.status;
673
+
674
+ *size = data.size;
675
+
676
+ return SQLITE_OK;
677
+ }
678
+
679
+ static int
680
+ paravfs__on_lock(sqlite3_file *handle, int eLock) {
681
+ return SQLITE_OK;
682
+ }
683
+
684
+ static int
685
+ paravfs__on_unlock(sqlite3_file *handle, int eLock) {
686
+ return SQLITE_OK;
687
+ }
688
+
689
+ static int
690
+ paravfs__on_check_reserved_lock(sqlite3_file *handle, int *pResOut) {
691
+ *pResOut = 0;
692
+ return SQLITE_OK;
693
+ }
694
+
695
+ static int
696
+ paravfs__on_control(sqlite3_file *handle, int op, void *pArg) {
697
+ return SQLITE_NOTFOUND;
698
+ }
699
+
700
+ static int
701
+ paravfs__on_sector_size(sqlite3_file *handle) {
702
+ return 512;
703
+ }
704
+
705
+ static int
706
+ paravfs__on_device_characteristics(sqlite3_file *handle) {
707
+ return 0;
708
+ }
709
+
710
+ static int
711
+ paravfs__on_open(sqlite3_vfs *vfs_handle, const char *name, sqlite3_file *handle, int flags, int *pflags) {
712
+ paravfs_t *vfs = (paravfs_t *) vfs_handle;
713
+
714
+ paravfs_file_t *file = (paravfs_file_t *) handle;
715
+
716
+ if (name != NULL) {
717
+ strcpy((char *) file->name, name);
718
+ } else {
719
+ paravfs__temporary_name((char *) file->name, 32);
720
+ }
721
+
722
+ file->delete_on_close = flags & SQLITE_OPEN_DELETEONCLOSE;
723
+ file->vfs = (paravfs_t *) vfs;
724
+
725
+ static const sqlite3_io_methods methods = {
726
+ 1, // Version
727
+ paravfs__on_close,
728
+ paravfs__on_read,
729
+ paravfs__on_write,
730
+ paravfs__on_truncate,
731
+ paravfs__on_sync,
732
+ paravfs__on_size,
733
+ paravfs__on_lock,
734
+ paravfs__on_unlock,
735
+ paravfs__on_check_reserved_lock,
736
+ paravfs__on_control,
737
+ paravfs__on_sector_size,
738
+ paravfs__on_device_characteristics,
739
+ };
740
+
741
+ file->handle.pMethods = &methods;
742
+
743
+ return SQLITE_OK;
744
+ }
745
+
746
+ static js_value_t *
747
+ paravfs__on_delete_done(js_env_t *env, js_callback_info_t *info) {
748
+ int err;
749
+
750
+ paravfs_delete_t *data;
751
+
752
+ size_t argc = 1;
753
+ js_value_t *argv[1];
754
+
755
+ err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &data);
756
+ assert(err == 0);
757
+
758
+ assert(argc == 1);
759
+
760
+ data->status = paravfs__error_from(env, argv[0], SQLITE_IOERR_DELETE);
761
+
762
+ uv_sem_post(&data->vfs->done);
763
+
764
+ return NULL;
765
+ }
766
+
767
+ static void
768
+ paravfs__on_delete_call(js_env_t *env, js_value_t *on_delete, void *context, void *arg) {
769
+ int err;
770
+
771
+ paravfs_t *vfs = (paravfs_t *) context;
772
+
773
+ paravfs_delete_t *data = (paravfs_delete_t *) arg;
774
+
775
+ js_value_t *ctx;
776
+ err = js_get_reference_value(env, vfs->ctx, &ctx);
777
+ assert(err == 0);
778
+
779
+ js_value_t *args[2];
780
+
781
+ err = js_create_string_utf8(env, (utf8_t *) data->name, -1, &args[0]);
782
+ assert(err == 0);
783
+
784
+ err = js_create_function(env, "done", -1, paravfs__on_delete_done, (void *) data, &args[1]);
785
+ assert(err == 0);
786
+
787
+ err = js_call_function(env, ctx, on_delete, 2, args, NULL);
788
+ assert(err == 0);
789
+ }
790
+
791
+ static int
792
+ paravfs__on_delete(sqlite3_vfs *handle, const char *name, int sync) {
793
+ int err;
794
+
795
+ paravfs_t *vfs = (paravfs_t *) handle;
796
+
797
+ paravfs_delete_t data = {
798
+ vfs,
799
+ name,
800
+ sync,
801
+ };
802
+
803
+ err = js_call_threadsafe_function(vfs->on_delete, (void *) &data, js_threadsafe_function_blocking);
804
+ assert(err == 0);
805
+
806
+ uv_sem_wait(&vfs->done);
807
+
808
+ return data.status;
809
+ }
810
+
811
+ static js_value_t *
812
+ paravfs__on_access_done(js_env_t *env, js_callback_info_t *info) {
813
+ int err;
814
+
815
+ paravfs_access_t *data;
816
+
817
+ size_t argc = 2;
818
+ js_value_t *argv[2];
819
+
820
+ err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &data);
821
+ assert(err == 0);
822
+
823
+ assert(argc >= 1);
824
+
825
+ data->status = paravfs__error_from(env, argv[0], SQLITE_IOERR_ACCESS);
826
+
827
+ if (data->status == SQLITE_OK) {
828
+ assert(argc == 2);
829
+
830
+ err = js_get_value_bool(env, argv[1], &data->exists);
831
+ assert(err == 0);
832
+ }
833
+
834
+ uv_sem_post(&data->vfs->done);
835
+
836
+ return NULL;
837
+ }
838
+
839
+ static void
840
+ paravfs__on_access_call(js_env_t *env, js_value_t *on_access, void *context, void *arg) {
841
+ int err;
842
+
843
+ paravfs_t *vfs = (paravfs_t *) context;
844
+
845
+ paravfs_access_t *data = (paravfs_access_t *) arg;
846
+
847
+ js_value_t *ctx;
848
+ err = js_get_reference_value(env, vfs->ctx, &ctx);
849
+ assert(err == 0);
850
+
851
+ js_value_t *args[2];
852
+
853
+ err = js_create_string_utf8(env, (utf8_t *) data->name, -1, &args[0]);
854
+ assert(err == 0);
855
+
856
+ err = js_create_function(env, "done", -1, paravfs__on_access_done, (void *) data, &args[1]);
857
+ assert(err == 0);
858
+
859
+ err = js_call_function(env, ctx, on_access, 2, args, NULL);
860
+ assert(err == 0);
861
+ }
862
+
863
+ static int
864
+ paravfs__on_access(sqlite3_vfs *handle, const char *name, int flags, int *exists) {
865
+ int err;
866
+
867
+ paravfs_t *vfs = (paravfs_t *) handle;
868
+
869
+ paravfs_access_t data = {
870
+ vfs,
871
+ name,
872
+ flags,
873
+ };
874
+
875
+ err = js_call_threadsafe_function(vfs->on_access, (void *) &data, js_threadsafe_function_blocking);
876
+ assert(err == 0);
877
+
878
+ uv_sem_wait(&vfs->done);
879
+
880
+ if (data.status != SQLITE_OK) return data.status;
881
+
882
+ *exists = data.exists;
883
+
884
+ return SQLITE_OK;
885
+ }
886
+
887
+ static int
888
+ paravfs__on_fullpathname(sqlite3_vfs *vfs, const char *name, int len, char *out) {
889
+ if (strlen(name) >= len) return SQLITE_ERROR;
890
+
891
+ strcpy(out, name);
892
+
893
+ return SQLITE_OK;
894
+ }
895
+
896
+ static void *
897
+ paravfs__on_dlopen(sqlite3_vfs *vfs, const char *path) {
898
+ return NULL;
899
+ }
900
+
901
+ static int
902
+ paravfs__on_randomness(sqlite3_vfs *vfs, int bytes, char *buf) {
903
+ memset(buf, 0, bytes);
904
+
905
+ return 0;
906
+ }
907
+
908
+ static int
909
+ paravfs__on_sleep(sqlite3_vfs *vfs, int nMicro) {
910
+ return SQLITE_OK;
911
+ }
912
+
913
+ static int
914
+ paravfs__on_current_time(sqlite3_vfs *vfs, double *time) {
915
+ int err;
916
+
917
+ uv_timespec64_t ts;
918
+ err = uv_clock_gettime(UV_CLOCK_REALTIME, &ts);
919
+ assert(err == 0);
920
+
921
+ *time = ts.tv_sec / 86400.0 + 2440587.5;
922
+
923
+ return SQLITE_OK;
924
+ }
925
+
926
+ static js_value_t *
927
+ paravfs_init(js_env_t *env, js_callback_info_t *info) {
928
+ int err;
929
+
930
+ size_t argc = 8;
931
+ js_value_t *argv[8];
932
+
933
+ err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
934
+ assert(err == 0);
935
+
936
+ assert(argc == 8);
937
+
938
+ uv_loop_t *loop;
939
+ err = js_get_env_loop(env, &loop);
940
+ assert(err == 0);
941
+
942
+ js_value_t *handle;
943
+
944
+ paravfs_t *vfs;
945
+ err = js_create_arraybuffer(env, sizeof(paravfs_t), (void **) &vfs, &handle);
946
+ assert(err == 0);
947
+
948
+ err = uv_sem_init(&vfs->done, 0);
949
+ assert(err == 0);
950
+
951
+ vfs->env = env;
952
+
953
+ err = js_create_reference(env, argv[0], 1, &vfs->ctx);
954
+ assert(err == 0);
955
+
956
+ err = js_create_threadsafe_function(env, argv[1], paraql__queue_limit, 1, NULL, NULL, (void *) vfs, paravfs__on_delete_call, &vfs->on_delete);
957
+ assert(err == 0);
958
+
959
+ err = js_create_threadsafe_function(env, argv[2], paraql__queue_limit, 1, NULL, NULL, (void *) vfs, paravfs__on_access_call, &vfs->on_access);
960
+ assert(err == 0);
961
+
962
+ err = js_create_threadsafe_function(env, argv[3], paraql__queue_limit, 1, NULL, NULL, (void *) vfs, paravfs__on_read_call, &vfs->on_read);
963
+ assert(err == 0);
964
+
965
+ err = js_create_threadsafe_function(env, argv[4], paraql__queue_limit, 1, NULL, NULL, (void *) vfs, paravfs__on_write_call, &vfs->on_write);
966
+ assert(err == 0);
967
+
968
+ err = js_create_threadsafe_function(env, argv[5], paraql__queue_limit, 1, NULL, NULL, (void *) vfs, paravfs__on_truncate_call, &vfs->on_truncate);
969
+ assert(err == 0);
970
+
971
+ err = js_create_threadsafe_function(env, argv[6], paraql__queue_limit, 1, NULL, NULL, (void *) vfs, paravfs__on_sync_call, &vfs->on_sync);
972
+ assert(err == 0);
973
+
974
+ err = js_create_threadsafe_function(env, argv[7], paraql__queue_limit, 1, NULL, NULL, (void *) vfs, paravfs__on_size_call, &vfs->on_size);
975
+ assert(err == 0);
976
+
977
+ vfs->handle = (sqlite3_vfs) {
978
+ 1, // Version
979
+ sizeof(paravfs_file_t),
980
+ sizeof(paraql_path_t),
981
+ NULL,
982
+ PARAVFS,
983
+ NULL,
984
+ paravfs__on_open,
985
+ paravfs__on_delete,
986
+ paravfs__on_access,
987
+ paravfs__on_fullpathname,
988
+ paravfs__on_dlopen,
989
+ NULL, // dlerror
990
+ NULL, // dlsym
991
+ NULL, // dlclose
992
+ paravfs__on_randomness,
993
+ paravfs__on_sleep,
994
+ paravfs__on_current_time,
995
+ };
996
+
997
+ err = sqlite3_vfs_register(&vfs->handle, false);
998
+ assert(err == 0);
999
+
1000
+ return handle;
1001
+ }
1002
+
1003
+ static js_value_t *
1004
+ paravfs_destroy(js_env_t *env, js_callback_info_t *info) {
1005
+ int err;
1006
+
1007
+ size_t argc = 1;
1008
+ js_value_t *argv[1];
1009
+
1010
+ err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1011
+ assert(err == 0);
1012
+
1013
+ assert(argc == 1);
1014
+
1015
+ paravfs_t *vfs;
1016
+ err = js_get_arraybuffer_info(env, argv[0], (void **) &vfs, NULL);
1017
+ assert(err == 0);
1018
+
1019
+ err = sqlite3_vfs_unregister(&vfs->handle);
1020
+ assert(err == 0);
1021
+
1022
+ err = js_release_threadsafe_function(vfs->on_delete, js_threadsafe_function_release);
1023
+ assert(err == 0);
1024
+
1025
+ err = js_release_threadsafe_function(vfs->on_access, js_threadsafe_function_release);
1026
+ assert(err == 0);
1027
+
1028
+ err = js_release_threadsafe_function(vfs->on_read, js_threadsafe_function_release);
1029
+ assert(err == 0);
1030
+
1031
+ err = js_release_threadsafe_function(vfs->on_write, js_threadsafe_function_release);
1032
+ assert(err == 0);
1033
+
1034
+ err = js_release_threadsafe_function(vfs->on_truncate, js_threadsafe_function_release);
1035
+ assert(err == 0);
1036
+
1037
+ err = js_release_threadsafe_function(vfs->on_sync, js_threadsafe_function_release);
1038
+ assert(err == 0);
1039
+
1040
+ err = js_release_threadsafe_function(vfs->on_size, js_threadsafe_function_release);
1041
+ assert(err == 0);
1042
+
1043
+ err = js_delete_reference(env, vfs->ctx);
1044
+ assert(err == 0);
1045
+
1046
+ uv_sem_destroy(&vfs->done);
1047
+
1048
+ return NULL;
1049
+ }
1050
+
1051
+ static void
1052
+ paraql__insert_statement(paraql_t *db, paraql_statement_t *stmt) {
1053
+ stmt->db = db;
1054
+ stmt->prev = NULL;
1055
+ stmt->next = db->statements;
1056
+
1057
+ if (db->statements != NULL) db->statements->prev = stmt;
1058
+
1059
+ db->statements = stmt;
1060
+ }
1061
+
1062
+ static void
1063
+ paraql__remove_statement(paraql_statement_t *stmt) {
1064
+ if (stmt->db == NULL) return;
1065
+
1066
+ if (stmt->prev != NULL) stmt->prev->next = stmt->next;
1067
+ else stmt->db->statements = stmt->next;
1068
+
1069
+ if (stmt->next != NULL) stmt->next->prev = stmt->prev;
1070
+
1071
+ stmt->db = NULL;
1072
+ stmt->prev = NULL;
1073
+ stmt->next = NULL;
1074
+ }
1075
+
1076
+ static void
1077
+ paraql__finalize_statements(paraql_t *db) {
1078
+ paraql_statement_t *stmt = db->statements;
1079
+
1080
+ while (stmt != NULL) {
1081
+ paraql_statement_t *next = stmt->next;
1082
+
1083
+ if (stmt->handle != NULL) {
1084
+ sqlite3_finalize(stmt->handle);
1085
+ stmt->handle = NULL;
1086
+ }
1087
+
1088
+ stmt->db = NULL;
1089
+ stmt->prev = NULL;
1090
+ stmt->next = NULL;
1091
+
1092
+ stmt = next;
1093
+ }
1094
+
1095
+ db->statements = NULL;
1096
+ }
1097
+
1098
+ static const char *
1099
+ paraql__code(int errcode) {
1100
+ switch (errcode & 0xff) {
1101
+ #define V(name) \
1102
+ case SQLITE_##name: \
1103
+ return #name;
1104
+ V(ERROR)
1105
+ V(INTERNAL)
1106
+ V(PERM)
1107
+ V(ABORT)
1108
+ V(BUSY)
1109
+ V(LOCKED)
1110
+ V(NOMEM)
1111
+ V(READONLY)
1112
+ V(INTERRUPT)
1113
+ V(IOERR)
1114
+ V(CORRUPT)
1115
+ V(NOTFOUND)
1116
+ V(FULL)
1117
+ V(CANTOPEN)
1118
+ V(PROTOCOL)
1119
+ V(EMPTY)
1120
+ V(SCHEMA)
1121
+ V(TOOBIG)
1122
+ V(CONSTRAINT)
1123
+ V(MISMATCH)
1124
+ V(MISUSE)
1125
+ V(NOLFS)
1126
+ V(AUTH)
1127
+ V(FORMAT)
1128
+ V(RANGE)
1129
+ V(NOTADB)
1130
+ V(NOTICE)
1131
+ V(WARNING)
1132
+ #undef V
1133
+ default:
1134
+ return "ERROR";
1135
+ }
1136
+ }
1137
+
1138
+ static int
1139
+ paraql__make_error(js_env_t *env, int errcode, const char *errmsg, js_value_t **error) {
1140
+ int err;
1141
+
1142
+ js_value_t *code;
1143
+ err = js_create_string_utf8(env, (utf8_t *) paraql__code(errcode), -1, &code);
1144
+ assert(err == 0);
1145
+
1146
+ js_value_t *message;
1147
+ err = js_create_string_utf8(env, (utf8_t *) errmsg, -1, &message);
1148
+ assert(err == 0);
1149
+
1150
+ return js_create_error(env, code, message, error);
1151
+ }
1152
+
1153
+ static void
1154
+ paraql__on_after_finalize_db(uv_work_t *handle, int status) {
1155
+ free(handle);
1156
+ }
1157
+
1158
+ static void
1159
+ paraql__on_before_finalize_db(uv_work_t *handle) {
1160
+ paraql_t *db = (paraql_t *) handle->data;
1161
+
1162
+ paraql__finalize_statements(db);
1163
+
1164
+ if (db->handle != NULL) sqlite3_close_v2(db->handle);
1165
+
1166
+ free(db);
1167
+ }
1168
+
1169
+ static void
1170
+ paraql__on_finalize_db(js_env_t *env, void *data, void *hint) {
1171
+ int err;
1172
+
1173
+ paraql_t *db = (paraql_t *) data;
1174
+
1175
+ uv_loop_t *loop;
1176
+ err = js_get_env_loop(env, &loop);
1177
+ assert(err == 0);
1178
+
1179
+ uv_work_t *handle = malloc(sizeof(uv_work_t));
1180
+
1181
+ handle->data = (void *) db;
1182
+
1183
+ err = uv_queue_work(loop, handle, paraql__on_before_finalize_db, paraql__on_after_finalize_db);
1184
+ assert(err == 0);
1185
+ }
1186
+
1187
+ static void
1188
+ paraql__on_after_finalize_statement(uv_work_t *handle, int status) {
1189
+ free(handle);
1190
+ }
1191
+
1192
+ static void
1193
+ paraql__on_before_finalize_statement(uv_work_t *handle) {
1194
+ paraql_statement_t *stmt = (paraql_statement_t *) handle->data;
1195
+
1196
+ if (stmt->handle != NULL) sqlite3_finalize(stmt->handle);
1197
+
1198
+ paraql__remove_statement(stmt);
1199
+
1200
+ free(stmt);
1201
+ }
1202
+
1203
+ static void
1204
+ paraql__on_finalize_statement(js_env_t *env, void *data, void *hint) {
1205
+ int err;
1206
+
1207
+ paraql_statement_t *stmt = (paraql_statement_t *) data;
1208
+
1209
+ uv_loop_t *loop;
1210
+ err = js_get_env_loop(env, &loop);
1211
+ assert(err == 0);
1212
+
1213
+ uv_work_t *handle = malloc(sizeof(uv_work_t));
1214
+
1215
+ handle->data = stmt;
1216
+
1217
+ err = uv_queue_work(loop, handle, paraql__on_before_finalize_statement, paraql__on_after_finalize_statement);
1218
+ assert(err == 0);
1219
+ }
1220
+
1221
+ static void
1222
+ paraql__on_after_open(uv_work_t *handle, int status) {
1223
+ int err;
1224
+
1225
+ paraql_open_t *req = (paraql_open_t *) handle->data;
1226
+
1227
+ paraql_t *db = req->db;
1228
+
1229
+ js_env_t *env = db->env;
1230
+
1231
+ js_handle_scope_t *scope;
1232
+ err = js_open_handle_scope(env, &scope);
1233
+ assert(err == 0);
1234
+
1235
+ if (req->errcode) {
1236
+ js_value_t *error;
1237
+ err = paraql__make_error(env, req->errcode, req->errmsg, &error);
1238
+ assert(err == 0);
1239
+
1240
+ err = js_reject_deferred(env, req->deferred, error);
1241
+ assert(err == 0);
1242
+ } else {
1243
+ js_value_t *result;
1244
+ err = js_create_external(env, db, paraql__on_finalize_db, NULL, &result);
1245
+ assert(err == 0);
1246
+
1247
+ err = js_resolve_deferred(env, req->deferred, result);
1248
+ assert(err == 0);
1249
+ }
1250
+
1251
+ err = js_close_handle_scope(env, scope);
1252
+ assert(err == 0);
1253
+
1254
+ free(req);
1255
+ }
1256
+
1257
+ static void
1258
+ paraql__on_before_open(uv_work_t *handle) {
1259
+ paraql_open_t *req = (paraql_open_t *) handle->data;
1260
+
1261
+ paraql_t *db = req->db;
1262
+
1263
+ int status = sqlite3_open_v2((char *) req->name, &db->handle, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, PARAVFS);
1264
+
1265
+ if (status != SQLITE_OK) {
1266
+ const char *errmsg = db->handle != NULL ? sqlite3_errmsg(db->handle) : sqlite3_errstr(status);
1267
+
1268
+ req->errcode = status;
1269
+ req->errmsg = errmsg;
1270
+
1271
+ if (db->handle != NULL) sqlite3_close_v2(db->handle);
1272
+ }
1273
+ }
1274
+
1275
+ static js_value_t *
1276
+ paraql_open(js_env_t *env, js_callback_info_t *info) {
1277
+ int err;
1278
+
1279
+ size_t argc = 1;
1280
+ js_value_t *argv[1];
1281
+
1282
+ err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1283
+ assert(err == 0);
1284
+
1285
+ assert(argc == 1);
1286
+
1287
+ uv_loop_t *loop;
1288
+ err = js_get_env_loop(env, &loop);
1289
+ assert(err == 0);
1290
+
1291
+ paraql_path_t name;
1292
+ err = js_get_value_string_utf8(env, argv[0], name, sizeof(name), NULL);
1293
+ assert(err == 0);
1294
+
1295
+ paraql_t *db = malloc(sizeof(paraql_t));
1296
+
1297
+ db->env = env;
1298
+ db->statements = NULL;
1299
+
1300
+ paraql_open_t *req = malloc(sizeof(paraql_open_t));
1301
+
1302
+ req->db = db;
1303
+ req->errcode = 0;
1304
+ req->db->env = env;
1305
+
1306
+ memcpy(req->name, name, sizeof(name));
1307
+
1308
+ req->handle.data = (void *) req;
1309
+
1310
+ js_value_t *promise;
1311
+ err = js_create_promise(env, &req->deferred, &promise);
1312
+ assert(err == 0);
1313
+
1314
+ err = uv_queue_work(loop, &req->handle, paraql__on_before_open, paraql__on_after_open);
1315
+ assert(err == 0);
1316
+
1317
+ return promise;
1318
+ }
1319
+
1320
+ static void
1321
+ paraql__on_after_close(uv_work_t *handle, int status) {
1322
+ int err;
1323
+
1324
+ paraql_close_t *req = (paraql_close_t *) handle->data;
1325
+
1326
+ paraql_t *db = req->db;
1327
+
1328
+ js_env_t *env = db->env;
1329
+
1330
+ js_handle_scope_t *scope;
1331
+ err = js_open_handle_scope(env, &scope);
1332
+ assert(err == 0);
1333
+
1334
+ if (req->errcode) {
1335
+ js_value_t *error;
1336
+ err = paraql__make_error(env, req->errcode, req->errmsg, &error);
1337
+ assert(err == 0);
1338
+
1339
+ err = js_reject_deferred(env, req->deferred, error);
1340
+ assert(err == 0);
1341
+ } else {
1342
+ js_value_t *result;
1343
+ err = js_get_undefined(env, &result);
1344
+ assert(err == 0);
1345
+
1346
+ err = js_resolve_deferred(env, req->deferred, result);
1347
+ assert(err == 0);
1348
+ }
1349
+
1350
+ err = js_close_handle_scope(env, scope);
1351
+ assert(err == 0);
1352
+
1353
+ free(req);
1354
+ }
1355
+
1356
+ static void
1357
+ paraql__on_before_close(uv_work_t *handle) {
1358
+ paraql_close_t *req = (paraql_close_t *) handle->data;
1359
+
1360
+ paraql_t *db = req->db;
1361
+
1362
+ int status = sqlite3_close_v2(req->db->handle);
1363
+
1364
+ if (status != SQLITE_OK) {
1365
+ req->errcode = status;
1366
+ req->errmsg = sqlite3_errmsg(db->handle);
1367
+
1368
+ return;
1369
+ }
1370
+
1371
+ db->handle = NULL;
1372
+ }
1373
+
1374
+ static js_value_t *
1375
+ paraql_close(js_env_t *env, js_callback_info_t *info) {
1376
+ int err;
1377
+
1378
+ size_t argc = 1;
1379
+ js_value_t *argv[1];
1380
+
1381
+ err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1382
+ assert(err == 0);
1383
+
1384
+ assert(argc == 1);
1385
+
1386
+ uv_loop_t *loop;
1387
+ err = js_get_env_loop(env, &loop);
1388
+ assert(err == 0);
1389
+
1390
+ paraql_close_t *req = malloc(sizeof(paraql_close_t));
1391
+
1392
+ req->errcode = 0;
1393
+
1394
+ err = js_get_value_external(env, argv[0], (void **) &req->db);
1395
+ assert(err == 0);
1396
+
1397
+ req->handle.data = (void *) req;
1398
+
1399
+ js_value_t *promise;
1400
+ err = js_create_promise(env, &req->deferred, &promise);
1401
+ assert(err == 0);
1402
+
1403
+ err = uv_queue_work(loop, &req->handle, paraql__on_before_close, paraql__on_after_close);
1404
+ assert(err == 0);
1405
+
1406
+ return promise;
1407
+ }
1408
+
1409
+ static void
1410
+ paraql__on_after_exec(uv_work_t *handle, int status) {
1411
+ int err;
1412
+
1413
+ paraql_exec_t *req = (paraql_exec_t *) handle->data;
1414
+
1415
+ paraql_t *db = req->db;
1416
+
1417
+ js_env_t *env = db->env;
1418
+
1419
+ js_handle_scope_t *scope;
1420
+ err = js_open_handle_scope(env, &scope);
1421
+ assert(err == 0);
1422
+
1423
+ if (req->errcode) {
1424
+ js_value_t *error;
1425
+ err = paraql__make_error(env, req->errcode, req->errmsg, &error);
1426
+ assert(err == 0);
1427
+
1428
+ err = js_reject_deferred(env, req->deferred, error);
1429
+ assert(err == 0);
1430
+ } else {
1431
+ js_value_t *result;
1432
+ err = js_get_undefined(env, &result);
1433
+ assert(err == 0);
1434
+
1435
+ err = js_resolve_deferred(env, req->deferred, result);
1436
+ assert(err == 0);
1437
+ }
1438
+
1439
+ err = js_close_handle_scope(env, scope);
1440
+ assert(err == 0);
1441
+
1442
+ free(req);
1443
+ }
1444
+
1445
+ static void
1446
+ paraql__on_before_exec(uv_work_t *handle) {
1447
+ paraql_exec_t *req = (paraql_exec_t *) handle->data;
1448
+
1449
+ paraql_t *db = req->db;
1450
+
1451
+ const char *cursor = (const char *) req->sql;
1452
+
1453
+ while (*cursor != '\0') {
1454
+ sqlite3_stmt *stmt = NULL;
1455
+ const char *tail;
1456
+ int status = sqlite3_prepare_v2(db->handle, cursor, -1, &stmt, &tail);
1457
+
1458
+ if (status != SQLITE_OK) {
1459
+ req->errcode = status;
1460
+ req->errmsg = sqlite3_errmsg(db->handle);
1461
+
1462
+ if (stmt != NULL) sqlite3_finalize(stmt);
1463
+
1464
+ free(req->sql);
1465
+ return;
1466
+ }
1467
+
1468
+ cursor = tail;
1469
+
1470
+ if (stmt == NULL) continue;
1471
+
1472
+ while ((status = sqlite3_step(stmt)) == SQLITE_ROW) {
1473
+ }
1474
+
1475
+ sqlite3_finalize(stmt);
1476
+
1477
+ if (status != SQLITE_DONE) {
1478
+ req->errcode = status;
1479
+ req->errmsg = sqlite3_errmsg(db->handle);
1480
+
1481
+ free(req->sql);
1482
+ return;
1483
+ }
1484
+ }
1485
+
1486
+ free(req->sql);
1487
+ }
1488
+
1489
+ static js_value_t *
1490
+ paraql_exec(js_env_t *env, js_callback_info_t *info) {
1491
+ int err;
1492
+
1493
+ size_t argc = 2;
1494
+ js_value_t *argv[2];
1495
+
1496
+ err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1497
+ assert(err == 0);
1498
+
1499
+ assert(argc == 2);
1500
+
1501
+ uv_loop_t *loop;
1502
+ err = js_get_env_loop(env, &loop);
1503
+ assert(err == 0);
1504
+
1505
+ paraql_t *db;
1506
+ err = js_get_value_external(env, argv[0], (void **) &db);
1507
+ assert(err == 0);
1508
+
1509
+ size_t sql_len;
1510
+ err = js_get_value_string_utf8(env, argv[1], NULL, 0, &sql_len);
1511
+ assert(err == 0);
1512
+
1513
+ sql_len += 1; // NULL
1514
+
1515
+ utf8_t *sql = malloc(sql_len);
1516
+
1517
+ err = js_get_value_string_utf8(env, argv[1], sql, sql_len, NULL);
1518
+ assert(err == 0);
1519
+
1520
+ paraql_exec_t *req = malloc(sizeof(paraql_exec_t));
1521
+
1522
+ req->errcode = 0;
1523
+ req->db = db;
1524
+ req->sql = sql;
1525
+
1526
+ req->handle.data = (void *) req;
1527
+
1528
+ js_value_t *promise;
1529
+ err = js_create_promise(env, &req->deferred, &promise);
1530
+ assert(err == 0);
1531
+
1532
+ err = uv_queue_work(loop, &req->handle, paraql__on_before_exec, paraql__on_after_exec);
1533
+ assert(err == 0);
1534
+
1535
+ return promise;
1536
+ }
1537
+
1538
+ static void
1539
+ paraql__on_after_prepare(uv_work_t *handle, int status) {
1540
+ int err;
1541
+
1542
+ paraql_prepare_t *req = (paraql_prepare_t *) handle->data;
1543
+
1544
+ paraql_t *db = req->db;
1545
+
1546
+ js_env_t *env = db->env;
1547
+
1548
+ paraql_statement_t *stmt = req->stmt;
1549
+
1550
+ js_handle_scope_t *scope;
1551
+ err = js_open_handle_scope(env, &scope);
1552
+ assert(err == 0);
1553
+
1554
+ if (req->errcode) {
1555
+ js_value_t *error;
1556
+ err = paraql__make_error(env, req->errcode, req->errmsg, &error);
1557
+ assert(err == 0);
1558
+
1559
+ err = js_reject_deferred(env, req->deferred, error);
1560
+ assert(err == 0);
1561
+ } else {
1562
+ js_value_t *result;
1563
+ err = js_create_external(env, stmt, paraql__on_finalize_statement, NULL, &result);
1564
+ assert(err == 0);
1565
+
1566
+ err = js_resolve_deferred(env, req->deferred, result);
1567
+ assert(err == 0);
1568
+ }
1569
+
1570
+ err = js_close_handle_scope(env, scope);
1571
+ assert(err == 0);
1572
+
1573
+ free(req);
1574
+ }
1575
+
1576
+ static void
1577
+ paraql__on_before_prepare(uv_work_t *handle) {
1578
+ paraql_prepare_t *req = (paraql_prepare_t *) handle->data;
1579
+
1580
+ paraql_t *db = req->db;
1581
+
1582
+ paraql_statement_t *stmt = malloc(sizeof(paraql_statement_t));
1583
+
1584
+ int status = sqlite3_prepare_v2(db->handle, (const char *) req->sql, -1, &stmt->handle, NULL);
1585
+
1586
+ free(req->sql);
1587
+
1588
+ if (status != SQLITE_OK) {
1589
+ req->errcode = status;
1590
+ req->errmsg = sqlite3_errmsg(db->handle);
1591
+
1592
+ if (stmt->handle != NULL) sqlite3_finalize(stmt->handle);
1593
+
1594
+ return;
1595
+ }
1596
+
1597
+ paraql__insert_statement(db, stmt);
1598
+
1599
+ req->stmt = stmt;
1600
+ }
1601
+
1602
+ static js_value_t *
1603
+ paraql_prepare(js_env_t *env, js_callback_info_t *info) {
1604
+ int err;
1605
+
1606
+ size_t argc = 2;
1607
+ js_value_t *argv[2];
1608
+
1609
+ err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1610
+ assert(err == 0);
1611
+
1612
+ assert(argc == 2);
1613
+
1614
+ uv_loop_t *loop;
1615
+ err = js_get_env_loop(env, &loop);
1616
+ assert(err == 0);
1617
+
1618
+ paraql_t *db;
1619
+ err = js_get_value_external(env, argv[0], (void **) &db);
1620
+ assert(err == 0);
1621
+
1622
+ size_t sql_len;
1623
+ err = js_get_value_string_utf8(env, argv[1], NULL, 0, &sql_len);
1624
+ assert(err == 0);
1625
+
1626
+ sql_len += 1;
1627
+
1628
+ utf8_t *sql = malloc(sql_len);
1629
+
1630
+ err = js_get_value_string_utf8(env, argv[1], sql, sql_len, NULL);
1631
+ assert(err == 0);
1632
+
1633
+ paraql_prepare_t *req = malloc(sizeof(paraql_prepare_t));
1634
+
1635
+ req->errcode = 0;
1636
+ req->db = db;
1637
+ req->sql = sql;
1638
+
1639
+ req->handle.data = (void *) req;
1640
+
1641
+ js_value_t *promise;
1642
+ err = js_create_promise(env, &req->deferred, &promise);
1643
+ assert(err == 0);
1644
+
1645
+ err = uv_queue_work(loop, &req->handle, paraql__on_before_prepare, paraql__on_after_prepare);
1646
+ assert(err == 0);
1647
+
1648
+ return promise;
1649
+ }
1650
+
1651
+ static void
1652
+ paraql__on_after_finalize(uv_work_t *handle, int status) {
1653
+ int err;
1654
+
1655
+ paraql_finalize_t *req = (paraql_finalize_t *) handle->data;
1656
+
1657
+ js_env_t *env = req->env;
1658
+
1659
+ js_handle_scope_t *scope;
1660
+ err = js_open_handle_scope(env, &scope);
1661
+ assert(err == 0);
1662
+
1663
+ js_value_t *result;
1664
+ err = js_get_undefined(env, &result);
1665
+ assert(err == 0);
1666
+
1667
+ err = js_resolve_deferred(env, req->deferred, result);
1668
+ assert(err == 0);
1669
+
1670
+ err = js_close_handle_scope(env, scope);
1671
+ assert(err == 0);
1672
+
1673
+ free(req);
1674
+ }
1675
+
1676
+ static void
1677
+ paraql__on_before_finalize(uv_work_t *handle) {
1678
+ paraql_finalize_t *req = (paraql_finalize_t *) handle->data;
1679
+
1680
+ paraql_statement_t *stmt = req->stmt;
1681
+
1682
+ if (stmt->handle != NULL) {
1683
+ sqlite3_finalize(stmt->handle);
1684
+ stmt->handle = NULL;
1685
+ }
1686
+
1687
+ paraql__remove_statement(stmt);
1688
+ }
1689
+
1690
+ static js_value_t *
1691
+ paraql_finalize(js_env_t *env, js_callback_info_t *info) {
1692
+ int err;
1693
+
1694
+ size_t argc = 1;
1695
+ js_value_t *argv[1];
1696
+
1697
+ err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1698
+ assert(err == 0);
1699
+
1700
+ assert(argc == 1);
1701
+
1702
+ uv_loop_t *loop;
1703
+ err = js_get_env_loop(env, &loop);
1704
+ assert(err == 0);
1705
+
1706
+ paraql_statement_t *stmt;
1707
+ err = js_get_value_external(env, argv[0], (void **) &stmt);
1708
+ assert(err == 0);
1709
+
1710
+ paraql_finalize_t *req = malloc(sizeof(paraql_finalize_t));
1711
+
1712
+ req->env = env;
1713
+ req->stmt = stmt;
1714
+
1715
+ req->handle.data = (void *) req;
1716
+
1717
+ js_value_t *promise;
1718
+ err = js_create_promise(env, &req->deferred, &promise);
1719
+ assert(err == 0);
1720
+
1721
+ err = uv_queue_work(loop, &req->handle, paraql__on_before_finalize, paraql__on_after_finalize);
1722
+ assert(err == 0);
1723
+
1724
+ return promise;
1725
+ }
1726
+
1727
+ static void
1728
+ paraql__on_after_reset(uv_work_t *handle, int status) {
1729
+ int err;
1730
+
1731
+ paraql_reset_t *req = (paraql_reset_t *) handle->data;
1732
+
1733
+ js_env_t *env = req->env;
1734
+
1735
+ js_handle_scope_t *scope;
1736
+ err = js_open_handle_scope(env, &scope);
1737
+ assert(err == 0);
1738
+
1739
+ if (req->errcode) {
1740
+ js_value_t *error;
1741
+ err = paraql__make_error(env, req->errcode, req->errmsg, &error);
1742
+ assert(err == 0);
1743
+
1744
+ err = js_reject_deferred(env, req->deferred, error);
1745
+ assert(err == 0);
1746
+ } else {
1747
+ js_value_t *result;
1748
+ err = js_get_undefined(env, &result);
1749
+ assert(err == 0);
1750
+
1751
+ err = js_resolve_deferred(env, req->deferred, result);
1752
+ assert(err == 0);
1753
+ }
1754
+
1755
+ err = js_close_handle_scope(env, scope);
1756
+ assert(err == 0);
1757
+
1758
+ free(req);
1759
+ }
1760
+
1761
+ static void
1762
+ paraql__on_before_reset(uv_work_t *handle) {
1763
+ paraql_reset_t *req = (paraql_reset_t *) handle->data;
1764
+
1765
+ paraql_statement_t *stmt = req->stmt;
1766
+
1767
+ if (stmt->handle != NULL) {
1768
+ sqlite3_reset(stmt->handle);
1769
+ sqlite3_clear_bindings(stmt->handle);
1770
+ } else {
1771
+ req->errcode = SQLITE_MISUSE;
1772
+ req->errmsg = STMT_FINALIZED;
1773
+ }
1774
+ }
1775
+
1776
+ static js_value_t *
1777
+ paraql_reset(js_env_t *env, js_callback_info_t *info) {
1778
+ int err;
1779
+
1780
+ size_t argc = 1;
1781
+ js_value_t *argv[1];
1782
+
1783
+ err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
1784
+ assert(err == 0);
1785
+
1786
+ assert(argc == 1);
1787
+
1788
+ uv_loop_t *loop;
1789
+ err = js_get_env_loop(env, &loop);
1790
+ assert(err == 0);
1791
+
1792
+ paraql_statement_t *stmt;
1793
+ err = js_get_value_external(env, argv[0], (void **) &stmt);
1794
+ assert(err == 0);
1795
+
1796
+ paraql_reset_t *req = malloc(sizeof(paraql_reset_t));
1797
+
1798
+ req->errcode = 0;
1799
+ req->env = env;
1800
+ req->stmt = stmt;
1801
+
1802
+ req->handle.data = (void *) req;
1803
+
1804
+ js_value_t *promise;
1805
+ err = js_create_promise(env, &req->deferred, &promise);
1806
+ assert(err == 0);
1807
+
1808
+ err = uv_queue_work(loop, &req->handle, paraql__on_before_reset, paraql__on_after_reset);
1809
+ assert(err == 0);
1810
+
1811
+ return promise;
1812
+ }
1813
+
1814
+ paraql_bind_value_t *
1815
+ paraql__parse_value(js_env_t *env, js_value_t *value) {
1816
+ int err;
1817
+
1818
+ paraql_bind_value_t *val = malloc(sizeof(paraql_bind_value_t));
1819
+
1820
+ js_value_type_t type;
1821
+ err = js_typeof(env, value, &type);
1822
+ assert(err == 0);
1823
+
1824
+ switch (type) {
1825
+ case js_null:
1826
+ case js_undefined:
1827
+ val->type = js_null;
1828
+ break;
1829
+
1830
+ case js_number: {
1831
+ double n;
1832
+ err = js_get_value_double(env, value, &n);
1833
+ assert(err == 0);
1834
+
1835
+ int64_t i = (int64_t) n;
1836
+
1837
+ val->type = js_number;
1838
+
1839
+ if (n == (double) i) {
1840
+ val->is_double = false;
1841
+ val->value.i = i;
1842
+ } else {
1843
+ val->is_double = true;
1844
+ val->value.d = n;
1845
+ }
1846
+ break;
1847
+ }
1848
+
1849
+ case js_bigint: {
1850
+ int64_t n;
1851
+ bool lossless;
1852
+ err = js_get_value_bigint_int64(env, value, &n, &lossless);
1853
+ assert(err == 0);
1854
+
1855
+ val->type = js_bigint;
1856
+ val->value.i = n;
1857
+ }
1858
+
1859
+ case js_string: {
1860
+ size_t len;
1861
+ err = js_get_value_string_utf8(env, value, NULL, 0, &len);
1862
+ assert(err == 0);
1863
+
1864
+ utf8_t *str = malloc(len + 1);
1865
+
1866
+ err = js_get_value_string_utf8(env, value, str, len + 1, NULL);
1867
+ assert(err == 0);
1868
+
1869
+ val->type = js_string;
1870
+ val->value.buffer.data = (void *) str;
1871
+ val->value.buffer.len = len;
1872
+ break;
1873
+ }
1874
+
1875
+ case js_object: {
1876
+ bool is_typedarray;
1877
+ err = js_is_typedarray(env, value, &is_typedarray);
1878
+ assert(err == 0);
1879
+
1880
+ if (is_typedarray) {
1881
+ void *data;
1882
+ size_t len;
1883
+ err = js_get_typedarray_info(env, value, NULL, &data, &len, NULL, NULL);
1884
+ assert(err == 0);
1885
+
1886
+ val->type = js_object;
1887
+ val->value.buffer.data = data;
1888
+ val->value.buffer.len = len;
1889
+ break;
1890
+ }
1891
+
1892
+ bool is_arraybuffer;
1893
+ err = js_is_arraybuffer(env, value, &is_arraybuffer);
1894
+ assert(err == 0);
1895
+
1896
+ if (is_arraybuffer) {
1897
+ void *data;
1898
+ size_t len;
1899
+ err = js_get_arraybuffer_info(env, value, &data, &len);
1900
+ assert(err == 0);
1901
+
1902
+ val->type = js_object;
1903
+ val->value.buffer.data = data;
1904
+ val->value.buffer.len = len;
1905
+ break;
1906
+ }
1907
+
1908
+ return NULL;
1909
+ }
1910
+
1911
+ default:
1912
+ return NULL;
1913
+ }
1914
+
1915
+ return val;
1916
+ }
1917
+
1918
+ static void
1919
+ paraql__cancel_bind(js_env_t *env, js_handle_scope_t *scope, paraql_bind_t *req, int index, const char *errmsg) {
1920
+ int err;
1921
+
1922
+ free(req->param_names);
1923
+
1924
+ for (int i = 0; i < index; i++) {
1925
+ paraql_bind_value_t *value = req->values[i];
1926
+
1927
+ if (value->type == js_string) {
1928
+ free(value->value.buffer.data);
1929
+ }
1930
+
1931
+ free(value);
1932
+ }
1933
+
1934
+ free(req->values);
1935
+
1936
+ js_value_t *message;
1937
+ err = js_create_string_utf8(env, (utf8_t *) errmsg, -1, &message);
1938
+ assert(err == 0);
1939
+
1940
+ js_value_t *error;
1941
+ err = js_create_type_error(env, NULL, message, &error);
1942
+ assert(err == 0);
1943
+
1944
+ err = js_reject_deferred(env, req->deferred, error);
1945
+ assert(err == 0);
1946
+
1947
+ err = js_close_handle_scope(env, scope);
1948
+ assert(err == 0);
1949
+
1950
+ free(req);
1951
+ }
1952
+
1953
+ static void
1954
+ paraql__free_bind_values(paraql_bind_t *req, int start) {
1955
+ for (int i = start; i < req->param_count; i++) {
1956
+ paraql_bind_value_t *value = req->values[i];
1957
+
1958
+ if (value->type == js_string) {
1959
+ free(value->value.buffer.data);
1960
+ }
1961
+
1962
+ free(value);
1963
+ }
1964
+ }
1965
+
1966
+ static void
1967
+ paraql__on_after_bind(uv_work_t *handle, int status) {
1968
+ int err;
1969
+
1970
+ paraql_bind_t *req = (paraql_bind_t *) handle->data;
1971
+
1972
+ js_env_t *env = req->env;
1973
+
1974
+ js_handle_scope_t *scope;
1975
+ err = js_open_handle_scope(env, &scope);
1976
+ assert(err == 0);
1977
+
1978
+ err = js_delete_reference(env, req->named);
1979
+ assert(err == 0);
1980
+
1981
+ err = js_delete_reference(env, req->positional);
1982
+ assert(err == 0);
1983
+
1984
+ if (req->errcode) {
1985
+ js_value_t *error;
1986
+ err = paraql__make_error(env, req->errcode, req->errmsg, &error);
1987
+ assert(err == 0);
1988
+
1989
+ err = js_reject_deferred(env, req->deferred, error);
1990
+ assert(err == 0);
1991
+ } else {
1992
+ js_value_t *result;
1993
+ err = js_get_undefined(env, &result);
1994
+ assert(err == 0);
1995
+
1996
+ err = js_resolve_deferred(env, req->deferred, result);
1997
+ assert(err == 0);
1998
+ }
1999
+
2000
+ err = js_close_handle_scope(env, scope);
2001
+ assert(err == 0);
2002
+
2003
+ free(req);
2004
+ }
2005
+
2006
+ static void
2007
+ paraql__on_before_bind(uv_work_t *handle) {
2008
+ int status;
2009
+
2010
+ paraql_bind_t *req = (paraql_bind_t *) handle->data;
2011
+
2012
+ paraql_statement_t *stmt = req->stmt;
2013
+
2014
+ if (stmt->handle != NULL) {
2015
+ for (int i = 1; i <= req->param_count; i++) {
2016
+ paraql_bind_value_t *value = req->values[i - 1];
2017
+
2018
+ switch (value->type) {
2019
+ case js_null:
2020
+ case js_undefined:
2021
+ status = sqlite3_bind_null(stmt->handle, i);
2022
+ break;
2023
+
2024
+ case js_number:
2025
+ if (value->is_double) {
2026
+ status = sqlite3_bind_double(stmt->handle, i, value->value.d);
2027
+ } else {
2028
+ status = sqlite3_bind_int64(stmt->handle, i, value->value.i);
2029
+ }
2030
+ break;
2031
+
2032
+ case js_bigint:
2033
+ status = sqlite3_bind_int64(stmt->handle, i, value->value.i);
2034
+ break;
2035
+
2036
+ case js_string:
2037
+ status = sqlite3_bind_text(stmt->handle, i, (const char *) value->value.buffer.data, (int) value->value.buffer.len, SQLITE_TRANSIENT);
2038
+ free(value->value.buffer.data);
2039
+ break;
2040
+
2041
+ case js_object:
2042
+ status = sqlite3_bind_blob(stmt->handle, i, value->value.buffer.data, (int) value->value.buffer.len, SQLITE_TRANSIENT);
2043
+ break;
2044
+
2045
+ default:
2046
+ break;
2047
+ }
2048
+
2049
+ free(value);
2050
+
2051
+ if (status != SQLITE_OK) {
2052
+ req->errcode = status;
2053
+ req->errmsg = sqlite3_errmsg(stmt->db->handle);
2054
+
2055
+ paraql__free_bind_values(req, i);
2056
+
2057
+ free(req->values);
2058
+
2059
+ return;
2060
+ }
2061
+ }
2062
+ } else {
2063
+ req->errcode = SQLITE_MISUSE;
2064
+ req->errmsg = STMT_FINALIZED;
2065
+
2066
+ paraql__free_bind_values(req, 0);
2067
+ }
2068
+
2069
+ free(req->values);
2070
+ }
2071
+
2072
+ static void
2073
+ paraql__on_after_parse(uv_work_t *handle, int status) {
2074
+ int err;
2075
+
2076
+ paraql_bind_t *req = (paraql_bind_t *) handle->data;
2077
+
2078
+ js_env_t *env = req->env;
2079
+
2080
+ js_handle_scope_t *scope;
2081
+ err = js_open_handle_scope(env, &scope);
2082
+ assert(err == 0);
2083
+
2084
+ if (req->errcode) {
2085
+ err = js_delete_reference(env, req->named);
2086
+ assert(err == 0);
2087
+
2088
+ err = js_delete_reference(env, req->positional);
2089
+ assert(err == 0);
2090
+
2091
+ js_value_t *error;
2092
+ err = paraql__make_error(env, req->errcode, req->errmsg, &error);
2093
+ assert(err == 0);
2094
+
2095
+ err = js_reject_deferred(env, req->deferred, error);
2096
+ assert(err == 0);
2097
+
2098
+ free(req);
2099
+ } else {
2100
+ js_value_t *named;
2101
+ err = js_get_reference_value(env, req->named, &named);
2102
+ assert(err == 0);
2103
+
2104
+ js_value_t *positional;
2105
+ err = js_get_reference_value(env, req->positional, &positional);
2106
+ assert(err == 0);
2107
+
2108
+ uint32_t pos_len;
2109
+ err = js_get_array_length(env, positional, &pos_len);
2110
+ assert(err == 0);
2111
+
2112
+ js_value_type_t named_type;
2113
+ err = js_typeof(env, named, &named_type);
2114
+ assert(err == 0);
2115
+
2116
+ bool has_named = named_type == js_object;
2117
+
2118
+ uint32_t pos_idx = 0;
2119
+
2120
+ for (int i = 0; i < req->param_count; i++) {
2121
+ const char *name = req->param_names[i];
2122
+
2123
+ if (name == NULL) {
2124
+ if (pos_idx >= pos_len) {
2125
+ return paraql__cancel_bind(env, scope, req, i, "Missing positional parameter");
2126
+ }
2127
+
2128
+ js_value_t *value;
2129
+ err = js_get_element(env, positional, pos_idx++, &value);
2130
+ assert(err == 0);
2131
+
2132
+ paraql_bind_value_t *val = paraql__parse_value(env, value);
2133
+
2134
+ if (val == NULL) {
2135
+ return paraql__cancel_bind(env, scope, req, i, "Unsupported parameter type");
2136
+ }
2137
+
2138
+ req->values[i] = val;
2139
+
2140
+ continue;
2141
+ }
2142
+
2143
+ if (!has_named) {
2144
+ return paraql__cancel_bind(env, scope, req, i, "Missing named parameters object");
2145
+ }
2146
+
2147
+ bool found;
2148
+ err = js_has_named_property(env, named, name, &found);
2149
+ assert(err == 0);
2150
+
2151
+ const char *key = name;
2152
+
2153
+ if (!found) {
2154
+ err = js_has_named_property(env, named, name + 1, &found);
2155
+ assert(err == 0);
2156
+
2157
+ if (found) key = name + 1;
2158
+ }
2159
+
2160
+ if (!found) {
2161
+ return paraql__cancel_bind(env, scope, req, i, "Missing named parameter");
2162
+ }
2163
+
2164
+ js_value_t *value;
2165
+ err = js_get_named_property(env, named, key, &value);
2166
+ assert(err == 0);
2167
+
2168
+ paraql_bind_value_t *val = paraql__parse_value(env, value);
2169
+
2170
+ if (val == NULL) {
2171
+ return paraql__cancel_bind(env, scope, req, i, "Unsupported parameter type");
2172
+ }
2173
+
2174
+ req->values[i] = val;
2175
+ }
2176
+
2177
+ if (pos_idx < pos_len) {
2178
+ return paraql__cancel_bind(env, scope, req, req->param_count, "Too many positional parameters");
2179
+ }
2180
+
2181
+ if (has_named) {
2182
+ js_value_t *keys;
2183
+ err = js_get_property_names(env, named, &keys);
2184
+ assert(err == 0);
2185
+
2186
+ uint32_t keys_len;
2187
+ err = js_get_array_length(env, keys, &keys_len);
2188
+ assert(err == 0);
2189
+
2190
+ for (uint32_t k = 0; k < keys_len; k++) {
2191
+ js_value_t *key_value;
2192
+ err = js_get_element(env, keys, k, &key_value);
2193
+ assert(err == 0);
2194
+
2195
+ utf8_t key[256];
2196
+ err = js_get_value_string_utf8(env, key_value, key, sizeof(key), NULL);
2197
+ assert(err == 0);
2198
+
2199
+ bool known = false;
2200
+
2201
+ for (int i = 0; i < req->param_count; i++) {
2202
+ const char *name = req->param_names[i];
2203
+
2204
+ if (name == NULL) continue;
2205
+
2206
+ if (strcmp(name, (const char *) key) == 0) {
2207
+ known = true;
2208
+ break;
2209
+ }
2210
+
2211
+ if (strcmp(name + 1, (const char *) key) == 0) {
2212
+ known = true;
2213
+ break;
2214
+ }
2215
+ }
2216
+
2217
+ if (!known) {
2218
+ return paraql__cancel_bind(env, scope, req, req->param_count, "Unknown named parameter");
2219
+ }
2220
+ }
2221
+ }
2222
+
2223
+ free(req->param_names);
2224
+
2225
+ uv_loop_t *loop;
2226
+ err = js_get_env_loop(env, &loop);
2227
+ assert(err == 0);
2228
+
2229
+ err = uv_queue_work(loop, &req->handle, paraql__on_before_bind, paraql__on_after_bind);
2230
+ assert(err == 0);
2231
+ }
2232
+
2233
+ err = js_close_handle_scope(env, scope);
2234
+ assert(err == 0);
2235
+ }
2236
+
2237
+ static void
2238
+ paraql__on_before_parse(uv_work_t *handle) {
2239
+ paraql_bind_t *req = (paraql_bind_t *) handle->data;
2240
+
2241
+ paraql_statement_t *stmt = req->stmt;
2242
+
2243
+ if (stmt->handle == NULL) {
2244
+ req->errcode = SQLITE_MISUSE;
2245
+ return;
2246
+ }
2247
+
2248
+ if (stmt->handle != NULL) {
2249
+ sqlite3_reset(stmt->handle);
2250
+ sqlite3_clear_bindings(stmt->handle);
2251
+
2252
+ req->param_count = sqlite3_bind_parameter_count(stmt->handle);
2253
+ req->param_names = malloc(sizeof(char *) * req->param_count);
2254
+ req->values = malloc(sizeof(paraql_bind_value_t *) * req->param_count);
2255
+
2256
+ for (int i = 1; i <= req->param_count; i++) {
2257
+ req->param_names[i - 1] = sqlite3_bind_parameter_name(stmt->handle, i);
2258
+ }
2259
+ } else {
2260
+ req->errcode = SQLITE_MISUSE;
2261
+ req->errmsg = STMT_FINALIZED;
2262
+ }
2263
+ }
2264
+
2265
+ static js_value_t *
2266
+ paraql_bind(js_env_t *env, js_callback_info_t *info) {
2267
+ int err;
2268
+
2269
+ size_t argc = 3;
2270
+ js_value_t *argv[3];
2271
+
2272
+ err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
2273
+ assert(err == 0);
2274
+
2275
+ assert(argc == 3);
2276
+
2277
+ uv_loop_t *loop;
2278
+ err = js_get_env_loop(env, &loop);
2279
+ assert(err == 0);
2280
+
2281
+ paraql_statement_t *stmt;
2282
+ err = js_get_value_external(env, argv[0], (void **) &stmt);
2283
+ assert(err == 0);
2284
+
2285
+ js_ref_t *named;
2286
+ err = js_create_reference(env, argv[1], 1, &named);
2287
+ assert(err == 0);
2288
+
2289
+ js_ref_t *positional;
2290
+ err = js_create_reference(env, argv[2], 1, &positional);
2291
+ assert(err == 0);
2292
+
2293
+ paraql_bind_t *req = malloc(sizeof(paraql_bind_t));
2294
+
2295
+ req->errcode = 0;
2296
+ req->env = env;
2297
+ req->stmt = stmt;
2298
+ req->named = named;
2299
+ req->positional = positional;
2300
+
2301
+ req->handle.data = (void *) req;
2302
+
2303
+ js_value_t *promise;
2304
+ err = js_create_promise(env, &req->deferred, &promise);
2305
+ assert(err == 0);
2306
+
2307
+ err = uv_queue_work(loop, &req->handle, paraql__on_before_parse, paraql__on_after_parse);
2308
+ assert(err == 0);
2309
+
2310
+ return promise;
2311
+ }
2312
+
2313
+ static void
2314
+ paraql__on_after_step(uv_work_t *handle, int status) {
2315
+ int err;
2316
+
2317
+ paraql_step_t *req = (paraql_step_t *) handle->data;
2318
+
2319
+ js_env_t *env = req->env;
2320
+
2321
+ js_handle_scope_t *scope;
2322
+ err = js_open_handle_scope(env, &scope);
2323
+ assert(err == 0);
2324
+
2325
+ if (req->errcode) {
2326
+ js_value_t *error;
2327
+ err = paraql__make_error(env, req->errcode, req->errmsg, &error);
2328
+ assert(err == 0);
2329
+
2330
+ err = js_reject_deferred(env, req->deferred, error);
2331
+ assert(err == 0);
2332
+ } else if (req->done) {
2333
+ js_value_t *result;
2334
+ err = js_get_undefined(env, &result);
2335
+ assert(err == 0);
2336
+
2337
+ err = js_resolve_deferred(env, req->deferred, result);
2338
+ assert(err == 0);
2339
+ } else {
2340
+ js_value_t *row;
2341
+ err = js_create_object(env, &row);
2342
+ assert(err == 0);
2343
+
2344
+ for (int i = 0; i < req->count; i++) {
2345
+ paraql_step_value_t val = req->values[i];
2346
+
2347
+ js_value_t *value;
2348
+
2349
+ switch (val.type) {
2350
+ case SQLITE_INTEGER:
2351
+ err = js_create_int64(env, val.value.i, &value);
2352
+ assert(err == 0);
2353
+ break;
2354
+
2355
+ case SQLITE_FLOAT:
2356
+ err = js_create_double(env, val.value.d, &value);
2357
+ assert(err == 0);
2358
+ break;
2359
+
2360
+ case SQLITE_TEXT:
2361
+ err = js_create_string_utf8(env, (const utf8_t *) val.value.buffer.data, val.value.buffer.len, &value);
2362
+ assert(err == 0);
2363
+ break;
2364
+
2365
+ case SQLITE_BLOB: {
2366
+ void *buf;
2367
+ err = js_create_arraybuffer(env, val.value.buffer.len, &buf, &value);
2368
+ assert(err == 0);
2369
+
2370
+ if (val.value.buffer.len > 0) memcpy(buf, val.value.buffer.data, val.value.buffer.len);
2371
+ break;
2372
+ }
2373
+
2374
+ case SQLITE_NULL:
2375
+ default:
2376
+ err = js_get_null(env, &value);
2377
+ assert(err == 0);
2378
+ }
2379
+
2380
+ err = js_set_named_property(env, row, val.name, value);
2381
+ assert(err == 0);
2382
+ }
2383
+
2384
+ err = js_resolve_deferred(env, req->deferred, row);
2385
+ assert(err == 0);
2386
+
2387
+ free(req->values);
2388
+ }
2389
+
2390
+ err = js_close_handle_scope(env, scope);
2391
+ assert(err == 0);
2392
+
2393
+ free(req);
2394
+ }
2395
+
2396
+ static void
2397
+ paraql__on_before_step(uv_work_t *handle) {
2398
+ int status;
2399
+
2400
+ paraql_step_t *req = (paraql_step_t *) handle->data;
2401
+
2402
+ paraql_statement_t *stmt = req->stmt;
2403
+
2404
+ if (stmt->handle != NULL) {
2405
+ status = sqlite3_step(stmt->handle);
2406
+
2407
+ if (status == SQLITE_ROW) {
2408
+ int n = sqlite3_column_count(stmt->handle);
2409
+
2410
+ req->done = false;
2411
+ req->count = n;
2412
+ req->values = malloc(sizeof(paraql_step_value_t) * n);
2413
+
2414
+ for (int i = 0; i < n; i++) {
2415
+ req->values[i].name = sqlite3_column_name(stmt->handle, i);
2416
+
2417
+ switch (sqlite3_column_type(stmt->handle, i)) {
2418
+ case SQLITE_INTEGER: {
2419
+ req->values[i].type = SQLITE_INTEGER;
2420
+ req->values[i].value.i = sqlite3_column_int64(stmt->handle, i);
2421
+ break;
2422
+ }
2423
+
2424
+ case SQLITE_FLOAT: {
2425
+ req->values[i].type = SQLITE_FLOAT;
2426
+ req->values[i].value.d = sqlite3_column_double(stmt->handle, i);
2427
+ break;
2428
+ }
2429
+
2430
+ case SQLITE_TEXT: {
2431
+ req->values[i].type = SQLITE_TEXT;
2432
+ req->values[i].value.buffer.data = (const void *) sqlite3_column_text(stmt->handle, i);
2433
+ req->values[i].value.buffer.len = sqlite3_column_bytes(stmt->handle, i);
2434
+ break;
2435
+ }
2436
+
2437
+ case SQLITE_BLOB: {
2438
+ req->values[i].type = SQLITE_BLOB;
2439
+ req->values[i].value.buffer.data = sqlite3_column_blob(stmt->handle, i);
2440
+ req->values[i].value.buffer.len = sqlite3_column_bytes(stmt->handle, i);
2441
+ break;
2442
+ }
2443
+
2444
+ case SQLITE_NULL:
2445
+ default:
2446
+ req->values[i].type = SQLITE_NULL;
2447
+ }
2448
+ }
2449
+
2450
+ return;
2451
+ }
2452
+
2453
+ if (status == SQLITE_DONE) {
2454
+ req->done = true;
2455
+ return;
2456
+ }
2457
+
2458
+ req->errcode = status;
2459
+ req->errmsg = sqlite3_errmsg(stmt->db->handle);
2460
+ } else {
2461
+ req->errcode = SQLITE_MISUSE;
2462
+ req->errmsg = STMT_FINALIZED;
2463
+ }
2464
+ }
2465
+
2466
+ static js_value_t *
2467
+ paraql_step(js_env_t *env, js_callback_info_t *info) {
2468
+ int err;
2469
+
2470
+ size_t argc = 1;
2471
+ js_value_t *argv[1];
2472
+
2473
+ err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
2474
+ assert(err == 0);
2475
+
2476
+ assert(argc == 1);
2477
+
2478
+ uv_loop_t *loop;
2479
+ err = js_get_env_loop(env, &loop);
2480
+ assert(err == 0);
2481
+
2482
+ paraql_statement_t *stmt;
2483
+ err = js_get_value_external(env, argv[0], (void **) &stmt);
2484
+ assert(err == 0);
2485
+
2486
+ paraql_step_t *req = malloc(sizeof(paraql_step_t));
2487
+
2488
+ req->errcode = 0;
2489
+ req->env = env;
2490
+ req->stmt = stmt;
2491
+
2492
+ req->handle.data = (void *) req;
2493
+
2494
+ js_value_t *promise;
2495
+ err = js_create_promise(env, &req->deferred, &promise);
2496
+ assert(err == 0);
2497
+
2498
+ err = uv_queue_work(loop, &req->handle, paraql__on_before_step, paraql__on_after_step);
2499
+ assert(err == 0);
2500
+
2501
+ return promise;
2502
+ }
2503
+
2504
+ static void
2505
+ paraql__on_after_run(uv_work_t *handle, int status) {
2506
+ int err;
2507
+
2508
+ paraql_run_t *req = (paraql_run_t *) handle->data;
2509
+
2510
+ js_env_t *env = req->env;
2511
+
2512
+ js_handle_scope_t *scope;
2513
+ err = js_open_handle_scope(env, &scope);
2514
+ assert(err == 0);
2515
+
2516
+ if (req->errcode) {
2517
+ js_value_t *error;
2518
+ err = paraql__make_error(env, req->errcode, req->errmsg, &error);
2519
+ assert(err == 0);
2520
+
2521
+ err = js_reject_deferred(env, req->deferred, error);
2522
+ assert(err == 0);
2523
+ } else {
2524
+ js_value_t *result;
2525
+ err = js_create_object(env, &result);
2526
+ assert(err == 0);
2527
+
2528
+ js_value_t *changes;
2529
+ err = js_create_int64(env, req->changes, &changes);
2530
+ assert(err == 0);
2531
+
2532
+ err = js_set_named_property(env, result, "changes", changes);
2533
+ assert(err == 0);
2534
+
2535
+ js_value_t *last_insert_rowid;
2536
+ err = js_create_int64(env, req->last_insert_rowid, &last_insert_rowid);
2537
+ assert(err == 0);
2538
+
2539
+ err = js_set_named_property(env, result, "lastInsertRowid", last_insert_rowid);
2540
+ assert(err == 0);
2541
+
2542
+ err = js_resolve_deferred(env, req->deferred, result);
2543
+ assert(err == 0);
2544
+ }
2545
+
2546
+ err = js_close_handle_scope(env, scope);
2547
+ assert(err == 0);
2548
+
2549
+ free(req);
2550
+ }
2551
+
2552
+ static void
2553
+ paraql__on_before_run(uv_work_t *handle) {
2554
+ int status;
2555
+
2556
+ paraql_run_t *req = (paraql_run_t *) handle->data;
2557
+
2558
+ paraql_statement_t *stmt = req->stmt;
2559
+
2560
+ if (stmt->handle != NULL) {
2561
+ while ((status = sqlite3_step(stmt->handle)) == SQLITE_ROW) {
2562
+ }
2563
+
2564
+ if (status != SQLITE_DONE) {
2565
+ req->errcode = status;
2566
+ req->errmsg = sqlite3_errmsg(stmt->db->handle);
2567
+ return;
2568
+ }
2569
+
2570
+ req->changes = sqlite3_changes64(stmt->db->handle);
2571
+ req->last_insert_rowid = sqlite3_last_insert_rowid(stmt->db->handle);
2572
+ } else {
2573
+ req->errcode = SQLITE_MISUSE;
2574
+ req->errmsg = STMT_FINALIZED;
2575
+ }
2576
+ }
2577
+
2578
+ static js_value_t *
2579
+ paraql_run(js_env_t *env, js_callback_info_t *info) {
2580
+ int err;
2581
+
2582
+ size_t argc = 1;
2583
+ js_value_t *argv[1];
2584
+
2585
+ err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
2586
+ assert(err == 0);
2587
+
2588
+ assert(argc == 1);
2589
+
2590
+ uv_loop_t *loop;
2591
+ err = js_get_env_loop(env, &loop);
2592
+ assert(err == 0);
2593
+
2594
+ paraql_statement_t *stmt;
2595
+ err = js_get_value_external(env, argv[0], (void **) &stmt);
2596
+ assert(err == 0);
2597
+
2598
+ paraql_run_t *req = malloc(sizeof(paraql_run_t));
2599
+
2600
+ req->errcode = 0;
2601
+ req->env = env;
2602
+ req->stmt = stmt;
2603
+
2604
+ req->handle.data = (void *) req;
2605
+
2606
+ js_value_t *promise;
2607
+ err = js_create_promise(env, &req->deferred, &promise);
2608
+ assert(err == 0);
2609
+
2610
+ err = uv_queue_work(loop, &req->handle, paraql__on_before_run, paraql__on_after_run);
2611
+ assert(err == 0);
2612
+
2613
+ return promise;
2614
+ }
2615
+
2616
+ static js_value_t *
2617
+ paraql_exports(js_env_t *env, js_value_t *exports) {
2618
+ int err;
2619
+
2620
+ #define V(name, fn) \
2621
+ { \
2622
+ js_value_t *val; \
2623
+ err = js_create_function(env, name, -1, fn, NULL, &val); \
2624
+ assert(err == 0); \
2625
+ err = js_set_named_property(env, exports, name, val); \
2626
+ assert(err == 0); \
2627
+ }
2628
+
2629
+ V("vfsInit", paravfs_init)
2630
+ V("vfsDestroy", paravfs_destroy)
2631
+
2632
+ V("open", paraql_open)
2633
+ V("close", paraql_close)
2634
+ V("exec", paraql_exec)
2635
+ V("prepare", paraql_prepare)
2636
+ V("finalize", paraql_finalize)
2637
+ V("reset", paraql_reset)
2638
+ V("bind", paraql_bind)
2639
+ V("step", paraql_step)
2640
+ V("run", paraql_run)
2641
+ #undef V
2642
+
2643
+ return exports;
2644
+ }
2645
+
2646
+ BARE_MODULE(paraql, paraql_exports)