sqlmath 0.0.4 → 0.0.5

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/sqlmath_base.c DELETED
@@ -1,1832 +0,0 @@
1
- // copyright nobody
2
- // LINT_C_FILE
3
-
4
-
5
- /*
6
- file sqlmath_h - start
7
- */
8
- #ifndef SQLMATH_H
9
- #define SQLMATH_H
10
- // header
11
- #include <assert.h>
12
- #include <ctype.h>
13
- #include <errno.h>
14
- #include <math.h>
15
- #include <stdint.h>
16
- #include <stdio.h>
17
- #include <stdlib.h>
18
- #include <string.h>
19
- // header2
20
- #ifdef WIN32
21
- #include <windows.h>
22
- #endif
23
- #include <sqlite3.h>
24
- // define
25
- #define ALLOCC calloc
26
- #define ALLOCF free
27
- #define ALLOCM malloc
28
- inline void *ALLOCR(
29
- void *ptr,
30
- size_t size
31
- ) {
32
- // handle null-case
33
- if (ptr == NULL) {
34
- return NULL;
35
- }
36
- void *ptr2 = realloc(ptr, size);
37
- // if nomem, cleanup old ptr
38
- if (ptr2 == NULL) {
39
- free(ptr);
40
- }
41
- return ptr2;
42
- }
43
-
44
- #define JS_MAX_SAFE_INTEGER 0x1fffffffffffff
45
- #define JS_MIN_SAFE_INTEGER -0x1fffffffffffff
46
- #define MAX(aa, bb) (((aa) < (bb)) ? (bb) : (aa))
47
- #define MIN(aa, bb) (((aa) > (bb)) ? (bb) : (aa))
48
- #define SIZEOF_MESSAGE_DEFAULT 1024
49
- #define SQLITE_DATATYPE_BLOB 0x04
50
- #define SQLITE_DATATYPE_BLOB_0 0x14
51
- #define SQLITE_DATATYPE_FLOAT 0x02
52
- #define SQLITE_DATATYPE_FLOAT_0 0x12
53
- #define SQLITE_DATATYPE_INTEGER 0x01
54
- #define SQLITE_DATATYPE_INTEGER_0 0x11
55
- #define SQLITE_DATATYPE_INTEGER_1 0x21
56
- #define SQLITE_DATATYPE_NULL 0x05
57
- #define SQLITE_DATATYPE_SHAREDARRAYBUFFER -0x01
58
- #define SQLITE_DATATYPE_TEXT 0x03
59
- #define SQLITE_DATATYPE_TEXT_0 0x13
60
- #define SQLITE_ERROR_DATATYPE_INVALID 0x10003
61
- #define SQLITE_ERROR_NOMEM2 0x10001
62
- #define SQLITE_ERROR_TOOBIG2 0x10002
63
- #define SQLITE_MAX_LENGTH2 1000000000
64
- #define SQLITE_RESPONSETYPE_LAST_MATRIX_DOUBLE 2
65
- #define SQLITE_RESPONSETYPE_LAST_VALUE 1
66
- #define SQLMATH_API
67
- #define SWAP(aa, bb) tmp = (aa); (aa)=(bb); (bb) = tmp
68
- #define UNUSED(x) (void)(x)
69
- // define2
70
- /*
71
- ** A macro to hint to the compiler that a function should not be
72
- ** inlined.
73
- */
74
- #if defined(__GNUC__)
75
- # define NOINLINE __attribute__((noinline))
76
- #elif defined(_MSC_VER) && _MSC_VER >= 1310
77
- # define NOINLINE __declspec(noinline)
78
- #else
79
- # define NOINLINE
80
- #endif
81
-
82
-
83
- /*
84
- file sqlmath_h_struct
85
- */
86
- #define JSBATON_ARGC 16
87
- typedef struct napi_async_work__ *napi_async_work;
88
- typedef struct napi_deferred__ *napi_deferred;
89
- typedef struct napi_value__ *napi_value;
90
- typedef struct BindElem {
91
- const char *buf;
92
- char *key;
93
- int buflen;
94
- char datatype;
95
- } BindElem;
96
- typedef struct Jsbaton {
97
- // data
98
- int64_t argint64[JSBATON_ARGC];
99
- const char *bufin[JSBATON_ARGC];
100
- char *bufout[JSBATON_ARGC];
101
- char errmsg[SIZEOF_MESSAGE_DEFAULT];
102
- napi_value result;
103
- // async
104
- napi_async_work work;
105
- napi_deferred deferred;
106
- } Jsbaton;
107
-
108
-
109
- /*
110
- file sqlmath_h_assert
111
- */
112
- #define ASSERT_SQLITE_CONTEXT_OK(context, errcode) \
113
- if (!IS_SQLITE_OK(errcode)) { \
114
- sqlite3_result_error_code(context, errcode); \
115
- return; \
116
- }
117
-
118
- // this function will exec <sql> and if <errcode> is not ok,
119
- // throw <baton->errmsg>
120
- #define ASSERT_SQLITE_EXEC(baton, db, sql, errcode) \
121
- errcode = sqlite3_exec(db, sql, NULL, NULL, NULL); \
122
- ASSERT_SQLITE_OK(baton, db, errcode);
123
-
124
- // this function will if <errcode> is not ok, throw <baton->errmsg>
125
- #define ASSERT_SQLITE_OK(baton, db, errcode) \
126
- if (!IS_SQLITE_OK(errcode)) { \
127
- assertSqliteOk(baton, db, errcode, __func__, __FILE__, __LINE__); \
128
- goto catch_error; \
129
- }
130
-
131
- // this function will return if <errcode> is ok or not
132
- #define IS_SQLITE_OK(errcode) \
133
- (errcode == 0 || errcode == SQLITE_ROW || errcode == SQLITE_DONE)
134
-
135
- static const char *__snprintfTrace(
136
- char *buf,
137
- const char *prefix,
138
- const char *errmsg,
139
- const char *func,
140
- const char *file,
141
- int line
142
- ) {
143
- // this function will write <errmsg> to <buf> with additional trace-info
144
- if (snprintf(buf, // NO_LINT
145
- SIZEOF_MESSAGE_DEFAULT, "%s%s\n at %s (%s:%d)", prefix, errmsg,
146
- func, file, line) < 0) {
147
- abort();
148
- }
149
- return (const char *) buf;
150
- }
151
-
152
- static NOINLINE int assertSqliteOk(
153
- Jsbaton * baton,
154
- sqlite3 * db,
155
- int errcode,
156
- const char *func,
157
- const char *file,
158
- int line
159
- ) {
160
- // this function will if errcode != 0, set baton->errmsg
161
- switch (errcode) {
162
- case SQLITE_DONE:
163
- case SQLITE_OK:
164
- case SQLITE_ROW:
165
- return errcode;
166
- }
167
- if (baton == NULL || baton->errmsg[0] != '\x00') {
168
- return errcode;
169
- }
170
- switch (errcode) {
171
- case SQLITE_ERROR_DATATYPE_INVALID:
172
- __snprintfTrace(baton->errmsg, "sqlite - ", "invalid datatype", func,
173
- file, line);
174
- return errcode;
175
- case SQLITE_ERROR_NOMEM2:
176
- __snprintfTrace(baton->errmsg, "sqlite - ", "out of memory", func,
177
- file, line);
178
- return errcode;
179
- case SQLITE_ERROR_TOOBIG2:
180
- __snprintfTrace(baton->errmsg, "sqlite - ", "string or blob too big",
181
- func, file, line);
182
- return errcode;
183
- default:
184
- __snprintfTrace(baton->errmsg, "sqlite - ",
185
- db == NULL ? sqlite3_errstr(errcode) : sqlite3_errmsg(db), func,
186
- file, line);
187
- return errcode;
188
- }
189
- }
190
-
191
- inline static int doubleCompare(
192
- const void *aa,
193
- const void *bb
194
- ) {
195
- // this function will compare aa with bb
196
- const double cc = *(double *) aa - *(double *) bb;
197
- return cc == 0 ? 0 : cc > 0 ? 1 : -1;
198
- }
199
-
200
- inline static double doubleMax(
201
- double aa,
202
- double bb
203
- ) {
204
- // this function will return max of aa, bb
205
- return aa < bb ? bb : aa;
206
- }
207
-
208
- inline static double doubleMin(
209
- double aa,
210
- double bb
211
- ) {
212
- // this function will return min of aa, bb
213
- return aa > bb ? bb : aa;
214
- }
215
-
216
- inline static int noop(
217
- ) {
218
- // this function will do nothing except return 0
219
- return 0;
220
- }
221
- #endif // SQLMATH_H
222
- /*
223
- file sqlmath_h - end
224
- */
225
-
226
-
227
- /*
228
- file sqlmath_c - start
229
- */
230
- #ifdef SQLMATH_C
231
- // header
232
- #include <sqlite3ext.h>
233
- static const sqlite3_api_routines *sqlite3_api;
234
-
235
-
236
- /*
237
- file sqlmath_c_base
238
- */
239
- static char *base64Encode(
240
- const unsigned char *blob,
241
- int *nn
242
- ) {
243
- // this function will base64-encode <blob> to <text>
244
- #define base64EncodeCleanup ALLOCF
245
- if (blob == NULL || *nn < 0) {
246
- *nn = 0;
247
- }
248
- // declare var
249
- char *text = NULL;
250
- int aa = *nn - 3;
251
- int bb = 0;
252
- int ii = 0;
253
- int triplet = 0;
254
- static const char BASE64_ENCODE_TABLE[] =
255
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
256
- // init bb
257
- bb = 4 * ceil((double) *nn / 3);
258
- // init text
259
- text = ALLOCM(MAX(bb, 4));
260
- // handle nomem
261
- if (text == NULL) {
262
- return NULL;
263
- }
264
- // handle null-case
265
- if (bb < 4) {
266
- text[0] = '\x00';
267
- }
268
- // base64-encode loop
269
- while (ii < aa) {
270
- triplet = blob[0];
271
- triplet = triplet << 8 | blob[1];
272
- triplet = triplet << 8 | blob[2];
273
- blob += 3;
274
- text[0] = BASE64_ENCODE_TABLE[(triplet >> 18) & 0x3f];
275
- text[1] = BASE64_ENCODE_TABLE[(triplet >> 12) & 0x3f];
276
- text[2] = BASE64_ENCODE_TABLE[(triplet >> 6) & 0x3f];
277
- text[3] = BASE64_ENCODE_TABLE[triplet & 0x3f];
278
- text += 4;
279
- ii += 3;
280
- }
281
- // base64-encode '='
282
- if (bb >= 4 && blob != NULL) {
283
- aa += 3;
284
- triplet = blob[0];
285
- triplet = ii + 1 < aa ? triplet << 8 | blob[1] : triplet << 8;
286
- triplet = ii + 2 < aa ? triplet << 8 | blob[2] : triplet << 8;
287
- blob += 3;
288
- text[0] = BASE64_ENCODE_TABLE[(triplet >> 18) & 0x3f];
289
- text[1] = BASE64_ENCODE_TABLE[(triplet >> 12) & 0x3f];
290
- text[2] =
291
- (ii + 1 < aa) ? BASE64_ENCODE_TABLE[(triplet >> 6) & 0x3f] : '=';
292
- text[3] = (ii + 2 < aa) ? BASE64_ENCODE_TABLE[triplet & 0x3f] : '=';
293
- text += 4;
294
- ii += 3;
295
- }
296
- // save bb
297
- *nn = bb;
298
- // return text
299
- return text - bb;
300
- }
301
-
302
-
303
- /*
304
- file sqlmath_c_str99
305
- */
306
- // dynamically growable string
307
- #define STR99_APPEND_CHAR(cc) \
308
- errcode = str99AppendChar(str99, cc, errcode); \
309
- if (!IS_SQLITE_OK(errcode)) { goto catch_error; }
310
-
311
- #define STR99_APPEND_DOUBLE(ff) \
312
- errcode = str99AppendDouble(str99, ff, errcode); \
313
- if (!IS_SQLITE_OK(errcode)) { goto catch_error; }
314
-
315
- #define STR99_APPEND_JSON(zz, nn) \
316
- errcode = str99AppendJson(str99, zz, nn, errcode); \
317
- if (!IS_SQLITE_OK(errcode)) { goto catch_error; }
318
-
319
- #define STR99_APPEND_RAW(zz, nn) \
320
- errcode = str99AppendRaw(str99, zz, nn, errcode); \
321
- if (!IS_SQLITE_OK(errcode)) { goto catch_error; }
322
-
323
- typedef struct Str99 {
324
- char *zBuf; /* Accumulated string */
325
- int nAlloced; /* Space allocated for zBuf[] */
326
- int nUsed; /* Number of used-bytes in zBuf[] */
327
- } Str99;
328
-
329
- static NOINLINE int str99AppendRawAfterGrow(
330
- Str99 * str99,
331
- const char *zz,
332
- int nn,
333
- int errcode
334
- );
335
-
336
- static int str99AppendChar(
337
- Str99 * str99,
338
- const char cc,
339
- int errcode
340
- ) {
341
- /*
342
- ** Append <cc> to <str99->zBuf>.
343
- ** Increase the size of the memory allocation for <str99->zBuf> if necessary.
344
- */
345
- // write <cc> to <str99->zBuf> if space available
346
- if (str99->nUsed < str99->nAlloced) {
347
- str99->zBuf[str99->nUsed] = cc;
348
- str99->nUsed += 1;
349
- return errcode;
350
- }
351
- // else resize and retry
352
- return str99AppendRawAfterGrow(str99, &cc, 1, errcode);
353
- }
354
-
355
- static int str99AppendDouble(
356
- Str99 * str99,
357
- double ff,
358
- int errcode
359
- ) {
360
- /*
361
- ** Append <ff> to <str99->zBuf>.
362
- ** Increase the size of the memory allocation for <str99->zBuf> if necessary.
363
- */
364
- // write <ff> to <str99->zBuf> if space available
365
- if (str99->nUsed < str99->nAlloced) {
366
- ((double *) (str99->zBuf + str99->nUsed))[0] = ff;
367
- str99->nUsed += 8;
368
- return errcode;
369
- }
370
- // else resize and retry
371
- return str99AppendRawAfterGrow(str99, (char *) (&ff), 8, errcode);
372
- }
373
-
374
- static int str99AppendRaw(
375
- Str99 * str99,
376
- const char *zz,
377
- int nn,
378
- int errcode
379
- ) {
380
- /*
381
- ** Append <nn> bytes of text from <zz> to <str99->zBuf>.
382
- ** Increase the size of the memory allocation for <str99->zBuf> if necessary.
383
- */
384
- if (nn == 0) {
385
- return errcode;
386
- }
387
- // write <zz> to <str99->zBuf> if space available
388
- if (0 < nn && str99->nUsed + nn <= str99->nAlloced) {
389
- memcpy(str99->zBuf + str99->nUsed, zz, nn);
390
- str99->nUsed += nn;
391
- return errcode;
392
- }
393
- // else resize and retry
394
- return str99AppendRawAfterGrow(str99, zz, nn, errcode);
395
- }
396
-
397
- static NOINLINE int str99AppendRawAfterGrow(
398
- Str99 * str99,
399
- const char *zz,
400
- int nn,
401
- int errcode
402
- ) {
403
- /*
404
- ** Increase the size of the memory allocation for <str99->zBuf>.
405
- */
406
- // declare var
407
- int nAlloc;
408
- // sanity check
409
- if (!IS_SQLITE_OK(errcode)) {
410
- return errcode;
411
- }
412
- // check SQLITE_MAX_LENGTH2
413
- if (nn < 0 || str99->nUsed + nn > SQLITE_MAX_LENGTH2) {
414
- return SQLITE_ERROR_TOOBIG2;
415
- }
416
- // grow str99 exponentially
417
- nAlloc = str99->nAlloced;
418
- while (nAlloc < str99->nUsed + nn) {
419
- nAlloc *= 2;
420
- }
421
- if (nAlloc > str99->nAlloced) {
422
- str99->zBuf = ALLOCR(str99->zBuf, nAlloc);
423
- if (str99->zBuf == NULL) {
424
- return SQLITE_ERROR_NOMEM2;
425
- }
426
- str99->nAlloced = nAlloc;
427
- }
428
- if (zz == NULL) {
429
- return errcode;
430
- }
431
- // recurse
432
- return str99AppendRaw(str99, zz, nn, errcode);
433
- }
434
-
435
- static int str99AppendJson(
436
- Str99 * str99,
437
- const char *zz,
438
- int nn,
439
- int errcode
440
- ) {
441
- /*
442
- ** Append <nn> bytes of text from <zz> to <str99->zBuf> with json-encoding.
443
- ** Increase the size of the memory allocation for <str99->zBuf> if necessary.
444
- */
445
- // declare var
446
- const char *zz2 = zz + nn;
447
- // double-quote open
448
- STR99_APPEND_RAW("\"", 1);
449
- while (zz < zz2) {
450
- switch (*zz) {
451
- case '\x00':
452
- STR99_APPEND_RAW("\\u0000", 6);
453
- break;
454
- case '\x01':
455
- STR99_APPEND_RAW("\\u0001", 6);
456
- break;
457
- case '\x02':
458
- STR99_APPEND_RAW("\\u0002", 6);
459
- break;
460
- case '\x03':
461
- STR99_APPEND_RAW("\\u0003", 6);
462
- break;
463
- case '\x04':
464
- STR99_APPEND_RAW("\\u0004", 6);
465
- break;
466
- case '\x05':
467
- STR99_APPEND_RAW("\\u0005", 6);
468
- break;
469
- case '\x06':
470
- STR99_APPEND_RAW("\\u0006", 6);
471
- break;
472
- case '\x07':
473
- STR99_APPEND_RAW("\\u0007", 6);
474
- break;
475
- case '\x08':
476
- STR99_APPEND_CHAR('\\');
477
- STR99_APPEND_CHAR('b');
478
- break;
479
- case '\x09':
480
- STR99_APPEND_CHAR('\\');
481
- STR99_APPEND_CHAR('t');
482
- break;
483
- case '\x0a':
484
- STR99_APPEND_CHAR('\\');
485
- STR99_APPEND_CHAR('n');
486
- break;
487
- case '\x0b':
488
- STR99_APPEND_RAW("\\u000b", 6);
489
- break;
490
- case '\x0c':
491
- STR99_APPEND_CHAR('\\');
492
- STR99_APPEND_CHAR('f');
493
- break;
494
- case '\x0d':
495
- STR99_APPEND_CHAR('\\');
496
- STR99_APPEND_CHAR('r');
497
- break;
498
- case '\x0e':
499
- STR99_APPEND_RAW("\\u000e", 6);
500
- break;
501
- case '\x0f':
502
- STR99_APPEND_RAW("\\u000f", 6);
503
- break;
504
- case '\x10':
505
- STR99_APPEND_RAW("\\u0010", 6);
506
- break;
507
- case '\x11':
508
- STR99_APPEND_RAW("\\u0011", 6);
509
- break;
510
- case '\x12':
511
- STR99_APPEND_RAW("\\u0012", 6);
512
- break;
513
- case '\x13':
514
- STR99_APPEND_RAW("\\u0013", 6);
515
- break;
516
- case '\x14':
517
- STR99_APPEND_RAW("\\u0014", 6);
518
- break;
519
- case '\x15':
520
- STR99_APPEND_RAW("\\u0015", 6);
521
- break;
522
- case '\x16':
523
- STR99_APPEND_RAW("\\u0016", 6);
524
- break;
525
- case '\x17':
526
- STR99_APPEND_RAW("\\u0017", 6);
527
- break;
528
- case '\x18':
529
- STR99_APPEND_RAW("\\u0018", 6);
530
- break;
531
- case '\x19':
532
- STR99_APPEND_RAW("\\u0019", 6);
533
- break;
534
- case '\x1a':
535
- STR99_APPEND_RAW("\\u001a", 6);
536
- break;
537
- case '\x1b':
538
- STR99_APPEND_RAW("\\u001b", 6);
539
- break;
540
- case '\x1c':
541
- STR99_APPEND_RAW("\\u001c", 6);
542
- break;
543
- case '\x1d':
544
- STR99_APPEND_RAW("\\u001d", 6);
545
- break;
546
- case '\x22':
547
- STR99_APPEND_CHAR('\\');
548
- STR99_APPEND_CHAR('\"');
549
- break;
550
- case '\x5c':
551
- STR99_APPEND_CHAR('\\');
552
- STR99_APPEND_CHAR('\\');
553
- break;
554
- default:
555
- STR99_APPEND_CHAR(*zz);
556
- }
557
- zz += 1;
558
- }
559
- // double-quote close
560
- STR99_APPEND_RAW("\"", 1);
561
- catch_error:
562
- return errcode;
563
- }
564
-
565
-
566
- /*
567
- file sqlmath_c_dbXxx
568
- */
569
- SQLMATH_API int dbExec(
570
- sqlite3 * db, /* The database on which the SQL executes */
571
- Jsbaton * baton
572
- ) {
573
- // This function will run <zSql> in <db> and save any result (list of tables
574
- // containing rows from SELECT/pragma/etc) as serialized json-string in <str99>.
575
- #define STR99_APPEND_CHAR2(cc) \
576
- if (!responseType) { \
577
- errcode = str99AppendChar(str99, cc, errcode); \
578
- if (!IS_SQLITE_OK(errcode)) { goto catch_error; } \
579
- }
580
- // declare var
581
- BindElem *bindElem;
582
- BindElem *bindList = NULL;
583
- Str99 *str99 = NULL;
584
- Str99 str0 = { 0 };
585
- const char **pzShared = baton->bufin + 6;
586
- const char *zBind = baton->bufin[3];
587
- const char *zSql = baton->bufin[1];
588
- const char *zTmp = NULL;
589
- double rTmp = 0;
590
- int bindByKey = (int) baton->argint64[4];
591
- int bindIdx = 0;
592
- int bindListLength = (int) baton->argint64[2];
593
- int errcode = 0;
594
- int ii = 0;
595
- int jj = 0;
596
- int nCol = 0;
597
- int nRow = 0;
598
- int responseType = (int) baton->argint64[5];
599
- int64_t *pnShared = baton->argint64 + 6;
600
- int64_t iTmp = 0;
601
- sqlite3_stmt *pStmt = NULL; /* The current SQL statement */
602
- static const char bindPrefix[] = "$:@";
603
- // printf("\n[errcode=%d, sql=%s]\n", errcode, zSql);
604
- // mutext enter
605
- sqlite3_mutex_enter(sqlite3_db_mutex(db));
606
- // init bindList
607
- bindList = ALLOCC(bindListLength, sizeof(BindElem));
608
- if (bindListLength > 0 && bindList == NULL) {
609
- errcode = SQLITE_ERROR_NOMEM2;
610
- ASSERT_SQLITE_OK(baton, db, errcode);
611
- }
612
- bindElem = bindList;
613
- ii = 1;
614
- while (ii <= bindListLength) {
615
- // init key and
616
- if (bindByKey) {
617
- zBind += 1;
618
- bindElem->key = (char *) zBind + 8;
619
- zBind += 8 + *(int *) zBind;
620
- }
621
- // init datatype
622
- bindElem->datatype = zBind[0];
623
- zBind += 1;
624
- switch (bindElem->datatype) {
625
- case SQLITE_DATATYPE_BLOB:
626
- case SQLITE_DATATYPE_TEXT:
627
- bindElem->buflen = *(int *) zBind;
628
- bindElem->buf = zBind + 8;
629
- zBind += 8 + bindElem->buflen;
630
- break;
631
- case SQLITE_DATATYPE_FLOAT:
632
- case SQLITE_DATATYPE_INTEGER:
633
- bindElem->buf = zBind;
634
- zBind += 8;
635
- break;
636
- case SQLITE_DATATYPE_INTEGER_0:
637
- case SQLITE_DATATYPE_INTEGER_1:
638
- case SQLITE_DATATYPE_NULL:
639
- case SQLITE_DATATYPE_TEXT_0:
640
- break;
641
- case SQLITE_DATATYPE_SHAREDARRAYBUFFER:
642
- bindElem->buflen = *(int *) pnShared;
643
- bindElem->buf = *pzShared;
644
- pnShared += 1;
645
- pzShared += 1;
646
- break;
647
- default:
648
- printf("\n[ii=%d, datatype=%d, len=%d]\n", ii, bindElem->datatype,
649
- bindElem->buflen);
650
- errcode = SQLITE_ERROR_DATATYPE_INVALID;
651
- ASSERT_SQLITE_OK(baton, db, errcode);
652
- }
653
- bindElem += 1;
654
- ii += 1;
655
- }
656
- // init str99
657
- str99 = &str0;
658
- // will be cleaned up by jsbatonBufferFinalize()
659
- str99->zBuf = ALLOCM(SIZEOF_MESSAGE_DEFAULT);
660
- if (str99->zBuf == NULL) {
661
- errcode = SQLITE_ERROR_NOMEM2;
662
- ASSERT_SQLITE_OK(baton, db, errcode);
663
- }
664
- str99->nAlloced = SIZEOF_MESSAGE_DEFAULT;
665
- // bracket database [
666
- STR99_APPEND_CHAR2('[');
667
- // loop over each table
668
- while (1) {
669
- // ignore whitespace
670
- while (*zSql == ' ' || *zSql == '\t' || *zSql == '\n'
671
- || *zSql == '\r') {
672
- zSql += 1;
673
- }
674
- // printf("\n[prepare=%s]\n", zSql);
675
- errcode = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zTmp);
676
- if (errcode != 0 || *zSql == '\x00') {
677
- break;
678
- }
679
- zSql = zTmp;
680
- // bind bindList to pStmt
681
- bindElem = bindList;
682
- ii = 1;
683
- while (ii <= bindListLength) {
684
- bindIdx = ii;
685
- jj = 0;
686
- while (jj < 3) {
687
- // if bindByKey, then get idx for given key
688
- if (bindByKey) {
689
- bindElem->key[0] = bindPrefix[jj];
690
- bindIdx =
691
- sqlite3_bind_parameter_index(pStmt, bindElem->key);
692
- }
693
- // printf("\n[errcode=%d, ii=%d, idx=%d, key=%s, datatype=%d,"
694
- // " len=%d]\n", errcode, ii, bindIdx, bindElem->key,
695
- // bindElem->datatype, bindElem->buflen);
696
- if (bindIdx > 0) {
697
- switch (bindElem->datatype) {
698
- case SQLITE_DATATYPE_BLOB:
699
- errcode =
700
- sqlite3_bind_blob(pStmt, bindIdx, bindElem->buf,
701
- bindElem->buflen, SQLITE_TRANSIENT);
702
- break;
703
- case SQLITE_DATATYPE_FLOAT:
704
- errcode =
705
- sqlite3_bind_double(pStmt, bindIdx,
706
- *(double *) bindElem->buf);
707
- break;
708
- case SQLITE_DATATYPE_INTEGER:
709
- errcode =
710
- sqlite3_bind_int64(pStmt, bindIdx,
711
- *(int64_t *) bindElem->buf);
712
- break;
713
- case SQLITE_DATATYPE_INTEGER_0:
714
- errcode = sqlite3_bind_int(pStmt, bindIdx, 0);
715
- break;
716
- case SQLITE_DATATYPE_INTEGER_1:
717
- errcode = sqlite3_bind_int(pStmt, bindIdx, 1);
718
- break;
719
- case SQLITE_DATATYPE_NULL:
720
- errcode = sqlite3_bind_null(pStmt, bindIdx);
721
- break;
722
- case SQLITE_DATATYPE_SHAREDARRAYBUFFER:
723
- errcode =
724
- sqlite3_bind_blob(pStmt, bindIdx, bindElem->buf,
725
- bindElem->buflen, SQLITE_STATIC);
726
- break;
727
- case SQLITE_DATATYPE_TEXT_0:
728
- errcode =
729
- sqlite3_bind_text(pStmt, bindIdx, "", 0,
730
- SQLITE_STATIC);
731
- break;
732
- case SQLITE_DATATYPE_TEXT:
733
- errcode =
734
- sqlite3_bind_text(pStmt, bindIdx, bindElem->buf,
735
- bindElem->buflen, SQLITE_TRANSIENT);
736
- break;
737
- default:
738
- printf("\n[ii=%d, datatype=%d, len=%d]\n", ii,
739
- bindElem->datatype, bindElem->buflen);
740
- errcode = SQLITE_ERROR_DATATYPE_INVALID;
741
- }
742
- // ignore bind-range-error
743
- if (errcode != SQLITE_RANGE) {
744
- ASSERT_SQLITE_OK(baton, db, errcode);
745
- }
746
- }
747
- if (!bindByKey) {
748
- break;
749
- }
750
- jj += 1;
751
- }
752
- bindElem += 1;
753
- ii += 1;
754
- }
755
- nCol = -1;
756
- // loop over each row
757
- while (1) {
758
- errcode = sqlite3_step(pStmt);
759
- if (errcode != SQLITE_ROW) {
760
- sqlite3_finalize(pStmt);
761
- pStmt = NULL;
762
- if (errcode == SQLITE_DONE || errcode == SQLITE_OK) {
763
- break;
764
- }
765
- // printf("\n[errcode=%d, line=%d]\n", errcode, __LINE__);
766
- goto catch_error;
767
- }
768
- // insert row of column-names
769
- if (nCol == -1) {
770
- nRow = 0;
771
- if (str99->nUsed > 1) {
772
- STR99_APPEND_CHAR2(',');
773
- STR99_APPEND_CHAR2('\n');
774
- STR99_APPEND_CHAR2('\n');
775
- }
776
- // bracket table [
777
- STR99_APPEND_CHAR2('[');
778
- // bracket column [
779
- STR99_APPEND_CHAR2('[');
780
- // loop over each column-name
781
- nCol = sqlite3_column_count(pStmt);
782
- // SQLITE_RESPONSETYPE_LAST_MATRIX_DOUBLE - save nCol
783
- if (responseType == SQLITE_RESPONSETYPE_LAST_MATRIX_DOUBLE) {
784
- str99->nUsed = 8;
785
- STR99_APPEND_DOUBLE((double) nCol);
786
- } else {
787
- ii = 0;
788
- while (ii < nCol) {
789
- if (ii > 0) {
790
- STR99_APPEND_CHAR2(',');
791
- }
792
- zTmp = sqlite3_column_name(pStmt, ii);
793
- STR99_APPEND_JSON(zTmp, strlen(zTmp));
794
- ii += 1;
795
- }
796
- // bracket column ]
797
- STR99_APPEND_CHAR2(']');
798
- }
799
- }
800
- // bracket row [
801
- STR99_APPEND_CHAR2(',');
802
- STR99_APPEND_CHAR2('\n');
803
- STR99_APPEND_CHAR2('[');
804
- ii = 0;
805
- nRow += 1;
806
- // loop over each column-value
807
- while (ii < nCol) {
808
- switch (responseType) {
809
- case SQLITE_RESPONSETYPE_LAST_VALUE:
810
- // export last-value as blob
811
- str99->nUsed = 0;
812
- errcode =
813
- str99AppendRaw(str99, sqlite3_column_blob(pStmt, ii),
814
- sqlite3_column_bytes(pStmt, ii), errcode);
815
- if (!IS_SQLITE_OK(errcode)) {
816
- // printf("\n[errcode=%d, line=%d]\n", errcode,
817
- // __LINE__);
818
- goto catch_error;
819
- }
820
- ii += 1;
821
- continue;
822
- case SQLITE_RESPONSETYPE_LAST_MATRIX_DOUBLE:
823
- // export last-table as matrix of doubles
824
- STR99_APPEND_DOUBLE(sqlite3_column_double(pStmt, ii));
825
- ii += 1;
826
- continue;
827
- }
828
- if (ii > 0) {
829
- STR99_APPEND_CHAR2(',');
830
- }
831
- switch (sqlite3_column_type(pStmt, ii)) {
832
- case SQLITE_INTEGER:
833
- iTmp = sqlite3_column_int64(pStmt, ii);
834
- if (JS_MIN_SAFE_INTEGER <= iTmp
835
- // convert integer to double
836
- && iTmp <= JS_MAX_SAFE_INTEGER) {
837
- STR99_APPEND_RAW((const char *)
838
- sqlite3_column_text(pStmt, ii),
839
- sqlite3_column_bytes(pStmt, ii));
840
- } else {
841
- // convert integer to string
842
- STR99_APPEND_JSON((const char *)
843
- sqlite3_column_text(pStmt, ii),
844
- sqlite3_column_bytes(pStmt, ii));
845
- }
846
- break;
847
- case SQLITE_FLOAT:
848
- rTmp = sqlite3_column_double(pStmt, ii);
849
- if (isnan(rTmp) || rTmp == -INFINITY || rTmp == INFINITY) {
850
- STR99_APPEND_RAW("null", 4);
851
- } else {
852
- STR99_APPEND_RAW((const char *)
853
- sqlite3_column_text(pStmt, ii),
854
- sqlite3_column_bytes(pStmt, ii));
855
- }
856
- break;
857
- case SQLITE_TEXT:
858
- // append text as json-escaped string
859
- STR99_APPEND_JSON((const char *)
860
- sqlite3_column_text(pStmt, ii),
861
- sqlite3_column_bytes(pStmt, ii));
862
- break;
863
- // case SQLITE_BLOB:
864
- default: /* case SQLITE_NULL: */
865
- STR99_APPEND_RAW("null", 4);
866
- break;
867
- }
868
- ii += 1;
869
- }
870
- // bracket row ]
871
- STR99_APPEND_CHAR2(']');
872
- if (errcode != SQLITE_ROW) {
873
- break;
874
- }
875
- }
876
- if (nCol != -1) {
877
- // bracket table ]
878
- STR99_APPEND_CHAR2(']');
879
- }
880
- }
881
- // bracket database ]
882
- STR99_APPEND_CHAR2(']');
883
- STR99_APPEND_CHAR2('\n');
884
- // SQLITE_RESPONSETYPE_LAST_MATRIX_DOUBLE - save nRow
885
- if (responseType == SQLITE_RESPONSETYPE_LAST_MATRIX_DOUBLE) {
886
- ((double *) str99->zBuf)[0] = nRow;
887
- }
888
- // shrink str99
889
- str99->nAlloced = str99->nUsed;
890
- str99->zBuf = (char *) ALLOCR(str99->zBuf, MAX(str99->nAlloced, 1));
891
- if (str99->zBuf == NULL) {
892
- errcode = SQLITE_ERROR_NOMEM2;
893
- ASSERT_SQLITE_OK(baton, db, errcode);
894
- }
895
- catch_error:
896
- // cleanup bindList
897
- ALLOCF(bindList);
898
- // cleanup pStmt
899
- sqlite3_finalize(pStmt);
900
- // handle errcode
901
- if (errcode != 0) {
902
- // cleanup str99
903
- ALLOCF(str99->zBuf);
904
- assertSqliteOk(baton, db, errcode, __func__, __FILE__, __LINE__);
905
- // printf("\n[errcode=%d, errmsg=%s]\n", errcode, baton->errmsg);
906
- // mutext leave
907
- sqlite3_mutex_leave(sqlite3_db_mutex(db));
908
- return errcode;
909
- }
910
- // save str99
911
- baton->argint64[0] = (int64_t) str99->nAlloced;
912
- baton->bufout[0] = str99->zBuf;
913
- // mutext leave
914
- sqlite3_mutex_leave(sqlite3_db_mutex(db));
915
- return 0;
916
- }
917
-
918
- SQLMATH_API int dbTableInsert(
919
- sqlite3 * db, /* The database on which the SQL executes */
920
- Jsbaton * baton
921
- ) {
922
- // This function will run <zSql> in <db> and save any result (list of tables
923
- // containing rows from SELECT/pragma/etc) as serialized json-string in <str99>.
924
- // declare var
925
- const char *pp = baton->bufin[3];
926
- const char *zTmp = NULL;
927
- char datatype = 0;
928
- int bTxn = 0;
929
- int errcode = 0;
930
- int ii = 0;
931
- int jj = 0;
932
- int nCol = (int) baton->argint64[4];
933
- int nLen = 0;
934
- int nRow = (int) baton->argint64[5];
935
- sqlite3_stmt *pStmt = NULL;
936
- // mutext enter
937
- sqlite3_mutex_enter(sqlite3_db_mutex(db));
938
- // create temp table
939
- ASSERT_SQLITE_EXEC(baton, db, baton->bufin[1], errcode);
940
- // begin transaction
941
- ASSERT_SQLITE_EXEC(baton, db, "BEGIN TRANSACTION;", errcode);
942
- bTxn = 1;
943
- // init pStmt
944
- errcode = sqlite3_prepare_v2(db, baton->bufin[2], -1, &pStmt, &zTmp);
945
- // printf("\n[errcode=%d, nCol=%d, nRow=%d]\n", errcode, nCol, nRow);
946
- while (ii < nRow) {
947
- jj = 1;
948
- // type - js
949
- // 1. bigint
950
- // 2. boolean
951
- // 3. null
952
- // 4. number
953
- // 5. object
954
- // 6. string
955
- // 7. symbol
956
- // 8. undefined
957
- while (jj <= nCol) {
958
- datatype = pp[0];
959
- pp += 1;
960
- switch (datatype) {
961
- case SQLITE_DATATYPE_BLOB:
962
- nLen = *(int *) pp;
963
- errcode = sqlite3_bind_blob(pStmt, jj, pp + 8, nLen,
964
- SQLITE_TRANSIENT);
965
- ASSERT_SQLITE_OK(baton, db, errcode);
966
- pp += 8 + nLen;
967
- break;
968
- case SQLITE_DATATYPE_FLOAT:
969
- errcode = sqlite3_bind_double(pStmt, jj, *(double *) pp);
970
- ASSERT_SQLITE_OK(baton, db, errcode);
971
- pp += 8;
972
- break;
973
- case SQLITE_DATATYPE_INTEGER:
974
- errcode = sqlite3_bind_int64(pStmt, jj, *(int64_t *) pp);
975
- ASSERT_SQLITE_OK(baton, db, errcode);
976
- pp += 8;
977
- break;
978
- case SQLITE_DATATYPE_INTEGER_0:
979
- errcode = sqlite3_bind_int(pStmt, jj, 0);
980
- ASSERT_SQLITE_OK(baton, db, errcode);
981
- break;
982
- case SQLITE_DATATYPE_INTEGER_1:
983
- errcode = sqlite3_bind_int(pStmt, jj, 1);
984
- ASSERT_SQLITE_OK(baton, db, errcode);
985
- break;
986
- case SQLITE_DATATYPE_NULL:
987
- errcode = sqlite3_bind_null(pStmt, jj);
988
- ASSERT_SQLITE_OK(baton, db, errcode);
989
- break;
990
- case SQLITE_DATATYPE_TEXT_0:
991
- errcode = sqlite3_bind_text(pStmt, jj, "", 0, SQLITE_STATIC);
992
- ASSERT_SQLITE_OK(baton, db, errcode);
993
- break;
994
- case SQLITE_DATATYPE_TEXT:
995
- nLen = *(int *) pp;
996
- errcode = sqlite3_bind_text(pStmt, jj, pp + 8, nLen,
997
- SQLITE_TRANSIENT);
998
- ASSERT_SQLITE_OK(baton, db, errcode);
999
- pp += 8 + nLen;
1000
- break;
1001
- default:
1002
- printf("\n[ii=%d, jj=%d, datatype=%d, len=%d]\n",
1003
- ii, jj, datatype, *(int *) pp);
1004
- errcode = SQLITE_ERROR_DATATYPE_INVALID;
1005
- ASSERT_SQLITE_OK(baton, db, errcode);
1006
- }
1007
- jj += 1;
1008
- }
1009
- errcode = sqlite3_step(pStmt);
1010
- ASSERT_SQLITE_OK(baton, db, errcode);
1011
- errcode = sqlite3_clear_bindings(pStmt);
1012
- ASSERT_SQLITE_OK(baton, db, errcode);
1013
- errcode = sqlite3_reset(pStmt);
1014
- ASSERT_SQLITE_OK(baton, db, errcode);
1015
- ii += 1;
1016
- }
1017
- catch_error:
1018
- // end transaction
1019
- if (bTxn) {
1020
- bTxn = 0;
1021
- ASSERT_SQLITE_EXEC(baton, db, "END TRANSACTION;", errcode);
1022
- }
1023
- // cleanup pStmt
1024
- sqlite3_finalize(pStmt);
1025
- // mutext leave
1026
- sqlite3_mutex_leave(sqlite3_db_mutex(db));
1027
- return errcode;
1028
- }
1029
-
1030
-
1031
- /*
1032
- file sqlmath_c_func
1033
- */
1034
- static void sql_cot_func(
1035
- sqlite3_context * context,
1036
- int argc,
1037
- sqlite3_value ** argv
1038
- ) {
1039
- // this function will return cot(argv[0])
1040
- UNUSED(argc);
1041
- assert(argc == 1);
1042
- switch (sqlite3_value_numeric_type(argv[0])) {
1043
- case SQLITE_INTEGER:
1044
- case SQLITE_FLOAT:
1045
- if (argv[0] == 0) {
1046
- sqlite3_result_double(context, INFINITY);
1047
- return;
1048
- }
1049
- sqlite3_result_double(context,
1050
- 1.0 / tan(sqlite3_value_double(argv[0])));
1051
- }
1052
- }
1053
-
1054
- static void sql_coth_func(
1055
- sqlite3_context * context,
1056
- int argc,
1057
- sqlite3_value ** argv
1058
- ) {
1059
- // this function will return coth(argv[0])
1060
- UNUSED(argc);
1061
- assert(argc == 1);
1062
- switch (sqlite3_value_numeric_type(argv[0])) {
1063
- case SQLITE_INTEGER:
1064
- case SQLITE_FLOAT:
1065
- if (argv[0] == 0) {
1066
- sqlite3_result_double(context, INFINITY);
1067
- return;
1068
- }
1069
- sqlite3_result_double(context,
1070
- 1.0 / tanh(sqlite3_value_double(argv[0])));
1071
- }
1072
- }
1073
-
1074
- static void sql_sign_func(
1075
- sqlite3_context * context,
1076
- int argc,
1077
- sqlite3_value ** argv
1078
- ) {
1079
- /*
1080
- ** Implementation of the sign() function
1081
- ** return one of 3 possibilities +1,0 or -1 when the argument is respectively
1082
- ** positive, 0 or negative.
1083
- ** When the argument is NULL the result is also NULL (completly conventional)
1084
- */
1085
- UNUSED(argc);
1086
- assert(argc == 1);
1087
- switch (sqlite3_value_numeric_type(argv[0])) {
1088
- case SQLITE_INTEGER:
1089
- case SQLITE_FLOAT:
1090
- {
1091
- double rVal = sqlite3_value_double(argv[0]);
1092
- sqlite3_result_double(context,
1093
- (rVal > 0) ? 1 : (rVal < 0) ? -1 : 0);
1094
- }
1095
- return;
1096
- }
1097
- }
1098
-
1099
- static void sql_throwerror_func(
1100
- sqlite3_context * context,
1101
- int argc,
1102
- sqlite3_value ** argv
1103
- ) {
1104
- // this function will return sqlite3_result_error_code(argv[0])
1105
- UNUSED(argc);
1106
- assert(argc == 1);
1107
- // declare var
1108
- int errcode = sqlite3_value_int(argv[0]);
1109
- switch (errcode) {
1110
- case SQLITE_DONE:
1111
- case SQLITE_ROW:
1112
- sqlite3_result_error_code(context, 2);
1113
- break;
1114
- case SQLITE_NOMEM:
1115
- sqlite3_result_error_nomem(context);
1116
- break;
1117
- case SQLITE_TOOBIG:
1118
- sqlite3_result_error_toobig(context);
1119
- break;
1120
- default:
1121
- sqlite3_result_error_code(context, errcode);
1122
- }
1123
- }
1124
-
1125
- static void sql_tobase64_func(
1126
- sqlite3_context * context,
1127
- int argc,
1128
- sqlite3_value ** argv
1129
- ) {
1130
- // this function will convert blob to base64-encoded-text
1131
- UNUSED(argc);
1132
- assert(argc == 1);
1133
- // declare var
1134
- char *text = NULL;
1135
- int nn = sqlite3_value_bytes(argv[0]);
1136
- // base64-encode blob to text
1137
- text =
1138
- base64Encode((const unsigned char *) sqlite3_value_blob(argv[0]),
1139
- &nn);
1140
- if (text == NULL) {
1141
- sqlite3_result_error_nomem(context);
1142
- return;
1143
- }
1144
- sqlite3_result_text(context, (const char *) text, nn,
1145
- base64EncodeCleanup);
1146
- }
1147
-
1148
- static void sql_tostring_func(
1149
- sqlite3_context * context,
1150
- int argc,
1151
- sqlite3_value ** argv
1152
- ) {
1153
- // this function will convert blob to text
1154
- UNUSED(argc);
1155
- assert(argc == 1);
1156
- sqlite3_result_text(context, (const char *) sqlite3_value_text(argv[0]),
1157
- -1, SQLITE_TRANSIENT);
1158
- }
1159
-
1160
-
1161
- /*
1162
- file sqlmath_c_init
1163
- */
1164
- static int sqlite3_sqlmath_init(
1165
- sqlite3 * db,
1166
- char **pzErrMsg,
1167
- const sqlite3_api_routines * pApi
1168
- ) {
1169
- #define SQLITE3_CREATE_FUNCTION1(func, argc) \
1170
- errcode = sqlite3_create_function(db, #func, argc, \
1171
- SQLITE_DETERMINISTIC | SQLITE_DIRECTONLY | SQLITE_UTF8, NULL, \
1172
- sql_##func##_func, NULL, NULL); \
1173
- ASSERT_SQLITE_OK(NULL, NULL, errcode)
1174
- #define SQLITE3_CREATE_FUNCTION2(func, argc) \
1175
- errcode = sqlite3_create_function(db, #func, argc, \
1176
- SQLITE_DETERMINISTIC | SQLITE_DIRECTONLY | SQLITE_UTF8, NULL, \
1177
- NULL, sql_##func##_step, sql_##func##_final); \
1178
- ASSERT_SQLITE_OK(NULL, NULL, errcode)
1179
- UNUSED(pzErrMsg);
1180
- // declare var
1181
- int errcode = 0;
1182
- // init sqlite3_api
1183
- sqlite3_api = pApi;
1184
- SQLITE3_CREATE_FUNCTION1(cot, 1);
1185
- SQLITE3_CREATE_FUNCTION1(coth, 1);
1186
- SQLITE3_CREATE_FUNCTION1(sign, 1);
1187
- SQLITE3_CREATE_FUNCTION1(throwerror, 1);
1188
- SQLITE3_CREATE_FUNCTION1(tobase64, 1);
1189
- SQLITE3_CREATE_FUNCTION1(tostring, 1);
1190
- catch_error:
1191
- return errcode;
1192
- }
1193
- #endif // SQLMATH_C
1194
- /*
1195
- file sqlmath_c - end
1196
- */
1197
-
1198
-
1199
- /*
1200
- file sqlmath_napi - start
1201
- */
1202
- #ifdef SQLMATH_NAPI
1203
- // header
1204
- #define NAPI_VERSION 8
1205
- #include <node_api.h>
1206
- static int dbCount = 0;
1207
-
1208
-
1209
- /*
1210
- file sqlmath_napi_assert
1211
- */
1212
- // printf("\n[napi errcode=%d]\n", errcode);
1213
-
1214
- // this function will if <cond> is falsy, throw <msg> in <env>
1215
- #define ASSERT_NAPI(env, cond, msg) \
1216
- if (!(cond)) { \
1217
- char buf[SIZEOF_MESSAGE_DEFAULT] = { 0 }; \
1218
- napi_throw_error(env, NULL, \
1219
- __snprintfTrace(buf, "", msg, __func__, __FILE__, __LINE__)); \
1220
- return 0; \
1221
- }
1222
-
1223
- // this function will if <cond> is falsy, terminate process with <msg>
1224
- #define ASSERT_NAPI_FATAL(cond, msg) \
1225
- if (!(cond)) { \
1226
- napi_fatal_error(__func__, NAPI_AUTO_LENGTH , msg, NAPI_AUTO_LENGTH); \
1227
- }
1228
-
1229
- // this function will assert <errcode> == napi_ok in <env>
1230
- #define ASSERT_NAPI_OK(env, errcode) \
1231
- if (0 != assertNapiOk(env, __func__, __FILE__, __LINE__, errcode)) { \
1232
- return 0; \
1233
- }
1234
-
1235
- static int assertNapiOk(
1236
- napi_env env,
1237
- const char *func,
1238
- const char *file,
1239
- int line,
1240
- int errcode
1241
- ) {
1242
- // this function will throw error if <errcode> != napi_ok
1243
- // derived from https://github.com/nodejs/node-addon-api/blob/3.2.1/napi-inl.h
1244
- // typedef struct {
1245
- // const char* error_message;
1246
- // void* engine_reserved;
1247
- // uint32_t engine_error_code;
1248
- // napi_status error_code;
1249
- // } napi_extended_error_info;
1250
- if (errcode == napi_ok) {
1251
- return errcode;
1252
- }
1253
- // declare var
1254
- char buf[SIZEOF_MESSAGE_DEFAULT] = { 0 };
1255
- bool is_exception_pending;
1256
- const napi_extended_error_info *info;
1257
- napi_value val = NULL;
1258
- // We must retrieve the last error info before doing anything else, because
1259
- // doing anything else will replace the last error info.
1260
- #ifdef _MSC_VER
1261
- #pragma warning(push)
1262
- #pragma warning(disable: 26812)
1263
- #endif
1264
- errcode = napi_get_last_error_info(env, &info);
1265
- #ifdef _MSC_VER
1266
- #pragma warning(pop)
1267
- #endif
1268
- ASSERT_NAPI_FATAL(errcode == 0, "napi_get_last_error_info");
1269
- errcode = napi_is_exception_pending(env, &is_exception_pending);
1270
- ASSERT_NAPI_FATAL(errcode == 0, "napi_is_exception_pending");
1271
- // A pending exception takes precedence over any internal error status.
1272
- if (is_exception_pending) {
1273
- errcode = napi_get_and_clear_last_exception(env, &val);
1274
- ASSERT_NAPI_FATAL(errcode == 0, "napi_get_and_clear_last_exception");
1275
- napi_throw(env, val);
1276
- return errcode;
1277
- }
1278
- errcode =
1279
- napi_throw_error(env, NULL, __snprintfTrace(buf, "",
1280
- (info->error_message !=
1281
- NULL ? info->error_message : "error in native code"), func,
1282
- file, line));
1283
- ASSERT_NAPI_FATAL(errcode == 0, "napi_throw_error");
1284
- return errcode;
1285
- }
1286
-
1287
-
1288
- /*
1289
- file sqlmath_napi_promise
1290
- */
1291
- #define JSBATON_CREATE(env, info) \
1292
- jsbatonCreate(env, info); if (baton == NULL) {return NULL;}
1293
-
1294
- #define JSPROMISE_CREATE(func, env, data) \
1295
- __##func(void *data); \
1296
- static void _##func(napi_env env, void *data) { \
1297
- UNUSED(env); \
1298
- __##func(data); \
1299
- } \
1300
- static napi_value func(napi_env env, napi_callback_info info) { \
1301
- return jspromiseCreate(env, info, _##func); \
1302
- } \
1303
- static int __##func(void *data)
1304
-
1305
- static void jsbatonBufferFinalize(
1306
- napi_env env,
1307
- void *finalize_data,
1308
- void *finalize_hint
1309
- ) {
1310
- // this function will finalize <finalize_data>
1311
- UNUSED(env);
1312
- UNUSED(finalize_hint);
1313
- // cleanup baton->bufout[ii]
1314
- ALLOCF(finalize_data);
1315
- }
1316
-
1317
- static Jsbaton *jsbatonCreate(
1318
- napi_env env,
1319
- napi_callback_info info
1320
- ) {
1321
- // this function will create a baton for passing data between nodejs <-> c
1322
- // declare var
1323
- Jsbaton *baton = NULL;
1324
- bool is_dataview;
1325
- int errcode = 0;
1326
- napi_value argv;
1327
- size_t ii = 1;
1328
- // init argv
1329
- errcode = napi_get_cb_info(env, info, &ii, &argv, NULL, NULL);
1330
- ASSERT_NAPI_OK(env, errcode);
1331
- // init baton
1332
- errcode = napi_get_element(env, argv, 0, (napi_value *) & baton);
1333
- ASSERT_NAPI_OK(env, errcode);
1334
- errcode =
1335
- napi_get_typedarray_info(env, (napi_value) baton, NULL, NULL,
1336
- (void **) &baton, NULL, NULL);
1337
- ASSERT_NAPI_OK(env, errcode);
1338
- // save argv
1339
- baton->result = argv;
1340
- // init bufin
1341
- ii = 0;
1342
- while (ii < JSBATON_ARGC) {
1343
- errcode = napi_get_element(env, baton->result, ii + 1, &argv);
1344
- ASSERT_NAPI_OK(env, errcode);
1345
- errcode = napi_is_dataview(env, argv, &is_dataview);
1346
- ASSERT_NAPI_OK(env, errcode);
1347
- if (is_dataview) {
1348
- errcode =
1349
- napi_get_dataview_info(env, argv, NULL,
1350
- (void **) &baton->bufin[ii], NULL, NULL);
1351
- ASSERT_NAPI_OK(env, errcode);
1352
- }
1353
- ii += 1;
1354
- }
1355
- return baton;
1356
- }
1357
-
1358
- static napi_value jsbatonExport(
1359
- napi_env env,
1360
- Jsbaton * baton
1361
- ) {
1362
- // this function will export c-data to js-data in <jsbaton>
1363
- // declare var
1364
- int errcode = 0;
1365
- napi_value val;
1366
- size_t ii = 0;
1367
- // export baton->argint64 and baton->bufout to baton->result
1368
- while (ii < JSBATON_ARGC) {
1369
- if (baton->bufout[ii] == NULL) {
1370
- errcode =
1371
- napi_create_double(env, (double) baton->argint64[ii], &val);
1372
- ASSERT_NAPI_OK(env, errcode);
1373
- } else {
1374
- // init baton->bufout[ii]
1375
- errcode = napi_create_external_arraybuffer(env, // napi_env env,
1376
- (void *) baton->bufout[ii], // void* external_data,
1377
- (size_t) baton->argint64[ii], // size_t byte_length,
1378
- jsbatonBufferFinalize, // napi_finalize finalize_cb,
1379
- NULL, // void* finalize_hint,
1380
- &val); // napi_value* result
1381
- ASSERT_NAPI_OK(env, errcode);
1382
- }
1383
- errcode = napi_set_element(env, baton->result, ii + 1, val);
1384
- ASSERT_NAPI_OK(env, errcode);
1385
- ii += 1;
1386
- }
1387
- return baton->result;
1388
- }
1389
-
1390
- static napi_value jsstringCreate(
1391
- napi_env env,
1392
- const char *ss
1393
- ) {
1394
- // This API creates a JavaScript string value from a UTF8-encoded C string.
1395
- // The native string is copied.
1396
- // declare var
1397
- int errcode = 0;
1398
- napi_value result = NULL;
1399
- // return result
1400
- errcode = napi_create_string_utf8(env, ss, NAPI_AUTO_LENGTH, &result);
1401
- ASSERT_NAPI_OK(env, errcode);
1402
- return result;
1403
- }
1404
-
1405
- static int __jspromiseResolve(
1406
- napi_env env,
1407
- napi_status errcode,
1408
- void *data
1409
- ) {
1410
- // This function runs on the main thread after `jspromiseExecute` exits.
1411
- ASSERT_NAPI_FATAL(errcode == 0, __func__);
1412
- // init baton
1413
- Jsbaton *baton = (Jsbaton *) data;
1414
- // declare var
1415
- napi_ref ref = (napi_ref) baton->result;
1416
- uint32_t refcount = 1;
1417
- // dereference result to allow gc
1418
- errcode = napi_reference_unref(env, ref, &refcount);
1419
- ASSERT_NAPI_FATAL(errcode == 0, "napi_reference_unref");
1420
- ASSERT_NAPI_FATAL(refcount == 0, "memory leak");
1421
- errcode = napi_get_reference_value(env, ref, &baton->result);
1422
- ASSERT_NAPI_FATAL(errcode == 0, "napi_get_reference_value");
1423
- errcode = napi_delete_reference(env, ref);
1424
- ASSERT_NAPI_FATAL(errcode == 0, "napi_delete_reference");
1425
- // Resolve or reject the promise associated with the deferred depending on
1426
- // whether the asynchronous action succeeded.
1427
- if (baton->errmsg[0] == 0) {
1428
- // resolve promise with result
1429
- if (jsbatonExport(env, baton) == NULL) {
1430
- return 0;
1431
- }
1432
- errcode = napi_resolve_deferred(env, baton->deferred, baton->result);
1433
- ASSERT_NAPI_FATAL(errcode == 0, "napi_resolve_deferred");
1434
- } else {
1435
- // declare var
1436
- napi_value err;
1437
- // create error
1438
- errcode =
1439
- napi_create_error(env, NULL, jsstringCreate(env, baton->errmsg),
1440
- &err);
1441
- ASSERT_NAPI_FATAL(errcode == 0, "napi_create_error");
1442
- // reject promise with error
1443
- errcode = napi_reject_deferred(env, baton->deferred, err);
1444
- ASSERT_NAPI_FATAL(errcode == 0, "napi_reject_deferred");
1445
- }
1446
- // Clean up the work item associated with this run.
1447
- errcode = napi_delete_async_work(env, baton->work);
1448
- ASSERT_NAPI_FATAL(errcode == 0, "napi_delete_async_work");
1449
- // Set both values to NULL so JavaScript can order a new run of the thread.
1450
- baton->work = NULL;
1451
- baton->deferred = NULL;
1452
- return 0;
1453
- }
1454
-
1455
- static void jspromiseResolve(
1456
- napi_env env,
1457
- napi_status errcode,
1458
- void *data
1459
- ) {
1460
- // This function runs on the main thread after `jspromiseExecute` exits.
1461
- __jspromiseResolve(env, errcode, data);
1462
- }
1463
-
1464
- static napi_value jspromiseCreate(
1465
- napi_env env,
1466
- napi_callback_info info,
1467
- napi_async_execute_callback jspromiseExecute
1468
- ) {
1469
- // Create a deferred promise and an async queue work item.
1470
- // init baton
1471
- Jsbaton *baton = JSBATON_CREATE(env, info);
1472
- // declare var
1473
- int errcode = 0;
1474
- napi_value promise = 0;
1475
- napi_value async_resource_name =
1476
- jsstringCreate(env, "Node-API Deferred Promise from Async Work Item");
1477
- // reference result to prevent gc
1478
- errcode = napi_create_reference(env, // napi_env env
1479
- baton->result, // napi_value value
1480
- 1, // uint32_t initial_refcount
1481
- (napi_ref *) & baton->result); // napi_ref* result
1482
- ASSERT_NAPI_OK(env, errcode);
1483
- // Ensure that no work is currently in progress.
1484
- ASSERT_NAPI(env, baton->work == NULL,
1485
- "Only one work item must exist at a time");
1486
- // Create a deferred promise which we will resolve at the completion of the
1487
- // work.
1488
- errcode = napi_create_promise(env, &(baton->deferred), &promise);
1489
- ASSERT_NAPI_OK(env, errcode);
1490
- // Create an async work item, passing in the addon data, which will give the
1491
- // worker thread access to the above-created deferred promise.
1492
- errcode = napi_create_async_work(env, // napi_env env,
1493
- NULL, // napi_value async_resource,
1494
- async_resource_name, // napi_value async_resource_name,
1495
- jspromiseExecute, // napi_async_execute_callback execute,
1496
- jspromiseResolve, // napi_async_complete_callback complete,
1497
- baton, // void* data,
1498
- &(baton->work)); // napi_async_work* result);
1499
- ASSERT_NAPI_OK(env, errcode);
1500
- // Queue the work item for execution.
1501
- errcode = napi_queue_async_work(env, baton->work);
1502
- ASSERT_NAPI_OK(env, errcode);
1503
- // This causes created `promise` to be returned to JavaScript.
1504
- return promise;
1505
- }
1506
-
1507
-
1508
- /*
1509
- file sqlmath_napi_db
1510
- */
1511
- static int JSPROMISE_CREATE(
1512
- __dbCloseAsync,
1513
- env,
1514
- data
1515
- ) {
1516
- // int sqlite3_close_v2(sqlite3*);
1517
- // init baton
1518
- Jsbaton *baton = (Jsbaton *) data;
1519
- // declare var
1520
- int errcode = 0;
1521
- sqlite3 *db = (sqlite3 *) (intptr_t) baton->argint64[0];
1522
- // call c-function
1523
- errcode = sqlite3_close_v2(db);
1524
- if (db != NULL) {
1525
- dbCount -= 1;
1526
- // fprintf(stderr, "\nsqlite - __dbCloseAsync(%d)\n", dbCount);
1527
- }
1528
- ASSERT_SQLITE_OK(baton, db, errcode);
1529
- // save result
1530
- baton->argint64[0] = (int64_t) (intptr_t) db;
1531
- catch_error:
1532
- return 0;
1533
- }
1534
-
1535
- static int JSPROMISE_CREATE(
1536
- __dbExecAsync,
1537
- env,
1538
- data
1539
- ) {
1540
- // This function will run <bufin[1]> in <db> and save any result
1541
- // (list of tables containing rows from SELECT/pragma/etc) as serialized
1542
- // json-string in <pResult>.
1543
- /* *INDENT-OFF* */
1544
- SQLMATH_API int dbExec(sqlite3 *, Jsbaton *);
1545
- /* *INDENT-ON* */
1546
- // init baton
1547
- Jsbaton *baton = (Jsbaton *) data;
1548
- // declare var
1549
- int errcode = 0;
1550
- sqlite3 *db = (sqlite3 *) (intptr_t) baton->argint64[0];
1551
- // call c-function
1552
- errcode = dbExec(db, baton);
1553
- ASSERT_SQLITE_OK(baton, db, errcode);
1554
- catch_error:
1555
- return 0;
1556
- }
1557
-
1558
- static int loadOrSaveDb(
1559
- sqlite3 * pInMemory,
1560
- const char *zFilename,
1561
- int isSave
1562
- ) {
1563
- /*
1564
- ** https://www.sqlite.org/backup.html
1565
- ** This function is used to load the contents of a database file on disk
1566
- ** into the "main" database of open database connection pInMemory, or
1567
- ** to save the current contents of the database opened by pInMemory into
1568
- ** a database file on disk. pInMemory is probably an in-memory database,
1569
- ** but this function will also work fine if it is not.
1570
- **
1571
- ** Parameter zFilename points to a nul-terminated string containing the
1572
- ** name of the database file on disk to load from or save to. If parameter
1573
- ** isSave is non-zero, then the contents of the file zFilename are
1574
- ** overwritten with the contents of the database opened by pInMemory. If
1575
- ** parameter isSave is zero, then the contents of the database opened by
1576
- ** pInMemory are replaced by data loaded from the file zFilename.
1577
- **
1578
- ** If the operation is successful, SQLITE_OK is returned. Otherwise, if
1579
- ** an error occurs, an SQLite error code is returned.
1580
- */
1581
- int rc; /* Function return code */
1582
- sqlite3 *pFile; /* Database connection opened on zFilename */
1583
- sqlite3_backup *pBackup; /* Backup object used to copy data */
1584
- sqlite3 *pTo; /* Database to copy to (pFile or pInMemory) */
1585
- sqlite3 *pFrom; /* Database to copy from (pFile or pInMemory) */
1586
- /* Open the database file identified by zFilename. Exit early if this fails
1587
- ** for any reason. */
1588
- rc = sqlite3_open(zFilename, &pFile);
1589
- if (rc == SQLITE_OK) {
1590
- /* If this is a 'load' operation (isSave==0), then data is copied
1591
- ** from the database file just opened to database pInMemory.
1592
- ** Otherwise, if this is a 'save' operation (isSave==1), then data
1593
- ** is copied from pInMemory to pFile. Set the variables pFrom and
1594
- ** pTo accordingly. */
1595
- pFrom = (isSave ? pInMemory : pFile);
1596
- pTo = (isSave ? pFile : pInMemory);
1597
-
1598
- /* Set up the backup procedure to copy from the "main" database of
1599
- ** connection pFile to the main database of connection pInMemory.
1600
- ** If something goes wrong, pBackup will be set to NULL and an error
1601
- ** code and message left in connection pTo.
1602
- **
1603
- ** If the backup object is successfully created, call backup_step()
1604
- ** to copy data from pFile to pInMemory. Then call backup_finish()
1605
- ** to release resources associated with the pBackup object. If an
1606
- ** error occurred, then an error code and message will be left in
1607
- ** connection pTo. If no error occurred, then the error code belonging
1608
- ** to pTo is set to SQLITE_OK.
1609
- */
1610
- pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
1611
- if (pBackup) {
1612
- (void) sqlite3_backup_step(pBackup, -1);
1613
- (void) sqlite3_backup_finish(pBackup);
1614
- }
1615
- rc = sqlite3_errcode(pTo);
1616
- }
1617
- /* Close the database connection opened on database file zFilename
1618
- ** and return the result of this function. */
1619
- (void) sqlite3_close(pFile);
1620
- return rc;
1621
- }
1622
-
1623
- static int JSPROMISE_CREATE(
1624
- __dbMemoryLoadOrSave,
1625
- env,
1626
- data
1627
- ) {
1628
- // This function will load/save filename <bufin[0]> to/from <db>
1629
- /* *INDENT-OFF* */
1630
- SQLMATH_API int dbMemoryLoadOrSave(sqlite3 *, Jsbaton *);
1631
- /* *INDENT-ON* */
1632
- // init baton
1633
- Jsbaton *baton = (Jsbaton *) data;
1634
- // declare var
1635
- int errcode = 0;
1636
- sqlite3 *db = (sqlite3 *) (intptr_t) baton->argint64[0];
1637
- // call c-function
1638
- errcode = loadOrSaveDb(db, //
1639
- baton->bufin[1], // filename
1640
- baton->argint64[2]); // isSave
1641
- ASSERT_SQLITE_OK(baton, db, errcode);
1642
- catch_error:
1643
- return 0;
1644
- }
1645
-
1646
- static int JSPROMISE_CREATE(
1647
- __dbOpenAsync,
1648
- env,
1649
- data
1650
- ) {
1651
- // int sqlite3_open_v2(
1652
- // const char *filename, /* Database filename (UTF-8) */
1653
- // sqlite3 **ppDb, /* OUT: SQLite db handle */
1654
- // int flags, /* Flags */
1655
- // const char *zVfs /* Name of VFS module to use */
1656
- // );
1657
- // init baton
1658
- Jsbaton *baton = (Jsbaton *) data;
1659
- // declare var
1660
- int errcode = 0;
1661
- sqlite3 *db = NULL;
1662
- // call c-function
1663
- errcode = sqlite3_open_v2(baton->bufin[0], // filename
1664
- &db, // db
1665
- (int) baton->argint64[2], // flags // NOLINT
1666
- NULL);
1667
- dbCount += 1;
1668
- // fprintf(stderr, "\nsqlite - __dbOpenAsync(%d)\n", dbCount);
1669
- ASSERT_SQLITE_OK(baton, db, errcode);
1670
- // printf("\n[napi db=%zd]\n", (intptr_t) db);
1671
- // save result
1672
- baton->argint64[0] = (int64_t) (intptr_t) db;
1673
- catch_error:
1674
- return 0;
1675
- }
1676
-
1677
- static int JSPROMISE_CREATE(
1678
- __dbTableInsertAsync,
1679
- env,
1680
- data
1681
- ) {
1682
- // this function will bulk-insert <bufin[1]> to table <bufin[2]>
1683
- /* *INDENT-OFF* */
1684
- SQLMATH_API int dbTableInsert(sqlite3 *, Jsbaton *);
1685
- /* *INDENT-ON* */
1686
- // init baton
1687
- Jsbaton *baton = (Jsbaton *) data;
1688
- // declare var
1689
- int errcode = 0;
1690
- sqlite3 *db = (sqlite3 *) (intptr_t) baton->argint64[0];
1691
- // call c-function
1692
- errcode = dbTableInsert(db, baton);
1693
- ASSERT_SQLITE_OK(baton, db, errcode);
1694
- catch_error:
1695
- return 0;
1696
- }
1697
-
1698
- static void __dbFinalizer(
1699
- napi_env env,
1700
- void *finalize_data,
1701
- void *finalize_hint
1702
- ) {
1703
- // this function will finalize <finalize_data>
1704
- UNUSED(env);
1705
- UNUSED(finalize_hint);
1706
- // declare var
1707
- int errcode = 0;
1708
- sqlite3 *db = *(sqlite3 **) finalize_data;
1709
- // printf("\n[napi finalize_data=%zd]\n", db);
1710
- // printf("\n[napi finalize_hint=%s]\n", (const char *) finalize_hint);
1711
- // close db
1712
- errcode = sqlite3_close_v2(db);
1713
- if (db != NULL) {
1714
- dbCount -= 1;
1715
- // fprintf(stderr, "\nsqlite - __dbFinalizer(%d)\n", dbCount);
1716
- }
1717
- ASSERT_NAPI_FATAL(errcode == 0, "sqlite3_close_v2");
1718
- // cleanup aDb
1719
- ALLOCF(finalize_data);
1720
- }
1721
-
1722
- static napi_value __dbFinalizerCreate(
1723
- napi_env env,
1724
- napi_callback_info info
1725
- ) {
1726
- // this function will create empty finalizer for db
1727
- UNUSED(info);
1728
- // declare var
1729
- int errcode = 0;
1730
- napi_value val = NULL;
1731
- // init aDb
1732
- int64_t *aDb = (int64_t *) ALLOCM(sizeof(int64_t));
1733
- ASSERT_NAPI_FATAL(aDb != NULL, "out of memory");
1734
- errcode = napi_create_external_arraybuffer(env, // napi_env env,
1735
- (void *) aDb, // void* external_data,
1736
- sizeof(int64_t), // size_t byte_length,
1737
- __dbFinalizer, // napi_finalize finalize_cb,
1738
- NULL, // void* finalize_hint,
1739
- &val); // napi_value* result
1740
- ASSERT_NAPI_OK(env, errcode);
1741
- return val;
1742
- }
1743
-
1744
-
1745
- /*
1746
- file sqlmath_napi_noop
1747
- */
1748
- static void noopAsyncExecute(
1749
- napi_env env,
1750
- void *data
1751
- ) {
1752
- // This function runs on a worker thread. It has no access to the JavaScript.
1753
- UNUSED(env);
1754
- // init baton
1755
- Jsbaton *baton = (Jsbaton *) data;
1756
- UNUSED(baton);
1757
- }
1758
-
1759
- static napi_value noopAsync(
1760
- napi_env env,
1761
- napi_callback_info info
1762
- ) {
1763
- // Create a deferred promise and an async queue work item.
1764
- return jspromiseCreate(env, info, noopAsyncExecute);
1765
- }
1766
-
1767
- /*
1768
- static int JSPROMISE_CREATE(noopAsync, env, data) {
1769
- // This function runs on a worker thread. It has no access to the JavaScript.
1770
- UNUSED(env);
1771
- // init baton
1772
- Jsbaton *baton = (Jsbaton *) data;
1773
- UNUSED(baton);
1774
- }
1775
- */
1776
-
1777
- static napi_value noopSync(
1778
- napi_env env,
1779
- napi_callback_info info
1780
- ) {
1781
- // this function will do nothing
1782
- // init baton
1783
- Jsbaton *baton = JSBATON_CREATE(env, info);
1784
- return jsbatonExport(env, baton);
1785
- }
1786
-
1787
-
1788
- /*
1789
- file sqlmath_napi_init
1790
- */
1791
- napi_value napi_module_init(
1792
- napi_env env,
1793
- napi_value exports
1794
- ) {
1795
- // typedef struct {
1796
- // // One of utf8name or name should be NULL.
1797
- // const char* utf8name;
1798
- // napi_value name;
1799
- //
1800
- // napi_callback method;
1801
- // napi_callback getter;
1802
- // napi_callback setter;
1803
- // napi_value value;
1804
- //
1805
- // napi_property_attributes attributes;
1806
- // void* data;
1807
- // } napi_property_descriptor;
1808
- #define NAPI_EXPORT_MEMBER(name) \
1809
- {#name, NULL, name, NULL, NULL, NULL, napi_default, NULL}
1810
- // declare var
1811
- int errcode = 0;
1812
- const napi_property_descriptor propList[] = {
1813
- NAPI_EXPORT_MEMBER(__dbCloseAsync),
1814
- NAPI_EXPORT_MEMBER(__dbExecAsync),
1815
- NAPI_EXPORT_MEMBER(__dbFinalizerCreate),
1816
- NAPI_EXPORT_MEMBER(__dbMemoryLoadOrSave),
1817
- NAPI_EXPORT_MEMBER(__dbOpenAsync),
1818
- NAPI_EXPORT_MEMBER(__dbTableInsertAsync),
1819
- NAPI_EXPORT_MEMBER(noopAsync),
1820
- NAPI_EXPORT_MEMBER(noopSync),
1821
- };
1822
- errcode = napi_define_properties(env, exports,
1823
- sizeof(propList) / sizeof(napi_property_descriptor), propList);
1824
- ASSERT_NAPI_OK(env, errcode);
1825
- return exports;
1826
- }
1827
-
1828
- // NAPI_MODULE(NODE_GYP_MODULE_NAME, napi_module_init)
1829
- #endif // SQLMATH_NAPI
1830
- /*
1831
- file sqlmath_napi - end
1832
- */