mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
- 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
This commit is contained in:
@@ -469,9 +469,12 @@ RCODE CntReadNext(PGLOBAL g, PTDB tdbp)
|
|||||||
|
|
||||||
} while (rc == RC_NF);
|
} while (rc == RC_NF);
|
||||||
|
|
||||||
|
if (rc == RC_OK)
|
||||||
|
rc= EvalColumns(g, tdbp, false);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
g->jump_level--;
|
g->jump_level--;
|
||||||
return (rc != RC_OK) ? rc : EvalColumns(g, tdbp, false);
|
return rc;
|
||||||
} // end of CntReadNext
|
} // end of CntReadNext
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
@@ -34,7 +34,7 @@
|
|||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
|
PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
|
||||||
{
|
{
|
||||||
int i;
|
int i, rc;
|
||||||
bool b = false;
|
bool b = false;
|
||||||
PJSON jsp = NULL;
|
PJSON jsp = NULL;
|
||||||
STRG src;
|
STRG src;
|
||||||
@@ -48,22 +48,32 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
|
|||||||
src.str = s;
|
src.str = s;
|
||||||
src.len = len;
|
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++)
|
for (i = 0; i < len; i++)
|
||||||
switch (s[i]) {
|
switch (s[i]) {
|
||||||
case '[':
|
case '[':
|
||||||
if (jsp) {
|
if (jsp) {
|
||||||
strcpy(g->Message, "More than one item in file");
|
strcpy(g->Message, "More than one item in file");
|
||||||
return NULL;
|
goto err;
|
||||||
} else if (!(jsp = ParseArray(g, ++i, src)))
|
} else if (!(jsp = ParseArray(g, ++i, src)))
|
||||||
return NULL;
|
goto err;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case '{':
|
case '{':
|
||||||
if (jsp) {
|
if (jsp) {
|
||||||
strcpy(g->Message, "More than one item in file");
|
strcpy(g->Message, "More than one item in file");
|
||||||
return NULL;
|
goto err;
|
||||||
} else if (!(jsp = ParseObject(g, ++i, src)))
|
} else if (!(jsp = ParseObject(g, ++i, src)))
|
||||||
return NULL;
|
goto err;
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
case '\t':
|
case '\t':
|
||||||
@@ -79,7 +89,7 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
|
|||||||
} // endif pretty
|
} // endif pretty
|
||||||
|
|
||||||
sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
|
sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
|
||||||
return NULL;
|
goto err;
|
||||||
case '(':
|
case '(':
|
||||||
b = true;
|
b = true;
|
||||||
break;
|
break;
|
||||||
@@ -92,13 +102,18 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
|
|||||||
default:
|
default:
|
||||||
sprintf(g->Message, "Bad '%c' character near %.*s",
|
sprintf(g->Message, "Bad '%c' character near %.*s",
|
||||||
s[i], ARGS);
|
s[i], ARGS);
|
||||||
return NULL;
|
goto err;
|
||||||
}; // endswitch s[i]
|
}; // endswitch s[i]
|
||||||
|
|
||||||
if (!jsp)
|
if (!jsp)
|
||||||
sprintf(g->Message, "Invalid Json string '%.*s'", 50, s);
|
sprintf(g->Message, "Invalid Json string '%.*s'", 50, s);
|
||||||
|
|
||||||
|
g->jump_level--;
|
||||||
return jsp;
|
return jsp;
|
||||||
|
|
||||||
|
err:
|
||||||
|
g->jump_level--;
|
||||||
|
return NULL;
|
||||||
} // end of ParseJson
|
} // end of ParseJson
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
@@ -316,6 +331,12 @@ char *ParseString(PGLOBAL g, int& i, STRG& src)
|
|||||||
uchar *p;
|
uchar *p;
|
||||||
int n = 0, len = src.len;
|
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
|
// The size to allocate is not known yet
|
||||||
p = (uchar*)PlugSubAlloc(g, NULL, 0);
|
p = (uchar*)PlugSubAlloc(g, NULL, 0);
|
||||||
|
|
||||||
|
@@ -44,9 +44,10 @@ DllExport void Json_Object_Grp_deinit(UDF_INIT*);
|
|||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
/* Allocate and initialise the memory area. */
|
/* 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) {
|
if (!g) {
|
||||||
strcpy(message, "Allocation error");
|
strcpy(message, "Allocation error");
|
||||||
@@ -59,7 +60,7 @@ my_bool JsonInit(UDF_INIT *initid, char *message, unsigned long len)
|
|||||||
initid->ptr = (char*)g;
|
initid->ptr = (char*)g;
|
||||||
|
|
||||||
initid->maybe_null = false;
|
initid->maybe_null = false;
|
||||||
initid->max_length = len - 512;
|
initid->max_length = reslen;
|
||||||
return false;
|
return false;
|
||||||
} // end of Json_Object_init
|
} // end of Json_Object_init
|
||||||
|
|
||||||
@@ -72,6 +73,92 @@ static my_bool IsJson(UDF_ARGS *args, int i)
|
|||||||
!strnicmp(args->attributes[i], "Json_", 5));
|
!strnicmp(args->attributes[i], "Json_", 5));
|
||||||
} // end of IsJson
|
} // 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. */
|
/* 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)
|
static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i)
|
||||||
{
|
{
|
||||||
char *str;
|
char *sap = args->args[i];
|
||||||
PJVAL jvp = new(g) JVALUE;
|
PJVAL jvp = new(g) JVALUE;
|
||||||
|
|
||||||
switch (args->arg_type[i]) {
|
if (sap) switch (args->arg_type[i]) {
|
||||||
case STRING_RESULT:
|
case STRING_RESULT:
|
||||||
if ((str = MakePSZ(g, args, i))) {
|
if (args->lengths[i]) {
|
||||||
if (IsJson(args, i))
|
if (IsJson(args, i))
|
||||||
jvp->SetValue(ParseJson(g, str, strlen(str), 0));
|
jvp->SetValue(ParseJson(g, sap, args->lengths[i], 0));
|
||||||
else
|
else
|
||||||
jvp->SetString(g, str);
|
jvp->SetString(g, MakePSZ(g, args, i));
|
||||||
|
|
||||||
} // endif str
|
} // endif str
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case INT_RESULT:
|
case INT_RESULT:
|
||||||
jvp->SetInteger(g, *(int*)args->args[i]);
|
jvp->SetInteger(g, *(int*)sap);
|
||||||
break;
|
break;
|
||||||
case REAL_RESULT:
|
case REAL_RESULT:
|
||||||
jvp->SetFloat(g, *(double*)args->args[i]);
|
jvp->SetFloat(g, *(double*)sap);
|
||||||
break;
|
break;
|
||||||
case DECIMAL_RESULT:
|
case DECIMAL_RESULT:
|
||||||
jvp->SetFloat(g, atof(MakePSZ(g, args, i)));
|
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)
|
my_bool Json_Value_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
|
||||||
{
|
{
|
||||||
|
unsigned long reslen, memlen;
|
||||||
|
|
||||||
if (args->arg_count > 1) {
|
if (args->arg_count > 1) {
|
||||||
strcpy(message, "Json_Value cannot accept more than 1 argument");
|
strcpy(message, "Json_Value cannot accept more than 1 argument");
|
||||||
return true;
|
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
|
} // end of Json_Value_init
|
||||||
|
|
||||||
char *Json_Value(UDF_INIT *initid, UDF_ARGS *args, char *result,
|
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)
|
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
|
} // end of Json_Array_init
|
||||||
|
|
||||||
char *Json_Array(UDF_INIT *initid, UDF_ARGS *args, char *result,
|
char *Json_Array(UDF_INIT *initid, UDF_ARGS *args, char *result,
|
||||||
@@ -240,11 +333,14 @@ void Json_Array_deinit(UDF_INIT* initid)
|
|||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
my_bool Json_Object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
|
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
|
} // end of Json_Object_init
|
||||||
|
|
||||||
char *Json_Object(UDF_INIT *initid, UDF_ARGS *args, char *result,
|
char *Json_Object(UDF_INIT *initid, UDF_ARGS *args, char *result,
|
||||||
unsigned long *res_length, char *is_null, char *error)
|
unsigned long *res_length, char *is_null, char *error)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
uint i;
|
uint i;
|
||||||
@@ -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)
|
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) {
|
if (args->arg_count != 1) {
|
||||||
strcpy(message, "Json_Array_Grp can only accept 1 argument");
|
strcpy(message, "Json_Array_Grp can only accept 1 argument");
|
||||||
return true;
|
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;
|
return true;
|
||||||
|
|
||||||
PGLOBAL g = (PGLOBAL)initid->ptr;
|
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)
|
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) {
|
if (args->arg_count != 2) {
|
||||||
strcpy(message, "Json_Array_Grp can only accept 2 argument");
|
strcpy(message, "Json_Array_Grp can only accept 2 argument");
|
||||||
return true;
|
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;
|
return true;
|
||||||
|
|
||||||
PGLOBAL g = (PGLOBAL)initid->ptr;
|
PGLOBAL g = (PGLOBAL)initid->ptr;
|
||||||
|
@@ -825,7 +825,9 @@ PJSON JSONCOL::GetRow(PGLOBAL g)
|
|||||||
PJSON nwr, row = Tjp->Row;
|
PJSON nwr, row = Tjp->Row;
|
||||||
|
|
||||||
for (int i = 0; i < Nod-1 && row; i++) {
|
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:
|
case TYPE_JOB:
|
||||||
if (!Nodes[i].Key)
|
if (!Nodes[i].Key)
|
||||||
// Expected Array was not there
|
// Expected Array was not there
|
||||||
@@ -932,7 +934,11 @@ void JSONCOL::WriteColumn(PGLOBAL g)
|
|||||||
jsp = ParseJson(g, s, (int)strlen(s), 0);
|
jsp = ParseJson(g, s, (int)strlen(s), 0);
|
||||||
|
|
||||||
if (arp) {
|
if (arp) {
|
||||||
arp->AddValue(g, new(g) JVALUE(jsp));
|
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);
|
arp->InitArray(g);
|
||||||
} else if (objp) {
|
} else if (objp) {
|
||||||
if (Nod > 1 && Nodes[Nod-2].Key)
|
if (Nod > 1 && Nodes[Nod-2].Key)
|
||||||
|
Reference in New Issue
Block a user