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