Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024, 2025 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /*
14 : * (c) 2013 Martin Kersten
15 : */
16 : #include "monetdb_config.h"
17 : #include "gdk.h"
18 : #include "mal.h"
19 : #include "mal_client.h"
20 : #include "mal_instruction.h"
21 : #include "mal_exception.h"
22 : #include "mal_interpreter.h"
23 :
24 : #include "json.h"
25 :
26 : typedef str json;
27 :
28 : // just validate the string according to www.json.org
29 : // A straightforward recursive solution
30 : #define skipblancs(J) \
31 : do { \
32 : for(; *(J); (J)++) \
33 : if (*(J) != ' ' && \
34 : *(J) != '\n' && \
35 : *(J) != '\t' && \
36 : *(J) != '\r') \
37 : break; \
38 : } while (0)
39 :
40 : #define CHECK_JSON(jt) \
41 : do { \
42 : if (jt == NULL || jt->error) { \
43 : char *msg; \
44 : if (jt) { \
45 : msg = jt->error; \
46 : jt->error = NULL; \
47 : JSONfree(jt); \
48 : } else { \
49 : msg = createException(MAL, "json.new", SQLSTATE(HY013) MAL_MALLOC_FAIL); \
50 : } \
51 : return msg; \
52 : } \
53 : } while (0)
54 :
55 : static int TYPE_json;
56 :
57 : /* Internal constructors. */
58 : static int jsonhint = 8;
59 :
60 : static JSON *
61 2181398 : JSONnewtree(void)
62 : {
63 2181398 : JSON *js;
64 :
65 2181398 : js = GDKzalloc(sizeof(JSON));
66 2181404 : if (js == NULL)
67 : return NULL;
68 2181404 : js->elm = GDKzalloc(sizeof(JSONterm) * jsonhint);
69 2181404 : if (js->elm == NULL) {
70 0 : GDKfree(js);
71 0 : return NULL;
72 : }
73 2181404 : js->size = jsonhint;
74 2181404 : return js;
75 : }
76 :
77 : static int
78 48065451 : JSONnew(JSON *js)
79 : {
80 48065451 : JSONterm *term;
81 :
82 48065451 : if (js->free == js->size) {
83 3239 : term = GDKrealloc(js->elm, sizeof(JSONterm) * (js->size + 8));
84 3239 : if (term == NULL) {
85 0 : js->error = createException(MAL, "json.new",
86 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
87 0 : return js->free - 1;
88 : }
89 3239 : js->elm = term;
90 3239 : memset(term + js->size, 0, 8 * sizeof(JSONterm));
91 3239 : js->size += 8;
92 3239 : if (jsonhint < js->size)
93 3239 : jsonhint = js->size;
94 : }
95 48065451 : return js->free++;
96 : }
97 :
98 : /* Delete a JSON structure. */
99 : void
100 2181399 : JSONfree(JSON *c)
101 : {
102 2181399 : if (c == 0)
103 : return;
104 2181398 : freeException(c->error);
105 2181398 : GDKfree(c->elm);
106 2181404 : GDKfree(c);
107 : }
108 :
109 : static str
110 48005325 : JSONtoStorageString(JSON *jt, int idx, json *ret, size_t *out_size)
111 : {
112 48005325 : char *p = *ret;
113 48005325 : size_t sz = 0;
114 48005325 : str msg = MAL_SUCCEED;
115 :
116 48005325 : if (THRhighwater()) {
117 0 : msg = createException(MAL, "json.new",
118 : SQLSTATE(42000)
119 : "JSON object too complex to render into string.");
120 0 : return msg;
121 : }
122 :
123 :
124 48005325 : switch(jt->elm[idx].kind) {
125 3304326 : case JSON_OBJECT:
126 3304326 : *p++ = '{';
127 3304326 : *out_size += 1;
128 25526072 : for(int i = jt->elm[idx].next; i != 0; i = jt->elm[i].next) {
129 22221746 : sz = 0;
130 22221746 : if (i != jt->elm[idx].next) {
131 18924563 : *p++ = ',';
132 18924563 : *out_size += 1;
133 : }
134 22221746 : msg = JSONtoStorageString(jt, i, &p, &sz);
135 22221746 : if (msg != MAL_SUCCEED) {
136 0 : return msg;
137 : }
138 22221746 : *out_size += sz;
139 22221746 : p += sz;
140 : }
141 3304326 : *p++ = '}';
142 3304326 : *out_size += 1;
143 3304326 : break;
144 1582093 : case JSON_ARRAY:
145 1582093 : *p++ = '[';
146 1582093 : *out_size += 1;
147 2621074 : for(int i = jt->elm[idx].next; i != 0; i = jt->elm[i].next) {
148 1038981 : sz = 0;
149 1038981 : if (i != jt->elm[idx].next) {
150 437794 : *p++ = ',';
151 437794 : *out_size += 1;
152 : }
153 1038981 : msg = JSONtoStorageString(jt, i, &p, &sz);
154 1038981 : if (msg != MAL_SUCCEED) {
155 0 : return msg;
156 : }
157 1038981 : *out_size += sz;
158 1038981 : p += sz;
159 : }
160 1582093 : *p++ = ']';
161 1582093 : *out_size += 1;
162 1582093 : break;
163 22221746 : case JSON_ELEMENT:
164 22221746 : *p++ = '"';
165 22221746 : strncpy(p, jt->elm[idx].value, jt->elm[idx].valuelen);
166 22221746 : p += jt->elm[idx].valuelen;
167 22221746 : *p++ = '"';
168 22221746 : *p++ = ':';
169 22221746 : *out_size = jt->elm[idx].valuelen + 3;
170 22221746 : msg = JSONtoStorageString(jt, jt->elm[idx].child, &p, &sz);
171 22221746 : if (msg != MAL_SUCCEED) {
172 : return msg;
173 : }
174 22221746 : *out_size += sz;
175 22221746 : p += sz;
176 22221746 : break;
177 17590033 : case JSON_NUMBER:
178 : /* fall through */
179 : case JSON_STRING:
180 17590033 : strncpy(p, jt->elm[idx].value, jt->elm[idx].valuelen);
181 17590033 : *out_size += jt->elm[idx].valuelen;
182 17590033 : p += *out_size;
183 17590033 : break;
184 342592 : case JSON_VALUE:
185 342592 : msg = JSONtoStorageString(jt, jt->elm[idx].child, &p, &sz);
186 342592 : if (msg != MAL_SUCCEED) {
187 : return msg;
188 : }
189 342592 : *out_size += sz;
190 342592 : p += sz;
191 342592 : break;
192 2964535 : case JSON_NULL:
193 2964535 : strncpy(p, "null", 5);
194 2964535 : *out_size += 4;
195 2964535 : p += *out_size;
196 2964535 : break;
197 0 : default:
198 0 : msg = createException(MAL, "json.new", SQLSTATE(HY013) MAL_MALLOC_FAIL);
199 0 : break;
200 : }
201 :
202 48005325 : *p = 0;
203 :
204 48005325 : return msg;
205 : }
206 :
207 : static str JSONstr2json(json *ret, const char *const*j);
208 :
209 : static ssize_t
210 2200098 : JSONfromString(const char *src, size_t *len, void **J, bool external)
211 : {
212 2200098 : json *buf = (json *) J;
213 2200098 : if(*buf) {
214 2200036 : GDKfree(*buf);
215 2200036 : *buf = NULL;
216 : }
217 4380196 : if (strNil(src) || (external && strncmp(src, "nil", 3) == 0)) {
218 20000 : *buf = GDKstrdup(str_nil);
219 20000 : if (*buf == NULL)
220 : return -1;
221 20000 : *len = 2;
222 40000 : return strNil(src) ? 1 : 3;
223 : } else {
224 2180098 : str msg = JSONstr2json(buf, &src);
225 2180098 : if (msg != MAL_SUCCEED) {
226 2 : GDKerror("%s", getExceptionMessageAndState(msg));
227 2 : freeException(msg);
228 2 : return -1;
229 : }
230 : }
231 2180096 : *len = strlen(*buf) + 1;
232 2180096 : return (ssize_t) *len - 1;
233 : }
234 :
235 : static ssize_t
236 564 : JSONtoString(str *s, size_t *len, const void *SRC, bool external)
237 : {
238 564 : const char *src = SRC;
239 564 : size_t cnt;
240 564 : const char *c;
241 564 : char *dst;
242 :
243 564 : if (strNil(src)) {
244 1 : if (*s == NULL || *len < 4) {
245 1 : GDKfree(*s);
246 1 : *len = 4;
247 1 : *s = GDKmalloc(4);
248 1 : if (*s == NULL)
249 : return -1;
250 : }
251 1 : if (external) {
252 1 : assert(*len >= strlen("nil") + 1);
253 1 : strcpy(*s, "nil");
254 1 : return 3;
255 : }
256 0 : assert(*len >= strlen(str_nil) + 1);
257 0 : strcpy(*s, str_nil);
258 0 : return 1;
259 : }
260 : /* count how much space we need for the output string */
261 563 : if (external) {
262 : cnt = 3; /* two times " plus \0 */
263 25308 : for (c = src; *c; c++)
264 24760 : switch (*c) {
265 4253 : case '"':
266 : case '\\':
267 : case '\n':
268 4253 : cnt++;
269 : /* fall through */
270 24760 : default:
271 24760 : cnt++;
272 24760 : break;
273 : }
274 : } else {
275 15 : cnt = strlen(src) + 1; /* just the \0 */
276 : }
277 :
278 563 : if (cnt > (size_t) *len) {
279 95 : GDKfree(*s);
280 95 : *s = GDKmalloc(cnt);
281 95 : if (*s == NULL)
282 : return -1;
283 95 : *len = cnt;
284 : }
285 563 : dst = *s;
286 563 : if (external) {
287 548 : *dst++ = '"';
288 25308 : for (c = src; *c; c++) {
289 24760 : switch (*c) {
290 4253 : case '"':
291 : case '\\':
292 4253 : *dst++ = '\\';
293 : /* fall through */
294 24760 : default:
295 24760 : *dst++ = *c;
296 24760 : break;
297 0 : case '\n':
298 0 : *dst++ = '\\';
299 0 : *dst++ = 'n';
300 0 : break;
301 : }
302 : }
303 548 : *dst++ = '"';
304 548 : *dst = 0;
305 : } else {
306 15 : dst += snprintf(dst, cnt, "%s", src);
307 : }
308 563 : return (ssize_t) (dst - *s);
309 : }
310 :
311 : static BAT *
312 1 : JSONdumpInternal(const JSON *jt, int depth)
313 : {
314 1 : int i, idx;
315 1 : JSONterm *je;
316 1 : size_t buflen = 1024;
317 1 : char *buffer = GDKmalloc(buflen);
318 1 : BAT *bn = COLnew(0, TYPE_str, 0, TRANSIENT);
319 :
320 1 : if (!buffer || !bn) {
321 0 : GDKfree(buffer);
322 0 : BBPreclaim(bn);
323 0 : return NULL;
324 : }
325 :
326 56 : for (idx = 0; idx < jt->free; idx++) {
327 55 : size_t datlen = 0;
328 55 : je = jt->elm + idx;
329 :
330 55 : if (datlen + depth * 4 + 512 > buflen) {
331 0 : do {
332 0 : buflen += 1024;
333 0 : } while (datlen + depth * 4 + 512 > buflen);
334 0 : char *newbuf = GDKrealloc(buffer, buflen);
335 0 : if (newbuf == NULL) {
336 0 : GDKfree(buffer);
337 0 : BBPreclaim(bn);
338 0 : return NULL;
339 : }
340 : buffer = newbuf;
341 : }
342 55 : datlen += snprintf(buffer + datlen, buflen - datlen, "%*s", depth * 4,
343 : "");
344 55 : datlen += snprintf(buffer + datlen, buflen - datlen, "[%d] ", idx);
345 55 : switch (je->kind) {
346 7 : case JSON_OBJECT:
347 7 : datlen += snprintf(buffer + datlen, buflen - datlen, "object ");
348 7 : break;
349 1 : case JSON_ARRAY:
350 1 : datlen += snprintf(buffer + datlen, buflen - datlen, "array ");
351 1 : break;
352 23 : case JSON_ELEMENT:
353 23 : datlen += snprintf(buffer + datlen, buflen - datlen, "element ");
354 23 : break;
355 4 : case JSON_VALUE:
356 4 : datlen += snprintf(buffer + datlen, buflen - datlen, "value ");
357 4 : break;
358 15 : case JSON_STRING:
359 15 : datlen += snprintf(buffer + datlen, buflen - datlen, "string ");
360 15 : break;
361 5 : case JSON_NUMBER:
362 5 : datlen += snprintf(buffer + datlen, buflen - datlen, "number ");
363 5 : break;
364 0 : case JSON_BOOL:
365 0 : datlen += snprintf(buffer + datlen, buflen - datlen, "bool ");
366 0 : break;
367 0 : case JSON_NULL:
368 0 : datlen += snprintf(buffer + datlen, buflen - datlen, "null ");
369 0 : break;
370 0 : default:
371 0 : datlen += snprintf(buffer + datlen, buflen - datlen, "unknown %d ",
372 : (int) je->kind);
373 : }
374 55 : datlen += snprintf(buffer + datlen, buflen - datlen, "child %d list ",
375 : je->child);
376 122 : for (i = je->next; i; i = jt->elm[i].next) {
377 67 : if (datlen + 10 > buflen) {
378 0 : buflen += 1024;
379 0 : char *newbuf = GDKrealloc(buffer, buflen);
380 0 : if (newbuf == NULL) {
381 0 : GDKfree(buffer);
382 0 : BBPreclaim(bn);
383 0 : return NULL;
384 : }
385 : buffer = newbuf;
386 : }
387 67 : datlen += snprintf(buffer + datlen, buflen - datlen, "%d ", i);
388 : }
389 55 : if (je->name) {
390 0 : if (datlen + 10 + je->namelen > buflen) {
391 0 : do {
392 0 : buflen += 1024;
393 0 : } while (datlen + 10 + je->namelen > buflen);
394 0 : char *newbuf = GDKrealloc(buffer, buflen);
395 0 : if (newbuf == NULL) {
396 0 : GDKfree(buffer);
397 0 : BBPreclaim(bn);
398 0 : return NULL;
399 : }
400 : buffer = newbuf;
401 : }
402 0 : datlen += snprintf(buffer + datlen, buflen - datlen, "%.*s : ",
403 0 : (int) je->namelen, je->name);
404 : }
405 55 : if (je->value) {
406 51 : if (datlen + 10 + je->valuelen > buflen) {
407 0 : do {
408 0 : buflen += 1024;
409 0 : } while (datlen + 10 + je->valuelen > buflen);
410 0 : char *newbuf = GDKrealloc(buffer, buflen);
411 0 : if (newbuf == NULL) {
412 0 : GDKfree(buffer);
413 0 : BBPreclaim(bn);
414 0 : return NULL;
415 : }
416 : buffer = newbuf;
417 : }
418 51 : datlen += snprintf(buffer + datlen, buflen - datlen, "%.*s",
419 51 : (int) je->valuelen, je->value);
420 : }
421 55 : if (BUNappend(bn, buffer, false) != GDK_SUCCEED) {
422 0 : BBPreclaim(bn);
423 0 : GDKfree(buffer);
424 0 : return NULL;
425 : }
426 : }
427 1 : GDKfree(buffer);
428 1 : return bn;
429 : }
430 :
431 : static str
432 1 : JSONdump(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
433 : {
434 1 : (void) mb;
435 1 : (void) cntxt;
436 :
437 1 : bat *ret = getArgReference_bat(stk, pci, 0);
438 1 : const json *val = (json *) getArgReference(stk, pci, 1);
439 1 : JSON *jt = JSONparse(*val);
440 :
441 1 : CHECK_JSON(jt);
442 1 : BAT *bn = JSONdumpInternal(jt, 0);
443 1 : JSONfree(jt);
444 1 : if (bn == NULL)
445 0 : throw(MAL, "json.dump", SQLSTATE(HY013) MAL_MALLOC_FAIL);
446 1 : *ret = bn->batCacheid;
447 1 : BBPkeepref(bn);
448 1 : return MAL_SUCCEED;
449 : }
450 :
451 : static str
452 0 : JSONjson2str(str *ret, json *j)
453 : {
454 0 : char *s = *j, *c;
455 :
456 0 : if (*s == '"')
457 0 : s++;
458 0 : if ((s = GDKstrdup(s)) == NULL)
459 0 : throw(MAL, "json.str", SQLSTATE(HY013) MAL_MALLOC_FAIL);
460 0 : c = s + strlen(s) - 1;
461 0 : if (*c == '"')
462 0 : *c = 0;
463 0 : *ret = s;
464 0 : return MAL_SUCCEED;
465 : }
466 :
467 : static str
468 0 : JSON2json(json *ret, const json *j)
469 : {
470 0 : *ret = GDKstrdup(*j);
471 0 : if (*ret == NULL)
472 0 : throw(MAL, "json.json", SQLSTATE(HY013) MAL_MALLOC_FAIL);
473 : return MAL_SUCCEED;
474 : }
475 :
476 : static str
477 2180283 : JSONstr2json(json *ret, const char *const*j)
478 : {
479 2180283 : str msg = MAL_SUCCEED;
480 2180283 : json buf = NULL;
481 2180283 : size_t ln = strlen(*j)+1;
482 2180283 : size_t out_size = 0;
483 :
484 2180283 : JSON *jt = NULL;
485 :
486 2180283 : if (strNil(*j)) {
487 1 : buf = GDKstrdup(*j);
488 : } else {
489 2180282 : jt = JSONparse(*j);
490 2180282 : CHECK_JSON(jt);
491 :
492 2180260 : buf = (json)GDKmalloc(ln);
493 : }
494 2180261 : if (buf == NULL) {
495 0 : msg = createException(MAL, "json.new", SQLSTATE(HY013) MAL_MALLOC_FAIL);
496 0 : goto bailout;
497 : }
498 :
499 2180261 : if (jt != NULL) {
500 2180260 : msg = JSONtoStorageString(jt, 0, &buf, &out_size);
501 2180260 : if (msg != MAL_SUCCEED) {
502 0 : GDKfree(buf);
503 0 : goto bailout;
504 : }
505 : }
506 :
507 2180261 : *ret = buf;
508 :
509 2180261 : bailout:
510 2180261 : JSONfree(jt);
511 2180261 : return msg;
512 : }
513 :
514 : static str
515 370 : JSONisvalid(bit *ret, const char *const *j)
516 : {
517 370 : if (strNil(*j)) {
518 0 : *ret = bit_nil;
519 : } else {
520 370 : JSON *jt = JSONparse(*j);
521 370 : if (jt == NULL)
522 0 : throw(MAL, "json.isvalid", SQLSTATE(HY013) MAL_MALLOC_FAIL);
523 370 : *ret = jt->error == MAL_SUCCEED;
524 370 : JSONfree(jt);
525 : }
526 : return MAL_SUCCEED;
527 : }
528 :
529 : static str
530 15 : JSONisobject(bit *ret, const json *js)
531 : {
532 15 : if (strNil(*js)) {
533 0 : *ret = bit_nil;
534 : } else {
535 : const char *j = *js;
536 :
537 15 : skipblancs(j);
538 15 : *ret = *j == '{';
539 : }
540 15 : return MAL_SUCCEED;
541 : }
542 :
543 : static str
544 16 : JSONisarray(bit *ret, const json *js)
545 : {
546 16 : if (strNil(*js)) {
547 0 : *ret = bit_nil;
548 : } else {
549 : const char *j = *js;
550 :
551 16 : skipblancs(j);
552 16 : *ret = *j == '[';
553 : }
554 16 : return MAL_SUCCEED;
555 : }
556 :
557 : #ifdef GDKLIBRARY_JSON
558 : static gdk_return
559 0 : upgradeJSONStorage(char **out, const char **in)
560 : {
561 0 : str msg;
562 0 : if ((msg = JSONstr2json(out, in)) != MAL_SUCCEED) {
563 0 : freeException(msg);
564 0 : return GDK_FAIL;
565 : }
566 : return GDK_SUCCEED;
567 : }
568 :
569 : static str
570 0 : jsonRead(str a, size_t *dstlen, stream *s, size_t cnt)
571 : {
572 0 : str out = NULL;
573 0 : str msg;
574 :
575 0 : if ((a = BATatoms[TYPE_str].atomRead(a, dstlen, s, cnt)) == NULL)
576 : return NULL;
577 :
578 0 : if ((msg = JSONstr2json(&out, &(const char *){a})) != MAL_SUCCEED) {
579 0 : freeException(msg);
580 0 : GDKfree(a);
581 0 : return NULL;
582 : }
583 0 : *dstlen = strlen(out) + 1;
584 0 : GDKfree(a);
585 :
586 0 : return out;
587 : }
588 :
589 : #endif
590 :
591 :
592 : static str
593 358 : JSONprelude(void)
594 : {
595 358 : TYPE_json = ATOMindex("json");
596 : #ifdef GDKLIBRARY_JSON
597 : /* Run the gdk upgrade library function with a callback that
598 : * performs the actual upgrade.
599 : */
600 358 : char jsonupgrade[MAXPATH];
601 358 : struct stat st;
602 358 : if (GDKfilepath(jsonupgrade, sizeof(jsonupgrade), 0, BATDIR, "jsonupgradeneeded", NULL) != GDK_SUCCEED)
603 0 : throw(MAL, "json.prelude", "cannot allocate filename for json upgrade signal file");
604 358 : int r = stat(jsonupgrade, &st);
605 358 : if (r == 0) {
606 : /* The file exists so we need to run the upgrade code */
607 0 : if (BBPjson_upgrade(upgradeJSONStorage) != GDK_SUCCEED) {
608 0 : throw(MAL, "json.prelude", "JSON storage upgrade failed");
609 : }
610 : /* Change the read function of the json atom so that any values in the WAL
611 : * will also be upgraded.
612 : */
613 0 : BATatoms[TYPE_json].atomRead = (void *(*)(void *, size_t *, stream *, size_t)) jsonRead;
614 : }
615 : #endif
616 : return MAL_SUCCEED;
617 : }
618 :
619 : static void
620 23271125 : JSONappend(JSON *jt, int idx, int nxt)
621 : {
622 23271125 : int chld;
623 :
624 23271125 : if (jt->elm[nxt].kind == JSON_OBJECT || jt->elm[nxt].kind == JSON_ARRAY) {
625 0 : chld = JSONnew(jt);
626 0 : if (jt->error)
627 : return;
628 0 : jt->elm[chld].kind = jt->elm[nxt].kind;
629 0 : jt->elm[chld].name = jt->elm[nxt].name;
630 0 : jt->elm[chld].namelen = jt->elm[nxt].namelen;
631 0 : jt->elm[chld].value = jt->elm[nxt].value;
632 0 : jt->elm[chld].valuelen = jt->elm[nxt].valuelen;
633 0 : jt->elm[chld].child = jt->elm[nxt].child;
634 0 : jt->elm[chld].next = jt->elm[nxt].next;
635 0 : jt->elm[chld].tail = jt->elm[nxt].tail;
636 0 : jt->elm[chld].child = nxt;
637 :
638 0 : jt->elm[nxt].child = 0;
639 0 : jt->elm[nxt].next = 0;
640 0 : jt->elm[nxt].tail = 0;
641 0 : nxt = chld;
642 : }
643 23271125 : if (jt->elm[idx].next == 0)
644 3901556 : jt->elm[idx].next = jt->elm[idx].tail = nxt;
645 : else {
646 19369569 : jt->elm[jt->elm[idx].tail].next = nxt;
647 19369569 : jt->elm[idx].tail = nxt;
648 : }
649 : }
650 :
651 : /*
652 : * The JSON filter operation takes a path expression which is
653 : * purposely kept simple, It provides step (.), multistep (..) and
654 : * indexed ([nr]) access to the JSON elements. A wildcard * can be
655 : * used as placeholder for a step identifier.
656 : *
657 : * A path expression is always validated upfront and can only be
658 : * applied to valid json strings.
659 : * Path samples:
660 : * .store.book
661 : * .store.book[0]
662 : * .store.book.author
663 : * ..author
664 : */
665 : #define MAXTERMS 256
666 :
667 : typedef enum path_token {
668 : ROOT_STEP, /* $ */
669 : CHILD_STEP, /* . */
670 : INDEX_STEP, /* [n] */
671 : ANY_STEP, /* .. */
672 : END_STEP /* end of expression */
673 : } path_token;
674 :
675 : typedef struct {
676 : path_token token; /* Token kind */
677 : char *name; /* specific key */
678 : size_t namelen; /* the size of the key */
679 : int index; /* if index == INT_MAX we got [*] */
680 : int first, last;
681 : } pattern;
682 :
683 : static str
684 422 : JSONcompile(const char *expr, pattern terms[])
685 : {
686 422 : int t = 0;
687 422 : const char *s, *beg;
688 :
689 609 : for (s = expr; *s; s++) {
690 552 : terms[t].token = CHILD_STEP;
691 552 : terms[t].index = INT_MAX;
692 552 : terms[t].first = INT_MAX;
693 552 : terms[t].last = INT_MAX;
694 552 : if (*s == '$') {
695 55 : if (t && terms[t - 1].token != END_STEP)
696 0 : throw(MAL, "json.compile", "Root node must be first");
697 55 : if (!(*(s + 1) == '.' || *(s + 1) == '[' || *(s + 1) == 0))
698 2 : throw(MAL, "json.compile", "Root node must be first");
699 53 : s++;
700 53 : if (*s == 0)
701 1 : terms[t].token = ROOT_STEP;
702 : }
703 550 : if (*s == '.' && *(s + 1) == '.') {
704 123 : terms[t].token = ANY_STEP;
705 123 : s += 2;
706 123 : if (*s == '.')
707 2 : throw(MAL, "json.compile", "Step identifier expected");
708 427 : } else if (*s == '.')
709 137 : s++;
710 :
711 : // child step
712 548 : if (*s != '[') {
713 2880 : for (beg = s; *s; s++)
714 2523 : if (*s == '.' || *s == '[' || *s == ',')
715 : break;
716 500 : terms[t].name = GDKzalloc(s - beg + 1);
717 497 : if (terms[t].name == NULL)
718 0 : throw(MAL, "json.compile", SQLSTATE(HY013) MAL_MALLOC_FAIL);
719 497 : terms[t].namelen = s - beg;
720 497 : strncpy(terms[t].name, beg, s - beg);
721 497 : if (*s == '.')
722 68 : s--;
723 497 : if (*s == 0) {
724 353 : t++;
725 353 : break;
726 : }
727 : }
728 192 : if (*s == '[') {
729 : // array step
730 82 : bool closed = false;
731 82 : s++;
732 82 : skipblancs(s);
733 82 : if (*s != '*') {
734 : /* TODO: Implement [start:step:end] indexing */
735 75 : if (isdigit((unsigned char) *s)) {
736 71 : terms[t].index = atoi(s);
737 71 : terms[t].first = terms[t].last = atoi(s);
738 : } else
739 4 : throw(MAL, "json.path", "'*' or digit expected");
740 : }
741 156 : for (; *s; s++)
742 155 : if (*s == ']') {
743 : closed = true;
744 : break;
745 : }
746 78 : if (*s == 0) {
747 1 : if (!closed) {
748 1 : throw(MAL, "json.path", "] expected");
749 : }
750 0 : t++;
751 0 : break;
752 : }
753 : if (*s != ']')
754 : throw(MAL, "json.path", "] expected");
755 : }
756 187 : if (*s == ',') {
757 42 : if (++t == MAXTERMS)
758 0 : throw(MAL, "json.path", "too many terms");
759 42 : terms[t].token = END_STEP;
760 : }
761 187 : if (++t == MAXTERMS)
762 0 : throw(MAL, "json.path", "too many terms");
763 : }
764 410 : if (t >= MAXTERMS - 1)
765 0 : throw(MAL, "json.path", "too many terms");
766 410 : terms[t].token = END_STEP;
767 410 : return MAL_SUCCEED;
768 : }
769 :
770 : static str
771 516 : JSONgetValue(const JSON *jt, int idx)
772 : {
773 516 : str s;
774 :
775 516 : if (jt->elm[idx].valuelen == 0)
776 0 : return GDKstrdup(str_nil);
777 516 : s = GDKmalloc(jt->elm[idx].valuelen + 1);
778 516 : if (s)
779 516 : strcpy_len(s, jt->elm[idx].value, jt->elm[idx].valuelen + 1);
780 : return s;
781 : }
782 :
783 : /* eats res and r */
784 : static str
785 2286 : JSONglue(str res, str r, char sep)
786 : {
787 2286 : size_t len, l;
788 2286 : str n;
789 :
790 2286 : if (r == 0 || *r == 0) {
791 0 : GDKfree(r);
792 1890 : return res;
793 : }
794 396 : len = strlen(r);
795 396 : if (res == 0)
796 : return r;
797 128 : l = strlen(res);
798 128 : n = GDKmalloc(l + len + 3);
799 128 : if (n == NULL) {
800 0 : GDKfree(res);
801 0 : GDKfree(r);
802 0 : return NULL;
803 : }
804 128 : snprintf(n, l + len + 3, "%s%s%s", res, sep ? "," : "", r);
805 128 : GDKfree(res);
806 128 : GDKfree(r);
807 128 : return n;
808 : }
809 :
810 : /* return NULL on no match, return (str) -1 on (malloc) failure, (str) -2 on stack overflow */
811 : static str
812 2281 : JSONmatch(JSON *jt, int ji, const pattern *terms, int ti, bool accumulate)
813 : {
814 2281 : str r = NULL, res = NULL;
815 2281 : int i;
816 2281 : int cnt;
817 :
818 2281 : if (THRhighwater())
819 : return (str) -2;
820 2283 : if (ti >= MAXTERMS)
821 : return res;
822 :
823 2283 : if (terms[ti].token == ROOT_STEP) {
824 1 : if (ti + 1 == MAXTERMS)
825 : return NULL;
826 1 : if (terms[ti + 1].token == END_STEP) {
827 1 : res = JSONgetValue(jt, 0);
828 1 : if (res == NULL)
829 0 : res = (str) -1;
830 1 : return res;
831 : }
832 0 : ti++;
833 : }
834 :
835 2282 : switch (jt->elm[ji].kind) {
836 149 : case JSON_ARRAY:
837 149 : if (terms[ti].name != 0 && terms[ti].token != ANY_STEP) {
838 6 : if (terms[ti].token == END_STEP) {
839 0 : res = JSONgetValue(jt, ji);
840 0 : if (res == NULL)
841 0 : res = (str) -1;
842 : }
843 6 : return res;
844 : }
845 143 : cnt = 0;
846 554 : for (i = jt->elm[ji].next; i && cnt >= 0; i = jt->elm[i].next, cnt++) {
847 411 : if (terms[ti].index == INT_MAX
848 131 : || (cnt >= terms[ti].first && cnt <= terms[ti].last)) {
849 321 : if (terms[ti].token == ANY_STEP) {
850 276 : if (jt->elm[i].child)
851 55 : r = JSONmatch(jt, jt->elm[i].child, terms, ti, true);
852 : else
853 : r = 0;
854 45 : } else if (ti + 1 == MAXTERMS) {
855 : return NULL;
856 45 : } else if (terms[ti + 1].token == END_STEP) {
857 24 : if (jt->elm[i].kind == JSON_VALUE)
858 8 : r = JSONgetValue(jt, jt->elm[i].child);
859 : else
860 16 : r = JSONgetValue(jt, i);
861 24 : if (r == NULL)
862 0 : r = (str) -1;
863 : } else {
864 21 : r = JSONmatch(jt, jt->elm[i].child, terms, ti + 1, terms[ti].index == INT_MAX);
865 : }
866 321 : if (r == (str) -1 || r == (str) -2) {
867 0 : GDKfree(res);
868 0 : return r;
869 : }
870 321 : res = JSONglue(res, r, ',');
871 : }
872 : }
873 : break;
874 629 : case JSON_OBJECT:
875 629 : cnt = 0;
876 6509 : for (i = jt->elm[ji].next; i && cnt >= 0; i = jt->elm[i].next) {
877 : // check the element label
878 5880 : if ((terms[ti].name && jt->elm[i].valuelen == terms[ti].namelen
879 2096 : && strncmp(terms[ti].name, jt->elm[i].value,
880 5418 : terms[ti].namelen) == 0) || terms[ti].name == 0
881 5416 : || terms[ti].name[0] == '*') {
882 471 : if (terms[ti].index == INT_MAX
883 24 : || (cnt >= terms[ti].first && cnt <= terms[ti].last)) {
884 463 : if (ti + 1 == MAXTERMS)
885 : return NULL;
886 463 : if (terms[ti + 1].token == END_STEP) {
887 393 : r = JSONgetValue(jt, jt->elm[i].child);
888 394 : if (r == NULL)
889 0 : r = (str) -1;
890 : } else {
891 70 : r = JSONmatch(jt, jt->elm[i].child, terms, ti + 1, terms[ti].index == INT_MAX);
892 : }
893 462 : if (r == (str) -1 || r == (str) -2) {
894 0 : GDKfree(res);
895 0 : return r;
896 : }
897 462 : if (accumulate) {
898 180 : res = JSONglue(res, r, ',');
899 : } else { // Keep the last matching value
900 282 : if (res)
901 0 : GDKfree(res);
902 : res = r;
903 : }
904 : }
905 471 : cnt++;
906 5409 : } else if (terms[ti].token == ANY_STEP && jt->elm[i].child) {
907 1684 : r = JSONmatch(jt, jt->elm[i].child, terms, ti, true);
908 1684 : if (r == (str) -1 || r == (str) -2) {
909 0 : GDKfree(res);
910 0 : return r;
911 : }
912 1684 : res = JSONglue(res, r, ',');
913 1684 : cnt++;
914 : }
915 : }
916 : break;
917 : default:
918 : res = NULL;
919 : }
920 : return res;
921 : }
922 :
923 : static str
924 419 : JSONfilterInternal(json *ret, const json *js, const char *const *expr, const char *other)
925 : {
926 419 : pattern terms[MAXTERMS];
927 419 : int tidx = 0;
928 419 : JSON *jt;
929 419 : str j = *js, msg = MAL_SUCCEED, s;
930 419 : json result = 0;
931 419 : size_t l;
932 :
933 419 : (void) other;
934 419 : if (strNil(j)) {
935 0 : *ret = GDKstrdup(j);
936 0 : if (*ret == NULL)
937 0 : throw(MAL, "JSONfilterInternal", SQLSTATE(HY013) MAL_MALLOC_FAIL);
938 : return MAL_SUCCEED;
939 : }
940 419 : jt = JSONparse(j);
941 420 : CHECK_JSON(jt);
942 420 : memset(terms, 0, sizeof(terms));
943 420 : msg = JSONcompile(*expr, terms);
944 419 : if (msg)
945 9 : goto bailout;
946 :
947 410 : bool accumulate = terms[tidx].token == ANY_STEP || (terms[tidx].name && terms[tidx].name[0] == '*');
948 410 : s = JSONmatch(jt, 0, terms, tidx, accumulate);
949 412 : if (s == (char *) -1) {
950 0 : msg = createException(MAL, "JSONfilterInternal",
951 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
952 0 : goto bailout;
953 : }
954 412 : if (s == (char *) -2) {
955 0 : msg = createException(MAL, "JSONfilterInternal",
956 : SQLSTATE(42000)
957 : "Expression too complex to parse");
958 0 : goto bailout;
959 : }
960 : result = s;
961 : bool return_array = false;
962 : // process all other PATH expression
963 950 : for (tidx++; tidx < MAXTERMS && terms[tidx].token; tidx++)
964 540 : if (terms[tidx].token == END_STEP && tidx + 1 < MAXTERMS
965 455 : && terms[tidx + 1].token) {
966 42 : tidx += 1;
967 42 : accumulate = terms[tidx].token == ANY_STEP || (terms[tidx].name && terms[tidx].name[0] == '*');
968 42 : s = JSONmatch(jt, 0, terms, tidx, accumulate);
969 42 : if (s == (char *) -1) {
970 0 : msg = createException(MAL, "JSONfilterInternal",
971 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
972 0 : goto bailout;
973 : }
974 42 : if (s == (char *) -2) {
975 0 : msg = createException(MAL, "JSONfilterInternal",
976 : SQLSTATE(42000)
977 : "Expression too complex to parse");
978 0 : goto bailout;
979 : }
980 42 : return_array = true;
981 42 : result = JSONglue(result, s, ',');
982 : }
983 410 : if (result) {
984 338 : l = strlen(result);
985 338 : if (result[l - 1] == ',')
986 0 : result[l - 1] = 0;
987 : } else
988 : l = 3;
989 :
990 1141 : for (int i = 0; i < MAXTERMS && terms[i].token; i++) {
991 : // pattern contains the .. operator
992 825 : if (terms[i].token == ANY_STEP ||
993 : // pattern contains the [*] operator
994 736 : (terms[i].token == CHILD_STEP && terms[i].index == INT_MAX && terms[i].name == NULL) ||
995 407 : (terms[i].token == CHILD_STEP && terms[i].index == INT_MAX && *terms[i].name == '*')) {
996 :
997 : return_array = true;
998 : break;
999 : }
1000 : }
1001 410 : if (return_array || accumulate) {
1002 105 : s = GDKmalloc(l + 3);
1003 105 : if (s)
1004 176 : snprintf(s, l + 3, "[%s]", (result ? result : ""));
1005 : }
1006 305 : else if (result == NULL || *result == 0) {
1007 38 : s = GDKstrdup("[]");
1008 : }
1009 : else {
1010 267 : s = GDKmalloc(l + 1);
1011 268 : if (s)
1012 268 : snprintf(s, l + 1, "%s", (result ? result : ""));
1013 : }
1014 413 : if (s == NULL) {
1015 0 : msg = createException(MAL, "JSONfilterInternal", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1016 0 : goto bailout;
1017 : }
1018 413 : *ret = s;
1019 :
1020 413 : bailout:
1021 422 : GDKfree(result);
1022 108320 : for (l = 0; l < MAXTERMS; l++)
1023 107477 : if (terms[l].name)
1024 496 : GDKfree(terms[l].name);
1025 421 : JSONfree(jt);
1026 421 : return msg;
1027 : }
1028 :
1029 :
1030 : static str
1031 31157157 : JSONstringParser(const char *j, const char **next)
1032 : {
1033 31157157 : unsigned int u;
1034 31157157 : bool seensurrogate = false;
1035 :
1036 31157157 : assert(*j == '"');
1037 31157157 : j++;
1038 473720797 : for (; *j; j++) {
1039 473720788 : switch (*j) {
1040 16757433 : case '\\':
1041 : // parse all escapes
1042 16757433 : j++;
1043 16757433 : switch (*j) {
1044 9849188 : case '"':
1045 : case '\\':
1046 : case '/':
1047 : case 'b':
1048 : case 'f':
1049 : case 'n':
1050 : case 'r':
1051 : case 't':
1052 9849188 : if (seensurrogate)
1053 2 : throw(MAL, "json.parser", "illegal escape char");
1054 9849186 : continue;
1055 : case 'u':
1056 : u = 0;
1057 34541164 : for (int i = 0; i < 4; i++) {
1058 27632934 : u <<= 4;
1059 27632934 : j++;
1060 27632934 : if ('0' <= *j && *j <= '9')
1061 22675810 : u |= *j - '0';
1062 4957124 : else if ('a' <= *j && *j <= 'f')
1063 4957030 : u |= *j - 'a' + 10;
1064 94 : else if ('A' <= *j && *j <= 'F')
1065 87 : u |= *j - 'A' + 10;
1066 : else
1067 7 : throw(MAL, "json.parser", "illegal escape char");
1068 : }
1069 6908230 : if (seensurrogate) {
1070 96220 : if ((u & 0xFC00) == 0xDC00)
1071 : seensurrogate = false;
1072 : else
1073 3 : throw(MAL, "json.parser", "illegal escape char");
1074 : } else {
1075 6812010 : if ((u & 0xFC00) == 0xD800)
1076 : seensurrogate = true;
1077 6715781 : else if ((u & 0xFC00) == 0xDC00)
1078 4 : throw(MAL, "json.parser", "illegal escape char");
1079 : }
1080 : break;
1081 8 : default:
1082 8 : *next = j;
1083 8 : throw(MAL, "json.parser", "illegal escape char");
1084 : }
1085 : break;
1086 31157120 : case '"':
1087 31157120 : if (seensurrogate)
1088 2 : throw(MAL, "json.parser", "illegal escape char");
1089 31157118 : j++;
1090 31157118 : *next = j;
1091 31157118 : return MAL_SUCCEED;
1092 425806235 : default:
1093 425806235 : if ((unsigned char) *j < ' ')
1094 3 : throw(MAL, "json.parser", "illegal control char");
1095 425806232 : if (seensurrogate)
1096 1 : throw(MAL, "json.parser", "illegal escape char");
1097 : break;
1098 : }
1099 : }
1100 9 : *next = j;
1101 9 : throw(MAL, "json.parser", "Nonterminated string");
1102 : }
1103 :
1104 : static bool
1105 5613952 : JSONintegerParser(const char *j, const char **next)
1106 : {
1107 5613952 : if (*j == '-')
1108 116377 : j++;
1109 :
1110 : // skipblancs(j);
1111 5613952 : if (!isdigit((unsigned char) *j)) {
1112 6 : *next = j;
1113 6 : return false;
1114 : }
1115 :
1116 5613946 : if (*j == '0') {
1117 544271 : *next = ++j;
1118 544271 : return true;
1119 : }
1120 :
1121 33918384 : for (; *j; j++)
1122 33918278 : if (!(isdigit((unsigned char) *j)))
1123 : break;
1124 5069675 : *next = j;
1125 :
1126 5069675 : return true;
1127 : }
1128 :
1129 : static bool
1130 5613947 : JSONfractionParser(const char *j, const char **next)
1131 : {
1132 5613947 : if (*j != '.')
1133 : return false;
1134 :
1135 : // skip the period character
1136 82787 : j++;
1137 : // must be followed by more digits
1138 82787 : if (!isdigit((unsigned char) *j))
1139 : return false;
1140 633879 : for (; *j; j++)
1141 633864 : if (!isdigit((unsigned char) *j))
1142 : break;
1143 82780 : *next = j;
1144 :
1145 82780 : return true;
1146 : }
1147 :
1148 : static bool
1149 5613947 : JSONexponentParser(const char *j, const char **next)
1150 : {
1151 5613947 : const char *s = j;
1152 5613947 : bool saw_digit = false;
1153 :
1154 5613947 : if (*j != 'e' && *j != 'E') {
1155 : return false;
1156 : }
1157 :
1158 45 : j++;
1159 45 : if (*j == '-' || *j == '+')
1160 20 : j++;
1161 :
1162 248 : for (; *j; j++) {
1163 245 : if (!isdigit((unsigned char) *j))
1164 : break;
1165 203 : saw_digit = true;
1166 : }
1167 :
1168 :
1169 45 : if (!saw_digit) {
1170 5613947 : j = s;
1171 : return false;
1172 : }
1173 :
1174 :
1175 32 : *next = j;
1176 :
1177 32 : return true;
1178 : }
1179 :
1180 : static str
1181 5613951 : JSONnumberParser(const char *j, const char **next)
1182 : {
1183 5613951 : if (!JSONintegerParser(j, next)) {
1184 6 : throw(MAL, "json.parser", "Number expected");
1185 : }
1186 :
1187 5613946 : j = *next;
1188 : // backup = j;
1189 : // skipblancs(j);
1190 :
1191 5613946 : if (!JSONfractionParser(j, next)) {
1192 5531166 : *next = j;
1193 : }
1194 :
1195 5613945 : j = *next;
1196 :
1197 5613945 : if (!JSONexponentParser(j, next)) {
1198 5613915 : *next = j;
1199 : }
1200 : return MAL_SUCCEED;
1201 : }
1202 :
1203 : static int
1204 47721749 : JSONtoken(JSON *jt, const char *j, const char **next)
1205 : {
1206 47721749 : str msg;
1207 47721749 : int nxt, idx = JSONnew(jt);
1208 47721763 : const char *string_start = j;
1209 47721763 : int pidx;
1210 :
1211 47721763 : if (jt->error)
1212 : return idx;
1213 47721765 : if (THRhighwater()) {
1214 2 : jt->error = createException(MAL, "json.parser",
1215 : SQLSTATE(42000)
1216 : "Expression too complex to parse");
1217 2 : return idx;
1218 : }
1219 47721853 : skipblancs(j);
1220 47721853 : switch (*j) {
1221 3314278 : case '{':
1222 3314278 : jt->elm[idx].kind = JSON_OBJECT;
1223 3314278 : jt->elm[idx].value = j;
1224 3314278 : j++;
1225 22245025 : while (*j) {
1226 22257346 : skipblancs(j);
1227 22245019 : if (*j == '}')
1228 : break;
1229 22237846 : nxt = JSONtoken(jt, j, next);
1230 22237862 : if (jt->error)
1231 : return idx;
1232 22237841 : j = *next;
1233 22237852 : skipblancs(j);
1234 22237841 : if (jt->elm[nxt].kind != JSON_STRING || *j != ':') {
1235 22 : jt->error = createException(MAL, "json.parser",
1236 : "JSON syntax error: element expected at offset %td",
1237 11 : jt->elm[nxt].value - string_start);
1238 11 : return idx;
1239 : }
1240 22237830 : j++;
1241 22239713 : skipblancs(j);
1242 22237830 : jt->elm[nxt].kind = JSON_ELEMENT;
1243 : /* do in two steps since JSONtoken may realloc jt->elm */
1244 22237830 : int chld = JSONtoken(jt, j, next);
1245 22237815 : if (jt->error)
1246 : return idx;
1247 :
1248 : /* Search for a duplicate key */
1249 263019433 : for(pidx = jt->elm[idx].next; pidx != 0; pidx = jt->elm[pidx].next) {
1250 240789506 : if (jt->elm[pidx].kind == JSON_ELEMENT &&
1251 240789451 : jt->elm[pidx].valuelen == jt->elm[nxt].valuelen - 2 &&
1252 7094795 : strncmp(jt->elm[pidx].value, jt->elm[nxt].value + 1,
1253 : jt->elm[nxt].valuelen) == 0) {
1254 : break;
1255 : }
1256 : }
1257 :
1258 : /* Duplicate found: Change the value of the previous key. */
1259 22229943 : if (pidx > 0) {
1260 16 : jt->elm[pidx].child = chld;
1261 : /* Note that we do not call JSONappend here.
1262 : *
1263 : * Normally we would de-allocate the old child value and the new key,
1264 : * but since we are using an arena provided by JSONnew, we don't need to.
1265 : * This might get expensive for big objects with lagre values for
1266 : * repeated keys.
1267 : */
1268 :
1269 : } else {
1270 22229927 : jt->elm[nxt].child = chld;
1271 22229927 : jt->elm[nxt].value++;
1272 22229927 : jt->elm[nxt].valuelen -= 2;
1273 22229927 : JSONappend(jt, idx, nxt);
1274 22229928 : if (jt->error)
1275 : return idx;
1276 : }
1277 22229944 : j = *next;
1278 22240280 : skipblancs(j);
1279 22229944 : if (*j == '}')
1280 : break;
1281 18930757 : if (*j != ',') {
1282 8 : jt->error = createException(MAL, "json.parser",
1283 : "JSON syntax error: ',' or '}' expected at offset %td",
1284 : j - string_start);
1285 8 : return idx;
1286 : }
1287 18930749 : j++;
1288 18939431 : skipblancs(j);
1289 18930749 : if (*j == '}') {
1290 2 : jt->error = createException(MAL, "json.parser",
1291 : "JSON syntax error: '}' not expected at offset %td",
1292 : j - string_start);
1293 2 : return idx;
1294 : }
1295 : }
1296 3306366 : if (*j != '}') {
1297 6 : jt->error = createException(MAL, "json.parser",
1298 : "JSON syntax error: '}' expected at offset %td",
1299 : j - string_start);
1300 6 : return idx;
1301 : } else
1302 3306360 : j++;
1303 3306360 : *next = j;
1304 3306360 : jt->elm[idx].valuelen = *next - jt->elm[idx].value;
1305 3306360 : return idx;
1306 1607000 : case '[':
1307 1607000 : jt->elm[idx].kind = JSON_ARRAY;
1308 1607000 : jt->elm[idx].value = j;
1309 1607000 : j++;
1310 2045858 : while (*j) {
1311 2045950 : skipblancs(j);
1312 2045854 : if (*j == ']')
1313 : break;
1314 1064878 : nxt = JSONtoken(jt, j, next);
1315 1064878 : if (jt->error)
1316 : return idx;
1317 1041206 : switch (jt->elm[nxt].kind) {
1318 0 : case JSON_ELEMENT:{
1319 0 : int k = JSONnew(jt);
1320 0 : if (jt->error)
1321 : return idx;
1322 0 : jt->elm[k].kind = JSON_OBJECT;
1323 0 : jt->elm[k].child = nxt;
1324 0 : nxt = k;
1325 : }
1326 : /* fall through */
1327 343702 : case JSON_OBJECT:
1328 : case JSON_ARRAY:
1329 343702 : if (jt->elm[nxt].kind == JSON_OBJECT
1330 343702 : || jt->elm[nxt].kind == JSON_ARRAY) {
1331 343702 : int k = JSONnew(jt);
1332 343702 : if (jt->error)
1333 : return idx;
1334 343702 : JSONappend(jt, idx, k);
1335 343702 : if (jt->error)
1336 : return idx;
1337 343702 : jt->elm[k].kind = JSON_VALUE;
1338 343702 : jt->elm[k].child = nxt;
1339 : }
1340 : break;
1341 697504 : default:
1342 697504 : JSONappend(jt, idx, nxt);
1343 697504 : if (jt->error)
1344 : return idx;
1345 : }
1346 1041206 : j = *next;
1347 1041253 : skipblancs(j);
1348 1041206 : if (*j == ']')
1349 : break;
1350 438909 : if (jt->elm[nxt].kind == JSON_ELEMENT) {
1351 0 : jt->error = createException(MAL, "json.parser",
1352 : "JSON syntax error: Array value expected at offset %td",
1353 : j - string_start);
1354 0 : return idx;
1355 : }
1356 438909 : if (*j != ',') {
1357 98 : jt->error = createException(MAL, "json.parser",
1358 : "JSON syntax error: ',' or ']' expected at offset %td (context: %c%c%c)",
1359 49 : j - string_start, *(j - 1), *j,
1360 49 : *(j + 1));
1361 49 : return idx;
1362 : }
1363 438860 : j++;
1364 439364 : skipblancs(j);
1365 438860 : if (*j == ']') {
1366 2 : jt->error = createException(MAL, "json.parser",
1367 : "JSON syntax error: '}' not expected at offset %td",
1368 : j - string_start);
1369 2 : return idx;
1370 : }
1371 : }
1372 1583277 : if (*j != ']') {
1373 4 : jt->error = createException(MAL, "json.parser",
1374 : "JSON syntax error: ']' expected at offset %td",
1375 : j - string_start);
1376 : } else
1377 1583273 : j++;
1378 1583277 : *next = j;
1379 1583277 : jt->elm[idx].valuelen = *next - jt->elm[idx].value;
1380 1583277 : return idx;
1381 31157108 : case '"':
1382 31157108 : msg = JSONstringParser(j, next);
1383 31157146 : if (msg) {
1384 38 : jt->error = msg;
1385 38 : return idx;
1386 : }
1387 31157108 : jt->elm[idx].kind = JSON_STRING;
1388 31157108 : jt->elm[idx].value = j;
1389 31157108 : jt->elm[idx].valuelen = *next - j;
1390 31157108 : return idx;
1391 2964610 : case 'n':
1392 2964610 : if (strncmp("null", j, 4) == 0) {
1393 2964608 : *next = j + 4;
1394 2964608 : jt->elm[idx].kind = JSON_NULL;
1395 2964608 : jt->elm[idx].value = j;
1396 2964608 : jt->elm[idx].valuelen = 4;
1397 2964608 : return idx;
1398 : }
1399 2 : jt->error = createException(MAL, "json.parser",
1400 : "JSON syntax error: NULL expected at offset %td",
1401 : j - string_start);
1402 2 : return idx;
1403 508579 : case 't':
1404 508579 : if (strncmp("true", j, 4) == 0) {
1405 508576 : *next = j + 4;
1406 508576 : jt->elm[idx].kind = JSON_NUMBER;
1407 508576 : jt->elm[idx].value = j;
1408 508576 : jt->elm[idx].valuelen = 4;
1409 508576 : return idx;
1410 : }
1411 3 : jt->error = createException(MAL, "json.parser",
1412 : "JSON syntax error: True expected at offset %td",
1413 : j - string_start);
1414 3 : return idx;
1415 2556250 : case 'f':
1416 2556250 : if (strncmp("false", j, 5) == 0) {
1417 2556248 : *next = j + 5;
1418 2556248 : jt->elm[idx].kind = JSON_NUMBER;
1419 2556248 : jt->elm[idx].value = j;
1420 2556248 : jt->elm[idx].valuelen = 5;
1421 2556248 : return idx;
1422 : }
1423 2 : jt->error = createException(MAL, "json.parser",
1424 : "JSON syntax error: False expected at offset %td",
1425 : j - string_start);
1426 2 : return idx;
1427 5614028 : default:
1428 5614028 : if (*j == '-' || isdigit((unsigned char) *j)) {
1429 5613952 : jt->elm[idx].value = j;
1430 5613952 : msg = JSONnumberParser(j, next);
1431 5613953 : if (msg)
1432 6 : jt->error = msg;
1433 5613953 : jt->elm[idx].kind = JSON_NUMBER;
1434 5613953 : jt->elm[idx].valuelen = *next - jt->elm[idx].value;
1435 5613953 : return idx;
1436 : }
1437 76 : jt->error = createException(MAL, "json.parser",
1438 : "JSON syntax error: value expected at offset %td",
1439 : j - string_start);
1440 76 : return idx;
1441 : }
1442 : }
1443 :
1444 :
1445 : JSON *
1446 2181400 : JSONparse(const char *j)
1447 : {
1448 2181400 : JSON *jt = JSONnewtree();
1449 :
1450 2181404 : if (jt == NULL)
1451 : return NULL;
1452 2181412 : skipblancs(j);
1453 2181404 : JSONtoken(jt, j, &j);
1454 2181402 : if (jt->error)
1455 : return jt;
1456 2181226 : skipblancs(j);
1457 2181190 : if (*j)
1458 28 : jt->error = createException(MAL, "json.parser",
1459 : "JSON syntax error: json parse failed");
1460 : return jt;
1461 : }
1462 :
1463 : static str
1464 9 : JSONlength(int *ret, const json *j)
1465 : {
1466 9 : int i, cnt = 0;
1467 9 : JSON *jt;
1468 :
1469 9 : if (strNil(*j)) {
1470 0 : *ret = int_nil;
1471 0 : return MAL_SUCCEED;
1472 : }
1473 :
1474 9 : jt = JSONparse(*j);
1475 9 : CHECK_JSON(jt);
1476 26 : for (i = jt->elm[0].next; i; i = jt->elm[i].next)
1477 17 : cnt++;
1478 9 : *ret = cnt;
1479 9 : JSONfree(jt);
1480 9 : return MAL_SUCCEED;
1481 : }
1482 :
1483 : static str
1484 17 : JSONfilterArrayDefault(json *ret, const json *js, lng index, const char *other)
1485 : {
1486 17 : char expr[BUFSIZ], *s = expr;
1487 :
1488 17 : if (index < 0)
1489 0 : throw(MAL, "json.filter",
1490 : SQLSTATE(42000) "Filter index cannot be negative");
1491 17 : snprintf(expr, BUFSIZ, "[" LLFMT "]", index);
1492 17 : return JSONfilterInternal(ret, js, &(const char *){s}, other);
1493 : }
1494 :
1495 : static str
1496 4 : JSONfilterArray_bte(json *ret, const json *js, const bte *index)
1497 : {
1498 8 : if (strNil(*js) || is_bte_nil(*index)) {
1499 0 : if (!(*ret = GDKstrdup(str_nil)))
1500 0 : throw(MAL, "json.filter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1501 : return MAL_SUCCEED;
1502 : }
1503 4 : return JSONfilterArrayDefault(ret, js, (lng) *index, 0);
1504 : }
1505 :
1506 : static str
1507 0 : JSONfilterArrayDefault_bte(json *ret, const json *js, const bte *index, const char *const *other)
1508 : {
1509 0 : if (strNil(*js) || is_bte_nil(*index) || strNil(*other)) {
1510 0 : if (!(*ret = GDKstrdup(str_nil)))
1511 0 : throw(MAL, "json.filter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1512 : return MAL_SUCCEED;
1513 : }
1514 0 : return JSONfilterArrayDefault(ret, js, (lng) *index, *other);
1515 : }
1516 :
1517 : static str
1518 0 : JSONfilterArray_sht(json *ret, const json *js, const sht *index)
1519 : {
1520 0 : if (strNil(*js) || is_sht_nil(*index)) {
1521 0 : if (!(*ret = GDKstrdup(str_nil)))
1522 0 : throw(MAL, "json.filter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1523 : return MAL_SUCCEED;
1524 : }
1525 0 : return JSONfilterArrayDefault(ret, js, (lng) *index, 0);
1526 : }
1527 :
1528 : static str
1529 0 : JSONfilterArrayDefault_sht(json *ret, const json *js, const sht *index, const char *const *other)
1530 : {
1531 0 : if (strNil(*js) || is_sht_nil(*index) || strNil(*other)) {
1532 0 : if (!(*ret = GDKstrdup(str_nil)))
1533 0 : throw(MAL, "json.filter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1534 : return MAL_SUCCEED;
1535 : }
1536 0 : return JSONfilterArrayDefault(ret, js, (lng) *index, *other);
1537 : }
1538 :
1539 : static str
1540 13 : JSONfilterArray_int(json *ret, const json *js, const int *index)
1541 : {
1542 26 : if (strNil(*js) || is_int_nil(*index)) {
1543 0 : if (!(*ret = GDKstrdup(str_nil)))
1544 0 : throw(MAL, "json.filter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1545 : return MAL_SUCCEED;
1546 : }
1547 13 : return JSONfilterArrayDefault(ret, js, (lng) *index, 0);
1548 : }
1549 :
1550 : static str
1551 0 : JSONfilterArrayDefault_int(json *ret, const json *js, const int *index, const char *const *other)
1552 : {
1553 0 : if (strNil(*js) || is_int_nil(*index) || strNil(*other)) {
1554 0 : if (!(*ret = GDKstrdup(str_nil)))
1555 0 : throw(MAL, "json.filter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1556 : return MAL_SUCCEED;
1557 : }
1558 0 : return JSONfilterArrayDefault(ret, js, (lng) *index, *other);
1559 : }
1560 :
1561 : static str
1562 0 : JSONfilterArray_lng(json *ret, const json *js, const lng *index)
1563 : {
1564 0 : if (strNil(*js) || is_lng_nil(*index)) {
1565 0 : if (!(*ret = GDKstrdup(str_nil)))
1566 0 : throw(MAL, "json.filter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1567 : return MAL_SUCCEED;
1568 : }
1569 0 : return JSONfilterArrayDefault(ret, js, (lng) *index, 0);
1570 : }
1571 :
1572 : static str
1573 0 : JSONfilterArrayDefault_lng(json *ret, const json *js, const lng *index, const char *const *other)
1574 : {
1575 0 : if (strNil(*js) || is_lng_nil(*index) || strNil(*other)) {
1576 0 : if (!(*ret = GDKstrdup(str_nil)))
1577 0 : throw(MAL, "json.filter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1578 : return MAL_SUCCEED;
1579 : }
1580 0 : return JSONfilterArrayDefault(ret, js, (lng) *index, *other);
1581 : }
1582 :
1583 : #ifdef HAVE_HGE
1584 : static str
1585 0 : JSONfilterArray_hge(json *ret, const json *js, const hge *index)
1586 : {
1587 0 : if (strNil(*js) || is_hge_nil(*index)) {
1588 0 : if (!(*ret = GDKstrdup(str_nil)))
1589 0 : throw(MAL, "json.filter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1590 : return MAL_SUCCEED;
1591 : }
1592 0 : if (*index < (hge) GDK_lng_min || *index > (hge) GDK_lng_max)
1593 0 : throw(MAL, "json.filter", "index out of range");
1594 0 : return JSONfilterArrayDefault(ret, js, (lng) *index, 0);
1595 : }
1596 :
1597 : static str
1598 0 : JSONfilterArrayDefault_hge(json *ret, const json *js, const hge *index, const char *const *other)
1599 : {
1600 0 : if (strNil(*js) || is_hge_nil(*index) || strNil(*other)) {
1601 0 : if (!(*ret = GDKstrdup(str_nil)))
1602 0 : throw(MAL, "json.filter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1603 : return MAL_SUCCEED;
1604 : }
1605 0 : if (*index < (hge) GDK_lng_min || *index > (hge) GDK_lng_max)
1606 0 : throw(MAL, "json.filter", "index out of range");
1607 0 : return JSONfilterArrayDefault(ret, js, (lng) *index, *other);
1608 : }
1609 : #endif
1610 :
1611 : static str
1612 402 : JSONfilter(json *ret, const json *js, const char *const *expr)
1613 : {
1614 804 : if (strNil(*js) || strNil(*expr)) {
1615 0 : if (!(*ret = GDKstrdup(str_nil)))
1616 0 : throw(MAL, "json.filter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1617 : return MAL_SUCCEED;
1618 : }
1619 402 : return JSONfilterInternal(ret, js, expr, 0);
1620 : }
1621 :
1622 : // glue all values together with an optional separator
1623 : // The json string should be valid
1624 :
1625 : static str
1626 235 : JSONplaintext(char **r, size_t *l, size_t *ilen, const JSON *jt, int idx, const char *sep,
1627 : size_t sep_len)
1628 : {
1629 235 : int i;
1630 235 : size_t j, next_len, next_concat_len;
1631 235 : unsigned int u;
1632 235 : str msg = MAL_SUCCEED;
1633 :
1634 235 : if (THRhighwater()) {
1635 0 : *r = *r - (*ilen - *l);
1636 0 : throw(MAL, "JSONplaintext",
1637 : SQLSTATE(42000) "Expression too complex to parse");
1638 : }
1639 :
1640 235 : switch (jt->elm[idx].kind) {
1641 30 : case JSON_OBJECT:
1642 86 : for (i = jt->elm[idx].next; i; i = jt->elm[i].next)
1643 56 : if (jt->elm[i].child
1644 56 : && (msg = JSONplaintext(r, l, ilen, jt, jt->elm[i].child, sep,
1645 : sep_len)))
1646 0 : return msg;
1647 : break;
1648 33 : case JSON_ARRAY:
1649 104 : for (i = jt->elm[idx].next; i; i = jt->elm[i].next)
1650 71 : if ((msg = JSONplaintext(r, l, ilen, jt, i, sep, sep_len)))
1651 0 : return msg;
1652 : break;
1653 3 : case JSON_ELEMENT:
1654 : case JSON_VALUE:
1655 3 : if (jt->elm[idx].child
1656 3 : && (msg = JSONplaintext(r, l, ilen, jt, jt->elm[idx].child, sep,
1657 : sep_len)))
1658 : return msg;
1659 : break;
1660 93 : case JSON_STRING:
1661 : // Make sure there is enough space for the value plus the separator plus the NULL byte
1662 93 : next_len = jt->elm[idx].valuelen;
1663 93 : next_concat_len = next_len - 2 + sep_len + 1;
1664 93 : if (*l < next_concat_len) {
1665 1 : size_t prev_ilen = *ilen, prev_l = *l;
1666 1 : char *p = *r - (prev_ilen - prev_l), *nr;
1667 :
1668 1 : *ilen = (prev_ilen * 2) + next_concat_len; /* make sure sep_len + 1 is always included */
1669 1 : if (!(nr = GDKrealloc(p, *ilen))) {
1670 0 : *r = p;
1671 0 : throw(MAL, "JSONplaintext", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1672 : }
1673 1 : *r = nr + (prev_ilen - prev_l);
1674 1 : *l = *ilen - prev_ilen + prev_l;
1675 : }
1676 93 : assert(next_len >= 2);
1677 93 : next_len--;
1678 869 : for (j = 1; j < next_len; j++) {
1679 776 : if (jt->elm[idx].value[j] == '\\') {
1680 8 : switch (jt->elm[idx].value[++j]) {
1681 4 : case '"':
1682 : case '\\':
1683 : case '/':
1684 4 : *(*r)++ = jt->elm[idx].value[j];
1685 4 : (*l)--;
1686 4 : break;
1687 0 : case 'b':
1688 0 : *(*r)++ = '\b';
1689 0 : (*l)--;
1690 0 : break;
1691 0 : case 'f':
1692 0 : *(*r)++ = '\f';
1693 0 : (*l)--;
1694 0 : break;
1695 0 : case 'r':
1696 0 : *(*r)++ = '\r';
1697 0 : (*l)--;
1698 0 : break;
1699 0 : case 'n':
1700 0 : *(*r)++ = '\n';
1701 0 : (*l)--;
1702 0 : break;
1703 0 : case 't':
1704 0 : *(*r)++ = '\t';
1705 0 : (*l)--;
1706 0 : break;
1707 : case 'u':
1708 : u = 0;
1709 20 : for (int i = 0; i < 4; i++) {
1710 16 : char c = jt->elm[idx].value[++j];
1711 16 : u <<= 4;
1712 16 : if ('0' <= c && c <= '9')
1713 9 : u |= c - '0';
1714 7 : else if ('a' <= c && c <= 'f')
1715 0 : u |= c - 'a' + 10;
1716 : else /* if ('A' <= c && c <= 'F') */
1717 7 : u |= c - 'A' + 10;
1718 : }
1719 4 : if (u <= 0x7F) {
1720 0 : *(*r)++ = (char) u;
1721 0 : (*l)--;
1722 4 : } else if (u <= 0x7FF) {
1723 1 : *(*r)++ = 0xC0 | (u >> 6);
1724 1 : *(*r)++ = 0x80 | (u & 0x3F);
1725 1 : (*l) -= 2;
1726 3 : } else if ((u & 0xFC00) == 0xD800) {
1727 : /* high surrogate; must be followed by low surrogate */
1728 1 : *(*r)++ = 0xF0 | (((u & 0x03C0) + 0x0040) >> 8);
1729 1 : *(*r)++ = 0x80 | ((((u & 0x3FF) + 0x0040) >> 2) & 0x3F);
1730 1 : **r = 0x80 | ((u & 0x0003) << 4); /* no increment */
1731 1 : (*l) -= 2;
1732 2 : } else if ((u & 0xFC00) == 0xDC00) {
1733 : /* low surrogate; must follow high surrogate */
1734 1 : *(*r)++ |= (u & 0x03C0) >> 6; /* amend last value */
1735 1 : *(*r)++ = 0x80 | (u & 0x3F);
1736 1 : (*l) -= 2;
1737 : } else { /* if (u <= 0xFFFF) */
1738 1 : *(*r)++ = 0xE0 | (u >> 12);
1739 1 : *(*r)++ = 0x80 | ((u >> 6) & 0x3F);
1740 1 : *(*r)++ = 0x80 | (u & 0x3F);
1741 1 : (*l) -= 3;
1742 : }
1743 : }
1744 : } else {
1745 768 : *(*r)++ = jt->elm[idx].value[j];
1746 768 : (*l)--;
1747 : }
1748 : }
1749 93 : memcpy(*r, sep, sep_len);
1750 93 : *l -= sep_len;
1751 93 : *r += sep_len;
1752 93 : break;
1753 76 : default:
1754 76 : next_len = jt->elm[idx].valuelen;
1755 76 : next_concat_len = next_len + sep_len + 1;
1756 76 : if (*l < next_concat_len) {
1757 21 : size_t prev_ilen = *ilen, prev_l = *l;
1758 21 : char *p = *r - (prev_ilen - prev_l), *nr;
1759 :
1760 21 : *ilen = (prev_ilen * 2) + next_concat_len; /* make sure sep_len + 1 is always included */
1761 21 : if (!(nr = GDKrealloc(p, *ilen))) {
1762 0 : *r = p;
1763 0 : throw(MAL, "JSONplaintext", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1764 : }
1765 21 : *r = nr + (prev_ilen - prev_l);
1766 21 : *l = *ilen - prev_ilen + prev_l;
1767 : }
1768 76 : memcpy(*r, jt->elm[idx].value, next_len);
1769 76 : *l -= next_len;
1770 76 : *r += next_len;
1771 76 : memcpy(*r, sep, sep_len);
1772 76 : *l -= sep_len;
1773 76 : *r += sep_len;
1774 : }
1775 235 : assert(*l > 0);
1776 235 : **r = 0;
1777 235 : return MAL_SUCCEED;
1778 : }
1779 :
1780 : static str
1781 107 : JSONjson2textSeparator(str *ret, const json *js, const char *const *sep)
1782 : {
1783 107 : size_t l, ilen, sep_len;
1784 107 : str s, msg;
1785 107 : JSON *jt;
1786 :
1787 213 : if (strNil(*js) || strNil(*sep)) {
1788 2 : if (!(*ret = GDKstrdup(str_nil)))
1789 0 : throw(MAL, "json2txt", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1790 : return MAL_SUCCEED;
1791 : }
1792 :
1793 105 : jt = JSONparse(*js);
1794 107 : CHECK_JSON(jt);
1795 107 : sep_len = strlen(*sep);
1796 107 : ilen = l = strlen(*js) + 1;
1797 107 : if (!(s = GDKmalloc(l))) {
1798 0 : JSONfree(jt);
1799 0 : throw(MAL, "json2txt", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1800 : }
1801 106 : msg = JSONplaintext(&s, &l, &ilen, jt, 0, *sep, sep_len);
1802 105 : JSONfree(jt);
1803 106 : if (msg) {
1804 0 : GDKfree(s);
1805 0 : return msg;
1806 : }
1807 106 : s -= ilen - l;
1808 106 : l = strlen(s);
1809 106 : if (l && sep_len)
1810 91 : s[l - sep_len] = 0;
1811 106 : *ret = s;
1812 106 : return MAL_SUCCEED;
1813 : }
1814 :
1815 : static str
1816 90 : JSONjson2text(str *ret, const json *js)
1817 : {
1818 90 : const char *sep = " ";
1819 90 : return JSONjson2textSeparator(ret, js, &sep);
1820 : }
1821 :
1822 : static str
1823 107 : JSONjson2numberInternal(void **ret, const json *js,
1824 : void (*str2num)(void **ret, const char *nptr,
1825 : size_t len))
1826 : {
1827 107 : JSON *jt;
1828 :
1829 107 : jt = JSONparse(*js);
1830 108 : CHECK_JSON(jt);
1831 108 : switch (jt->elm[0].kind) {
1832 90 : case JSON_NUMBER:
1833 90 : str2num(ret, jt->elm[0].value, jt->elm[0].valuelen);
1834 90 : break;
1835 8 : case JSON_ARRAY:
1836 8 : if (jt->free == 2) {
1837 6 : str2num(ret, jt->elm[1].value, jt->elm[1].valuelen);
1838 : } else {
1839 2 : *ret = NULL;
1840 : }
1841 : break;
1842 6 : case JSON_OBJECT:
1843 6 : if (jt->free == 3) {
1844 4 : str2num(ret, jt->elm[2].value, jt->elm[2].valuelen);
1845 : } else {
1846 2 : *ret = NULL;
1847 : }
1848 : break;
1849 4 : default:
1850 4 : *ret = NULL;
1851 : }
1852 107 : JSONfree(jt);
1853 :
1854 107 : return MAL_SUCCEED;
1855 : }
1856 :
1857 : static void
1858 72 : strtod_wrapper(void **ret, const char *nptr, size_t len)
1859 : {
1860 72 : char *rest;
1861 72 : dbl val;
1862 :
1863 72 : val = strtod(nptr, &rest);
1864 74 : if (rest && (size_t) (rest - nptr) != len) {
1865 0 : *ret = NULL;
1866 : } else {
1867 74 : **(dbl **) ret = val;
1868 : }
1869 74 : }
1870 :
1871 : static void
1872 26 : strtol_wrapper(void **ret, const char *nptr, size_t len)
1873 : {
1874 26 : char *rest;
1875 26 : lng val;
1876 :
1877 26 : val = strtol(nptr, &rest, 0);
1878 26 : if (rest && (size_t) (rest - nptr) != len) {
1879 2 : *ret = NULL;
1880 : } else {
1881 24 : **(lng **) ret = val;
1882 : }
1883 26 : }
1884 :
1885 : static str
1886 78 : JSONjson2number(dbl *ret, const json *js)
1887 : {
1888 78 : dbl val = 0;
1889 78 : dbl *val_ptr = &val;
1890 78 : str tmp;
1891 :
1892 78 : if (strNil(*js)) {
1893 0 : *ret = dbl_nil;
1894 0 : return MAL_SUCCEED;
1895 : }
1896 :
1897 78 : rethrow(__func__, tmp,
1898 : JSONjson2numberInternal((void **) &val_ptr, js, strtod_wrapper));
1899 78 : if (val_ptr == NULL)
1900 5 : *ret = dbl_nil;
1901 : else
1902 73 : *ret = val;
1903 :
1904 : return MAL_SUCCEED;
1905 : }
1906 :
1907 : static str
1908 29 : JSONjson2integer(lng *ret, const json *js)
1909 : {
1910 29 : lng val = 0;
1911 29 : lng *val_ptr = &val;
1912 29 : str tmp;
1913 :
1914 29 : if (strNil(*js)) {
1915 0 : *ret = lng_nil;
1916 0 : return MAL_SUCCEED;
1917 : }
1918 :
1919 29 : rethrow(__func__, tmp,
1920 : JSONjson2numberInternal((void **) &val_ptr, js, strtol_wrapper));
1921 29 : if (val_ptr == NULL)
1922 5 : *ret = lng_nil;
1923 : else
1924 24 : *ret = val;
1925 :
1926 : return MAL_SUCCEED;
1927 : }
1928 :
1929 : static str
1930 8 : JSONunfoldContainer(JSON *jt, int idx, BAT *bo, BAT *bk, BAT *bv, oid *o)
1931 : {
1932 8 : int i, last;
1933 8 : char *r;
1934 :
1935 8 : last = jt->elm[idx].tail;
1936 8 : if (jt->elm[idx].kind == JSON_OBJECT) {
1937 8 : for (i = jt->elm[idx].next; i; i = jt->elm[i].next) {
1938 8 : if ((r = JSONgetValue(jt, i)) == NULL)
1939 0 : goto memfail;
1940 8 : if (BUNappend(bk, r, false) != GDK_SUCCEED) {
1941 0 : GDKfree(r);
1942 0 : goto memfail;
1943 : }
1944 8 : GDKfree(r);
1945 8 : if ((r = JSONgetValue(jt, jt->elm[i].child)) == NULL)
1946 0 : goto memfail;
1947 8 : if (BUNappend(bv, r, false) != GDK_SUCCEED) {
1948 0 : GDKfree(r);
1949 0 : goto memfail;
1950 : }
1951 8 : GDKfree(r);
1952 8 : if (bo) {
1953 4 : if (BUNappend(bo, o, false) != GDK_SUCCEED)
1954 0 : goto memfail;
1955 : }
1956 8 : (*o)++;
1957 8 : if (i == last)
1958 : break;
1959 : }
1960 6 : } else if (jt->elm[idx].kind == JSON_ARRAY) {
1961 26 : for (i = jt->elm[idx].next; i; i = jt->elm[i].next) {
1962 26 : if (BUNappend(bk, str_nil, false) != GDK_SUCCEED)
1963 0 : goto memfail;
1964 26 : if (jt->elm[i].kind == JSON_VALUE)
1965 22 : r = JSONgetValue(jt, jt->elm[i].child);
1966 : else
1967 4 : r = JSONgetValue(jt, i);
1968 26 : if (r == NULL)
1969 0 : goto memfail;
1970 26 : if (BUNappend(bv, r, false) != GDK_SUCCEED) {
1971 0 : GDKfree(r);
1972 0 : goto memfail;
1973 : }
1974 26 : GDKfree(r);
1975 26 : if (bo) {
1976 13 : if (BUNappend(bo, o, false) != GDK_SUCCEED)
1977 0 : goto memfail;
1978 : }
1979 26 : (*o)++;
1980 26 : if (i == last)
1981 : break;
1982 : }
1983 : }
1984 : return MAL_SUCCEED;
1985 :
1986 0 : memfail:
1987 0 : throw(MAL, "json.unfold", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1988 : }
1989 :
1990 : static str
1991 8 : JSONunfoldInternal(bat *od, bat *key, bat *val, const json *js)
1992 : {
1993 8 : BAT *bo = NULL, *bk, *bv;
1994 8 : oid o = 0;
1995 8 : str msg = MAL_SUCCEED;
1996 :
1997 8 : JSON *jt = JSONparse(*js);
1998 :
1999 8 : CHECK_JSON(jt);
2000 8 : bk = COLnew(0, TYPE_str, 64, TRANSIENT);
2001 8 : if (bk == NULL) {
2002 0 : JSONfree(jt);
2003 0 : throw(MAL, "json.unfold", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2004 : }
2005 :
2006 8 : if (od) {
2007 4 : bo = COLnew(0, TYPE_oid, 64, TRANSIENT);
2008 4 : if (bo == NULL) {
2009 0 : BBPreclaim(bk);
2010 0 : JSONfree(jt);
2011 0 : throw(MAL, "json.unfold", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2012 : }
2013 : }
2014 :
2015 8 : bv = COLnew(0, TYPE_json, 64, TRANSIENT);
2016 8 : if (bv == NULL) {
2017 0 : JSONfree(jt);
2018 0 : BBPreclaim(bo);
2019 0 : BBPreclaim(bk);
2020 0 : throw(MAL, "json.unfold", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2021 : }
2022 :
2023 8 : if (jt->elm[0].kind == JSON_ARRAY || jt->elm[0].kind == JSON_OBJECT)
2024 12 : msg = JSONunfoldContainer(jt, 0, (od ? bo : 0), bk, bv, &o);
2025 : else
2026 0 : msg = createException(MAL, "json.unfold",
2027 : "JSON object or array expected");
2028 8 : JSONfree(jt);
2029 8 : if (msg) {
2030 0 : BBPreclaim(bk);
2031 0 : BBPreclaim(bo);
2032 0 : BBPreclaim(bv);
2033 : } else {
2034 8 : *key = bk->batCacheid;
2035 8 : BBPkeepref(bk);
2036 8 : *val = bv->batCacheid;
2037 8 : BBPkeepref(bv);
2038 8 : if (od) {
2039 4 : *od = bo->batCacheid;
2040 4 : BBPkeepref(bo);
2041 : }
2042 : }
2043 : return msg;
2044 : }
2045 :
2046 :
2047 :
2048 : static str
2049 6 : JSONkeyTable(bat *ret, const json *js)
2050 : {
2051 6 : BAT *bn;
2052 6 : char *r;
2053 6 : int i;
2054 6 : JSON *jt;
2055 :
2056 6 : jt = JSONparse(*js); // already validated
2057 6 : CHECK_JSON(jt);
2058 6 : bn = COLnew(0, TYPE_str, 64, TRANSIENT);
2059 6 : if (bn == NULL) {
2060 0 : JSONfree(jt);
2061 0 : throw(MAL, "json.keys", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2062 : }
2063 :
2064 20 : for (i = jt->elm[0].next; i; i = jt->elm[i].next) {
2065 14 : r = JSONgetValue(jt, i);
2066 14 : if (r == NULL || BUNappend(bn, r, false) != GDK_SUCCEED) {
2067 0 : GDKfree(r);
2068 0 : JSONfree(jt);
2069 0 : BBPreclaim(bn);
2070 0 : throw(MAL, "json.keys", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2071 : }
2072 14 : GDKfree(r);
2073 : }
2074 6 : JSONfree(jt);
2075 6 : *ret = bn->batCacheid;
2076 6 : BBPkeepref(bn);
2077 6 : return MAL_SUCCEED;
2078 : }
2079 :
2080 : static str
2081 7 : JSONkeyArray(json *ret, const json *js)
2082 : {
2083 7 : char *result = NULL;
2084 7 : str r;
2085 7 : int i;
2086 7 : JSON *jt;
2087 :
2088 7 : if (strNil(*js)) {
2089 0 : if (!(*ret = GDKstrdup(str_nil)))
2090 0 : throw(MAL, "json.keyarray", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2091 : return MAL_SUCCEED;
2092 : }
2093 :
2094 7 : jt = JSONparse(*js); // already validated
2095 :
2096 7 : CHECK_JSON(jt);
2097 7 : if (jt->elm[0].kind == JSON_OBJECT) {
2098 27 : for (i = jt->elm[0].next; i; i = jt->elm[i].next) {
2099 20 : if (jt->elm[i].valuelen) {
2100 18 : r = GDKmalloc(jt->elm[i].valuelen + 3);
2101 18 : if (r == NULL) {
2102 0 : JSONfree(jt);
2103 0 : goto memfail;
2104 : }
2105 18 : strcpy_len(r, jt->elm[i].value - 1, jt->elm[i].valuelen + 3);
2106 : } else {
2107 2 : r = GDKstrdup("\"\"");
2108 2 : if (r == NULL) {
2109 0 : JSONfree(jt);
2110 0 : goto memfail;
2111 : }
2112 : }
2113 20 : result = JSONglue(result, r, ',');
2114 20 : if (result == NULL) {
2115 0 : JSONfree(jt);
2116 0 : goto memfail;
2117 : }
2118 : }
2119 7 : JSONfree(jt);
2120 : } else {
2121 0 : JSONfree(jt);
2122 0 : throw(MAL, "json.keyarray", "Object expected");
2123 : }
2124 7 : r = GDKstrdup("[");
2125 7 : if (r == NULL)
2126 0 : goto memfail;
2127 7 : result = JSONglue(r, result, 0);
2128 7 : if (result == NULL)
2129 0 : goto memfail;
2130 7 : r = GDKstrdup("]");
2131 7 : if (r == NULL)
2132 0 : goto memfail;
2133 7 : result = JSONglue(result, r, 0);
2134 7 : if (result == NULL)
2135 0 : goto memfail;
2136 7 : *ret = result;
2137 7 : return MAL_SUCCEED;
2138 :
2139 0 : memfail:
2140 0 : GDKfree(result);
2141 0 : throw(MAL, "json.keyarray", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2142 : }
2143 :
2144 :
2145 : static str
2146 10 : JSONvalueTable(bat *ret, const json *js)
2147 : {
2148 10 : BAT *bn;
2149 10 : char *r;
2150 10 : int i;
2151 10 : JSON *jt;
2152 :
2153 10 : jt = JSONparse(*js); // already validated
2154 10 : CHECK_JSON(jt);
2155 10 : bn = COLnew(0, TYPE_json, 64, TRANSIENT);
2156 10 : if (bn == NULL) {
2157 0 : JSONfree(jt);
2158 0 : throw(MAL, "json.values", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2159 : }
2160 :
2161 34 : for (i = jt->elm[0].next; i; i = jt->elm[i].next) {
2162 24 : if (jt->elm[i].kind == JSON_ELEMENT)
2163 14 : r = JSONgetValue(jt, jt->elm[i].child);
2164 : else
2165 10 : r = JSONgetValue(jt, i);
2166 24 : if (r == NULL || BUNappend(bn, r, false) != GDK_SUCCEED) {
2167 0 : GDKfree(r);
2168 0 : BBPreclaim(bn);
2169 0 : JSONfree(jt);
2170 0 : throw(MAL, "json.values", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2171 : }
2172 24 : GDKfree(r);
2173 : }
2174 10 : JSONfree(jt);
2175 10 : *ret = bn->batCacheid;
2176 10 : BBPkeepref(bn);
2177 10 : return MAL_SUCCEED;
2178 : }
2179 :
2180 : static str
2181 4 : JSONvalueArray(json *ret, const json *js)
2182 : {
2183 4 : char *result = NULL;
2184 4 : str r;
2185 4 : int i;
2186 4 : JSON *jt;
2187 :
2188 4 : if (strNil(*js)) {
2189 0 : if (!(*ret = GDKstrdup(str_nil)))
2190 0 : throw(MAL, "json.valuearray", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2191 : return MAL_SUCCEED;
2192 : }
2193 :
2194 4 : jt = JSONparse(*js); // already validated
2195 :
2196 4 : CHECK_JSON(jt);
2197 4 : if (jt->elm[0].kind == JSON_OBJECT) {
2198 21 : for (i = jt->elm[0].next; i; i = jt->elm[i].next) {
2199 17 : r = JSONgetValue(jt, jt->elm[i].child);
2200 17 : if (r == NULL) {
2201 0 : JSONfree(jt);
2202 0 : goto memfail;
2203 : }
2204 17 : result = JSONglue(result, r, ',');
2205 17 : if (result == NULL) {
2206 0 : JSONfree(jt);
2207 0 : goto memfail;
2208 : }
2209 : }
2210 4 : JSONfree(jt);
2211 : } else {
2212 0 : JSONfree(jt);
2213 0 : throw(MAL, "json.valuearray", "Object expected");
2214 : }
2215 4 : r = GDKstrdup("[");
2216 4 : if (r == NULL)
2217 0 : goto memfail;
2218 4 : result = JSONglue(r, result, 0);
2219 4 : if (result == NULL)
2220 0 : goto memfail;
2221 4 : r = GDKstrdup("]");
2222 4 : if (r == NULL)
2223 0 : goto memfail;
2224 4 : result = JSONglue(result, r, 0);
2225 4 : if (result == NULL)
2226 0 : goto memfail;
2227 4 : *ret = result;
2228 4 : return MAL_SUCCEED;
2229 :
2230 0 : memfail:
2231 0 : GDKfree(result);
2232 0 : throw(MAL, "json.valuearray", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2233 : }
2234 :
2235 : static BAT **
2236 2 : JSONargumentlist(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2237 : {
2238 2 : int i, error = 0, bats = 0;
2239 2 : BUN cnt = 0;
2240 2 : BAT **bl;
2241 :
2242 2 : bl = GDKzalloc(sizeof(*bl) * pci->argc);
2243 2 : if (bl == NULL)
2244 : return NULL;
2245 11 : for (i = pci->retc; i < pci->argc; i++)
2246 9 : if (isaBatType(getArgType(mb, pci, i))) {
2247 6 : bats++;
2248 6 : bl[i] = BATdescriptor(stk->stk[getArg(pci, i)].val.bval);
2249 6 : if (bl[i] == NULL || (cnt > 0 && BATcount(bl[i]) != cnt)) {
2250 : error = 1;
2251 : break;
2252 : }
2253 6 : cnt = BATcount(bl[i]);
2254 : }
2255 2 : if (error || bats == 0) {
2256 0 : for (i = pci->retc; i < pci->argc; i++)
2257 0 : BBPreclaim(bl[i]);
2258 0 : GDKfree(bl);
2259 0 : return NULL;
2260 : }
2261 : return bl;
2262 : }
2263 :
2264 : static void
2265 2 : JSONfreeArgumentlist(BAT **bl, InstrPtr pci)
2266 : {
2267 2 : int i;
2268 :
2269 11 : for (i = pci->retc; i < pci->argc; i++)
2270 15 : BBPreclaim(bl[i]);
2271 2 : GDKfree(bl);
2272 2 : }
2273 :
2274 : static str
2275 3 : JSONrenderRowObject(BAT **bl, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
2276 : BUN idx)
2277 : {
2278 3 : int i, tpe;
2279 3 : char *row, *row2, *name = 0, *val = 0;
2280 3 : size_t len, lim, l;
2281 3 : void *p;
2282 3 : BATiter bi;
2283 :
2284 3 : row = GDKmalloc(lim = BUFSIZ);
2285 3 : if (row == NULL)
2286 : return NULL;
2287 3 : row[0] = '{';
2288 3 : row[1] = 0;
2289 3 : len = 1;
2290 12 : for (i = pci->retc; i < pci->argc; i += 2) {
2291 9 : name = stk->stk[getArg(pci, i)].val.sval;
2292 9 : tpe = getBatType(getArgType(mb, pci, i + 1));
2293 9 : bi = bat_iterator(bl[i + 1]);
2294 9 : p = BUNtail(bi, idx);
2295 9 : val = ATOMformat(tpe, p);
2296 9 : bat_iterator_end(&bi);
2297 9 : if (val == NULL) {
2298 0 : GDKfree(row);
2299 0 : return NULL;
2300 : }
2301 9 : if (strncmp(val, "nil", 3) == 0) {
2302 1 : GDKfree(val);
2303 1 : val = NULL;
2304 1 : l = 4;
2305 : } else {
2306 8 : l = strlen(val);
2307 : }
2308 9 : l += strlen(name) + 4;
2309 9 : while (l > lim - len)
2310 0 : lim += BUFSIZ;
2311 9 : row2 = GDKrealloc(row, lim);
2312 9 : if (row2 == NULL) {
2313 0 : GDKfree(row);
2314 0 : GDKfree(val);
2315 0 : return NULL;
2316 : }
2317 9 : row = row2;
2318 9 : snprintf(row + len, lim - len, "\"%s\":%s,", name, val ? val : "null");
2319 9 : len += l;
2320 9 : GDKfree(val);
2321 : }
2322 3 : if (row[1])
2323 3 : row[len - 1] = '}';
2324 : else {
2325 0 : row[1] = '}';
2326 0 : row[2] = 0;
2327 : }
2328 : return row;
2329 : }
2330 :
2331 : static str
2332 1 : JSONrenderobject(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2333 : {
2334 1 : BAT **bl;
2335 1 : char *result, *row;
2336 1 : int i;
2337 1 : size_t len, lim, l;
2338 1 : json *ret;
2339 1 : BUN j, cnt;
2340 :
2341 1 : (void) cntxt;
2342 1 : bl = JSONargumentlist(mb, stk, pci);
2343 1 : if (bl == 0)
2344 0 : throw(MAL, "json.renderobject", "Non-aligned BAT sizes");
2345 4 : for (i = pci->retc; i < pci->argc; i += 2) {
2346 3 : if (getArgType(mb, pci, i) != TYPE_str) {
2347 0 : JSONfreeArgumentlist(bl, pci);
2348 0 : throw(MAL, "json.renderobject", "Keys missing");
2349 : }
2350 : }
2351 :
2352 1 : cnt = BATcount(bl[pci->retc + 1]);
2353 1 : result = GDKmalloc(lim = BUFSIZ);
2354 1 : if (result == NULL) {
2355 0 : JSONfreeArgumentlist(bl, pci);
2356 0 : throw(MAL, "json.renderobject", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2357 : }
2358 1 : result[0] = '[';
2359 1 : result[1] = 0;
2360 1 : len = 1;
2361 :
2362 4 : for (j = 0; j < cnt; j++) {
2363 3 : char *result2;
2364 3 : row = JSONrenderRowObject(bl, mb, stk, pci, j);
2365 3 : if (row == NULL)
2366 0 : goto memfail;
2367 3 : l = strlen(row);
2368 6 : while (l + 2 > lim - len)
2369 0 : lim = cnt * l <= lim ? cnt * l : lim + BUFSIZ;
2370 3 : result2 = GDKrealloc(result, lim);
2371 3 : if (result2 == NULL)
2372 0 : goto memfail;
2373 3 : result = result2;
2374 3 : strcpy(result + len, row);
2375 3 : GDKfree(row);
2376 3 : len += l;
2377 3 : result[len++] = ',';
2378 3 : result[len] = 0;
2379 : }
2380 1 : result[len - 1] = ']';
2381 1 : ret = getArgReference_TYPE(stk, pci, 0, json);
2382 1 : *ret = result;
2383 1 : JSONfreeArgumentlist(bl, pci);
2384 1 : return MAL_SUCCEED;
2385 :
2386 0 : memfail:
2387 0 : GDKfree(result);
2388 0 : GDKfree(row);
2389 0 : JSONfreeArgumentlist(bl, pci);
2390 0 : throw(MAL, "json.renderobject", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2391 : }
2392 :
2393 : static str
2394 3 : JSONrenderRowArray(BAT **bl, MalBlkPtr mb, InstrPtr pci, BUN idx)
2395 : {
2396 3 : int i, tpe;
2397 3 : char *row, *row2, *val = 0;
2398 3 : size_t len, lim, l;
2399 3 : void *p;
2400 3 : BATiter bi;
2401 :
2402 3 : row = GDKmalloc(lim = BUFSIZ);
2403 3 : if (row == NULL)
2404 : return NULL;
2405 3 : row[0] = '[';
2406 3 : row[1] = 0;
2407 3 : len = 1;
2408 12 : for (i = pci->retc; i < pci->argc; i++) {
2409 9 : tpe = getBatType(getArgType(mb, pci, i));
2410 9 : bi = bat_iterator(bl[i]);
2411 9 : p = BUNtail(bi, idx);
2412 9 : val = ATOMformat(tpe, p);
2413 9 : bat_iterator_end(&bi);
2414 9 : if (val == NULL)
2415 0 : goto memfail;
2416 9 : if (strcmp(val, "nil") == 0) {
2417 1 : GDKfree(val);
2418 1 : val = NULL;
2419 1 : l = 4;
2420 : } else {
2421 8 : l = strlen(val);
2422 : }
2423 9 : while (len + l > lim)
2424 0 : lim += BUFSIZ;
2425 9 : row2 = GDKrealloc(row, lim);
2426 9 : if (row2 == NULL)
2427 0 : goto memfail;
2428 9 : row = row2;
2429 9 : snprintf(row + len, lim - len, "%s,", val ? val : "null");
2430 9 : len += l + 1;
2431 9 : GDKfree(val);
2432 9 : val = NULL;
2433 : }
2434 3 : if (row[1])
2435 3 : row[len - 1] = ']';
2436 : else {
2437 0 : row[1] = '}';
2438 0 : row[2] = 0;
2439 : }
2440 : return row;
2441 :
2442 0 : memfail:
2443 0 : GDKfree(row);
2444 0 : GDKfree(val);
2445 0 : return NULL;
2446 : }
2447 :
2448 : static str
2449 1 : JSONrenderarray(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2450 : {
2451 1 : BAT **bl;
2452 1 : char *result, *row;
2453 1 : size_t len, lim, l;
2454 1 : str *ret;
2455 1 : BUN j, cnt;
2456 :
2457 1 : (void) cntxt;
2458 1 : bl = JSONargumentlist(mb, stk, pci);
2459 1 : if (bl == 0)
2460 0 : throw(MAL, "json.renderrray", "Non-aligned BAT sizes");
2461 :
2462 1 : cnt = BATcount(bl[pci->retc + 1]);
2463 1 : result = GDKmalloc(lim = BUFSIZ);
2464 1 : if (result == NULL) {
2465 0 : goto memfail;
2466 : }
2467 1 : result[0] = '[';
2468 1 : result[1] = 0;
2469 1 : len = 1;
2470 :
2471 4 : for (j = 0; j < cnt; j++) {
2472 3 : char *result2;
2473 3 : row = JSONrenderRowArray(bl, mb, pci, j);
2474 3 : if (row == NULL) {
2475 0 : goto memfail;
2476 : }
2477 3 : l = strlen(row);
2478 6 : while (l + 2 > lim - len)
2479 0 : lim = cnt * l <= lim ? cnt * l : lim + BUFSIZ;
2480 3 : result2 = GDKrealloc(result, lim);
2481 3 : if (result2 == NULL) {
2482 0 : GDKfree(row);
2483 0 : goto memfail;
2484 : }
2485 3 : result = result2;
2486 3 : strcpy(result + len, row);
2487 3 : GDKfree(row);
2488 3 : len += l;
2489 3 : result[len++] = ',';
2490 3 : result[len] = 0;
2491 : }
2492 1 : result[len - 1] = ']';
2493 1 : ret = getArgReference_TYPE(stk, pci, 0, json);
2494 1 : *ret = result;
2495 1 : JSONfreeArgumentlist(bl, pci);
2496 1 : return MAL_SUCCEED;
2497 :
2498 0 : memfail:
2499 0 : GDKfree(result);
2500 0 : JSONfreeArgumentlist(bl, pci);
2501 0 : throw(MAL, "json.renderArray", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2502 : }
2503 :
2504 : static str
2505 7 : JSONfoldKeyValue(str *ret, const bat *id, const bat *key, const bat *values)
2506 : {
2507 7 : BAT *bo = 0, *bk = 0, *bv;
2508 7 : BATiter bki, bvi;
2509 7 : int tpe;
2510 7 : char *row, *val = 0, *nme = 0;
2511 7 : BUN i, cnt;
2512 7 : size_t len, lim, l;
2513 7 : void *p;
2514 7 : oid o = 0;
2515 :
2516 7 : if (key) {
2517 6 : bk = BATdescriptor(*key);
2518 6 : if (bk == NULL) {
2519 0 : throw(MAL, "json.fold", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2520 : }
2521 : }
2522 :
2523 7 : bv = BATdescriptor(*values);
2524 7 : if (bv == NULL) {
2525 0 : BBPreclaim(bk);
2526 0 : throw(MAL, "json.fold", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2527 : }
2528 7 : tpe = bv->ttype;
2529 7 : cnt = BATcount(bv);
2530 7 : if (id) {
2531 3 : bo = BATdescriptor(*id);
2532 3 : if (bo == NULL) {
2533 0 : BBPreclaim(bk);
2534 0 : BBPunfix(bv->batCacheid);
2535 0 : throw(MAL, "json.nest", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2536 : }
2537 : }
2538 :
2539 7 : row = GDKmalloc(lim = BUFSIZ);
2540 7 : if (row == NULL) {
2541 0 : goto memfail;
2542 : }
2543 7 : row[0] = '[';
2544 7 : row[1] = 0;
2545 7 : len = 1;
2546 7 : if (id) {
2547 3 : o = BUNtoid(bo, 0);
2548 : }
2549 :
2550 7 : bki = bat_iterator(bk);
2551 7 : bvi = bat_iterator(bv);
2552 46 : for (i = 0; i < cnt; i++) {
2553 32 : if (id && bk) {
2554 15 : if (BUNtoid(bo, i) != o) {
2555 9 : snprintf(row + len, lim - len, ", ");
2556 9 : len += 2;
2557 9 : o = BUNtoid(bo, i);
2558 : }
2559 : }
2560 :
2561 32 : if (bk) {
2562 29 : nme = (str) BUNtvar(bki, i);
2563 29 : l = strlen(nme);
2564 29 : while (l + 3 > lim - len)
2565 0 : lim = (lim / (i + 1)) * cnt + BUFSIZ + l + 3;
2566 29 : p = GDKrealloc(row, lim);
2567 29 : if (p == NULL) {
2568 0 : bat_iterator_end(&bki);
2569 0 : bat_iterator_end(&bvi);
2570 0 : goto memfail;
2571 : }
2572 29 : row = p;
2573 58 : if (!strNil(nme)) {
2574 14 : snprintf(row + len, lim - len, "\"%s\":", nme);
2575 14 : len += l + 3;
2576 : }
2577 : }
2578 :
2579 32 : p = BUNtail(bvi, i);
2580 32 : if (tpe == TYPE_json)
2581 : val = p;
2582 : else {
2583 9 : if ((val = ATOMformat(tpe, p)) == NULL) {
2584 0 : bat_iterator_end(&bki);
2585 0 : bat_iterator_end(&bvi);
2586 0 : goto memfail;
2587 : }
2588 9 : if (strcmp(val, "nil") == 0) {
2589 0 : GDKfree(val);
2590 0 : val = NULL;
2591 : }
2592 : }
2593 32 : l = val ? strlen(val) : 4;
2594 32 : while (l > lim - len)
2595 0 : lim = (lim / (i + 1)) * cnt + BUFSIZ + l + 3;
2596 32 : p = GDKrealloc(row, lim);
2597 32 : if (p == NULL) {
2598 0 : if (tpe != TYPE_json)
2599 0 : GDKfree(val);
2600 0 : bat_iterator_end(&bki);
2601 0 : bat_iterator_end(&bvi);
2602 0 : goto memfail;
2603 : }
2604 32 : row = p;
2605 32 : strncpy(row + len, val ? val : "null", l);
2606 32 : len += l;
2607 32 : row[len++] = ',';
2608 32 : row[len] = 0;
2609 32 : if (tpe != TYPE_json)
2610 9 : GDKfree(val);
2611 : }
2612 7 : bat_iterator_end(&bki);
2613 7 : bat_iterator_end(&bvi);
2614 7 : if (row[1]) {
2615 7 : row[len - 1] = ']';
2616 7 : row[len] = 0;
2617 : } else {
2618 0 : row[1] = ']';
2619 0 : row[2] = 0;
2620 : }
2621 7 : BBPreclaim(bo);
2622 7 : BBPreclaim(bk);
2623 7 : BBPunfix(bv->batCacheid);
2624 7 : *ret = row;
2625 7 : return MAL_SUCCEED;
2626 :
2627 0 : memfail:
2628 0 : GDKfree(row);
2629 0 : BBPreclaim(bo);
2630 0 : BBPreclaim(bk);
2631 0 : BBPunfix(bv->batCacheid);
2632 0 : throw(MAL, "json.fold", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2633 : }
2634 :
2635 : static str
2636 8 : JSONunfold(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2637 : {
2638 8 : bat *id = 0, *key = 0, *val = 0;
2639 8 : json *js;
2640 :
2641 8 : (void) cntxt;
2642 8 : (void) mb;
2643 :
2644 8 : switch (pci->retc) {
2645 4 : case 2:
2646 4 : key = getArgReference_bat(stk, pci, 0);
2647 4 : val = getArgReference_bat(stk, pci, 1);
2648 4 : break;
2649 4 : case 3:
2650 4 : id = getArgReference_bat(stk, pci, 0);
2651 4 : key = getArgReference_bat(stk, pci, 1);
2652 4 : val = getArgReference_bat(stk, pci, 2);
2653 4 : break;
2654 : default:
2655 0 : assert(0);
2656 : throw(MAL, "json.unfold", ILLEGAL_ARGUMENT);
2657 : }
2658 8 : js = getArgReference_TYPE(stk, pci, pci->retc, json);
2659 8 : return JSONunfoldInternal(id, key, val, js);
2660 : }
2661 :
2662 : static str
2663 7 : JSONfold(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2664 : {
2665 7 : bat *id = 0, *key = 0, *val = 0;
2666 7 : str *ret;
2667 :
2668 7 : (void) cntxt;
2669 7 : (void) mb;
2670 :
2671 7 : assert(pci->retc == 1);
2672 7 : switch (pci->argc - pci->retc) {
2673 1 : case 1:
2674 1 : val = getArgReference_bat(stk, pci, 1);
2675 1 : break;
2676 3 : case 2:
2677 3 : key = getArgReference_bat(stk, pci, 1);
2678 3 : val = getArgReference_bat(stk, pci, 2);
2679 3 : break;
2680 3 : case 3:
2681 3 : id = getArgReference_bat(stk, pci, 1);
2682 3 : key = getArgReference_bat(stk, pci, 2);
2683 3 : val = getArgReference_bat(stk, pci, 3);
2684 3 : break;
2685 : default:
2686 0 : assert(0);
2687 : throw(MAL, "json.fold", ILLEGAL_ARGUMENT);
2688 : }
2689 7 : ret = getArgReference_TYPE(stk, pci, 0, json);
2690 7 : return JSONfoldKeyValue(ret, id, key, val);
2691 : }
2692 :
2693 : #define JSON_STR_CPY \
2694 : do { \
2695 : for (; *v; v++) { \
2696 : switch (*v) { \
2697 : case '"': \
2698 : case '\\': \
2699 : *dst++ = '\\'; \
2700 : /* fall through */ \
2701 : default: \
2702 : *dst++ = *v; \
2703 : break; \
2704 : case '\n': \
2705 : *dst++ = '\\'; \
2706 : *dst++ = 'n'; \
2707 : break; \
2708 : } \
2709 : } \
2710 : } while (0)
2711 :
2712 : #define JSON_AGGR_CHECK_NEXT_LENGTH(CALC) \
2713 : do { \
2714 : len = CALC; \
2715 : if (len >= maxlen - buflen) { \
2716 : maxlen = maxlen + len + BUFSIZ; \
2717 : buf2 = GDKrealloc(buf, maxlen); \
2718 : if (buf2 == NULL) { \
2719 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL; \
2720 : goto bunins_failed; \
2721 : } \
2722 : buf = buf2; \
2723 : } \
2724 : } while (0)
2725 :
2726 : static str
2727 17 : JSONgroupStr(str *ret, const bat *bid)
2728 : {
2729 17 : BAT *b;
2730 17 : BUN p, q;
2731 17 : size_t len, maxlen = BUFSIZ, buflen = 0;
2732 17 : char *buf = GDKmalloc(maxlen), *buf2;
2733 17 : BATiter bi;
2734 17 : const char *err = NULL;
2735 17 : dbl *restrict vals;
2736 :
2737 17 : if (buf == NULL)
2738 0 : throw(MAL, "json.group", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2739 17 : if ((b = BATdescriptor(*bid)) == NULL) {
2740 0 : GDKfree(buf);
2741 0 : throw(MAL, "json.group", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2742 : }
2743 17 : assert(maxlen > 256); /* make sure every floating point fits on the dense case */
2744 17 : assert(b->ttype == TYPE_str || b->ttype == TYPE_dbl);
2745 :
2746 17 : bi = bat_iterator(b);
2747 17 : vals = (dbl *) Tloc(b, 0);
2748 17 : switch (b->ttype) {
2749 8 : case TYPE_str:
2750 23 : for (p = 0, q = BATcount(b); p < q; p++) {
2751 15 : const char *v = (const char *) BUNtvar(bi, p);
2752 :
2753 15 : if (strNil(v))
2754 3 : continue;
2755 : /* '[' or ',' plus space and null terminator and " ]" final string */
2756 12 : JSON_AGGR_CHECK_NEXT_LENGTH(strlen(v) * 2 + 7);
2757 12 : char *dst = buf + buflen, *odst = dst;
2758 12 : if (buflen == 0)
2759 6 : *dst++ = '[';
2760 : else
2761 6 : *dst++ = ',';
2762 12 : *dst++ = ' ';
2763 12 : *dst++ = '"';
2764 64 : JSON_STR_CPY;
2765 12 : *dst++ = '"';
2766 12 : buflen += (dst - odst);
2767 : }
2768 : break;
2769 9 : case TYPE_dbl:
2770 27 : for (p = 0, q = BATcount(b); p < q; p++) {
2771 18 : dbl val = vals[p];
2772 :
2773 18 : if (is_dbl_nil(val))
2774 7 : continue;
2775 : /* '[' or ',' plus space and null terminator and " ]" final string */
2776 11 : JSON_AGGR_CHECK_NEXT_LENGTH(130 + 6);
2777 11 : char *dst = buf + buflen;
2778 11 : if (buflen == 0)
2779 6 : *dst++ = '[';
2780 : else
2781 5 : *dst++ = ',';
2782 11 : *dst++ = ' ';
2783 11 : buflen += 2;
2784 11 : buflen += snprintf(buf + buflen, maxlen - buflen, "%f", val);
2785 : }
2786 : break;
2787 : default:
2788 0 : assert(0);
2789 : }
2790 17 : bat_iterator_end(&bi);
2791 17 : BBPunfix(b->batCacheid);
2792 17 : if (buflen > 0)
2793 12 : strcpy(buf + buflen, " ]");
2794 : else
2795 5 : strcpy(buf, str_nil);
2796 17 : *ret = GDKstrdup(buf);
2797 17 : GDKfree(buf);
2798 17 : if (!*ret) /* Don't return a too large string */
2799 0 : throw(MAL, "json.group", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2800 : return MAL_SUCCEED;
2801 0 : bunins_failed:
2802 0 : bat_iterator_end(&bi);
2803 0 : BBPunfix(b->batCacheid);
2804 0 : GDKfree(buf);
2805 0 : throw(MAL, "json.group", "%s", err);
2806 : }
2807 :
2808 : static const char *
2809 9 : JSONjsonaggr(BAT **bnp, BAT *b, BAT *g, BAT *e, BAT *s, int skip_nils)
2810 : {
2811 9 : BAT *bn = NULL, *t1, *t2 = NULL;
2812 9 : BATiter bi;
2813 9 : oid min, max, mapoff = 0, prev;
2814 9 : BUN ngrp, nils = 0, p, q;
2815 9 : struct canditer ci;
2816 9 : const char *err = NULL;
2817 9 : const oid *grps, *map;
2818 9 : int freeb = 0, freeg = 0, isnil = 0;
2819 9 : char *buf = NULL, *buf2;
2820 9 : size_t buflen, maxlen = BUFSIZ, len;
2821 9 : dbl *restrict vals;
2822 :
2823 9 : assert(maxlen > 256); /* make sure every floating point fits on the dense case */
2824 9 : assert(b->ttype == TYPE_str || b->ttype == TYPE_dbl);
2825 9 : if ((err = BATgroupaggrinit(b, g, e, s, &min, &max, &ngrp, &ci)) != NULL) {
2826 : return err;
2827 : }
2828 9 : if (BATcount(b) == 0 || ngrp == 0) {
2829 0 : bn = BATconstant(ngrp == 0 ? 0 : min, TYPE_str, ATOMnilptr(TYPE_str),
2830 : ngrp, TRANSIENT);
2831 0 : if (bn == NULL)
2832 : return SQLSTATE(HY013) MAL_MALLOC_FAIL;
2833 0 : *bnp = bn;
2834 0 : return NULL;
2835 : }
2836 9 : if (s) {
2837 0 : b = BATproject(s, b);
2838 0 : if (b == NULL) {
2839 0 : err = GDK_EXCEPTION;
2840 0 : goto out;
2841 : }
2842 0 : freeb = 1;
2843 0 : if (g) {
2844 0 : g = BATproject(s, g);
2845 0 : if (g == NULL) {
2846 0 : err = GDK_EXCEPTION;
2847 0 : goto out;
2848 : }
2849 : freeg = 1;
2850 : }
2851 : }
2852 :
2853 9 : if ((buf = GDKmalloc(maxlen)) == NULL) {
2854 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
2855 0 : goto out;
2856 : }
2857 9 : buflen = 0;
2858 9 : bn = COLnew(min, TYPE_str, ngrp, TRANSIENT);
2859 9 : if (bn == NULL) {
2860 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL;
2861 0 : goto out;
2862 : }
2863 9 : bi = bat_iterator(b);
2864 9 : vals = (dbl *) Tloc(b, 0);
2865 9 : if (g) {
2866 : /* stable sort g */
2867 9 : if (BATsort(&t1, &t2, NULL, g, NULL, NULL, false, false, true) != GDK_SUCCEED) {
2868 0 : err = GDK_EXCEPTION;
2869 0 : bat_iterator_end(&bi);
2870 0 : goto out;
2871 : }
2872 9 : if (freeg)
2873 0 : BBPunfix(g->batCacheid);
2874 9 : g = t1;
2875 9 : freeg = 1;
2876 9 : if (t2->ttype == TYPE_void) {
2877 : map = NULL;
2878 : } else {
2879 1 : map = (const oid *) Tloc(t2, 0);
2880 1 : mapoff = t2->tseqbase;
2881 : }
2882 9 : if (g && BATtdense(g)) {
2883 1 : switch (b->ttype) {
2884 0 : case TYPE_str:
2885 0 : for (p = 0, q = BATcount(g); p < q; p++) {
2886 0 : const char *v = (const char *) BUNtvar(bi,
2887 : (map ? (BUN) map[p] -
2888 : mapoff : p));
2889 0 : if (strNil(v)) {
2890 0 : if (skip_nils) {
2891 : /*
2892 : * if q is 1 and the value is
2893 : * null, then we need to fill
2894 : * in a value. Otherwise
2895 : * BATproject will fail.
2896 : */
2897 0 : if (p == 0 && q == 1)
2898 0 : strcpy(buf, "[ null ]");
2899 : else
2900 0 : continue;
2901 : } else {
2902 0 : strcpy(buf, str_nil);
2903 0 : nils = 1;
2904 : }
2905 : } else {
2906 0 : JSON_AGGR_CHECK_NEXT_LENGTH(strlen(v) * 2 + 7);
2907 0 : char *dst = buf;
2908 0 : *dst++ = '[';
2909 0 : *dst++ = ' ';
2910 0 : *dst++ = '"';
2911 0 : JSON_STR_CPY;
2912 0 : *dst++ = '"';
2913 0 : *dst++ = ' ';
2914 0 : *dst++ = ']';
2915 0 : *dst = '\0';
2916 : }
2917 0 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
2918 0 : goto bunins_failed;
2919 : }
2920 : break;
2921 1 : case TYPE_dbl:
2922 3 : for (p = 0, q = BATcount(g); p < q; p++) {
2923 2 : dbl val = vals[(map ? (BUN) map[p] - mapoff : p)];
2924 2 : if (is_dbl_nil(val)) {
2925 0 : if (skip_nils) {
2926 0 : if (p == 0 && q == 1)
2927 0 : strcpy(buf, "[ null ]");
2928 : else
2929 0 : continue;
2930 : } else {
2931 0 : strcpy(buf, str_nil);
2932 0 : nils = 1;
2933 : }
2934 : } else {
2935 2 : char *dst = buf;
2936 2 : *dst++ = '[';
2937 2 : *dst++ = ' ';
2938 2 : dst += sprintf(dst, "%f", val);
2939 2 : *dst++ = ' ';
2940 2 : *dst++ = ']';
2941 2 : *dst = '\0';
2942 : }
2943 2 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
2944 0 : goto bunins_failed;
2945 : }
2946 : break;
2947 : default:
2948 0 : assert(0);
2949 : }
2950 : } else {
2951 8 : grps = (const oid *) Tloc(g, 0);
2952 8 : prev = grps[0];
2953 2127 : for (p = 0, q = BATcount(g); p <= q; p++) {
2954 2127 : if (p == q || grps[p] != prev) {
2955 15 : if (isnil) {
2956 0 : strcpy(buf, str_nil);
2957 0 : nils = 1;
2958 15 : } else if (buflen == 0) {
2959 1 : strcpy(buf, "[ ]");
2960 : } else {
2961 14 : strcpy(buf + buflen, " ]");
2962 : }
2963 15 : while (BATcount(bn) < prev - min) {
2964 0 : if (bunfastapp_nocheckVAR(bn, str_nil) != GDK_SUCCEED)
2965 0 : goto bunins_failed;
2966 : nils = 1;
2967 : }
2968 15 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
2969 0 : goto bunins_failed;
2970 15 : if (p == q)
2971 : break;
2972 7 : buflen = 0;
2973 7 : isnil = 0;
2974 7 : prev = grps[p];
2975 : }
2976 2119 : if (isnil)
2977 0 : continue;
2978 2119 : switch (b->ttype) {
2979 2108 : case TYPE_str:{
2980 2108 : const char *v = (const char *) BUNtvar(bi, p);
2981 2108 : if (strNil(v)) {
2982 1 : if (skip_nils)
2983 1 : continue;
2984 : isnil = 1;
2985 : } else {
2986 : /* '[' or ',' plus space and null terminator and " ]" final string */
2987 2107 : JSON_AGGR_CHECK_NEXT_LENGTH(strlen(v) * 2 + 7);
2988 2107 : char *dst = buf + buflen, *odst = dst;
2989 2107 : if (buflen == 0)
2990 9 : *dst++ = '[';
2991 : else
2992 2098 : *dst++ = ',';
2993 2107 : *dst++ = ' ';
2994 2107 : *dst++ = '"';
2995 4243 : JSON_STR_CPY;
2996 2107 : *dst++ = '"';
2997 2107 : buflen += (dst - odst);
2998 : }
2999 : break;
3000 : }
3001 11 : case TYPE_dbl:{
3002 11 : dbl val = vals[p];
3003 11 : if (is_dbl_nil(val)) {
3004 4 : if (skip_nils)
3005 4 : continue;
3006 : isnil = 1;
3007 : } else {
3008 : /* '[' or ',' plus space and null terminator and " ]" final string */
3009 7 : JSON_AGGR_CHECK_NEXT_LENGTH(130 + 6);
3010 7 : char *dst = buf + buflen;
3011 7 : if (buflen == 0)
3012 5 : *dst++ = '[';
3013 : else
3014 2 : *dst++ = ',';
3015 7 : *dst++ = ' ';
3016 7 : buflen += 2;
3017 7 : buflen += snprintf(buf + buflen, maxlen - buflen, "%f",
3018 : val);
3019 : }
3020 : break;
3021 : }
3022 : default:
3023 0 : assert(0);
3024 : }
3025 : }
3026 8 : BBPunfix(t2->batCacheid);
3027 8 : t2 = NULL;
3028 : }
3029 : } else {
3030 0 : switch (b->ttype) {
3031 0 : case TYPE_str:
3032 0 : for (p = 0, q = p + BATcount(b); p < q; p++) {
3033 0 : const char *v = (const char *) BUNtvar(bi, p);
3034 0 : if (strNil(v)) {
3035 0 : if (skip_nils)
3036 0 : continue;
3037 : nils = 1;
3038 : break;
3039 : }
3040 : /* '[' or ',' plus space and null terminator and " ]" final string */
3041 0 : JSON_AGGR_CHECK_NEXT_LENGTH(strlen(v) * 2 + 7);
3042 0 : char *dst = buf + buflen, *odst = dst;
3043 0 : if (buflen == 0)
3044 0 : *dst++ = '[';
3045 : else
3046 0 : *dst++ = ',';
3047 0 : *dst++ = ' ';
3048 0 : *dst++ = '"';
3049 0 : JSON_STR_CPY;
3050 0 : *dst++ = '"';
3051 0 : buflen += (dst - odst);
3052 : }
3053 : break;
3054 0 : case TYPE_dbl:
3055 0 : for (p = 0, q = p + BATcount(b); p < q; p++) {
3056 0 : dbl val = vals[p];
3057 0 : if (is_dbl_nil(val)) {
3058 0 : if (skip_nils)
3059 0 : continue;
3060 : nils = 1;
3061 : break;
3062 : }
3063 : /* '[' or ',' plus space and null terminator and " ]" final string */
3064 0 : JSON_AGGR_CHECK_NEXT_LENGTH(130 + 6);
3065 0 : char *dst = buf + buflen;
3066 0 : if (buflen == 0)
3067 0 : *dst++ = '[';
3068 : else
3069 0 : *dst++ = ',';
3070 0 : *dst++ = ' ';
3071 0 : buflen += 2;
3072 0 : buflen += snprintf(buf + buflen, maxlen - buflen, "%f", val);
3073 : }
3074 : break;
3075 : default:
3076 0 : assert(0);
3077 : }
3078 0 : if (nils) {
3079 0 : strcpy(buf, str_nil);
3080 0 : } else if (buflen == 0) {
3081 0 : strcpy(buf, "[ ]");
3082 : } else {
3083 0 : strcpy(buf + buflen, " ]");
3084 : }
3085 0 : if (bunfastapp_nocheckVAR(bn, buf) != GDK_SUCCEED)
3086 0 : goto bunins_failed;
3087 : }
3088 9 : bat_iterator_end(&bi);
3089 9 : bn->tnil = nils != 0;
3090 9 : bn->tnonil = nils == 0;
3091 9 : bn->tsorted = BATcount(bn) <= 1;
3092 9 : bn->trevsorted = BATcount(bn) <= 1;
3093 9 : bn->tkey = BATcount(bn) <= 1;
3094 :
3095 9 : out:
3096 9 : if (bn)
3097 9 : bn->theap->dirty |= BATcount(bn) > 0;
3098 9 : BBPreclaim(t2);
3099 9 : if (freeb)
3100 0 : BBPunfix(b->batCacheid);
3101 9 : if (freeg)
3102 9 : BBPunfix(g->batCacheid);
3103 9 : GDKfree(buf);
3104 9 : if (err && bn) {
3105 0 : BBPreclaim(bn);
3106 0 : bn = NULL;
3107 : }
3108 9 : *bnp = bn;
3109 9 : return err;
3110 :
3111 0 : bunins_failed:
3112 0 : bat_iterator_end(&bi);
3113 0 : if (err == NULL)
3114 0 : err = SQLSTATE(HY013) MAL_MALLOC_FAIL; /* insertion into result BAT failed */
3115 0 : goto out;
3116 : }
3117 :
3118 : static str
3119 9 : JSONsubjsoncand(bat *retval, const bat *bid, const bat *gid, const bat *eid,
3120 : const bat *sid, const bit *skip_nils)
3121 : {
3122 9 : BAT *b, *g, *e, *s, *bn = NULL;
3123 9 : const char *err;
3124 :
3125 9 : b = BATdescriptor(*bid);
3126 9 : g = gid ? BATdescriptor(*gid) : NULL;
3127 9 : e = eid ? BATdescriptor(*eid) : NULL;
3128 9 : s = sid ? BATdescriptor(*sid) : NULL;
3129 9 : if (b == NULL || (gid != NULL && g == NULL) || (eid != NULL && e == NULL)
3130 9 : || (sid != NULL && s == NULL)) {
3131 : err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
3132 : } else {
3133 9 : err = JSONjsonaggr(&bn, b, g, e, s, *skip_nils);
3134 : }
3135 9 : BBPreclaim(b);
3136 9 : BBPreclaim(g);
3137 9 : BBPreclaim(e);
3138 9 : BBPreclaim(s);
3139 9 : if (err != NULL)
3140 0 : throw(MAL, "aggr.subjson", "%s", err);
3141 :
3142 9 : *retval = bn->batCacheid;
3143 9 : BBPkeepref(bn);
3144 9 : return MAL_SUCCEED;
3145 : }
3146 :
3147 : static str
3148 9 : JSONsubjson(bat *retval, const bat *bid, const bat *gid, const bat *eid,
3149 : const bit *skip_nils)
3150 : {
3151 9 : return JSONsubjsoncand(retval, bid, gid, eid, NULL, skip_nils);
3152 : }
3153 :
3154 :
3155 : #include "mel.h"
3156 : static mel_atom json_init_atoms[] = {
3157 : { .name="json", .basetype="str", .fromstr=JSONfromString, .tostr=JSONtoString }, { .cmp=NULL },
3158 : };
3159 : static mel_func json_init_funcs[] = {
3160 : command("json", "new", JSONstr2json, false, "Convert string to its JSON. Dealing with escape characters", args(1,2, arg("",json),arg("j",str))),
3161 : command("calc", "json", JSON2json, false, "Convert JSON to JSON", args(1,2, arg("",json),arg("s",json))),
3162 : command("calc", "json", JSONstr2json, false, "Convert string to its JSON. Dealing with escape characters", args(1,2, arg("",json),arg("j",str))),
3163 : command("json", "str", JSONjson2str, false, "Convert JSON to its string equivalent. Dealing with escape characters", args(1,2, arg("",str),arg("j",json))),
3164 : command("json", "text", JSONjson2text, false, "Convert JSON values to their plain string equivalent.", args(1,2, arg("",str),arg("j",json))),
3165 : command("json", "text", JSONjson2textSeparator, false, "Convert JSON values to their plain string equivalent, injecting a separator.", args(1,3, arg("",str),arg("j",json),arg("s",str))),
3166 : command("json", "number", JSONjson2number, false, "Convert simple JSON values to a double, return nil upon error.", args(1,2, arg("",dbl),arg("j",json))),
3167 : command("json", "integer", JSONjson2integer, false, "Convert simple JSON values to an integer, return nil upon error.", args(1,2, arg("",lng),arg("j",json))),
3168 : pattern("json", "dump", JSONdump, false, "", args(1,2, batarg("",str),arg("j",json))),
3169 : command("json", "filter", JSONfilter, false, "Filter all members of an object by a path expression, returning an array.\nNon-matching elements are skipped.", args(1,3, arg("",json),arg("name",json),arg("pathexpr",str))),
3170 : command("json", "filter", JSONfilterArray_bte, false, "", args(1,3, arg("",json),arg("name",json),arg("idx",bte))),
3171 : command("json", "filter", JSONfilterArrayDefault_bte, false, "", args(1,4, arg("",json),arg("name",json),arg("idx",bte),arg("other",str))),
3172 : command("json", "filter", JSONfilterArray_sht, false, "", args(1,3, arg("",json),arg("name",json),arg("idx",sht))),
3173 : command("json", "filter", JSONfilterArrayDefault_sht, false, "", args(1,4, arg("",json),arg("name",json),arg("idx",sht),arg("other",str))),
3174 : command("json", "filter", JSONfilterArray_int, false, "", args(1,3, arg("",json),arg("name",json),arg("idx",int))),
3175 : command("json", "filter", JSONfilterArrayDefault_int, false, "", args(1,4, arg("",json),arg("name",json),arg("idx",int),arg("other",str))),
3176 : command("json", "filter", JSONfilterArray_lng, false, "", args(1,3, arg("",json),arg("name",json),arg("idx",lng))),
3177 : command("json", "filter", JSONfilterArrayDefault_lng, false, "Extract a single array element", args(1,4, arg("",json),arg("name",json),arg("idx",lng),arg("other",str))),
3178 : #ifdef HAVE_HGE
3179 : command("json", "filter", JSONfilterArray_hge, false, "", args(1,3, arg("",json),arg("name",json),arg("idx",hge))),
3180 : command("json", "filter", JSONfilterArrayDefault_hge, false, "Extract a single array element", args(1,4, arg("",json),arg("name",json),arg("idx",hge),arg("other",str))),
3181 : #endif
3182 : command("json", "isobject", JSONisobject, false, "Validate the string as a valid JSON object", args(1,2, arg("",bit),arg("val",json))),
3183 : command("json", "isarray", JSONisarray, false, "Validate the string as a valid JSON array", args(1,2, arg("",bit),arg("val",json))),
3184 : command("json", "isvalid", JSONisvalid, false, "Validate the string as a valid JSON document", args(1,2, arg("",bit),arg("val",str))),
3185 : command("json", "length", JSONlength, false, "Returns the number of elements in the outermost JSON object.", args(1,2, arg("",int),arg("val",json))),
3186 : pattern("json", "unfold", JSONunfold, false, "Expands the outermost JSON object into key-value pairs.", args(2,3, batarg("k",str),batarg("v",json),arg("val",json))),
3187 : pattern("json", "unfold", JSONunfold, false, "Expands the outermost JSON object into key-value pairs.", args(3,4, batarg("o",oid),batarg("k",str),batarg("v",json),arg("val",json))),
3188 : pattern("json", "fold", JSONfold, false, "Combine the key-value pairs into a single json object list.", args(1,4, arg("",json),batarg("o",oid),batarg("k",str),batargany("v",0))),
3189 : pattern("json", "fold", JSONfold, false, "Combine the key-value pairs into a single json object list.", args(1,3, arg("",json),batarg("k",str),batargany("v",0))),
3190 : pattern("json", "fold", JSONfold, false, "Combine the value list into a single json array object.", args(1,2, arg("",json),batargany("v",0))),
3191 : command("json", "keyarray", JSONkeyArray, false, "Expands the outermost JSON object keys into a JSON value array.", args(1,2, arg("",json),arg("val",json))),
3192 : command("json", "valuearray", JSONvalueArray, false, "Expands the outermost JSON object values into a JSON value array.", args(1,2, arg("",json),arg("val",json))),
3193 : command("json", "keys", JSONkeyTable, false, "Expands the outermost JSON object names.", args(1,2, batarg("",str),arg("val",json))),
3194 : command("json", "values", JSONvalueTable, false, "Expands the outermost JSON values.", args(1,2, batarg("",json),arg("val",json))),
3195 : pattern("json", "renderobject", JSONrenderobject, false, "", args(1,2, arg("",json),varargany("val",0))),
3196 : pattern("json", "renderarray", JSONrenderarray, false, "", args(1,2, arg("",json),varargany("val",0))),
3197 : command("aggr", "jsonaggr", JSONgroupStr, false, "Aggregate the string values to array.", args(1,2, arg("",str),batarg("val",str))),
3198 : command("aggr", "jsonaggr", JSONgroupStr, false, "Aggregate the double values to array.", args(1,2, arg("",str),batarg("val",dbl))),
3199 : command("aggr", "subjsonaggr", JSONsubjson, false, "Grouped aggregation of values.", args(1,5, batarg("",str),batarg("val",str),batarg("g",oid),batargany("e",1),arg("skip_nils",bit))),
3200 : command("aggr", "subjsonaggr", JSONsubjson, false, "Grouped aggregation of values.", args(1,5, batarg("",str),batarg("val",dbl),batarg("g",oid),batargany("e",1),arg("skip_nils",bit))),
3201 : command("aggr", "subjsonaggr", JSONsubjsoncand, false, "Grouped aggregation of values with candidates list.", args(1,6, batarg("",str),batarg("val",str),batarg("g",oid),batargany("e",1),batarg("s",oid),arg("skip_nils",bit))),
3202 : command("aggr", "subjsonaggr", JSONsubjsoncand, false, "Grouped aggregation of values with candidates list.", args(1,6, batarg("",str),batarg("val",dbl),batarg("g",oid),batargany("e",1),batarg("s",oid),arg("skip_nils",bit))),
3203 : { .imp=NULL }
3204 : };
3205 : #include "mal_import.h"
3206 : #ifdef _MSC_VER
3207 : #undef read
3208 : #pragma section(".CRT$XCU",read)
3209 : #endif
3210 351 : LIB_STARTUP_FUNC(init_json_mal)
3211 351 : { mal_module2("json", json_init_atoms, json_init_funcs, JSONprelude, NULL); }
|