Changeset: 1e6389362cf8 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=1e6389362cf8
Modified Files:
        monetdb5/extras/jaql/json.c
        monetdb5/extras/jaql/json.h
        monetdb5/extras/jaql/json.mal
Branch: default
Log Message:

json: allow shredding from streams

Adopted the shredding to handle (buffered) streams, by requesting more
data before assuming end of file (stream).  Introduced shreduri function
to read JSON data from a URI.


diffs (truncated from 323 to 300 lines):

diff --git a/monetdb5/extras/jaql/json.c b/monetdb5/extras/jaql/json.c
--- a/monetdb5/extras/jaql/json.c
+++ b/monetdb5/extras/jaql/json.c
@@ -41,12 +41,50 @@ typedef struct _json_bats {
        BAT *object;  /* object members */
        BAT *name;    /* pair names */
        char *error;  /* set to non-NULL (an explanatory string) on failure */
+       stream *is;   /* set to non-NULL when reading directly from stream */
+       char *streambuf; /* buffer used for reading from the stream */
+       size_t streambuflen;
 } jsonbat;
 
 static char *parse_json_value(jsonbat *jb, oid *v, char *p);
 static char *parse_json_object(jsonbat *jb, oid *id, char *p);
 static char *parse_json_array(jsonbat *jb, oid *id, char *p);
 
