LCOV - code coverage report
Current view: top level - monetdb5/modules/atoms - json.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1189 1666 71.4 %
Date: 2021-10-13 02:24:04 Functions: 58 68 85.3 %

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

Generated by: LCOV version 1.14