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