LCOV - code coverage report
Current view: top level - monetdb5/modules/atoms - json.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1460 2010 72.6 %
Date: 2024-04-25 20:03:45 Functions: 60 71 84.5 %

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

Generated by: LCOV version 1.14