1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/*
10 * (c) 2013 Martin Kersten
11 */
12#include "monetdb_config.h"
13#include "json.h"
14#include "mal.h"
15#include "mal_instruction.h"
16#include "mal_interpreter.h"
17
18// just validate the string according to www.json.org
19// A straightforward recursive solution
20#define skipblancs(J) \
21 do { \
22 for(; *(J); (J)++) \
23 if (*(J) != ' ' && \
24 *(J) != '\n' && \
25 *(J) != '\t' && \
26 *(J) != '\f' && \
27 *(J) != '\r') \
28 break; \
29 } while (0)
30
31#define hex(J) \
32 do { \
33 if (isxdigit((unsigned char) *(J))) \
34 (J)++; \
35 else \
36 throw(MAL, "json.parser", "illegal escape char"); \
37 } while (0)
38
39#define CHECK_JSON(jt) \
40 if (jt == NULL || jt->error) { \
41 char *msg; \
42 if (jt) { \
43 msg = jt->error; \
44 jt->error = NULL; \
45 JSONfree(jt); \
46 } else { \
47 msg = createException(MAL, "json.new", \
48 SQLSTATE(HY001) MAL_MALLOC_FAIL); \
49 } \
50 return msg; \
51 }
52
53#define SEPARATOR ' '
54
55int TYPE_json;
56
57#define JSONlast(J) ((J)->free-1)
58
59/* Internal constructors. */
60static int jsonhint = 8;
61static JSON *JSONparse(const char *j);
62
63static JSON *
64JSONnewtree(void)
65{
66 JSON *js;
67
68 js = (JSON *) GDKzalloc(sizeof(JSON));
69 if (js == NULL)
70 return NULL;
71 js->elm = (JSONterm *) GDKzalloc(sizeof(JSONterm) * jsonhint);
72 if (js->elm == NULL) {
73 GDKfree(js);
74 return NULL;
75 }
76 js->size = jsonhint;
77 return js;
78}
79
80static int
81JSONnew(JSON *js)
82{
83 JSONterm *term;
84
85 if (js->free == js->size) {
86 term = (JSONterm *) GDKrealloc(js->elm, sizeof(JSONterm) * (js->size + 8));
87 if (term == NULL) {
88 js->error = createException(MAL, "json.new", SQLSTATE(HY001) MAL_MALLOC_FAIL);
89 return js->free - 1;
90 }
91 js->elm = term;
92 memset(term + js->size, 0, 8 * sizeof(JSONterm));
93 js->size += 8;
94 if (jsonhint < js->size)
95 jsonhint = js->size;
96 }
97 return js->free++;
98}
99
100/* Delete a JSON structure. */
101static void
102JSONfree(JSON *c)
103{
104 if (c == 0)
105 return;
106 freeException(c->error);
107 GDKfree(c->elm);
108 GDKfree(c);
109}
110
111ssize_t
112JSONfromString(const char *src, size_t *len, json *j, bool external)
113{
114 size_t slen = strlen(src);
115 JSON *jt;
116
117 if (GDK_STRNIL(src) || (external && strncmp(src, "nil", 3) == 0)) {
118 if (*len < 2 || *j == NULL) {
119 GDKfree(*j);
120 if ((*j = GDKmalloc(2)) == NULL)
121 return -1;
122 *len = 2;
123 }
124 strcpy(*j, str_nil);
125 return GDK_STRNIL(src) ? 1 : 3;
126 }
127 if (*len <= slen || *j == NULL) {
128 GDKfree(*j);
129 if ((*j = GDKmalloc(slen + 1)) == NULL)
130 return -1;
131 *len = slen + 1;
132 }
133 if (external) {
134 if (GDKstrFromStr((unsigned char *) *j,
135 (const unsigned char *) src, (ssize_t) slen) < 0)
136 return -1;
137 src = *j;
138 } else {
139 strcpy(*j, src);
140 }
141 jt = JSONparse(*j);
142 if (jt == NULL)
143 return -1;
144 if (jt->error) {
145 GDKerror("%s", getExceptionMessageAndState(jt->error));
146 JSONfree(jt);
147 return -1;
148 }
149 JSONfree(jt);
150
151 return (ssize_t) slen;
152}
153
154ssize_t
155JSONtoString(str *s, size_t *len, const char *src, bool external)
156{
157 size_t cnt;
158 const char *c;
159 char *dst;
160
161 if (GDK_STRNIL(src)) {
162 if (*s == NULL || *len < 4) {
163 GDKfree(*s);
164 *len = 4;
165 *s = GDKmalloc(4);
166 if (*s == NULL)
167 return -1;
168 }
169 if (external) {
170 return (ssize_t) strcpy_len(*s, "nil", 4);
171 }
172 strcpy(*s, str_nil);
173 return 1;
174 }
175 /* count how much space we need for the output string */
176 if (external) {
177 cnt = 3; /* two times " plus \0 */
178 for (c = src; *c; c++)
179 switch (*c) {
180 case '"':
181 case '\\':
182 case '\n':
183 cnt++;
184 /* fall through */
185 default:
186 cnt++;
187 break;
188 }
189 } else {
190 cnt = strlen(src) + 1; /* just the \0 */
191 }
192
193 if (cnt > (size_t) *len) {
194 GDKfree(*s);
195 *s = GDKmalloc(cnt);
196 if (*s == NULL)
197 return -1;
198 *len = cnt;
199 }
200 dst = *s;
201 if (external) {
202 *dst++ = '"';
203 for (c = src; *c; c++) {
204 switch (*c) {
205 case '"':
206 case '\\':
207 *dst++ = '\\';
208 /* fall through */
209 default:
210 *dst++ = *c;
211 break;
212 case '\n':
213 *dst++ = '\\';
214 *dst++ = 'n';
215 break;
216 }
217 }
218 *dst++ = '"';
219 *dst = 0;
220 } else {
221 dst += snprintf(dst, cnt, "%s", src);
222 }
223 return (ssize_t) (dst - *s);
224}
225
226#define tab(D) \
227 do { \
228 int kk; \
229 for (kk = 0; kk < (D) * 4; kk++) \
230 mnstr_printf(fd, " "); \
231 } while (0)
232
233static void
234JSONdumpInternal(stream *fd, JSON *jt, int depth)
235{
236 int i, idx;
237 JSONterm *je;
238
239 for (idx = 0; idx < jt->free; idx++) {
240 je = jt->elm + idx;
241
242 tab(depth);
243 mnstr_printf(fd, "[%d] ", idx);
244 switch (je->kind) {
245 case JSON_OBJECT:
246 mnstr_printf(fd, "object ");
247 break;
248 case JSON_ARRAY:
249 mnstr_printf(fd, "array ");
250 break;
251 case JSON_ELEMENT:
252 mnstr_printf(fd, "element ");
253 break;
254 case JSON_VALUE:
255 mnstr_printf(fd, "value ");
256 break;
257 case JSON_STRING:
258 mnstr_printf(fd, "string ");
259 break;
260 case JSON_NUMBER:
261 mnstr_printf(fd, "number ");
262 break;
263 case JSON_BOOL:
264 mnstr_printf(fd, "bool ");
265 break;
266 case JSON_NULL:
267 mnstr_printf(fd, "null ");
268 break;
269 default:
270 mnstr_printf(fd, "unknown %d ", je->kind);
271 }
272 mnstr_printf(fd, "child %d list ", je->child);
273 for (i = je->next; i; i = jt->elm[i].next)
274 mnstr_printf(fd, "%d ", i);
275 if (je->name) {
276 mnstr_printf(fd, "%.*s : ", (int) je->namelen, je->name);
277 }
278 if (je->value)
279 mnstr_printf(fd, "%.*s", (int) je->valuelen, je->value);
280 mnstr_printf(fd, "\n");
281 }
282}
283
284str
285JSONdump(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
286{
287 (void) mb;
288
289 json *val = (json*) getArgReference(stk, pci, 1);
290 JSON *jt = JSONparse(*val);
291
292 CHECK_JSON(jt);
293 JSONdumpInternal(cntxt->fdout, jt, 0);
294 JSONfree(jt);
295 return MAL_SUCCEED;
296}
297
298
299str
300JSONjson2str(str *ret, json *j)
301{
302 char *s = *j, *c;
303
304 if (*s == '"')
305 s++;
306 if ((s = GDKstrdup(s)) == NULL)
307 throw(MAL, "json.str", SQLSTATE(HY001) MAL_MALLOC_FAIL);
308 c = s + strlen(s) - 1;
309 if (*c == '"')
310 *c = 0;
311 *ret = s;
312 return MAL_SUCCEED;
313}
314
315str
316JSONstr2json(json *ret, str *j)
317{
318 JSON *jt = JSONparse(*j);
319
320 CHECK_JSON(jt);
321 JSONfree(jt);
322 if ((*ret = GDKstrdup(*j)) == NULL)
323 throw(MAL, "json.new", SQLSTATE(HY001) MAL_MALLOC_FAIL);
324 return MAL_SUCCEED;
325}
326
327str
328JSONisvalid(bit *ret, json *j)
329{
330 JSON *jt = JSONparse(*j);
331
332 if (jt == NULL)
333 throw(MAL, "json.isvalid", SQLSTATE(HY001) MAL_MALLOC_FAIL);
334 *ret = jt->error == MAL_SUCCEED;
335 JSONfree(jt);
336 return MAL_SUCCEED;
337}
338
339str
340JSONisobject(bit *ret, json *js)
341{
342 char *j = *js;
343
344 skipblancs(j);
345 *ret = *j == '{';
346 return MAL_SUCCEED;
347}
348
349str
350JSONisarray(bit *ret, json *js)
351{
352 char *j = *js;
353
354 skipblancs(j);
355 *ret = *j == '[';
356 return MAL_SUCCEED;
357}
358
359str
360JSONprelude(void *ret)
361{
362 (void) ret;
363 TYPE_json = ATOMindex("json");
364 return MAL_SUCCEED;
365}
366
367static void
368JSONappend(JSON *jt, int idx, int nxt)
369{
370 int chld;
371
372 if (jt->elm[nxt].kind == JSON_OBJECT || jt->elm[nxt].kind == JSON_ARRAY) {
373 chld = JSONnew(jt);
374 if (jt->error)
375 return;
376 jt->elm[chld].kind = jt->elm[nxt].kind;
377 jt->elm[chld].name = jt->elm[nxt].name;
378 jt->elm[chld].namelen = jt->elm[nxt].namelen;
379 jt->elm[chld].value = jt->elm[nxt].value;
380 jt->elm[chld].valuelen = jt->elm[nxt].valuelen;
381 jt->elm[chld].child = jt->elm[nxt].child;
382 jt->elm[chld].next = jt->elm[nxt].next;
383 jt->elm[chld].tail = jt->elm[nxt].tail;
384 jt->elm[chld].child = nxt;
385
386 jt->elm[nxt].child = 0;
387 jt->elm[nxt].next = 0;
388 jt->elm[nxt].tail = 0;
389 nxt = chld;
390 }
391 if (jt->elm[idx].next == 0)
392 jt->elm[idx].next = jt->elm[idx].tail = nxt;
393 else {
394 jt->elm[jt->elm[idx].tail].next = nxt;
395 jt->elm[idx].tail = nxt;
396 }
397}
398
399/*
400 * The JSON filter operation takes a path expression which is
401 * purposely kept simple, It provides step (.), multistep (..) and
402 * indexed ([nr]) access to the JSON elements. A wildcard * can be
403 * used as placeholder for a step identifier.
404 *
405 * A path expression is always validated upfront and can only be
406 * applied to valid json strings.
407 * Path samples:
408 * .store.book
409 * .store.book[0]
410 * .store.book.author
411 * ..author
412 */
413#define MAXTERMS 256
414#define ROOT_STEP 0
415#define CHILD_STEP 1
416#define INDEX_STEP 2
417#define ANY_STEP 3
418#define END_STEP 4
419
420typedef struct {
421 int token;
422 char *name;
423 size_t namelen;
424 int index;
425 int first, last;
426} pattern;
427
428static str
429JSONcompile(char *expr, pattern terms[])
430{
431 int t = 0;
432 char *s, *beg;
433
434 for (s = expr; *s; s++) {
435 terms[t].token = CHILD_STEP;
436 terms[t].index = INT_MAX;
437 terms[t].first = INT_MAX;
438 terms[t].last = INT_MAX;
439 if (*s == '$') {
440 if (t && terms[t - 1].token != END_STEP)
441 throw(MAL, "json.compile", "Root node must be first");
442 if (!(*(s + 1) == '.' || *(s + 1) == '[' || *(s + 1) == 0))
443 throw(MAL, "json.compile", "Root node must be first");
444 s++;
445 if (*s == 0)
446 terms[t].token = ROOT_STEP;
447 }
448 if (*s == '.' && *(s + 1) == '.') {
449 terms[t].token = ANY_STEP;
450 s += 2;
451 if (*s == '.')
452 throw(MAL, "json.compile", "Step identifier expected");
453 } else if (*s == '.')
454 s++;
455
456 // child step
457 if (*s != '[') {
458 for (beg = s; *s; s++)
459 if (*s == '.' || *s == '[' || *s == ',')
460 break;
461 terms[t].name = GDKzalloc(s - beg + 1);
462 if(terms[t].name == NULL)
463 throw(MAL, "json.compile", SQLSTATE(HY001) MAL_MALLOC_FAIL);
464 terms[t].namelen = s - beg;
465 strncpy(terms[t].name, beg, s - beg);
466 if (*s == '.')
467 s--;
468 if (*s == 0) {
469 t++;
470 break;
471 }
472 }
473 if (*s == '[') {
474 // array step
475 s++;
476 skipblancs(s);
477 if (*s != '*') {
478 if (isdigit((unsigned char) *s)) {
479 terms[t].index = atoi(s);
480 terms[t].first = terms[t].last = atoi(s);
481 } else
482 throw(MAL, "json.path", "'*' or digit expected");
483 }
484 for (; *s; s++)
485 if (*s == ']')
486 break;
487 if (*s == 0) {
488 t++;
489 break;
490 }
491 if (*s != ']')
492 throw(MAL, "json.path", "] expected");
493 }
494 if (*s == ',') {
495 if (++t == MAXTERMS)
496 throw(MAL, "json.path", "too many terms");
497 terms[t].token = END_STEP;
498 }
499 if (++t == MAXTERMS)
500 throw(MAL, "json.path", "too many terms");
501 }
502 if (t >= MAXTERMS - 1)
503 throw(MAL, "json.path", "too many terms");
504 terms[t].token = END_STEP;
505 return MAL_SUCCEED;
506}
507
508static str
509JSONgetValue(JSON *jt, int idx)
510{
511 str s;
512
513 if (jt->elm[idx].valuelen == 0)
514 return GDKstrdup(str_nil);
515 s = GDKzalloc(jt->elm[idx].valuelen + 1);
516 if (s)
517 strncpy(s, jt->elm[idx].value, jt->elm[idx].valuelen);
518 return s;
519}
520
521static str
522JSONglue(str res, str r, char sep)
523{
524 size_t len, l;
525 str n;
526
527 if (r == 0 || *r == 0)
528 return res;
529 len = strlen(r);
530 if (res == 0)
531 return r;
532 l = strlen(res);
533 n = GDKzalloc(l + len + 3);
534 if( n == NULL) {
535 GDKfree(res);
536 GDKfree(r);
537 return NULL;
538 }
539 snprintf(n, l + len + 3, "%s%s%s", res, sep ? "," : "", r);
540 GDKfree(res);
541 GDKfree(r);
542 return n;
543}
544
545/* return NULL on no match, return (str) -1 on (malloc) failure */
546static str
547JSONmatch(JSON *jt, int ji, pattern * terms, int ti)
548{
549 str r = NULL, res = NULL;
550 int i;
551 int cnt;
552
553 if (ti >= MAXTERMS)
554 return res;
555
556 if (terms[ti].token == ROOT_STEP) {
557 if (ti + 1 == MAXTERMS)
558 return NULL;
559 if (terms[ti + 1].token == END_STEP) {
560 res = JSONgetValue(jt, 0);
561 if (res == NULL)
562 res = (str) -1;
563 return res;
564 }
565 ti++;
566 }
567
568 switch (jt->elm[ji].kind) {
569 case JSON_ARRAY:
570 if (terms[ti].name != 0 && terms[ti].token != ANY_STEP) {
571 if (terms[ti].token == END_STEP) {
572 res = JSONgetValue(jt, ji);
573 if (res == NULL)
574 res = (str) -1;
575 }
576 return res;
577 }
578 cnt = 0;
579 for (i = jt->elm[ji].next; i && cnt >= 0; i = jt->elm[i].next, cnt++) {
580 if (terms[ti].index == INT_MAX || (cnt >= terms[ti].first && cnt <= terms[ti].last)) {
581 if (terms[ti].token == ANY_STEP) {
582 if (jt->elm[i].child)
583 r = JSONmatch(jt, jt->elm[i].child, terms, ti);
584 else
585 r = 0;
586 } else if (ti + 1 == MAXTERMS) {
587 return NULL;
588 } else if (terms[ti + 1].token == END_STEP) {
589 if (jt->elm[i].kind == JSON_VALUE)
590 r = JSONgetValue(jt, jt->elm[i].child);
591 else
592 r = JSONgetValue(jt, i);
593 if (r == NULL)
594 r = (str) -1;
595 } else
596 r = JSONmatch(jt, jt->elm[i].child, terms, ti + 1);
597 if (r == (str) -1) {
598 GDKfree(res);
599 return r;
600 }
601 res = JSONglue(res, r, ',');
602 }
603 }
604 break;
605 case JSON_OBJECT:
606 cnt = 0;
607 for (i = jt->elm[ji].next; i && cnt >= 0; i = jt->elm[i].next) {
608 // check the element label
609 if ((terms[ti].name &&
610 jt->elm[i].valuelen == terms[ti].namelen &&
611 strncmp(terms[ti].name, jt->elm[i].value, terms[ti].namelen) == 0) ||
612 terms[ti].name == 0 ||
613 terms[ti].name[0] == '*') {
614 if (terms[ti].index == INT_MAX ||
615 (cnt >= terms[ti].first && cnt <= terms[ti].last)) {
616 if (ti + 1 == MAXTERMS)
617 return NULL;
618 if (terms[ti + 1].token == END_STEP) {
619 r = JSONgetValue(jt, jt->elm[i].child);
620 if (r == NULL)
621 r = (str) -1;
622 } else
623 r = JSONmatch(jt, jt->elm[i].child, terms, ti + 1);
624 if (r == (str) -1) {
625 GDKfree(res);
626 return r;
627 }
628 res = JSONglue(res, r, ',');
629 }
630 cnt++;
631 } else if (terms[ti].token == ANY_STEP && jt->elm[i].child) {
632 r = JSONmatch(jt, jt->elm[i].child, terms, ti);
633 if (r == (str) -1) {
634 GDKfree(res);
635 return r;
636 }
637 res = JSONglue(res, r, ',');
638 cnt++;
639 }
640 }
641 }
642 return res;
643}
644
645static str
646JSONfilterInternal(json *ret, json *js, str *expr, str other)
647{
648 pattern terms[MAXTERMS];
649 int tidx = 0;
650 JSON *jt;
651 str j = *js, msg = MAL_SUCCEED, s;
652 json result = 0;
653 size_t l;
654
655 (void) other;
656 if (strNil(j)) {
657 *ret = GDKstrdup(j);
658 if (*ret == NULL)
659 throw(MAL,"JSONfilterInternal", SQLSTATE(HY001) MAL_MALLOC_FAIL);
660 return MAL_SUCCEED;
661 }
662 jt = JSONparse(j);
663 CHECK_JSON(jt);
664 memset(terms, 0, sizeof(terms));
665 msg = JSONcompile(*expr, terms);
666 if (msg)
667 goto bailout;
668
669 result = s = JSONmatch(jt, 0, terms, tidx);
670 if (s == (char *) -1) {
671 msg = createException(MAL,"JSONfilterInternal", SQLSTATE(HY001) MAL_MALLOC_FAIL);
672 goto bailout;
673 }
674 // process all other PATH expression
675 for (tidx++; tidx < MAXTERMS && terms[tidx].token; tidx++)
676 if (terms[tidx].token == END_STEP && tidx + 1 < MAXTERMS && terms[tidx + 1].token) {
677 s = JSONmatch(jt, 0, terms, ++tidx);
678 if (s == (char *) -1) {
679 msg = createException(MAL,"JSONfilterInternal", SQLSTATE(HY001) MAL_MALLOC_FAIL);
680 goto bailout;
681 }
682 result = JSONglue(result, s, ',');
683 }
684 if (result) {
685 l = strlen(result);
686 if (result[l - 1] == ',')
687 result[l - 1] = 0;
688 } else
689 l = 3;
690 s = GDKzalloc(l + 3);
691 if (s == NULL) {
692 GDKfree(result);
693 throw(MAL,"JSONfilterInternal", SQLSTATE(HY001) MAL_MALLOC_FAIL);
694 }
695 snprintf(s, l + 3, "[%s]", (result ? result : ""));
696 GDKfree(result);
697 *ret = s;
698
699 bailout:
700 for (l = 0; l < MAXTERMS; l++)
701 if (terms[l].name)
702 GDKfree(terms[l].name);
703 JSONfree(jt);
704 return msg;
705}
706
707
708static str
709JSONstringParser(const char *j, const char **next)
710{
711 assert(*j == '"');
712 j++;
713 for (; *j; j++) {
714 switch (*j) {
715 case '\\':
716 // parse all escapes
717 j++;
718 switch (*j) {
719 case '"':
720 case '\\':
721 case '/':
722 case 'b':
723 case 'f':
724 case 'n':
725 case 'r':
726 case 't':
727 continue;
728 case 'u':
729 j++;
730 hex(j);
731 hex(j);
732 hex(j);
733 hex(j);
734 break;
735 default:
736 *next = j;
737 throw(MAL, "json.parser", "illegal escape char");
738 }
739 break;
740 case '"':
741 j++;
742 *next = j;
743 return MAL_SUCCEED;
744 }
745 }
746 *next = j;
747 throw(MAL, "json.parser", "Nonterminated string");
748}
749
750static str
751JSONnumberParser(const char *j, const char **next)
752{
753 const char *backup = j;
754
755 if (*j == '-')
756 j++;
757 skipblancs(j);
758 if (!isdigit((unsigned char) *j)) {
759 *next = j;
760 throw(MAL, "json.parser", "Number expected");
761 }
762 for (; *j; j++)
763 if (!isdigit((unsigned char) *j))
764 break;
765 backup = j;
766 skipblancs(j);
767 if (*j == '.') {
768 j++;
769 skipblancs(j);
770 for (; *j; j++)
771 if (!isdigit((unsigned char) *j))
772 break;
773 backup = j;
774 } else
775 j = backup;
776 skipblancs(j);
777 if (*j == 'e' || *j == 'E') {
778 j++;
779 skipblancs(j);
780 if (*j == '-')
781 j++;
782 skipblancs(j);
783 for (; *j; j++)
784 if (!isdigit((unsigned char) *j))
785 break;
786 } else
787 j = backup;
788 *next = j;
789 return MAL_SUCCEED;
790}
791
792static int
793JSONtoken(JSON *jt, const char *j, const char **next)
794{
795 str msg;
796 int nxt, idx = JSONnew(jt);
797
798 if (jt->error)
799 return idx;
800 skipblancs(j);
801 switch (*j) {
802 case '{':
803 jt->elm[idx].kind = JSON_OBJECT;
804 jt->elm[idx].value = j;
805 j++;
806 while (*j) {
807 skipblancs(j);
808 if (*j == '}')
809 break;
810 nxt = JSONtoken(jt, j, next);
811 if (jt->error)
812 return idx;
813 if (jt->elm[nxt].kind != JSON_ELEMENT) {
814 jt->error = createException(MAL, "json.parser", "JSON syntax error: element expected");
815 return idx;
816 }
817 JSONappend(jt, idx, nxt);
818 if (jt->error)
819 return idx;
820 j = *next;
821 skipblancs(j);
822 if (*j == '}')
823 break;
824 if (*j != '}' && *j != ',') {
825 jt->error = createException(MAL, "json.parser", "JSON syntax error: ',' or '}' expected");
826 return idx;
827 }
828 j++;
829 }
830 if (*j != '}') {
831 jt->error = createException(MAL, "json.parser", "JSON syntax error: '}' expected");
832 return idx;
833 } else
834 j++;
835 *next = j;
836 jt->elm[idx].valuelen = *next - jt->elm[idx].value;
837 return idx;
838 case '[':
839 jt->elm[idx].kind = JSON_ARRAY;
840 jt->elm[idx].value = j;
841 j++;
842 while (*j) {
843 skipblancs(j);
844 if (*j == ']')
845 break;
846 nxt = JSONtoken(jt, j, next);
847 if (jt->error)
848 return idx;
849 switch (jt->elm[nxt].kind) {
850 case JSON_ELEMENT:{
851 int k = JSONnew(jt);
852 if (jt->error)
853 return idx;
854 jt->elm[k].kind = JSON_OBJECT;
855 jt->elm[k].child = nxt;
856 nxt = k;
857 }
858 /* fall through */
859 case JSON_OBJECT:
860 case JSON_ARRAY:
861 if (jt->elm[nxt].kind == JSON_OBJECT || jt->elm[nxt].kind == JSON_ARRAY) {
862 int k = JSONnew(jt);
863 if (jt->error)
864 return idx;
865 JSONappend(jt, idx, k);
866 if (jt->error)
867 return idx;
868 jt->elm[k].kind = JSON_VALUE;
869 jt->elm[k].child = nxt;
870 }
871 break;
872 default:
873 JSONappend(jt, idx, nxt);
874 if (jt->error)
875 return idx;
876 }
877 j = *next;
878 skipblancs(j);
879 if (*j == ']')
880 break;
881 if (jt->elm[nxt].kind == JSON_ELEMENT) {
882 jt->error = createException(MAL, "json.parser", "JSON syntax error: Array value expected");
883 return idx;
884 }
885 if (*j != ']' && *j != ',') {
886 jt->error = createException(MAL, "json.parser", "JSON syntax error: ',' or ']' expected");
887 return idx;
888 }
889 j++;
890 skipblancs(j);
891 }
892 if (*j != ']') {
893 jt->error = createException(MAL, "json.parser", "JSON syntax error: ']' expected");
894 } else
895 j++;
896 *next = j;
897 jt->elm[idx].valuelen = *next - jt->elm[idx].value;
898 return idx;
899 case '"':
900 msg = JSONstringParser(j, next);
901 if (msg) {
902 jt->error = msg;
903 return idx;
904 }
905 jt->elm[idx].kind = JSON_STRING;
906 jt->elm[idx].value = j;
907 jt->elm[idx].valuelen = *next - j;
908 j = *next;
909 skipblancs(j);
910 if (*j == ':') {
911 j++;
912 skipblancs(j);
913 jt->elm[idx].kind = JSON_ELEMENT;
914 nxt = JSONtoken(jt, j, next);
915 if (jt->error)
916 return idx;
917 jt->elm[idx].child = nxt;
918 jt->elm[idx].value++;
919 jt->elm[idx].valuelen -= 2;
920 }
921 return idx;
922 case 'n':
923 if (strncmp("null", j, 4) == 0) {
924 *next = j + 4;
925 jt->elm[idx].kind = JSON_NULL;
926 jt->elm[idx].value = j;
927 jt->elm[idx].valuelen = 4;
928 return idx;
929 }
930 jt->error = createException(MAL, "json.parser", "JSON syntax error: NULL expected");
931 return idx;
932 case 't':
933 if (strncmp("true", j, 4) == 0) {
934 *next = j + 4;
935 jt->elm[idx].kind = JSON_NUMBER;
936 jt->elm[idx].value = j;
937 jt->elm[idx].valuelen = 4;
938 return idx;
939 }
940 jt->error = createException(MAL, "json.parser", "JSON syntax error: True expected");
941 return idx;
942 case 'f':
943 if (strncmp("false", j, 5) == 0) {
944 *next = j + 5;
945 jt->elm[idx].kind = JSON_NUMBER;
946 jt->elm[idx].value = j;
947 jt->elm[idx].valuelen = 5;
948 return idx;
949 }
950 jt->error = createException(MAL, "json.parser", "JSON syntax error: False expected");
951 return idx;
952 default:
953 if (*j == '-' || isdigit((unsigned char) *j)) {
954 jt->elm[idx].value = j;
955 msg = JSONnumberParser(j, next);
956 if (msg)
957 jt->error = msg;
958 jt->elm[idx].kind = JSON_NUMBER;
959 jt->elm[idx].valuelen = *next - jt->elm[idx].value;
960 return idx;
961 }
962 jt->error = createException(MAL, "json.parser", "JSON syntax error: value expected");
963 return idx;
964 }
965}
966
967
968static JSON *
969JSONparse(const char *j)
970{
971 JSON *jt = JSONnewtree();
972
973 if (jt == NULL)
974 return NULL;
975 skipblancs(j);
976 if (!*j || !(*j == '{' || *j == '[')) {
977 jt->error = createException(MAL, "json.parser", "JSON syntax error: json parse failed, expecting '{', '['");
978 return jt;
979 }
980 JSONtoken(jt, j, &j);
981 if (jt->error)
982 return jt;
983 skipblancs(j);
984 if (*j)
985 jt->error = createException(MAL, "json.parser", "JSON syntax error: json parse failed");
986 return jt;
987}
988
989str
990JSONlength(int *ret, json *j)
991{
992 int i, cnt = 0;
993 JSON *jt = JSONparse(*j);
994
995 CHECK_JSON(jt);
996 for (i = jt->elm[0].next; i; i = jt->elm[i].next)
997 cnt++;
998 *ret = cnt;
999 JSONfree(jt);
1000 return MAL_SUCCEED;
1001}
1002
1003static str
1004JSONfilterArrayDefault(json *ret, json *js, lng index, str other)
1005{
1006 char expr[BUFSIZ], *s = expr;
1007 snprintf(expr, BUFSIZ, "[" LLFMT "]", index);
1008 return JSONfilterInternal(ret, js, &s, other);
1009}
1010
1011str
1012JSONfilterArray_bte(json *ret, json *js, bte *index)
1013{
1014 return JSONfilterArrayDefault(ret, js, (lng) *index, 0);
1015}
1016
1017str
1018JSONfilterArrayDefault_bte(json *ret, json *js, bte *index, str *other)
1019{
1020 return JSONfilterArrayDefault(ret, js, (lng) *index, *other);
1021}
1022
1023str
1024JSONfilterArray_sht(json *ret, json *js, sht *index)
1025{
1026 return JSONfilterArrayDefault(ret, js, (lng) *index, 0);
1027}
1028
1029str
1030JSONfilterArrayDefault_sht(json *ret, json *js, sht *index, str *other)
1031{
1032 return JSONfilterArrayDefault(ret, js, (lng) *index, *other);
1033}
1034
1035str
1036JSONfilterArray_int(json *ret, json *js, int *index)
1037{
1038 return JSONfilterArrayDefault(ret, js, (lng) *index, 0);
1039}
1040
1041str
1042JSONfilterArrayDefault_int(json *ret, json *js, int *index, str *other)
1043{
1044 return JSONfilterArrayDefault(ret, js, (lng) *index, *other);
1045}
1046
1047str
1048JSONfilterArray_lng(json *ret, json *js, lng *index)
1049{
1050 return JSONfilterArrayDefault(ret, js, (lng) *index, 0);
1051}
1052
1053str
1054JSONfilterArrayDefault_lng(json *ret, json *js, lng *index, str *other)
1055{
1056 return JSONfilterArrayDefault(ret, js, (lng) *index, *other);
1057}
1058
1059#ifdef HAVE_HGE
1060str
1061JSONfilterArray_hge(json *ret, json *js, hge *index)
1062{
1063 if (*index < (hge) GDK_lng_min || *index > (hge) GDK_lng_max)
1064 throw(MAL, "json.filter", "index out of range");
1065 return JSONfilterArrayDefault(ret, js, (lng) *index, 0);
1066}
1067
1068str
1069JSONfilterArrayDefault_hge(json *ret, json *js, hge *index, str *other)
1070{
1071 if (*index < (hge) GDK_lng_min || *index > (hge) GDK_lng_max)
1072 throw(MAL, "json.filter", "index out of range");
1073 return JSONfilterArrayDefault(ret, js, (lng) *index, *other);
1074}
1075#endif
1076
1077str
1078JSONfilter(json *ret, json *js, str *expr)
1079{
1080 return JSONfilterInternal(ret, js, expr, 0);
1081}
1082
1083// glue all values together with an optional separator
1084// The json string should be valid
1085
1086static char *
1087JSONplaintext(char *r, size_t *l, JSON *jt, int idx, char sep)
1088{
1089 int i;
1090 size_t j;
1091
1092 switch (jt->elm[idx].kind) {
1093 case JSON_OBJECT:
1094 for (i = jt->elm[idx].next; i; i = jt->elm[i].next)
1095 if (jt->elm[i].child)
1096 r = JSONplaintext(r, l, jt, jt->elm[i].child, sep);
1097 break;
1098 case JSON_ARRAY:
1099 for (i = jt->elm[idx].next; i; i = jt->elm[i].next)
1100 r = JSONplaintext(r, l, jt, i, sep);
1101 break;
1102 case JSON_ELEMENT:
1103 case JSON_VALUE:
1104 if (jt->elm[idx].child)
1105 r = JSONplaintext(r, l, jt, jt->elm[idx].child, sep);
1106 break;
1107 case JSON_STRING:
1108 for (j = 1; *l > 1 && j < jt->elm[idx].valuelen - 1; j++) {
1109 if (jt->elm[idx].value[j] == '\\')
1110 *r = jt->elm[idx].value[++j];
1111 else
1112 *r = jt->elm[idx].value[j];
1113 r++;
1114 (*l)--;
1115 }
1116 if (*l > 1 && sep) {
1117 *r++ = sep;
1118 (*l)--;
1119 }
1120 break;
1121 default:
1122 for (j = 0; *l > 1 && j < jt->elm[idx].valuelen; j++) {
1123 *r = jt->elm[idx].value[j];
1124 r++;
1125 (*l)--;
1126 }
1127 if (*l > 1 && sep) {
1128 *r++ = sep;
1129 (*l)--;
1130 }
1131 }
1132 assert(*l > 0);
1133 *r = 0;
1134 return r;
1135}
1136
1137str
1138JSONjson2text(str *ret, json *js)
1139{
1140 JSON *jt;
1141 size_t l;
1142 str s;
1143
1144 jt = JSONparse(*js);
1145
1146 CHECK_JSON(jt);
1147 l = strlen(*js) + 1;
1148 s = GDKmalloc(l);
1149 if(s == NULL) {
1150 JSONfree(jt);
1151 throw(MAL,"json2txt", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1152 }
1153 JSONplaintext(s, &l, jt, 0, ' ');
1154 l = strlen(s);
1155 if (l)
1156 s[l - 1] = 0;
1157 *ret = s;
1158 JSONfree(jt);
1159 return MAL_SUCCEED;
1160}
1161
1162str
1163JSONjson2textSeparator(str *ret, json *js, str *sep)
1164{
1165 JSON *jt;
1166 size_t l;
1167 str s;
1168
1169 jt = JSONparse(*js);
1170
1171 CHECK_JSON(jt);
1172 l = strlen(*js) + 1;
1173 s = GDKmalloc(l);
1174 if(s == NULL) {
1175 JSONfree(jt);
1176 throw(MAL,"json2txt", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1177 }
1178 JSONplaintext(s, &l, jt, 0, **sep);
1179 l = strlen(s);
1180 if (l)
1181 s[l - 1] = 0;
1182 *ret = s;
1183 JSONfree(jt);
1184 return MAL_SUCCEED;
1185}
1186
1187str
1188JSONjson2number(dbl *ret, json *js)
1189{
1190 JSON *jt;
1191 char *rest;
1192
1193 *ret = dbl_nil;
1194 jt = JSONparse(*js);
1195 CHECK_JSON(jt);
1196 switch (jt->elm[0].kind) {
1197 case JSON_NUMBER:
1198 *ret = strtod(jt->elm[0].value, &rest);
1199 if (rest && (size_t) (rest - jt->elm[0].value) !=jt->elm[0].valuelen)
1200 *ret = dbl_nil;
1201 break;
1202 case JSON_ARRAY:
1203 if (jt->free == 2) {
1204 *ret = strtod(jt->elm[1].value, &rest);
1205 if (rest && (size_t) (rest - jt->elm[1].value) !=jt->elm[1].valuelen)
1206 *ret = dbl_nil;
1207 }
1208 break;
1209 case JSON_OBJECT:
1210 if (jt->free == 3) {
1211 *ret = strtod(jt->elm[2].value, &rest);
1212 if (rest && (size_t) (rest - jt->elm[2].value) !=jt->elm[2].valuelen)
1213 *ret = dbl_nil;
1214 }
1215 }
1216 JSONfree(jt);
1217 return MAL_SUCCEED;
1218}
1219
1220str
1221JSONjson2integer(lng *ret, json *js)
1222{
1223 JSON *jt;
1224 char *rest;
1225
1226 *ret = lng_nil;
1227 jt = JSONparse(*js);
1228 CHECK_JSON(jt);
1229 switch (jt->elm[0].kind) {
1230 case JSON_NUMBER:
1231 *ret = strtol(jt->elm[0].value, &rest, 0);
1232 if (rest && (size_t) (rest - jt->elm[0].value) !=jt->elm[0].valuelen)
1233 *ret = lng_nil;
1234 break;
1235 case JSON_ARRAY:
1236 if (jt->free == 2) {
1237 *ret = strtol(jt->elm[1].value, &rest, 0);
1238 if (rest && (size_t) (rest - jt->elm[1].value) !=jt->elm[1].valuelen)
1239 *ret = lng_nil;
1240 }
1241 break;
1242 case JSON_OBJECT:
1243 if (jt->free == 3) {
1244 *ret = strtol(jt->elm[2].value, &rest, 0);
1245 if (rest && (size_t) (rest - jt->elm[2].value) !=jt->elm[2].valuelen)
1246 *ret = lng_nil;
1247 }
1248 }
1249 JSONfree(jt);
1250 return MAL_SUCCEED;
1251}
1252
1253static str
1254JSONunfoldContainer(JSON *jt, int idx, BAT *bo, BAT *bk, BAT *bv, oid *o)
1255{
1256 int i, last;
1257 int cnt = 0;
1258 char *r;
1259
1260 last = jt->elm[idx].tail;
1261 if (jt->elm[idx].kind == JSON_OBJECT) {
1262 for (i = jt->elm[idx].next; i; i = jt->elm[i].next) {
1263 if ((r = JSONgetValue(jt, i)) == NULL)
1264 goto memfail;
1265 if (BUNappend(bk, r, false) != GDK_SUCCEED) {
1266 GDKfree(r);
1267 goto memfail;
1268 }
1269 GDKfree(r);
1270 if ((r = JSONgetValue(jt, jt->elm[i].child)) == NULL)
1271 goto memfail;
1272 if (BUNappend(bv, r, false) != GDK_SUCCEED) {
1273 GDKfree(r);
1274 goto memfail;
1275 }
1276 GDKfree(r);
1277 if (bo) {
1278 if (BUNappend(bo, o, false) != GDK_SUCCEED)
1279 goto memfail;
1280 }
1281 (*o)++;
1282 if (i == last)
1283 break;
1284 }
1285 } else if (jt->elm[idx].kind == JSON_ARRAY) {
1286 for (i = jt->elm[idx].next; i; i = jt->elm[i].next) {
1287 if (BUNappend(bk, str_nil, false) != GDK_SUCCEED)
1288 goto memfail;
1289 if (jt->elm[i].kind == JSON_VALUE)
1290 r = JSONgetValue(jt, jt->elm[i].child);
1291 else
1292 r = JSONgetValue(jt, i);
1293 if (r == NULL)
1294 goto memfail;
1295 if (BUNappend(bv, r, false) != GDK_SUCCEED) {
1296 GDKfree(r);
1297 goto memfail;
1298 }
1299 GDKfree(r);
1300 if (bo) {
1301 if (BUNappend(bo, o, false) != GDK_SUCCEED)
1302 goto memfail;
1303 }
1304 (*o)++;
1305 cnt++;
1306 if (i == last)
1307 break;
1308 }
1309 }
1310 return MAL_SUCCEED;
1311
1312 memfail:
1313 throw(MAL, "json.unfold", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1314}
1315
1316static str
1317JSONunfoldInternal(bat *od, bat *key, bat *val, json *js)
1318{
1319 BAT *bo = NULL, *bk, *bv;
1320 oid o = 0;
1321 str msg = MAL_SUCCEED;
1322
1323 JSON *jt = JSONparse(*js);
1324
1325 CHECK_JSON(jt);
1326 bk = COLnew(0, TYPE_str, 64, TRANSIENT);
1327 if (bk == NULL) {
1328 JSONfree(jt);
1329 throw(MAL, "json.unfold", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1330 }
1331 bk->tsorted = true;
1332 bk->trevsorted = false;
1333 bk->tnonil = true;
1334
1335 if (od) {
1336 bo = COLnew(0, TYPE_oid, 64, TRANSIENT);
1337 if (bo == NULL) {
1338 BBPreclaim(bk);
1339 JSONfree(jt);
1340 throw(MAL, "json.unfold", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1341 }
1342 bo->tsorted = true;
1343 bo->trevsorted = false;
1344 bo->tnonil = true;
1345 }
1346
1347 bv = COLnew(0, TYPE_json, 64, TRANSIENT);
1348 if (bv == NULL) {
1349 JSONfree(jt);
1350 BBPreclaim(bo);
1351 BBPreclaim(bk);
1352 throw(MAL, "json.unfold", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1353 }
1354 bv->tsorted = true;
1355 bv->trevsorted = false;
1356 bv->tnonil = true;
1357
1358 if (jt->elm[0].kind == JSON_ARRAY || jt->elm[0].kind == JSON_OBJECT)
1359 msg = JSONunfoldContainer(jt, 0, (od ? bo : 0), bk, bv, &o);
1360 else
1361 msg = createException(MAL, "json.unfold", "JSON object or array expected");
1362 JSONfree(jt);
1363 if (msg) {
1364 BBPreclaim(bk);
1365 BBPreclaim(bo);
1366 BBPreclaim(bv);
1367 } else {
1368 BBPkeepref(*key = bk->batCacheid);
1369 BBPkeepref(*val = bv->batCacheid);
1370 if (od)
1371 BBPkeepref(*od = bo->batCacheid);
1372 }
1373 return msg;
1374}
1375
1376
1377
1378str
1379JSONkeyTable(bat *ret, json *js)
1380{
1381 BAT *bn;
1382 char *r;
1383 int i;
1384 JSON *jt;
1385
1386 jt = JSONparse(*js); // already validated
1387 CHECK_JSON(jt);
1388 bn = COLnew(0, TYPE_str, 64, TRANSIENT);
1389 if (bn == NULL) {
1390 JSONfree(jt);
1391 throw(MAL, "json.keys", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1392 }
1393 bn->tsorted = true;
1394 bn->trevsorted = false;
1395 bn->tnonil = true;
1396
1397 for (i = jt->elm[0].next; i; i = jt->elm[i].next) {
1398 r = JSONgetValue(jt, i);
1399 if (r == NULL ||
1400 BUNappend(bn, r, false) != GDK_SUCCEED) {
1401 GDKfree(r);
1402 JSONfree(jt);
1403 BBPreclaim(bn);
1404 throw(MAL, "json.keys", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1405 }
1406 GDKfree(r);
1407 }
1408 JSONfree(jt);
1409 BBPkeepref(*ret = bn->batCacheid);
1410 return MAL_SUCCEED;
1411}
1412
1413str
1414JSONkeyArray(json *ret, json *js)
1415{
1416 char *result = NULL;
1417 str r;
1418 int i;
1419 JSON *jt;
1420
1421 jt = JSONparse(*js); // already validated
1422
1423 CHECK_JSON(jt);
1424 if (jt->elm[0].kind == JSON_OBJECT) {
1425 for (i = jt->elm[0].next; i; i = jt->elm[i].next) {
1426 r = GDKzalloc(jt->elm[i].valuelen + 3);
1427 if (r == NULL) {
1428 JSONfree(jt);
1429 goto memfail;
1430 }
1431 if (jt->elm[i].valuelen)
1432 strncpy(r, jt->elm[i].value - 1, jt->elm[i].valuelen + 2);
1433 result = JSONglue(result, r, ',');
1434 if (result == NULL) {
1435 JSONfree(jt);
1436 goto memfail;
1437 }
1438 }
1439 JSONfree(jt);
1440 } else {
1441 JSONfree(jt);
1442 throw(MAL, "json.keyarray", "Object expected");
1443 }
1444 r = GDKstrdup("[");
1445 if (r == NULL)
1446 goto memfail;
1447 result = JSONglue(r, result, 0);
1448 if (result == NULL)
1449 goto memfail;
1450 r = GDKstrdup("]");
1451 if (r == NULL)
1452 goto memfail;
1453 result = JSONglue(result, r, 0);
1454 if (result == NULL)
1455 goto memfail;
1456 *ret = result;
1457 return MAL_SUCCEED;
1458
1459 memfail:
1460 GDKfree(result);
1461 throw(MAL, "json.keyarray", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1462}
1463
1464
1465str
1466JSONvalueTable(bat *ret, json *js)
1467{
1468 BAT *bn;
1469 char *r;
1470 int i;
1471 JSON *jt;
1472
1473 jt = JSONparse(*js); // already validated
1474 CHECK_JSON(jt);
1475 bn = COLnew(0, TYPE_json, 64, TRANSIENT);
1476 if (bn == NULL) {
1477 JSONfree(jt);
1478 throw(MAL, "json.values", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1479 }
1480 bn->tsorted = true;
1481 bn->trevsorted = false;
1482 bn->tnonil = true;
1483
1484 for (i = jt->elm[0].next; i; i = jt->elm[i].next) {
1485 if (jt->elm[i].kind == JSON_ELEMENT)
1486 r = JSONgetValue(jt, jt->elm[i].child);
1487 else
1488 r = JSONgetValue(jt, i);
1489 if (r == NULL ||
1490 BUNappend(bn, r, false) != GDK_SUCCEED) {
1491 GDKfree(r);
1492 BBPreclaim(bn);
1493 JSONfree(jt);
1494 throw(MAL, "json.values", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1495 }
1496 GDKfree(r);
1497 }
1498 JSONfree(jt);
1499 BBPkeepref(*ret = bn->batCacheid);
1500 return MAL_SUCCEED;
1501}
1502
1503str
1504JSONvalueArray(json *ret, json *js)
1505{
1506 char *result = NULL;
1507 str r;
1508 int i;
1509 JSON *jt;
1510
1511 jt = JSONparse(*js); // already validated
1512
1513 CHECK_JSON(jt);
1514 if (jt->elm[0].kind == JSON_OBJECT) {
1515 for (i = jt->elm[0].next; i; i = jt->elm[i].next) {
1516 r = JSONgetValue(jt, jt->elm[i].child);
1517 if (r == NULL) {
1518 JSONfree(jt);
1519 goto memfail;
1520 }
1521 result = JSONglue(result, r, ',');
1522 if (result == NULL) {
1523 JSONfree(jt);
1524 goto memfail;
1525 }
1526 }
1527 JSONfree(jt);
1528 } else {
1529 JSONfree(jt);
1530 throw(MAL, "json.valuearray", "Object expected");
1531 }
1532 r = GDKstrdup("[");
1533 if (r == NULL)
1534 goto memfail;
1535 result = JSONglue(r, result, 0);
1536 if (result == NULL)
1537 goto memfail;
1538 r = GDKstrdup("]");
1539 if (r == NULL)
1540 goto memfail;
1541 result = JSONglue(result, r, 0);
1542 if (result == NULL)
1543 goto memfail;
1544 *ret = result;
1545 return MAL_SUCCEED;
1546
1547 memfail:
1548 GDKfree(result);
1549 throw(MAL, "json.valuearray", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1550}
1551
1552static BAT **
1553JSONargumentlist(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1554{
1555 int i, error = 0, bats = 0;
1556 BUN cnt = 0;
1557 BAT **bl;
1558
1559 bl = (BAT **) GDKzalloc(sizeof(*bl) * pci->argc);
1560 if (bl == NULL)
1561 return NULL;
1562 for (i = pci->retc; i < pci->argc; i++)
1563 if (isaBatType(getArgType(mb, pci, i))) {
1564 bats++;
1565 bl[i] = BATdescriptor(stk->stk[getArg(pci, i)].val.bval);
1566 if (bl[i] == NULL || (cnt > 0 && BATcount(bl[i]) != cnt)) {
1567 error = 1;
1568 break;
1569 }
1570 cnt = BATcount(bl[i]);
1571 }
1572 if (error || bats == 0) {
1573 for (i = pci->retc; i < pci->argc; i++)
1574 if (bl[i])
1575 BBPunfix(bl[i]->batCacheid);
1576 GDKfree(bl);
1577 return NULL;
1578 }
1579 return bl;
1580}
1581
1582static void
1583JSONfreeArgumentlist(BAT **bl, InstrPtr pci)
1584{
1585 int i;
1586
1587 for (i = pci->retc; i < pci->argc; i++)
1588 if (bl[i])
1589 BBPunfix(bl[i]->batCacheid);
1590 GDKfree(bl);
1591}
1592
1593static str
1594JSONrenderRowObject(BAT **bl, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, BUN idx)
1595{
1596 int i, tpe;
1597 char *row, *row2, *name = 0, *val = 0;
1598 size_t len, lim, l;
1599 void *p;
1600 BATiter bi;
1601
1602 row = GDKmalloc(lim = BUFSIZ);
1603 if (row == NULL)
1604 return NULL;
1605 row[0] = '{';
1606 row[1] = 0;
1607 len = 1;
1608 for (i = pci->retc; i < pci->argc; i += 2) {
1609 name = stk->stk[getArg(pci, i)].val.sval;
1610 bi = bat_iterator(bl[i + 1]);
1611 p = BUNtail(bi, idx);
1612 tpe = getBatType(getArgType(mb, pci, i + 1));
1613 if ((val = ATOMformat(tpe, p)) == NULL) {
1614 GDKfree(row);
1615 return NULL;
1616 }
1617 if (strncmp(val, "nil", 3) == 0) {
1618 GDKfree(val);
1619 val = NULL;
1620 l = 4;
1621 } else {
1622 l = strlen(val);
1623 }
1624 l += strlen(name) + 4;
1625 while (l > lim - len)
1626 lim += BUFSIZ;
1627 row2 = GDKrealloc(row, lim);
1628 if (row2 == NULL) {
1629 GDKfree(row);
1630 GDKfree(val);
1631 return NULL;
1632 }
1633 row = row2;
1634 snprintf(row + len, lim - len, "\"%s\":%s,", name, val ? val : "null");
1635 len += l;
1636 GDKfree(val);
1637 }
1638 if (row[1])
1639 row[len - 1] = '}';
1640 else {
1641 row[1] = '}';
1642 row[2] = 0;
1643 }
1644 return row;
1645}
1646
1647str
1648JSONrenderobject(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1649{
1650 BAT **bl;
1651 char *result, *row;
1652 int i;
1653 size_t len, lim, l;
1654 json *ret;
1655 BUN j, cnt;
1656
1657 (void) cntxt;
1658 bl = JSONargumentlist(mb, stk, pci);
1659 if (bl == 0)
1660 throw(MAL, "json.renderobject", "Non-aligned BAT sizes");
1661 for (i = pci->retc; i < pci->argc; i += 2) {
1662 if (getArgType(mb, pci, i) != TYPE_str) {
1663 JSONfreeArgumentlist(bl, pci);
1664 throw(MAL, "json.renderobject", "Keys missing");
1665 }
1666 }
1667
1668 cnt = BATcount(bl[pci->retc + 1]);
1669 result = (char *) GDKmalloc(lim = BUFSIZ);
1670 if (result == NULL) {
1671 JSONfreeArgumentlist(bl, pci);
1672 throw(MAL,"json.renderobject", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1673 }
1674 result[0] = '[';
1675 result[1] = 0;
1676 len = 1;
1677
1678 for (j = 0; j < cnt; j++) {
1679 char *result2;
1680 row = JSONrenderRowObject(bl, mb, stk, pci, j);
1681 if (row == NULL)
1682 goto memfail;
1683 l = strlen(row);
1684 while (l + 2 > lim - len)
1685 lim = cnt * l <= lim ? cnt * l : lim + BUFSIZ;
1686 result2 = GDKrealloc(result, lim);
1687 if (result2 == NULL)
1688 goto memfail;
1689 result = result2;
1690 strcpy(result + len, row);
1691 GDKfree(row);
1692 len += l;
1693 result[len++] = ',';
1694 result[len] = 0;
1695 }
1696 result[len - 1] = ']';
1697 ret = getArgReference_TYPE(stk, pci, 0, json);
1698 *ret = result;
1699 JSONfreeArgumentlist(bl, pci);
1700 return MAL_SUCCEED;
1701
1702 memfail:
1703 GDKfree(result);
1704 GDKfree(row);
1705 JSONfreeArgumentlist(bl, pci);
1706 throw(MAL,"json.renderobject", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1707}
1708
1709static str
1710JSONrenderRowArray(BAT **bl, MalBlkPtr mb, InstrPtr pci, BUN idx)
1711{
1712 int i, tpe;
1713 char *row, *row2, *val = 0;
1714 size_t len, lim, l;
1715 void *p;
1716 BATiter bi;
1717
1718 row = GDKmalloc(lim = BUFSIZ);
1719 if (row == NULL)
1720 return NULL;
1721 row[0] = '[';
1722 row[1] = 0;
1723 len = 1;
1724 for (i = pci->retc; i < pci->argc; i++) {
1725 bi = bat_iterator(bl[i]);
1726 p = BUNtail(bi, idx);
1727 tpe = getBatType(getArgType(mb, pci, i));
1728 if ((val = ATOMformat(tpe, p)) == NULL) {
1729 goto memfail;
1730 }
1731 if (strcmp(val, "nil") == 0) {
1732 GDKfree(val);
1733 val = NULL;
1734 l = 4;
1735 } else {
1736 l = strlen(val);
1737 }
1738 while (len + l > lim)
1739 lim += BUFSIZ;
1740 row2 = GDKrealloc(row, lim);
1741 if (row2 == NULL)
1742 goto memfail;
1743 row = row2;
1744 snprintf(row + len, lim - len, "%s,", val ? val : "null");
1745 len += l + 1;
1746 GDKfree(val);
1747 val = NULL;
1748 }
1749 if (row[1])
1750 row[len - 1] = ']';
1751 else {
1752 row[1] = '}';
1753 row[2] = 0;
1754 }
1755 return row;
1756
1757 memfail:
1758 GDKfree(row);
1759 GDKfree(val);
1760 return NULL;
1761}
1762
1763str
1764JSONrenderarray(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1765{
1766 BAT **bl;
1767 char *result, *row;
1768 size_t len, lim, l;
1769 str *ret;
1770 BUN j, cnt;
1771
1772 (void) cntxt;
1773 bl = JSONargumentlist(mb, stk, pci);
1774 if (bl == 0)
1775 throw(MAL, "json.renderrray", "Non-aligned BAT sizes");
1776
1777 cnt = BATcount(bl[pci->retc + 1]);
1778 result = GDKmalloc(lim = BUFSIZ);
1779 if( result == NULL) {
1780 goto memfail;
1781 }
1782 result[0] = '[';
1783 result[1] = 0;
1784 len = 1;
1785
1786 for (j = 0; j < cnt; j++) {
1787 char *result2;
1788 row = JSONrenderRowArray(bl, mb, pci, j);
1789 if (row == NULL) {
1790 goto memfail;
1791 }
1792 l = strlen(row);
1793 while (l + 2 > lim - len)
1794 lim = cnt * l <= lim ? cnt * l : lim + BUFSIZ;
1795 result2 = GDKrealloc(result, lim);
1796 if (result2 == NULL) {
1797 GDKfree(row);
1798 goto memfail;
1799 }
1800 result = result2;
1801 strcpy(result + len, row);
1802 GDKfree(row);
1803 len += l;
1804 result[len++] = ',';
1805 result[len] = 0;
1806 }
1807 result[len - 1] = ']';
1808 ret = getArgReference_TYPE(stk, pci, 0, json);
1809 *ret = result;
1810 JSONfreeArgumentlist(bl, pci);
1811 return MAL_SUCCEED;
1812
1813 memfail:
1814 GDKfree(result);
1815 JSONfreeArgumentlist(bl, pci);
1816 throw(MAL,"json.renderArray", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1817}
1818
1819static str
1820JSONfoldKeyValue(str *ret, const bat *id, const bat *key, const bat *values)
1821{
1822 BAT *bo = 0, *bk = 0, *bv;
1823 BATiter bki, bvi;
1824 int tpe;
1825 char *row, *val = 0, *nme = 0;
1826 BUN i, cnt;
1827 size_t len, lim, l;
1828 void *p;
1829 oid o = 0;;
1830
1831 if (key) {
1832 bk = BATdescriptor(*key);
1833 if (bk == NULL) {
1834 throw(MAL, "json.fold", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1835 }
1836 }
1837
1838 bv = BATdescriptor(*values);
1839 if (bv == NULL) {
1840 if (bk)
1841 BBPunfix(bk->batCacheid);
1842 throw(MAL, "json.fold", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1843 }
1844 tpe = bv->ttype;
1845 cnt = BATcount(bv);
1846 bki = bat_iterator(bk);
1847 bvi = bat_iterator(bv);
1848 if (id) {
1849 bo = BATdescriptor(*id);
1850 if (bo == NULL) {
1851 if (bk)
1852 BBPunfix(bk->batCacheid);
1853 BBPunfix(bv->batCacheid);
1854 throw(MAL, "json.nest", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1855 }
1856 }
1857
1858 row = GDKmalloc(lim = BUFSIZ);
1859 if (row == NULL) {
1860 goto memfail;
1861 }
1862 row[0] = '[';
1863 row[1] = 0;
1864 len = 1;
1865 if (id) {
1866 o = BUNtoid(bo, 0);
1867 }
1868
1869 for (i = 0; i < cnt; i++) {
1870 if (id && bk) {
1871 if (BUNtoid(bo, i) != o) {
1872 snprintf(row + len, lim - len, ", ");
1873 len += 2;
1874 o = BUNtoid(bo, i);
1875 }
1876 }
1877
1878 if (bk) {
1879 nme = (str) BUNtvar(bki, i);
1880 l = strlen(nme);
1881 while (l + 3 > lim - len)
1882 lim = (lim / (i + 1)) * cnt + BUFSIZ + l + 3;
1883 p = GDKrealloc(row, lim);
1884 if (p == NULL) {
1885 goto memfail;
1886 }
1887 row = p;
1888 if (strcmp(nme, str_nil)) {
1889 snprintf(row + len, lim - len, "\"%s\":", nme);
1890 len += l + 3;
1891 }
1892 }
1893
1894 bvi = bat_iterator(bv);
1895 p = BUNtail(bvi, i);
1896 if (tpe == TYPE_json)
1897 val = p;
1898 else {
1899 if ((val = ATOMformat(tpe, p)) == NULL)
1900 goto memfail;
1901 if (strcmp(val, "nil") == 0) {
1902 GDKfree(val);
1903 val = NULL;
1904 }
1905 }
1906 l = val ? strlen(val) : 4;
1907 while (l > lim - len)
1908 lim = (lim / (i + 1)) * cnt + BUFSIZ + l + 3;
1909 p = GDKrealloc(row, lim);
1910 if (p == NULL) {
1911 if (tpe != TYPE_json)
1912 GDKfree(val);
1913 goto memfail;
1914 }
1915 row = p;
1916 strncpy(row + len, val ? val : "null", l);
1917 len += l;
1918 row[len++] = ',';
1919 row[len] = 0;
1920 if (tpe != TYPE_json)
1921 GDKfree(val);
1922 }
1923 if (row[1]) {
1924 row[len - 1] = ']';
1925 row[len] = 0;
1926 } else {
1927 row[1] = ']';
1928 row[2] = 0;
1929 }
1930 if (bo)
1931 BBPunfix(bo->batCacheid);
1932 if (bk)
1933 BBPunfix(bk->batCacheid);
1934 BBPunfix(bv->batCacheid);
1935 *ret = row;
1936 return MAL_SUCCEED;
1937
1938 memfail:
1939 GDKfree(row);
1940 if (bo)
1941 BBPunfix(bo->batCacheid);
1942 if (bk)
1943 BBPunfix(bk->batCacheid);
1944 BBPunfix(bv->batCacheid);
1945 throw(MAL, "json.fold", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1946}
1947
1948str
1949JSONunfold(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1950{
1951 bat *id = 0, *key = 0, *val = 0;
1952 json *js;
1953
1954 (void) cntxt;
1955 (void) mb;
1956
1957 switch (pci->retc) {
1958 case 2:
1959 key = getArgReference_bat(stk, pci, 0);
1960 val = getArgReference_bat(stk, pci, 1);
1961 break;
1962 case 3:
1963 id = getArgReference_bat(stk, pci, 0);
1964 key = getArgReference_bat(stk, pci, 1);
1965 val = getArgReference_bat(stk, pci, 2);
1966 break;
1967 default:
1968 assert(0);
1969 throw(MAL, "json.unfold", ILLEGAL_ARGUMENT);
1970 }
1971 js = getArgReference_TYPE(stk, pci, pci->retc, json);
1972 return JSONunfoldInternal(id, key, val, js);
1973}
1974
1975str
1976JSONfold(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1977{
1978 bat *id = 0, *key = 0, *val = 0;
1979 str *ret;
1980
1981 (void) cntxt;
1982 (void) mb;
1983
1984 assert(pci->retc == 1);
1985 switch (pci->argc - pci->retc) {
1986 case 1:
1987 val = getArgReference_bat(stk, pci, 1);
1988 break;
1989 case 2:
1990 key = getArgReference_bat(stk, pci, 1);
1991 val = getArgReference_bat(stk, pci, 2);
1992 break;
1993 case 3:
1994 id = getArgReference_bat(stk, pci, 1);
1995 key = getArgReference_bat(stk, pci, 2);
1996 val = getArgReference_bat(stk, pci, 3);
1997 break;
1998 default:
1999 assert(0);
2000 throw(MAL, "json.fold", ILLEGAL_ARGUMENT);
2001 }
2002 ret = getArgReference_TYPE(stk, pci, 0, json);
2003 return JSONfoldKeyValue(ret, id, key, val);
2004}
2005
2006str
2007JSONtextString(str *ret, bat *bid)
2008{
2009 (void) ret;
2010 (void) bid;
2011 throw(MAL, "json.text", SQLSTATE(0A000) PROGRAM_NYI);
2012}
2013
2014
2015str
2016JSONtextGrouped(bat *ret, bat *bid, bat *gid, bat *ext, bit *flg)
2017{
2018 (void) ret;
2019 (void) bid;
2020 (void) gid;
2021 (void) ext;
2022 (void) flg;
2023 throw(MAL, "json.text", SQLSTATE(0A000) PROGRAM_NYI);
2024}
2025
2026str
2027JSONgroupStr(str *ret, const bat *bid)
2028{
2029 BAT *b;
2030 BUN p, q;
2031 const char *t = NULL;
2032 size_t len, size = BUFSIZ, offset, cnt = 0;
2033 str buf = GDKmalloc(size);
2034 BATiter bi;
2035 const char *err = NULL;
2036 char temp[128] = "";
2037 const double *val = NULL;
2038
2039 if (buf == NULL)
2040 throw(MAL, "json.group", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2041 if ((b = BATdescriptor(*bid)) == NULL) {
2042 GDKfree(buf);
2043 throw(MAL, "json.agg", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2044 }
2045 assert(b->ttype == TYPE_str || b->ttype == TYPE_dbl);
2046
2047 strcpy(buf, str_nil);
2048 offset = 0;
2049 bi = bat_iterator(b);
2050 BATloop(b, p, q) {
2051 int n = 0, nil = 0;
2052
2053 switch (b->ttype) {
2054 case TYPE_str:
2055 t = (const char *) BUNtvar(bi, p);
2056 nil = (strNil(t));
2057 break;
2058 case TYPE_dbl:
2059 val = (const double *) BUNtloc(bi, p);
2060 nil = is_dbl_nil(*val);
2061 if (!nil)
2062 snprintf(temp, sizeof(temp), "%f", *val);
2063 t = (const char *) temp;
2064 break;
2065 }
2066
2067 if (nil)
2068 continue;
2069 if (!cnt)
2070 offset = snprintf(buf, size, "[ ");
2071 len = strlen(t) + 1 + 4; /* closing bracket and optional ',' */
2072 if (len >= size - offset) {
2073 str nbuf;
2074 size += len + 128;
2075 nbuf = GDKrealloc(buf, size);
2076 if (nbuf == NULL) {
2077 err = SQLSTATE(HY001) MAL_MALLOC_FAIL;
2078 goto failed;
2079 }
2080 buf = nbuf;
2081 }
2082 if (cnt)
2083 offset += snprintf(buf + offset, size - offset, ", ");
2084 switch (b->ttype) {
2085 case TYPE_str:
2086 n = snprintf(buf + offset, size - offset, "\"%s\"", t);
2087 break;
2088 case TYPE_dbl:
2089 n = snprintf(buf + offset, size - offset, "%s", t);
2090 break;
2091 }
2092 cnt++;
2093 offset += n;
2094 }
2095 if (cnt)
2096 offset += snprintf(buf + offset, size - offset, " ]");
2097 BBPunfix(b->batCacheid);
2098 *ret = buf;
2099 return MAL_SUCCEED;
2100 failed:
2101 BBPunfix(b->batCacheid);
2102 GDKfree(buf);
2103 throw(MAL, "json.agg", "%s", err);
2104}
2105
2106static const char *
2107JSONjsonaggr(BAT **bnp, BAT *b, BAT *g, BAT *e, BAT *s, int skip_nils)
2108{
2109 BAT *bn = NULL, *t1, *t2 = NULL;
2110 BATiter bi;
2111 oid min, max;
2112 BUN ngrp;
2113 BUN nils = 0;
2114 int isnil;
2115 struct canditer ci;
2116 BUN ncand;
2117 const char *v = NULL;
2118 const oid *grps, *map;
2119 oid mapoff = 0;
2120 oid prev;
2121 BUN p, q;
2122 int freeb = 0, freeg = 0;
2123 char *buf = NULL, *buf2;
2124 size_t buflen, maxlen, len;
2125 const char *err;
2126 char temp[128] = "";
2127 const double *val = NULL;
2128
2129 assert(b->ttype == TYPE_str || b->ttype == TYPE_dbl);
2130 if ((err = BATgroupaggrinit(b, g, e, s, &min, &max, &ngrp, &ci, &ncand)) != NULL) {
2131 return err;
2132 }
2133 if (BATcount(b) == 0 || ngrp == 0) {
2134 bn = BATconstant(ngrp == 0 ? 0 : min, TYPE_str, ATOMnilptr(TYPE_str), ngrp, TRANSIENT);
2135 if (bn == NULL)
2136 return SQLSTATE(HY001) MAL_MALLOC_FAIL;
2137 *bnp = bn;
2138 return NULL;
2139 }
2140 if (s) {
2141 b = BATproject(s, b);
2142 if (b == NULL) {
2143 err = "internal project failed";
2144 goto out;
2145 }
2146 freeb = 1;
2147 if (g) {
2148 g = BATproject(s, g);
2149 if (g == NULL) {
2150 err = "internal project failed";
2151 goto out;
2152 }
2153 freeg = 1;
2154 }
2155 }
2156
2157 maxlen = BUFSIZ;
2158 if ((buf = GDKmalloc(maxlen)) == NULL) {
2159 err = SQLSTATE(HY001) MAL_MALLOC_FAIL;
2160 goto out;
2161 }
2162 buflen = 0;
2163 bn = COLnew(min, TYPE_str, ngrp, TRANSIENT);
2164 if (bn == NULL) {
2165 err = SQLSTATE(HY001) MAL_MALLOC_FAIL;
2166 goto out;
2167 }
2168 bi = bat_iterator(b);
2169 if (g) {
2170 /* stable sort g */
2171 if (BATsort(&t1, &t2, NULL, g, NULL, NULL, false, false, true) != GDK_SUCCEED) {
2172 err = "internal sort failed";
2173 goto out;
2174 }
2175 if (freeg)
2176 BBPunfix(g->batCacheid);
2177 g = t1;
2178 freeg = 1;
2179 if (t2->ttype == TYPE_void) {
2180 map = NULL;
2181 mapoff = t2->tseqbase;
2182 } else {
2183 map = (const oid *) Tloc(t2, 0);
2184 }
2185 if (g && BATtdense(g)) {
2186 for (p = 0, q = BATcount(g); p < q; p++) {
2187 switch (b->ttype) {
2188 case TYPE_str:
2189 v = (const char *) BUNtvar(bi, (map ? (BUN) map[p] : p + mapoff));
2190 break;
2191 case TYPE_dbl:
2192 val = (const double *) BUNtloc(bi, (map ? (BUN) map[p] : p + mapoff));
2193 if (!is_dbl_nil(*val)) {
2194 snprintf(temp, sizeof(temp), "%f", *val);
2195 v = (const char *) temp;
2196 } else {
2197 v = NULL;
2198 }
2199 break;
2200 }
2201 if (!v || strNil(v)) {
2202 if (skip_nils) {
2203 /*
2204 * if q is 1 and the value is
2205 * null, then we need to fill
2206 * in a value. Otherwise
2207 * BATproject will fail.
2208 */
2209 if ((p == 0) && (q == 1)) {
2210 strcpy(buf, "[ null ]");
2211 isnil = 1;
2212 } else {
2213 continue;
2214 }
2215 } else {
2216 strcpy(buf, str_nil);
2217 isnil = 1;
2218 }
2219 } else {
2220 len = strlen(v);
2221 if (len + 7 >= maxlen) {
2222 maxlen += len + BUFSIZ;
2223 buf2 = GDKrealloc(buf, maxlen);
2224 if (buf2 == NULL) {
2225 err = SQLSTATE(HY001) MAL_MALLOC_FAIL;
2226 goto bunins_failed;
2227 }
2228 buf = buf2;
2229 }
2230 switch (b->ttype) {
2231 case TYPE_str:
2232 snprintf(buf, maxlen, "[ \"%s\" ]", v);
2233 break;
2234 case TYPE_dbl:
2235 snprintf(buf, maxlen, "[ %s ]", v);
2236 break;
2237 }
2238 }
2239 bunfastapp_nocheckVAR(bn, BUNlast(bn), buf, Tsize(bn));
2240 }
2241 bn->tnil = nils != 0;
2242 bn->tnonil = nils == 0;
2243 bn->tsorted = BATcount(bn) <= 1;
2244 bn->trevsorted = BATcount(bn) <= 1;
2245 bn->tkey = BATcount(bn) <= 1;
2246 goto out;
2247 }
2248 grps = (const oid *) Tloc(g, 0);
2249 prev = grps[0];
2250 isnil = 0;
2251 for (p = 0, q = BATcount(g); p <= q; p++) {
2252 if (p == 0) {
2253 strncpy(buf + buflen, "[ ", maxlen - buflen);
2254 buflen += 2;
2255 }
2256 if (p == q || grps[p] != prev) {
2257 strncpy(buf + buflen, " ]", maxlen - buflen);
2258 buflen += 2;
2259 while (BATcount(bn) < prev - min) {
2260 bunfastapp_nocheckVAR(bn, BUNlast(bn), str_nil, Tsize(bn));
2261 nils++;
2262 }
2263 bunfastapp_nocheckVAR(bn, BUNlast(bn), buf, Tsize(bn));
2264 nils += strNil(buf);
2265 strncpy(buf + buflen, str_nil, maxlen - buflen);
2266 buflen = 0;
2267 if (p == q)
2268 break;
2269 prev = grps[p];
2270 strncpy(buf + buflen, "[ ", maxlen - buflen);
2271 buflen += 2;
2272 isnil = 0;
2273 }
2274 if (isnil)
2275 continue;
2276 switch (b->ttype) {
2277 case TYPE_str:
2278 v = (const char *) BUNtvar(bi, (map ? (BUN) map[p] : p + mapoff));
2279 break;
2280 case TYPE_dbl:
2281 val = (const double *) BUNtloc(bi, (map ? (BUN) map[p] : p + mapoff));
2282 if (!is_dbl_nil(*val)) {
2283 snprintf(temp, sizeof(temp), "%f", *val);
2284 v = (const char *) temp;
2285 } else {
2286 v = NULL;
2287 }
2288 break;
2289 }
2290 if (!v || strNil(v)) {
2291 if (skip_nils)
2292 continue;
2293 strncpy(buf, str_nil, buflen);
2294 isnil = 1;
2295 } else {
2296 len = strlen(v);
2297 if (len >= maxlen - buflen) {
2298 maxlen += len + BUFSIZ;
2299 buf2 = GDKrealloc(buf, maxlen);
2300 if (buf2 == NULL) {
2301 err = SQLSTATE(HY001) MAL_MALLOC_FAIL;
2302 goto bunins_failed;
2303 }
2304 buf = buf2;
2305 }
2306 switch (b->ttype) {
2307 case TYPE_str:
2308 if (buflen == 2) {
2309 len = snprintf(buf + buflen, maxlen - buflen, "\"%s\"", v);
2310 buflen += len;
2311 } else {
2312 len = snprintf(buf + buflen, maxlen - buflen, ", \"%s\"", v);
2313 buflen += len;
2314 }
2315 break;
2316 case TYPE_dbl:
2317 if (buflen == 2) {
2318 len = snprintf(buf + buflen, maxlen - buflen, "%s", v);
2319 buflen += len;
2320 } else {
2321 len = snprintf(buf + buflen, maxlen - buflen, ", %s", v);
2322 buflen += len;
2323 }
2324 break;
2325 }
2326 }
2327 }
2328 BBPunfix(t2->batCacheid);
2329 t2 = NULL;
2330 } else {
2331 for (p = 0, q = p + BATcount(b); p < q; p++) {
2332 switch (b->ttype) {
2333 case TYPE_str:
2334 v = (const char *) BUNtvar(bi, p);
2335 break;
2336 case TYPE_dbl:
2337 val = (const double *) BUNtloc(bi, p);
2338 if (!is_dbl_nil(*val)) {
2339 snprintf(temp, sizeof(temp), "%f", *val);
2340 v = (const char *) temp;
2341 } else {
2342 v = NULL;
2343 }
2344 break;
2345 }
2346
2347 if (!v || strNil(v)) {
2348 if (skip_nils)
2349 continue;
2350 strncpy(buf, str_nil, buflen);
2351 nils++;
2352 break;
2353 }
2354 len = strlen(v);
2355 if (len >= maxlen - buflen) {
2356 maxlen += len + BUFSIZ;
2357 buf2 = GDKrealloc(buf, maxlen);
2358 if (buf2 == NULL) {
2359 err = SQLSTATE(HY001) MAL_MALLOC_FAIL;
2360 goto bunins_failed;
2361 }
2362 buf = buf2;
2363 }
2364 switch (b->ttype) {
2365 case TYPE_str:
2366 if (buflen == 2) {
2367 len = snprintf(buf + buflen, maxlen - buflen, "\"%s\"", v);
2368 buflen += len;
2369 } else {
2370 len = snprintf(buf + buflen, maxlen - buflen, ", \"%s\"", v);
2371 buflen += len;
2372 }
2373 break;
2374 case TYPE_dbl:
2375 if (buflen == 2) {
2376 len = snprintf(buf + buflen, maxlen - buflen, "%s", v);
2377 buflen += len;
2378 } else {
2379 len = snprintf(buf + buflen, maxlen - buflen, ", %s", v);
2380 buflen += len;
2381 }
2382 break;
2383 }
2384 }
2385 bunfastapp_nocheckVAR(bn, BUNlast(bn), buf, Tsize(bn));
2386 }
2387 bn->tnil = nils != 0;
2388 bn->tnonil = nils == 0;
2389 bn->tsorted = BATcount(bn) <= 1;
2390 bn->trevsorted = BATcount(bn) <= 1;
2391 bn->tkey = BATcount(bn) <= 1;
2392
2393 out:
2394 bn->theap.dirty |= BATcount(bn) > 0;
2395 if (t2)
2396 BBPunfix(t2->batCacheid);
2397 if (freeb)
2398 BBPunfix(b->batCacheid);
2399 if (freeg)
2400 BBPunfix(g->batCacheid);
2401 if (buf)
2402 GDKfree(buf);
2403 if (err && bn) {
2404 BBPreclaim(bn);
2405 bn = NULL;
2406 }
2407 *bnp = bn;
2408 return err;
2409
2410 bunins_failed:
2411 if (err == NULL)
2412 err = SQLSTATE(HY001) MAL_MALLOC_FAIL; /* insertion into result BAT failed */
2413 goto out;
2414}
2415
2416str
2417JSONsubjsoncand(bat *retval, bat *bid, bat *gid, bat *eid, bat *sid, bit *skip_nils)
2418{
2419 BAT *b, *g, *e, *s, *bn = NULL;
2420 const char *err;
2421
2422 b = BATdescriptor(*bid);
2423 g = gid ? BATdescriptor(*gid) : NULL;
2424 e = eid ? BATdescriptor(*eid) : NULL;
2425 s = sid ? BATdescriptor(*sid) : NULL;
2426 if (b == NULL ||
2427 (gid != NULL && g == NULL) ||
2428 (eid != NULL && e == NULL) ||
2429 (sid != NULL && s == NULL)) {
2430 err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
2431 } else {
2432 err = JSONjsonaggr(&bn, b, g, e, s, *skip_nils);
2433 }
2434 if (b)
2435 BBPunfix(b->batCacheid);
2436 if (g)
2437 BBPunfix(g->batCacheid);
2438 if (e)
2439 BBPunfix(e->batCacheid);
2440 if (s)
2441 BBPunfix(s->batCacheid);
2442 if (err != NULL)
2443 throw(MAL, "aggr.subjson", "%s", err);
2444
2445 *retval = bn->batCacheid;
2446 BBPkeepref(bn->batCacheid);
2447 return MAL_SUCCEED;
2448}
2449
2450str
2451JSONsubjson(bat *retval, bat *bid, bat *gid, bat *eid, bit *skip_nils)
2452{
2453 return JSONsubjsoncand(retval, bid, gid, eid, NULL, skip_nils);
2454}
2455