Commit 564d41fa authored by Olivier Bertrand's avatar Olivier Bertrand

- Work on JSON and JSON UDF's

modified:
  storage/connect/json.cpp
  storage/connect/jsonudf.cpp
  storage/connect/tabjson.cpp

- CntReadNext: Enable EvalColumns for longjmp
modified:
  storage/connect/connect.cc
parent 2201aa66
......@@ -469,9 +469,12 @@ RCODE CntReadNext(PGLOBAL g, PTDB tdbp)
} while (rc == RC_NF);
if (rc == RC_OK)
rc= EvalColumns(g, tdbp, false);
err:
g->jump_level--;
return (rc != RC_OK) ? rc : EvalColumns(g, tdbp, false);
return rc;
} // end of CntReadNext
/***********************************************************************/
......
......@@ -34,7 +34,7 @@
/***********************************************************************/
PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
{
int i;
int i, rc;
bool b = false;
PJSON jsp = NULL;
STRG src;
......@@ -48,22 +48,32 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
src.str = s;
src.len = len;
// Save stack and allocation environment and prepare error return
if (g->jump_level == MAX_JUMP) {
strcpy(g->Message, MSG(TOO_MANY_JUMPS));
return NULL;
} // endif jump_level
if ((rc= setjmp(g->jumper[++g->jump_level])) != 0) {
goto err;
} // endif rc
for (i = 0; i < len; i++)
switch (s[i]) {
case '[':
if (jsp) {
strcpy(g->Message, "More than one item in file");
return NULL;
goto err;
} else if (!(jsp = ParseArray(g, ++i, src)))
return NULL;
goto err;
break;
case '{':
if (jsp) {
strcpy(g->Message, "More than one item in file");
return NULL;
goto err;
} else if (!(jsp = ParseObject(g, ++i, src)))
return NULL;
goto err;
break;
case ' ':
case '\t':
......@@ -79,7 +89,7 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
} // endif pretty
sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
return NULL;
goto err;
case '(':
b = true;
break;
......@@ -92,13 +102,18 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
default:
sprintf(g->Message, "Bad '%c' character near %.*s",
s[i], ARGS);
return NULL;
goto err;
}; // endswitch s[i]
if (!jsp)
sprintf(g->Message, "Invalid Json string '%.*s'", 50, s);
g->jump_level--;
return jsp;
err:
g->jump_level--;
return NULL;
} // end of ParseJson
/***********************************************************************/
......@@ -316,6 +331,12 @@ char *ParseString(PGLOBAL g, int& i, STRG& src)
uchar *p;
int n = 0, len = src.len;
// Be sure of memory availability
if (len + 1 - i > (signed)((PPOOLHEADER)g->Sarea)->FreeBlk) {
strcpy(g->Message, "ParseString: Out of memory");
return NULL;
} // endif len
// The size to allocate is not known yet
p = (uchar*)PlugSubAlloc(g, NULL, 0);
......
......@@ -44,9 +44,10 @@ DllExport void Json_Object_Grp_deinit(UDF_INIT*);
/***********************************************************************/
/* Allocate and initialise the memory area. */
/***********************************************************************/
my_bool JsonInit(UDF_INIT *initid, char *message, unsigned long len)
my_bool JsonInit(UDF_INIT *initid, char *message, unsigned long reslen,
unsigned long memlen)
{
PGLOBAL g = PlugInit(NULL, len);
PGLOBAL g = PlugInit(NULL, memlen);
if (!g) {
strcpy(message, "Allocation error");
......@@ -59,7 +60,7 @@ my_bool JsonInit(UDF_INIT *initid, char *message, unsigned long len)
initid->ptr = (char*)g;
initid->maybe_null = false;
initid->max_length = len - 512;
initid->max_length = reslen;
return false;
} // end of Json_Object_init
......@@ -72,6 +73,92 @@ static my_bool IsJson(UDF_ARGS *args, int i)
!strnicmp(args->attributes[i], "Json_", 5));
} // end of IsJson
/***********************************************************************/
/* Calculate the reslen and memlen needed by a function. */
/***********************************************************************/
static my_bool CalcLen(UDF_ARGS *args, my_bool obj,
unsigned long& reslen, unsigned long& memlen)
{
unsigned long i, k;
reslen = args->arg_count + 2;
// Calculate the result max length
for (i = 0; i < args->arg_count; i++) {
if (obj) {
if (!(k = args->attribute_lengths[i]))
k = strlen(args->attributes[i]);
reslen += (k + 3); // For quotes and :
} // endif obj
switch (args->arg_type[i]) {
case STRING_RESULT:
if (IsJson(args, i))
reslen += args->lengths[i];
else
reslen += (args->lengths[i] + 1) * 2; // Pessimistic !
break;
case INT_RESULT:
reslen += 20;
break;
case REAL_RESULT:
reslen += 31;
break;
case DECIMAL_RESULT:
reslen += (args->lengths[i] + 7); // 6 decimals
break;
case TIME_RESULT:
case ROW_RESULT:
case IMPOSSIBLE_RESULT:
default:
// What should we do here ?
break;
} // endswitch arg_type
} // endfor i
// Calculate the amount of memory needed
memlen = 1024 + sizeof(JOUTSTR) + reslen;
for (i = 0; i < args->arg_count; i++) {
memlen += (args->lengths[i] + sizeof(JVALUE));
if (obj) {
if (!(k = args->attribute_lengths[i]))
k = strlen(args->attributes[i]);
memlen += (k + sizeof(JOBJECT) + sizeof(JPAIR));
} else
memlen += sizeof(JARRAY);
switch (args->arg_type[i]) {
case STRING_RESULT:
if (IsJson(args, i))
memlen += args->lengths[i] * 5; // Estimate parse memory
memlen += sizeof(TYPVAL<PSZ>);
break;
case INT_RESULT:
memlen += sizeof(TYPVAL<int>);
break;
case REAL_RESULT:
case DECIMAL_RESULT:
memlen += sizeof(TYPVAL<double>);
break;
case TIME_RESULT:
case ROW_RESULT:
case IMPOSSIBLE_RESULT:
default:
// What should we do here ?
break;
} // endswitch arg_type
} // endfor i
return false;
} // end of CalcLen
/***********************************************************************/
/* Make a zero terminated string from the passed argument. */
/***********************************************************************/
......@@ -131,25 +218,25 @@ static PSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i)
/***********************************************************************/
static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i)
{
char *str;
char *sap = args->args[i];
PJVAL jvp = new(g) JVALUE;
switch (args->arg_type[i]) {
if (sap) switch (args->arg_type[i]) {
case STRING_RESULT:
if ((str = MakePSZ(g, args, i))) {
if (args->lengths[i]) {
if (IsJson(args, i))
jvp->SetValue(ParseJson(g, str, strlen(str), 0));
jvp->SetValue(ParseJson(g, sap, args->lengths[i], 0));
else
jvp->SetString(g, str);
jvp->SetString(g, MakePSZ(g, args, i));
} // endif str
break;
case INT_RESULT:
jvp->SetInteger(g, *(int*)args->args[i]);
jvp->SetInteger(g, *(int*)sap);
break;
case REAL_RESULT:
jvp->SetFloat(g, *(double*)args->args[i]);
jvp->SetFloat(g, *(double*)sap);
break;
case DECIMAL_RESULT:
jvp->SetFloat(g, atof(MakePSZ(g, args, i)));
......@@ -169,12 +256,15 @@ static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i)
/***********************************************************************/
my_bool Json_Value_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count > 1) {
strcpy(message, "Json_Value cannot accept more than 1 argument");
return true;
} // endif arg_count
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, message, 1024);
return JsonInit(initid, message, reslen, memlen);
} // end of Json_Value_init
char *Json_Value(UDF_INIT *initid, UDF_ARGS *args, char *result,
......@@ -204,7 +294,10 @@ void Json_Value_deinit(UDF_INIT* initid)
/***********************************************************************/
my_bool Json_Array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return JsonInit(initid, message, 8192);
unsigned long reslen, memlen;
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, message, reslen, memlen);
} // end of Json_Array_init
char *Json_Array(UDF_INIT *initid, UDF_ARGS *args, char *result,
......@@ -240,7 +333,10 @@ void Json_Array_deinit(UDF_INIT* initid)
/***********************************************************************/
my_bool Json_Object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return JsonInit(initid, message, 8192);
unsigned long reslen, memlen;
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, message, reslen, memlen);
} // end of Json_Object_init
char *Json_Object(UDF_INIT *initid, UDF_ARGS *args, char *result,
......@@ -274,10 +370,18 @@ void Json_Object_deinit(UDF_INIT* initid)
/***********************************************************************/
my_bool Json_Array_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, n = 10;
if (args->arg_count != 1) {
strcpy(message, "Json_Array_Grp can only accept 1 argument");
return true;
} else if (JsonInit(initid, message, 16384))
} else
CalcLen(args, false, reslen, memlen);
reslen *= n;
memlen *= n;
if (JsonInit(initid, message, reslen, memlen))
return true;
PGLOBAL g = (PGLOBAL)initid->ptr;
......@@ -330,10 +434,18 @@ void Json_Array_Grp_deinit(UDF_INIT* initid)
/***********************************************************************/
my_bool Json_Object_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, n = 10;
if (args->arg_count != 2) {
strcpy(message, "Json_Array_Grp can only accept 2 argument");
return true;
} else if (JsonInit(initid, message, 16384))
} else
CalcLen(args, true, reslen, memlen);
reslen *= n;
memlen *= n;
if (JsonInit(initid, message, reslen, memlen))
return true;
PGLOBAL g = (PGLOBAL)initid->ptr;
......
......@@ -825,7 +825,9 @@ PJSON JSONCOL::GetRow(PGLOBAL g)
PJSON nwr, row = Tjp->Row;
for (int i = 0; i < Nod-1 && row; i++) {
switch (row->GetType()) {
if (Nodes[i+1].Op == OP_XX)
break;
else switch (row->GetType()) {
case TYPE_JOB:
if (!Nodes[i].Key)
// Expected Array was not there
......@@ -932,7 +934,11 @@ void JSONCOL::WriteColumn(PGLOBAL g)
jsp = ParseJson(g, s, (int)strlen(s), 0);
if (arp) {
if (Nod > 1 && Nodes[Nod-2].Rank)
arp->SetValue(g, new(g) JVALUE(jsp), Nodes[Nod-2].Rank-1);
else
arp->AddValue(g, new(g) JVALUE(jsp));
arp->InitArray(g);
} else if (objp) {
if (Nod > 1 && Nodes[Nod-2].Key)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment