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/.npmignore +10 -0
- package/README.md +1 -1
- package/_binary_sqlmath_napi8_darwin_x64.node +0 -0
- package/_binary_sqlmath_napi8_linux_x64.node +0 -0
- package/_binary_sqlmath_napi8_win32_x64.node +0 -0
- package/package.json +2 -2
- package/.gitconfig +0 -25
- package/.github/workflows/ci.yml +0 -119
- package/.github/workflows/publish.yml +0 -67
- package/.gitignore +0 -20
- package/asset_image_folder_open_solid.svg +0 -1
- package/jslint_ci.sh +0 -2795
- package/sqlite3.c +0 -248548
- package/sqlite3_ext.c +0 -8372
- package/sqlite3_shell.c +0 -22436
- package/sqlmath_base.c +0 -1832
- package/sqlmath_custom.c +0 -78
- package/sqlmath_custom.cpp +0 -0
- package/sqlmath_custom.mjs +0 -4
- package/sqlmath_old.js +0 -31038
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
|
-
*/
|