Changeset: ffc9dad1319f for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/ffc9dad1319f
Modified Files:
        cmake/monetdb-findpackages.cmake
        monetdb5/modules/atoms/CMakeLists.txt
        monetdb5/modules/atoms/json.c
        sql/backends/monet5/sql.c
        sql/backends/monet5/sql_statement.c
        sql/common/sql_types.c
        sql/server/rel_exp.c
        sql/server/rel_multiset.c
Branch: nested
Log Message:

add support for simple json casts


diffs (truncated from 434 to 300 lines):

diff --git a/cmake/monetdb-findpackages.cmake b/cmake/monetdb-findpackages.cmake
--- a/cmake/monetdb-findpackages.cmake
+++ b/cmake/monetdb-findpackages.cmake
@@ -132,6 +132,14 @@ endif()
 find_package(Sphinx)
 find_package(Semodule)
 find_package(Awk)
+find_package(yyjson REQUIRED)
+find_path(YYJSON_INCLUDE_DIR NAMES yyjson.h)
+find_library(YYJSON_LIBRARIES NAMES yyjson)
+add_library(YYJSON::YYJSON UNKNOWN IMPORTED)
+set_target_properties(YYJSON::YYJSON
+  PROPERTIES
+  INTERFACE_INCLUDE_DIRECTORIES "${YYJSON_INCLUDE_DIR}"
+  IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION 
"${YYJSON_LIBRARIES}")
 
 if(TAGS)
   find_program(CTAGS_PATH ctags)
diff --git a/monetdb5/modules/atoms/CMakeLists.txt 
b/monetdb5/modules/atoms/CMakeLists.txt
--- a/monetdb5/modules/atoms/CMakeLists.txt
+++ b/monetdb5/modules/atoms/CMakeLists.txt
@@ -20,7 +20,7 @@ target_sources(atoms
   strptime.c
   url.c
   uuid.c
-  json.c
+  json.c json.h
   mtime.c mtime.h
   inet.c
   xml.c xml.h
diff --git a/monetdb5/modules/atoms/json.c b/monetdb5/modules/atoms/json.c
--- a/monetdb5/modules/atoms/json.c
+++ b/monetdb5/modules/atoms/json.c
@@ -21,35 +21,7 @@
 #include "mal_exception.h"
 #include "mal_interpreter.h"
 
-typedef enum JSONkind {
-       JSON_OBJECT = 1,
-       JSON_ARRAY,
-       JSON_ELEMENT,
-       JSON_VALUE,
-       JSON_STRING,
-       JSON_NUMBER,
-       JSON_BOOL,
-       JSON_NULL
-} JSONkind;
-
-/* The JSON index structure is meant for short lived versions */
-typedef struct JSONterm {
-       JSONkind kind;
-       char *name;                                     /* exclude the quotes */
-       size_t namelen;
-       const char *value;                      /* start of string rep */
-       size_t valuelen;
-       int child, next, tail;          /* next offsets allow you to walk 
array/object chains
-                                                                  and append 
quickly */
-       /* An array or object item has a number of components */
-} JSONterm;
-
-typedef struct JSON {
-       JSONterm *elm;
-       str error;
-       int size;
-       int free;
-} JSON;
+#include "json.h"
 
 typedef str json;
 
@@ -84,7 +56,6 @@ int TYPE_json;
 
 /* Internal constructors. */
 static int jsonhint = 8;
-static JSON *JSONparse(const char *j);
 
 static JSON *
 JSONnewtree(void)
@@ -125,7 +96,7 @@ JSONnew(JSON *js)
 }
 
 /* Delete a JSON structure. */