+static size_t
+read_from_stream(jsonbat *jb, char **pos, char **start, char **recall)
+{
+       size_t shift = 0;
+       int sret = 0;
+       
+       assert(*start - jb->streambuf >= 0);
+       shift = *start - jb->streambuf;
+
+       if (shift > 0) {
+               memmove(jb->streambuf, *start, jb->streambuflen - shift);
+               if (pos != start)
+                       *pos -= shift;
+               *start -= shift;
+               if (recall != NULL)
+                       *recall -= shift;
+       }
+
+       shift = *pos - jb->streambuf;
+       if (*pos == jb->streambuf + jb->streambuflen) {
+               char *newbuf = realloc(jb->streambuf, jb->streambuflen += 8096);
+               if (newbuf == NULL)
+                       return 0;
+               jb->streambuf = newbuf;
+               *pos = jb->streambuf + shift;
+       }
+
+       sret = mnstr_read(jb->is, *pos, 1, jb->streambuflen - shift - 1);
+       if (sret <= 0)
+               return 0;
+       jb->streambuf[sret] = '\0';
+
+       return sret;
+}
+
 static char *
 parse_json_string(jsonbat *jb, oid *v, char pair, char *p)
 {
@@ -54,7 +92,10 @@ parse_json_string(jsonbat *jb, oid *v, c
        char *n = p;
        char *w = p;
 
-       for (; *p != '\0'; p++) {
+       for (; ; p++) {
+               if (*p == '\0' &&
+                               (jb->is == NULL || read_from_stream(jb, &p, &n, 
&w) == 0))
+                       break;
                switch (*p) {
                        case '\\':
                                if (escape) {
@@ -152,7 +193,10 @@ parse_json_number(jsonbat *jb, oid *v, c
        if (*p == '-')
                p++;
 
-       for (; *p != '\0'; p++) {
+       for (; ; p++) {
+               if (*p == '\0' &&
+                               (jb->is == NULL || read_from_stream(jb, &p, &n, 
NULL) == 0))
+                       break;
                if (strchr("0123456789", *p) != NULL) {
                        /* valid for ints */
                } else  if (strchr("eE.-+", *p) != NULL) {
@@ -272,15 +316,25 @@ parse_json_pair(jsonbat *jb, oid *v, cha
        x = p + 1;
        if ((p = parse_json_string(jb, &n, 1, x)) == NULL)
                return NULL;
-       for (; *p != '\0' && isspace(*p); p++)
-               ;
+       for (; ; p++) {
+               if (*p == '\0' &&
+                               (jb->is == NULL || read_from_stream(jb, &p, &x, 
NULL) == 0))
+                       break;
+               if (!isspace(*p))
+                       break;
+       }
        if (*p != ':') {
                jb->error = GDKstrdup("exected ':' for pair");
                return NULL;
        }
        p++;
-       for (; *p != '\0' && isspace(*p); p++)
-               ;
+       for (; ; p++) {
+               if (*p == '\0' &&
+                               (jb->is == NULL || read_from_stream(jb, &p, &x, 
NULL) == 0))
+                       break;
+               if (!isspace(*p))
+                       break;
+       }
        if ((p = parse_json_value(jb, v, p)) == NULL)
                return NULL;
 
@@ -297,7 +351,10 @@ parse_json_object(jsonbat *jb, oid *id, 
        BUNappend(jb->kind, "o", FALSE);
        *id = BUNlast(jb->kind) - 1;
 
-       for (; *p != '\0'; p++) {
+       for (; ; p++) {
+               if (*p == '\0' &&
+                               (jb->is == NULL || read_from_stream(jb, &p, &p, 
NULL) == 0))
+                       break;
                if (isspace(*p))
                        continue;
                switch (*p) {
@@ -329,7 +386,10 @@ parse_json_array(jsonbat *jb, oid *id, c
        BUNappend(jb->kind, "a", FALSE);
        *id = BUNlast(jb->kind) - 1;
 
-       for (; *p != '\0'; p++) {
+       for (; ; p++) {
+               if (*p == '\0' &&
+                               (jb->is == NULL || read_from_stream(jb, &p, &p, 
NULL) == 0))
+                       break;
                if (isspace(*p))
                        continue;
                switch (*p) {
@@ -379,71 +439,123 @@ parse_json_array(jsonbat *jb, oid *id, c
        unloadbat(name);
 
 str
-JSONshred(int *kind, int *string, int *integer, int *doble, int *array, int 
*object, int *name, str *json)
+shred_json(jsonbat *jb, int *kind, int *string, int *integer, int *doble, int 
*array, int *object, int *name, str *json)
 {
-       char *p = *json;
-       jsonbat jb;
+       char *p = NULL;
        oid v = (oid)0; 
 
-       memset(&jb, 0, sizeof(jsonbat));
+       /* initialise all bats */
+       jb->kind = BATnew(TYPE_void, TYPE_bte, BATTINY);
+       jb->kind = BATseqbase(jb->kind, (oid)0);
+       jb->string = BATnew(TYPE_oid, TYPE_str, BATTINY);
+       jb->doble = BATnew(TYPE_oid, TYPE_dbl, BATTINY);
+       jb->integer = BATnew(TYPE_oid, TYPE_lng, BATTINY);
+       jb->name = BATnew(TYPE_oid, TYPE_str, BATTINY);
+       jb->object = BATnew(TYPE_oid, TYPE_oid, BATTINY);
+       jb->array = BATnew(TYPE_oid, TYPE_oid, BATTINY);
 
-       /* initialise all bats */
-       jb.kind = BATnew(TYPE_void, TYPE_bte, BATTINY);
-       jb.kind = BATseqbase(jb.kind, (oid)0);
-       jb.string = BATnew(TYPE_oid, TYPE_str, BATTINY);
-       jb.doble = BATnew(TYPE_oid, TYPE_dbl, BATTINY);
-       jb.integer = BATnew(TYPE_oid, TYPE_lng, BATTINY);
-       jb.name = BATnew(TYPE_oid, TYPE_str, BATTINY);
-       jb.object = BATnew(TYPE_oid, TYPE_oid, BATTINY);
-       jb.array = BATnew(TYPE_oid, TYPE_oid, BATTINY);
+       if (json == NULL) {
+               p = jb->streambuf;
+       } else {
+               p = *json;
+       }
 
-       for (; *p != '\0' && isspace(*p); p++)
-               ;
+       for (; ; p++) {
+               if (*p == '\0' &&
+                               (jb->is == NULL || read_from_stream(jb, &p, &p, 
NULL) == 0))
+                       break;
+               if (!isspace(*p))
+                       break;
+       }
        if (*p == '\0') {
-               jb.error = GDKstrdup("expected data");
+               jb->error = GDKstrdup("expected data");
                p = NULL;
        } else {
-               p = parse_json_value(&jb, &v, p);
+               p = parse_json_value(jb, &v, p);
        }
 
-       for (; p != NULL && *p != '\0' && isspace(*p); p++)
-               ;
+       for (; p != NULL; p++) {
+               if (*p == '\0' &&
+                               (jb->is == NULL || read_from_stream(jb, &p, &p, 
NULL) == 0))
+                       break;
+               if (!isspace(*p))
+                       break;
+       }
        if (p == NULL || *p != '\0') {
                str e;
                if (p == NULL) {
                        /* parsing failed */
-                       e = createException(MAL, "json.shred", "%s", jb.error);
+                       e = createException(MAL, "json.shred", "%s", jb->error);
                } else {
                        e = createException(MAL, "json.shred", "invalid JSON 
data, "
                                        "trailing characters: %s", p);
                }
-               BBPunfix(jb.kind->batCacheid);
-               BBPunfix(jb.string->batCacheid);
-               BBPunfix(jb.integer->batCacheid);
-               BBPunfix(jb.doble->batCacheid);
-               BBPunfix(jb.array->batCacheid);
-               BBPunfix(jb.object->batCacheid);
-               BBPunfix(jb.name->batCacheid);
-               GDKfree(jb.error);
+               BBPunfix(jb->kind->batCacheid);
+               BBPunfix(jb->string->batCacheid);
+               BBPunfix(jb->integer->batCacheid);
+               BBPunfix(jb->doble->batCacheid);
+               BBPunfix(jb->array->batCacheid);
+               BBPunfix(jb->object->batCacheid);
+               BBPunfix(jb->name->batCacheid);
+               GDKfree(jb->error);
                return e;
        }
-       BBPkeepref(jb.kind->batCacheid);
-       *kind = jb.kind->batCacheid;
-       BBPkeepref(jb.string->batCacheid);
-       *string = jb.string->batCacheid;
-       BBPkeepref(jb.integer->batCacheid);
-       *integer = jb.integer->batCacheid;
-       BBPkeepref(jb.doble->batCacheid);
-       *doble = jb.doble->batCacheid;
-       BBPkeepref(jb.array->batCacheid);
-       *array = jb.array->batCacheid;
-       BBPkeepref(jb.object->batCacheid);
-       *object = jb.object->batCacheid;
-       BBPkeepref(jb.name->batCacheid);
-       *name = jb.name->batCacheid;
+       BBPkeepref(jb->kind->batCacheid);
+       *kind = jb->kind->batCacheid;
+       BBPkeepref(jb->string->batCacheid);
+       *string = jb->string->batCacheid;
+       BBPkeepref(jb->integer->batCacheid);
+       *integer = jb->integer->batCacheid;
+       BBPkeepref(jb->doble->batCacheid);
+       *doble = jb->doble->batCacheid;
+       BBPkeepref(jb->array->batCacheid);
+       *array = jb->array->batCacheid;
+       BBPkeepref(jb->object->batCacheid);
+       *object = jb->object->batCacheid;
+       BBPkeepref(jb->name->batCacheid);
+       *name = jb->name->batCacheid;
        return MAL_SUCCEED;
 }
 
+str
+JSONshred(int *kind, int *string, int *integer, int *doble, int *array, int 
*object, int *name, str *json)
+{
+       jsonbat jb;
+
+       memset(&jb, 0, sizeof(jsonbat));
+
+       return shred_json(&jb, kind, string, integer, doble, array, object, 
name, json);
+}
+
+str
+JSONshredstream(int *kind, int *string, int *integer, int *doble, int *array, 
int *object, int *name, str *uri)
+{
+       jsonbat jb;
+       str ret;
+
+       memset(&jb, 0, sizeof(jsonbat));
+       
+       if ((jb.is = open_urlstream(*uri)) == NULL)
+               throw(MAL, "json.shreduri", "failed to open urlstream");
+
+       if (mnstr_errnr(jb.is) != 0) {
+               str err = createException(MAL, "json.shreduri",
+                               "opening stream failed: %s", 
mnstr_error(jb.is));
+               mnstr_destroy(jb.is);
+               return err;
+       }
+
+       jb.streambuflen = 8096;
+       jb.streambuf = malloc(8096);
+       jb.streambuf[0] = '\0';
+
+       ret = shred_json(&jb, kind, string, integer, doble, array, object, 
name, NULL);
+
+       free(jb.streambuf);
+
+       return ret;
+}
+
 static size_t
 strlen_json_value(jsonbat *jb, oid id)
 {
diff --git a/monetdb5/extras/jaql/json.h b/monetdb5/extras/jaql/json.h
--- a/monetdb5/extras/jaql/json.h
_______________________________________________
Checkin-list mailing list
[email protected]
http://mail.monetdb.org/mailman/listinfo/checkin-list

Reply via email to