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