-static void
+void
 JSONfree(JSON *c)
 {
        if (c == 0)
@@ -1471,7 +1442,7 @@ JSONtoken(JSON *jt, const char *j, const
 }
 
 
-static JSON *
+JSON *
 JSONparse(const char *j)
 {
        JSON *jt = JSONnewtree();
diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c
--- a/sql/backends/monet5/sql.c
+++ b/sql/backends/monet5/sql.c
@@ -45,6 +45,7 @@
 #include "mal_instruction.h"
 #include "mal_resource.h"
 #include "mal_authorize.h"
+#include "json.h"
 
 static inline void
 BBPnreclaim(int nargs, ...)
@@ -5688,6 +5689,172 @@ bailout:
        throw(SQL, "SQLread_dump_rel", SQLSTATE(HY013) MAL_MALLOC_FAIL);
 }
 
+#if 0
+static str
+insert_json(JSON *js, BAT *bats, int nr, int elm, sql_subtype *t)
+{
+       for (int i = elm; i < js->free; i++) {
+               JSONterm *jt = js->elm+i;
+
+               switch (jt->kind) {
+               case JSON_OBJECT:
+               case JSON_ARRAY:
+               case JSON_ELEMENT: // field
+               case JSON_VALUE:
+               case JSON_STRING:
+               case JSON_NUMBER:
+               case JSON_BOOL:
+               case JSON_NULL:
+                       printf("%s\n", jt->name);
+               }
+       }
+       return MAL_SUCCEED;
+}
+#endif
+
+static int insert_json_object(char **msg, JSON *js, BAT **bats, int nr, int 
elm, int id, int anr, sql_subtype *t);
+static int insert_json_array(char **msg, JSON *js, BAT **bats, int nr, int 
elm, int id, int oanr, sql_subtype *t);
+
+static int
+insert_json_object(char **msg, JSON *js, BAT **bats, int nr, int elm, int id, 
int anr, sql_subtype *t)
+{
+       char buf[128]; /* TODO use proper buffer */
+       node *n;
+       JSONterm *jt = js->elm+elm;
+       if (jt->kind != JSON_OBJECT || !t->type->composite) {
+               *msg = "missing object start";
+               return -1;
+       }
+       const char *name = NULL;
+       int nlen = 0, pos = -1, w = list_length(t->type->d.fields), i = 0;
+       /* TODO check if full object is there */
+       for (elm++; elm >0 && elm <= jt->tail+1; elm++) {
+               JSONterm *jt = js->elm+elm;
+
+               switch (jt->kind) {
+               case JSON_OBJECT:
+                       elm = insert_json_object(msg, js, bats, nr, elm, id, 
anr, t);
+                       break;
+               case JSON_ARRAY:
+                       /* TODO get id for nested array from the a global 
struct */
+                       elm = insert_json_array(msg, js, bats, nr, elm, id, 
anr, t);
+                       break;
+               case JSON_ELEMENT: // field
+                       name = jt->value;
+                       nlen = jt->valuelen;
+                       break;
+               case JSON_VALUE:
+               case JSON_STRING:
+               case JSON_NUMBER:
+               case JSON_BOOL:
+               case JSON_NULL:
+                       pos = -1;
+                       for(i = 0, n = t->type->d.fields->h; i < w && n && pos 
< 0; i++, n = n->next) {
+                               sql_arg *a = n->data;
+                               int alen = strlen(a->name);
+                               if (nlen == alen && strncmp(name, a->name, 
nlen) == 0)
+                                       pos = i;
+                       }
+                       char *v = buf;
+                       if (pos < 0 || jt->valuelen > 128-1)
+                               return -8;
+                       strncpy(v, jt->value, jt->valuelen);
+                       v[jt->valuelen] = 0;
+                       /*
+                        * TODO check type of value
+                        * TODO insert value (not just strings)
+                        */
+                       if (elm > 0 && BUNappend(bats[pos], v, false) != 
GDK_SUCCEED) {
+                               return -5;
+                       }
+               }
+       }
+
+       if (elm > 0 && BUNappend(bats[w], &id, false) != GDK_SUCCEED)
+               elm = -3;
+       if (t->multiset == MS_ARRAY && elm > 0 && BUNappend(bats[w+1], &anr, 
false) != GDK_SUCCEED)
+               elm = -3;
+       return elm;
+}
+
+static int
+insert_json_array(char **msg, JSON *js, BAT **bats, int nr, int elm, int id, 
int oanr, sql_subtype *t)
+{
+       JSONterm *ja = js->elm+elm;
+       int tail = ja->tail;
+       if (ja->kind != JSON_ARRAY || !t->multiset) {
+               *msg = "missing array start";
+               return -1;
+       }
+       int anr = 1;
+       for (; elm < tail; elm=ja->next) { /* array begin, comma, end */
+               ja = js->elm+elm;
+               for (elm++; elm >0 && elm < ja->next; elm++) {
+                       JSONterm *jt = js->elm+elm;
+
+                       switch (jt->kind) {
+                       case JSON_OBJECT:
+                               elm = insert_json_object(msg, js, bats+1, nr, 
elm, id, anr++, t);
+                               (void)oanr;
+                               break;
+                       default:
+                               printf("todo\n");
+                       }
+               }
+               if (elm < 0)
+                       break;
+       }
+       if (elm > 0 && anr > 1 && BUNappend(bats[0], &id, false) != GDK_SUCCEED)
+               elm = -2;
+       return elm+1;
+}
+
+static str
+SQLfrom_json(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
+{
+       (void)cntxt;
+       str msg = NULL;
+       int mtype = getArgType(mb, pci, pci->retc);
+
+       if (strcmp(BATatoms[mtype].name, "json") != 0)
+               throw(SQL, "SQLfrom_json", SQLSTATE(HY013) "Incorrect argument 
type");
+       str json = *(str*)getArgReference(stk, pci, pci->retc);
+       sql_subtype *t = *(sql_subtype**)getArgReference(stk, pci, pci->retc+1);
+
+       BAT **bats = (BAT**)GDKzalloc(sizeof(BAT*) * pci->retc);
+       if (!bats)
+               throw(SQL, "SQLfrom_json", SQLSTATE(HY013) MAL_MALLOC_FAIL);
+       for(int i = 0; i < pci->retc; i++) {
+               bats[i] = COLnew(0, getBatType(getArgType(mb, pci, i)), 10, 
TRANSIENT);
+               if (!bats[i])
+                       goto bailout;
+       }
+
+       JSON *js = JSONparse(json);
+       if (!js) /* TODO output parser error ?? */
+               goto bailout;
+
+       if (t->multiset)
+               (void)insert_json_array(&msg, js, bats, pci->retc, 0, 1, 1, t);
+       else
+               (void)insert_json_object(&msg, js, bats, pci->retc, 0, 1, 1, t);
+       JSONfree(js);
+       if (msg)
+               goto bailout;
+       for(int i = 0; i < pci->retc && bats[i]; i++) {
+               *getArgReference_bat(stk, pci, i) = bats[i]->batCacheid;
+               BBPkeepref(bats[i]);
+       }
+       GDKfree(bats);
+       return MAL_SUCCEED;
+bailout:
+       for(int i = 0; i < pci->retc && bats[i]; i++)
+               BBPreclaim(bats[i]);
+       GDKfree(bats);
+       if (msg)
+               throw(SQL, "SQLfrom_json", SQLSTATE(42000) "%s", msg);
+       throw(SQL, "SQLfrom_json", SQLSTATE(HY013) MAL_MALLOC_FAIL);
+}
 
 static mel_func sql_init_funcs[] = {
  pattern("sql", "shutdown", SQLshutdown_wrap, true, "", args(1,3, 
arg("",str),arg("delay",bte),arg("force",bit))),
@@ -6638,6 +6805,7 @@ static mel_func sql_init_funcs[] = {
  pattern("sql", "stop_vacuum", SQLstr_stop_vacuum, true, "stop auto vacuum", 
args(0,2, arg("sname",str),arg("tname",str))),
  pattern("sql", "check", SQLcheck, false, "Return sql string of check 
constraint.", args(1,3, arg("sql",str), arg("sname", str), arg("name", str))),
  pattern("sql", "read_dump_rel", SQLread_dump_rel, false, "Reads sql_rel 
string into sql_rel object and then writes it to the return value", args(1,2, 
arg("sql",str), arg("sql_rel", str))),
+ pattern("sql", "from_json", SQLfrom_json, false, "Reads json string into 
table of nested structures", args(1,3, batvarargany("t",0), arg("input", json), 
arg("type", ptr))),
  { .imp=NULL }
 };
 #include "mal_import.h"
diff --git a/sql/backends/monet5/sql_statement.c 
b/sql/backends/monet5/sql_statement.c
--- a/sql/backends/monet5/sql_statement.c
+++ b/sql/backends/monet5/sql_statement.c
@@ -3938,6 +3938,94 @@ temporal_convert(backend *be, stmt *v, s
        return NULL;
 }
 
+static int
+composite_type_resultsize(sql_subtype *t)
+{
+       int nr = 0;
+
_______________________________________________
checkin-list mailing list -- checkin-list@monetdb.org
To unsubscribe send an email to checkin-list-le...@monetdb.org

Reply via email to