/****************** bsonudf C++ Program Source Code File (.CPP) ******************/ /* PROGRAM NAME: bsonudf Version 1.0 */ /* (C) Copyright to the author Olivier BERTRAND 2020 - 2021 */ /* This program are the BSON User Defined Functions. */ /*********************************************************************************/
/*********************************************************************************/ /* Include relevant sections of the MariaDB header file. */ /*********************************************************************************/ #include <my_global.h> #include <mysqld.h> #include <mysqld_error.h> #include <mysql.h> #include <sql_error.h> #include <stdio.h> #include <cassert>
/*********************************************************************************/ /* Replaces GetJsonGrpSize not usable when CONNECT is not installed. */ /*********************************************************************************/ int GetJsonDefPrec(void) { return (JsonDefPrec < 0) ? GetDefaultPrec() : JsonDefPrec;
} /* end of GetJsonDefPrec */
/*********************************************************************************/ /* Program for saving the status of the memory pools. */ /*********************************************************************************/ inlinevoid JsonMemSave(PGLOBAL g) {
g->Saved_Size = ((PPOOLHEADER)g->Sarea)->To_Free;
} /* end of JsonMemSave */
/*********************************************************************************/ /* Program for freeing the memory pools. */ /*********************************************************************************/ inlinevoid JsonFreeMem(PGLOBAL g) {
g->Activityp = NULL;
g = PlugExit(g);
} /* end of JsonFreeMem */
/* --------------------------- New Testing BJSON Stuff --------------------------*/
/*********************************************************************************/ /* SubAlloc a new BJNX class with protection against memory exhaustion. */ /*********************************************************************************/ #ifdef NOT_USED static PBJNX BjnxNew(PGLOBAL g, PBVAL vlp, int type, int len)
{
PBJNX bjnx;
PUSH_WARNING(g->Message);
bjnx = NULL;
} // end try/catch
return bjnx;
} /* end of BjnxNew */ #endif /* ----------------------------------- BSNX ------------------------------------ */
/*********************************************************************************/ /* BSNX public constructor. */ /*********************************************************************************/
BJNX::BJNX(PGLOBAL g) : BDOC(g)
{
Row = NULL;
Bvalp = NULL;
Jpnp = NULL;
Jp = NULL;
Nodes = NULL;
Value = NULL; //MulVal = NULL;
Jpath = NULL;
Buf_Type = TYPE_STRING; Long = len;
Prec = 0;
Nod = 0;
Xnod = -1;
K = 0;
I = -1;
Imax = 9;
B = 0;
Xpd = false;
Parsed = false;
Found = false;
Wr = false;
Jb = false;
Changed = false; Throw = false;
} // end of BJNX constructor
/*********************************************************************************/ /* BSNX public constructor. */ /*********************************************************************************/
BJNX::BJNX(PGLOBAL g, PBVAL row, int type, int len, int prec, my_bool wr) : BDOC(g)
{
Row = row;
Bvalp = NULL;
Jpnp = NULL;
Jp = NULL;
Nodes = NULL;
Value = AllocateValue(g, type, len, prec); //MulVal = NULL;
Jpath = NULL;
Buf_Type = type; Long = len;
Prec = prec;
Nod = 0;
Xnod = -1;
K = 0;
I = -1;
Imax = 9;
B = 0;
Xpd = false;
Parsed = false;
Found = false;
Wr = wr;
Jb = false;
Changed = false; Throw = false;
} // end of BJNX constructor
/*********************************************************************************/ /* SetJpath: set and parse the json path. */ /*********************************************************************************/
my_bool BJNX::SetJpath(PGLOBAL g, char* path, my_bool jb)
{ // Check Value was allocated if (Value)
Value->SetNullable(true);
Jpath = path;
// Parse the json path
Parsed = false;
Nod = 0;
Jb = jb; return ParseJpath(g);
} // end of SetJpath
/*********************************************************************************/ /* Analyse array processing options. */ /*********************************************************************************/
my_bool BJNX::SetArrayOptions(PGLOBAL g, char* p, int i)
{ int n = (int)strlen(p);
my_bool dg = true, b = false;
PJNODE jnp = &Nodes[i];
/*********************************************************************************/ /* Parse the eventual passed Jpath information. */ /* This information can be specified in the Fieldfmt column option when */ /* creating the table. It permits to indicate the position of the node */ /* corresponding to that column. */ /*********************************************************************************/
my_bool BJNX::ParseJpath(PGLOBAL g)
{ char* p, * p1 = NULL, * p2 = NULL, * pbuf = NULL; int i;
my_bool a;
if (trace(1))
htrc("ParseJpath %s\n", SVP(Jpath));
if (!(pbuf = PlgDBDup(g, Jpath))) returntrue;
if (*pbuf == '$') pbuf++; if (*pbuf == '.') pbuf++; if (*pbuf == '[') p1 = pbuf++;
// Estimate the required number of nodes for (i = 0, p = pbuf; (p = NextChr(p, '.')); i++, p++)
Nod++; // One path node found
if (!(Nodes = (PJNODE)PlgDBSubAlloc(g, NULL, (++Nod) * sizeof(JNODE)))) returntrue;
memset(Nodes, 0, (Nod) * sizeof(JNODE));
// Analyze the Jpath for this column for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) {
a = (p1 != NULL);
p1 = strchr(p, '[');
p2 = strchr(p, '.');
if (trace(1)) for (i = 0; i < Nod; i++)
htrc("Node(%d) Key=%s Op=%d Rank=%d\n",
i, SVP(Nodes[i].Key), Nodes[i].Op, Nodes[i].Rank);
Parsed = true; returnfalse;
} // end of ParseJpath
/*********************************************************************************/ /* Make a valid key from the passed argument. */ /*********************************************************************************/
PSZ BJNX::MakeKey(UDF_ARGS *args, int i)
{ if (args->arg_count > (unsigned)i) { int j = 0, n = args->attribute_lengths[i];
my_bool b; // true if attribute is zero terminated
PSZ p;
PCSZ s = args->attributes[i];
if (s && *s && (n || *s == '\'')) { if ((b = (!n || !s[n])))
n = strlen(s);
if (IsArgJson(args, i))
j = (int)(strchr(s, '_') - s + 1);
if (j && n > j) {
s += j;
n -= j;
} elseif (*s == '\'' && s[n-1] == '\'') {
s++;
n -= 2;
b = false;
} // endif *s
if (n < 1) return NewStr((PSZ)"Key");
if (!b) {
p = (PSZ)BsonSubAlloc(n + 1);
memcpy(p, s, n);
p[n] = 0; return p;
} // endif b
} // endif s
return NewStr((PSZ)s);
} // endif count
return NewStr((PSZ)"Key");
} // end of MakeKey
/*********************************************************************************/ /* MakeJson: Make the Json tree to serialize. */ /*********************************************************************************/
PBVAL BJNX::MakeJson(PGLOBAL g, PBVAL bvp, int n)
{
PBVAL vlp, jvp = bvp;
Jb = false;
if (n < Nod -1) { if (bvp->Type == TYPE_JAR) { int ars = GetArraySize(bvp);
PJNODE jnp = &Nodes[n];
jvp = NewVal(TYPE_JAR);
jnp->Op = OP_EQ;
for (int i = 0; i < ars; i++) {
jnp->Rank = i;
vlp = GetRowValue(g, bvp, n);
AddArrayValue(jvp, DupVal(vlp));
} // endfor i
/*********************************************************************************/ /* SetValue: Set a value from a BVALUE contains. */ /*********************************************************************************/ void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp)
{ if (vlp) {
vp->SetNull(false);
if (Jb) {
vp->SetValue_psz(Serialize(g, vlp, NULL, 0));
Jb = false;
} elseswitch (vlp->Type) { case TYPE_DTM: case TYPE_STRG:
vp->SetValue_psz(GetString(vlp)); break; case TYPE_INTG:
vp->SetValue(GetInteger(vlp)); break; case TYPE_BINT:
vp->SetValue(GetBigint(vlp)); break; case TYPE_DBL: case TYPE_FLOAT: if (vp->IsTypeNum())
vp->SetValue(GetDouble(vlp)); else// Get the proper number of decimals
vp->SetValue_psz(GetString(vlp));
break; case TYPE_BOOL: if (vp->IsTypeNum())
vp->SetValue(GetInteger(vlp) ? 1 : 0); else
vp->SetValue_psz(GetString(vlp));
break; case TYPE_JAR:
vp->SetValue_psz(GetArrayText(g, vlp, NULL)); break; case TYPE_JOB:
vp->SetValue_psz(GetObjectText(g, vlp, NULL)); break; case TYPE_NULL:
vp->SetNull(true); /* fall through */ default:
vp->Reset();
} // endswitch Type
} else {
vp->SetNull(true);
vp->Reset();
} // endif val
} // end of SetJsonValue
/*********************************************************************************/ /* GetJson: */ /*********************************************************************************/
PBVAL BJNX::GetJson(PGLOBAL g)
{ return GetRowValue(g, Row, 0);
} // end of GetJson
/*********************************************************************************/ /* ReadValue: */ /*********************************************************************************/ void BJNX::ReadValue(PGLOBAL g)
{
Value->SetValue_pval(GetColumnValue(g, Row, 0));
} // end of ReadValue
} else { // Unexpected array, unwrap it as [0]
vlp = GetArrayValue(bap, 0);
i--;
} // endif's
break; case TYPE_JVAL:
vlp = row; break; default:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->Type);
vlp = NULL;
} // endswitch Type
row = vlp;
} // endfor i
return vlp;
} // end of GetRowValue
/*********************************************************************************/ /* ExpandArray: */ /*********************************************************************************/
PVAL BJNX::ExpandArray(PGLOBAL g, PBVAL arp, int n)
{
snprintf(g->Message, sizeof(g->Message), "Expand cannot be done by this function"); return NULL;
} // end of ExpandArray
/*********************************************************************************/ /* Get the value used for calculating the array. */ /*********************************************************************************/
PVAL BJNX::GetCalcValue(PGLOBAL g, PBVAL bap, int n)
{ // For calculated arrays, a local Value must be used int lng = 0; short type = 0, prec = 0; bool b = n < Nod - 1;
PVAL valp;
PBVAL vlp, vp;
OPVAL op = Nodes[n].Op;
switch (op) { case OP_NUM:
type = TYPE_INT; break; case OP_ADD: case OP_MULT: if (!IsTypeNum(Buf_Type)) {
type = TYPE_INT;
prec = 0;
/***********************************************************************/ /* GetRow: Set the complete path of the object to be set. */ /***********************************************************************/
PBVAL BJNX::GetRow(PGLOBAL g)
{
PBVAL val = NULL;
PBVAL arp;
PBVAL nwr, row = Row;
for (int i = 0; i < Nod - 1 && row; i++) { if (Nodes[i].Op == OP_XX) break; elseif (Nodes[i].Op == OP_EXP) {
PUSH_WARNING("Expand not supported by this function"); return NULL;
} elseswitch (row->Type) { case TYPE_JOB: if (!Nodes[i].Key) // Expected Array was not there, wrap the value continue;
val = GetKeyValue(row, Nodes[i].Key); break; case TYPE_JAR:
arp = row;
if (!Nodes[i].Key) { if (Nodes[i].Op == OP_EQ)
val = GetArrayValue(arp, Nodes[i].Rank); else
val = GetArrayValue(arp, Nodes[i].Rx);
} else { // Unexpected array, unwrap it as [0]
val = GetArrayValue(arp, 0);
i--;
} // endif Nodes
break; case TYPE_JVAL:
val = MVP(row->To_Val); break; default:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->Type);
val = NULL;
} // endswitch Type
if (val) {
row = val;
} else { // Construct missing objects for (i++; row && i < Nod; i++) { if (Nodes[i].Op == OP_XX) break;
// Construct new row
nwr = NewVal();
if (row->Type == TYPE_JOB) {
SetKeyValue(row, MOF(nwr), Nodes[i - 1].Key);
} elseif (row->Type == TYPE_JAR) {
AddArrayValue(row, MOF(nwr));
} else {
snprintf(g->Message, sizeof(g->Message), "Wrong type when writing new row");
nwr = NULL;
} // endif's
/*********************************************************************************/ /* GetRowValue: */ /*********************************************************************************/
my_bool BJNX::DeleteItem(PGLOBAL g, PBVAL row)
{ int n = -1;
my_bool b = false; bool loop;
PBVAL vlp, pvp, rwp;
do {
loop = false;
vlp = NULL;
pvp = rwp = row;
for (int i = 0; i < Nod && rwp; i++) { if (Nodes[i].Op == OP_XX) break; elseswitch (rwp->Type) { case TYPE_JOB: if (!Nodes[i].Key) {
vlp = NULL;
} else
vlp = GetKeyValue(rwp, Nodes[i].Key);
break; case TYPE_JAR: if (!Nodes[i].Key) { if (Nodes[i].Op == OP_EXP) { if (loop) {
PUSH_WARNING("Only one expand can be handled"); return b;
} // endif loop
n++;
} else
n = Nodes[i].Rank;
vlp = GetArrayValue(rwp, n);
if (GetNext(vlp) && Nodes[i].Op == OP_EXP)
loop = true;
} else
vlp = NULL;
break; case TYPE_JVAL:
vlp = rwp; break; default:
vlp = NULL;
} // endswitch Type
pvp = rwp;
rwp = vlp;
vlp = NULL;
} // endfor i
if (rwp) { if (Nodes[Nod - 1].Op == OP_XX) { if (!IsJson(rwp))
rwp->Type = TYPE_NULL;
rwp->To_Val = 0;
} elseswitch (pvp->Type) { case TYPE_JOB:
b = DeleteKey(pvp, Nodes[Nod - 1].Key); break; case TYPE_JAR: if (Nodes[Nod - 1].Op == OP_EXP) {
pvp->To_Val = 0;
loop = false;
} else
b = DeleteValue(pvp, n);
break; default: break;
} // endswitch Type
} // endif rwp
} while (loop);
return b;
} // end of DeleteItem
/*********************************************************************************/ /* CheckPath: Checks whether the path exists in the document. */ /*********************************************************************************/
my_bool BJNX::CheckPath(PGLOBAL g)
{
PBVAL val = NULL;
PBVAL row = Row;
for (int i = 0; i < Nod && row; i++) {
val = NULL;
if (Nodes[i].Op == OP_NUM || Nodes[i].Op == OP_XX) {
} elseswitch (row->Type) { case TYPE_JOB: if (Nodes[i].Key)
val = GetKeyValue(row, Nodes[i].Key);
break; case TYPE_JAR: if (!Nodes[i].Key) if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
val = GetArrayValue(row, Nodes[i].Rank);
break; case TYPE_JVAL:
val = row; break; default:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->Type);
} // endswitch Type
if (i < Nod-1) if (!(row = (IsJson(val)) ? val : NULL))
val = NULL;
} // endfor i
return (val != NULL);
} // end of CheckPath
/*********************************************************************************/ /* Check if a path was specified and set jvp according to it. */ /*********************************************************************************/
my_bool BJNX::CheckPath(PGLOBAL g, UDF_ARGS *args, PBVAL jsp, PBVAL& jvp, int n)
{ for (uint i = n; i < args->arg_count; i++) if (args->arg_type[i] == STRING_RESULT && args->args[i]) { // A path to a subset of the json tree is given char *path = MakePSZ(g, args, i);
if (path) {
Row = jsp;
if (SetJpath(g, path)) returntrue;
if (!(jvp = GetJson(g))) {
snprintf(g->Message, sizeof(g->Message), "No sub-item at '%s'", path); returntrue;
} else returnfalse;
/*********************************************************************************/ /* Locate in a JSON Array. */ /*********************************************************************************/
my_bool BJNX::LocateArray(PGLOBAL g, PBVAL jarp)
{ char s[16]; int n = GetArraySize(jarp);
size_t m = Jp->N;
for (int i = 0; i < n && !Found; i++) {
Jp->N = m;
snprintf(s, sizeof(s), "[%d]", i + B);
if (Jp->WriteStr(s)) returntrue;
if (LocateValue(g, GetArrayValue(jarp, i))) returntrue;
} // endfor i
returnfalse;
} // end of LocateArray
/*********************************************************************************/ /* Locate in a JSON Object. */ /*********************************************************************************/
my_bool BJNX::LocateObject(PGLOBAL g, PBVAL jobp)
{
size_t m;
if (Jp->WriteChr('.')) returntrue;
m = Jp->N;
for (PBPR pair = GetObject(jobp); pair && !Found; pair = GetNext(pair)) {
Jp->N = m;
/*********************************************************************************/ /* Locate all occurrences of a value in a JSON tree: */ /*********************************************************************************/
PSZ BJNX::LocateAll(PGLOBAL g, PBVAL jsp, PBVAL bvp, int mx)
{
PSZ str = NULL;
my_bool err = true;
PJPN jnp;
/*********************************************************************************/ /* Locate in a JSON Array. */ /*********************************************************************************/
my_bool BJNX::LocateArrayAll(PGLOBAL g, PBVAL jarp)
{ int i = 0;
if (jp1->Type == TYPE_JAR) { for (int i = 0; found && i < GetArraySize(jp1); i++)
found = (CompareValues(g, GetArrayValue(jp1, i), GetArrayValue(jp2, i)));
// Keys can be differently ordered for (; found && p1 && p2; p1 = GetNext(p1))
found = CompareValues(g, GetVlp(p1), GetKeyValue(jp2, GetKey(p1)));
} elseif (jp1->Type == TYPE_JVAL) {
found = CompareTree(g, MVP(jp1->To_Val), (MVP(jp2->To_Val)));
} else
found = CompareValues(g, jp1, jp2);
return found;
} // end of CompareTree
/*********************************************************************************/ /* Compare two VAL values and return true if they are equal. */ /*********************************************************************************/
my_bool BJNX::CompareValues(PGLOBAL g, PBVAL v1, PBVAL v2)
{
my_bool b = false;
if (v1 && v2) switch (v1->Type) { case TYPE_JAR: case TYPE_JOB: if (v2->Type == v1->Type)
b = CompareTree(g, v1, v2);
break; case TYPE_STRG: if (v2->Type == TYPE_STRG) { if (v1->Nd || v2->Nd) // Case insensitive
b = (!stricmp(MZP(v1->To_Val), MZP(v2->To_Val))); else
b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
} // endif Type
break; case TYPE_DTM: if (v2->Type == TYPE_DTM)
b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
break; case TYPE_INTG: if (v2->Type == TYPE_INTG)
b = (v1->N == v2->N); elseif (v2->Type == TYPE_BINT)
b = ((longlong)v1->N == LLN(v2->To_Val));
break; case TYPE_BINT: if (v2->Type == TYPE_INTG)
b = (LLN(v1->To_Val) == (longlong)v2->N); elseif (v2->Type == TYPE_BINT)
b = (LLN(v1->To_Val) == LLN(v2->To_Val));
break; case TYPE_FLOAT: if (v2->Type == TYPE_FLOAT)
b = (v1->F == v2->F); elseif (v2->Type == TYPE_DBL)
b = ((double)v1->F == DBL(v2->To_Val));
break; case TYPE_DBL: if (v2->Type == TYPE_DBL)
b = (DBL(v1->To_Val) == DBL(v2->To_Val)); elseif (v2->Type == TYPE_FLOAT)
b = (DBL(v1->To_Val) == (double)v2->F);
break; case TYPE_BOOL: if (v2->Type == TYPE_BOOL)
b = (v1->B == v2->B);
break; case TYPE_NULL:
b = (v2->Type == TYPE_NULL); break; default: break;
} // endswitch Type
else
b = (!v1 && !v2);
return b;
} // end of CompareValues
/*********************************************************************************/ /* Add the found path to the list. */ /*********************************************************************************/
my_bool BJNX::AddPath(void)
{ char s[16];
if (Jp->WriteStr("\"$")) returntrue;
for (int i = 0; i <= I; i++) { if (Jpnp[i].Type == TYPE_JAR) {
snprintf(s, sizeof(s), "[%d]", Jpnp[i].N + B);
if (Jp->WriteStr(s)) returntrue;
} else { if (Jp->WriteChr('.')) returntrue;
if (Jp->WriteStr(Jpnp[i].Key)) returntrue;
} // endif's
} // endfor i
if (Jp->WriteStr("\",")) returntrue;
returnfalse;
} // end of AddPath
/*********************************************************************************/ /* Make a JSON value from the passed argument. */ /*********************************************************************************/
PBVAL BJNX::MakeValue(UDF_ARGS *args, uint i, bool b, PBVAL *top)
{ char *sap = (args->arg_count > i) ? args->args[i] : NULL; int n, len; int ci; longlong bigint;
PGLOBAL& g = G;
PBVAL jvp = NewVal();
if (top)
*top = NULL;
if (sap) switch (args->arg_type[i]) { case STRING_RESULT: if ((len = args->lengths[i])) { if ((n = IsArgJson(args, i)) < 3)
sap = MakePSZ(g, args, i);
if (n) { if (n == 3) {
PBSON bsp = (PBSON)sap;
if (i == 0) { if (top)
*top = (PBVAL)bsp->Top;
jvp = (PBVAL)bsp->Jsp;
G = bsp->G;
Base = G->Sarea;
} else {
BJNX bnx(bsp->G);
jvp = MoveJson(&bnx, (PBVAL)bsp->Jsp);
} // endelse i
} else { if (n == 2) { if (!(sap = GetJsonFile(g, sap))) {
PUSH_WARNING(g->Message); return jvp;
} // endif sap
break; case REAL_RESULT:
SetFloat(jvp, *(double*)sap); break; case DECIMAL_RESULT:
SetFloat(jvp, MakePSZ(g, args, i)); break; case TIME_RESULT: case ROW_RESULT: default: break;
} // endswitch arg_type
return jvp;
} // end of MakeValue
/*********************************************************************************/ /* Try making a JSON value of the passed type from the passed argument. */ /*********************************************************************************/
PBVAL BJNX::MakeTypedValue(PGLOBAL g, UDF_ARGS *args, uint i, JTYP type, PBVAL *top)
{ char *sap;
PBVAL jsp;
PBVAL jvp = MakeValue(args, i, false, top);
// Parse the json file and allocate its tree structure
g->Message[0] = 0;
jsp = ParseJson(g, memory, len);
pty = pretty;
CloseMemMap(memory, len); return jsp;
} // end of ParseJsonFile
/*********************************************************************************/ /* Make the result according to the first argument type. */ /*********************************************************************************/ char *BJNX::MakeResult(UDF_ARGS *args, PBVAL top, uint n)
{ char *str = NULL;
PGLOBAL& g = G;
if (IsArgJson(args, 0) == 2) { // Make the change in the json file
PSZ fn = MakePSZ(g, args, 0);
if (Changed) { int pretty = 2;
for (uint i = n; i < args->arg_count; i++) if (args->arg_type[i] == INT_RESULT) {
pretty = (int)*(longlong*)args->args[i]; break;
} // endif type
if (!Serialize(g, top, fn, pretty))
PUSH_WARNING(g->Message);
if (bsp->Filename) { if (Changed) { // Make the change in the json file if (!Serialize(g, (PBVAL)top, bsp->Filename, bsp->Pretty))
PUSH_WARNING(g->Message);
/*********************************************************************************/ /* Make the binary result according to the first argument type. */ /*********************************************************************************/
PBSON BJNX::MakeBinResult(UDF_ARGS *args, PBVAL top, ulong len, int n)
{ char* filename = NULL; int pretty = 2;
PBSON bnp = NULL;
if (IsArgJson(args, 0) == 3) {
bnp = (PBSON)args->args[0];
if (bnp->Top != (PJSON)top)
bnp->Top = bnp->Jsp = (PJSON)top;
return bnp;
} // endif 3
if (IsArgJson(args, 0) == 2) { for (uint i = n; i < args->arg_count; i++) if (args->arg_type[i] == INT_RESULT) {
pretty = (int)*(longlong*)args->args[i]; break;
} // endif type
/***********************************************************************/ /* Move a Json val block from one area to the current area. */ /***********************************************************************/
PBVAL BJNX::MoveVal(PBVAL vlp)
{
PBVAL nvp = NewVal(vlp->Type);
nvp->Nd = vlp->Nd; return nvp;
} // end of MovedVal
/***********************************************************************/ /* Move a Json tree from one area to current area. */ /***********************************************************************/
PBVAL BJNX::MoveJson(PBJNX bxp, PBVAL jvp)
{
PBVAL res = NULL;
if (jvp) switch (jvp->Type) { case TYPE_JAR:
res = MoveArray(bxp, jvp); break; case TYPE_JOB:
res = MoveObject(bxp, jvp); break; default:
res = MoveValue(bxp, jvp); break;
} // endswitch Type
/*********************************************************************************/ /* Returns a pointer to the first integer argument found from the nth argument. */ /*********************************************************************************/ staticint *GetIntArgPtr(PGLOBAL g, UDF_ARGS *args, uint& n)
{ int *x = NULL;
for (uint i = n; i < args->arg_count; i++) if (args->arg_type[i] == INT_RESULT) { if (args->args[i]) { if ((x = (int*)PlgDBSubAlloc(g, NULL, sizeof(int))))
*x = (int)*(longlong*)args->args[i]; else
PUSH_WARNING(g->Message);
} // endif args
n = i + 1; break;
} // endif arg_type
return x;
} // end of GetIntArgPtr
/*********************************************************************************/ /* Returns not 0 if the argument is a JSON item or file name. */ /*********************************************************************************/ int IsArgJson(UDF_ARGS *args, uint i)
{ constchar *pat = args->attributes[i]; int n = 0;
if (*pat == '@') {
pat++;
if (*pat == '\'' || *pat == '"')
pat++;
} // endif pat
if (i >= args->arg_count || args->arg_type[i] != STRING_RESULT) {
} elseif (!strnicmp(pat, "Bson_", 5) || !strnicmp(pat, "Json_", 5)) { if (!args->args[i] || strchr("[{ \t\r\n", *args->args[i]))
n = 1; // arg should be is a json item // else // n = 2; // A file name may have been returned
} elseif (!strnicmp(pat, "Bbin_", 5)) { if (args->lengths[i] == sizeof(BSON))
n = 3; // arg is a binary json item // else // n = 2; // A file name may have been returned
} elseif (!strnicmp(pat, "Bfile_", 6) || !strnicmp(pat, "Jfile_", 6)) {
n = 2; // arg is a json file name #if0
} elseif (args->lengths[i]) {
PGLOBAL g = PlugInit(NULL, (size_t)args->lengths[i] * M + 1024); char *sap = MakePSZ(g, args, i);
if (ParseJson(g, sap, strlen(sap)))
n = 4;
JsonFreeMem(g); #endif// 0
} // endif's
return n;
} // end of IsArgJson
/*********************************************************************************/ /* GetFileLength: returns file size in number of bytes. */ /*********************************************************************************/ staticlong GetFileLength(char *fn)
{ int h; long len;
h= open(fn, _O_RDONLY);
if (h != -1) { if ((len = _filelength(h)) < 0)
len = 0;
close(h);
} else
len = 0;
return len;
} // end of GetFileLength
/* ------------------------- Now the new Bin UDF's ----------------------------- */
/*********************************************************************************/ /* Make a Json value containing the parameter. */ /*********************************************************************************/
my_bool bsonvalue_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
{ unsignedlong reslen, memlen;
if (args->arg_count > 1) {
strcpy(message, "Cannot accept more than 1 argument"); returntrue;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of bsonvalue_init
// Keep result of constant function
g->Xchk = (initid->const_item) ? str : NULL;
} else
str = (char*)g->Xchk;
*res_length = strlen(str); return str;
} // end of bsonValue
void bsonvalue_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bsonvalue_deinit
/*********************************************************************************/ /* Make a Json array containing all the parameters. */ /* Note: jvp must be set before arp because it can be a binary argument. */ /*********************************************************************************/
my_bool bson_make_array_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
{ unsignedlong reslen, memlen;
CalcLen(args, false, reslen, memlen); return JsonInit(initid, args, message, false, reslen, memlen);
} // end of bson_make_array_init
// Keep result of constant function
g->Xchk = (initid->const_item) ? str : NULL;
} else
str = (char*)g->Xchk;
*res_length = strlen(str); return str;
} // end of bson_make_array
void bson_make_array_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_make_array_deinit
/*********************************************************************************/ /* Add one or several values to a Bson array. */ /*********************************************************************************/
my_bool bson_array_add_values_init(UDF_INIT* initid, UDF_ARGS* args, char* message) { unsignedlong reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments"); returntrue; //} else if (!IsArgJson(args, 0, true)) { // strcpy(message, "First argument must be a valid json string or item"); // return true;
} else
CalcLen(args, false, reslen, memlen);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
void bson_array_add_values_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_array_add_values_deinit
/*********************************************************************************/ /* Add one value to a Json array. */ /*********************************************************************************/
my_bool bson_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments"); returntrue; //} else if (!IsArgJson(args, 0, true)) { // strcpy(message, "First argument is not a valid Json item"); // return true;
} else
CalcLen(args, false, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
void bson_array_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_array_add_deinit
/*********************************************************************************/ /* Delete a value from a Json array. */ /*********************************************************************************/
my_bool bson_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments"); returntrue;
} else
CalcLen(args, false, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
if (!g->Xchk) { if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
BJNX bnx(g);
PBVAL jvp, objp;
if ((objp = bnx.NewVal(TYPE_JOB))) { for (uint i = 0; i < args->arg_count; i++) if (!bnx.IsValueNull(jvp = bnx.MakeValue(args, i)))
bnx.SetKeyValue(objp, jvp, bnx.MakeKey(args, i));
if (!g->Xchk) { if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
BJNX bnx(g);
PBVAL objp;
if ((objp = bnx.NewVal(TYPE_JOB))) { for (uint i = 0; i < args->arg_count; i += 2)
bnx.SetKeyValue(objp, bnx.MakeValue(args, i + 1), MakePSZ(g, args, i));
// Keep result of constant function
g->Xchk = (initid->const_item) ? str : NULL;
} else
str = (char*)g->Xchk;
*res_length = strlen(str); return str;
} // end of bson_object_key
void bson_object_key_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_object_key_deinit
/*********************************************************************************/ /* Add or replace a value in a Json Object. */ /*********************************************************************************/
my_bool bson_object_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments"); returntrue;
} elseif (!IsArgJson(args, 0)) {
strcpy(message, "First argument must be a json item"); returntrue;
} else
CalcLen(args, true, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
void bson_object_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_object_add_deinit
/*********************************************************************************/ /* Delete a value from a Json object. */ /*********************************************************************************/
my_bool bson_object_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have 2 or 3 arguments"); returntrue;
} elseif (!IsArgJson(args, 0)) {
strcpy(message, "First argument must be a json item"); returntrue;
} elseif (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument must be a key string"); returntrue;
} else
CalcLen(args, true, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
void bson_object_values_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_object_values_deinit
/*********************************************************************************/ /* Set the value of JsonGrpSize. */ /*********************************************************************************/
my_bool bsonset_def_prec_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ if (args->arg_count != 1 || args->arg_type[0] != INT_RESULT) {
strcpy(message, "This function must have 1 integer argument"); returntrue;
} else returnfalse;
JsonDefPrec = (int)n; return (longlong)GetJsonDefPrec();
} // end of bsonset_def_prec
/*********************************************************************************/ /* Get the value of JsonGrpSize. */ /*********************************************************************************/
my_bool bsonget_def_prec_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ if (args->arg_count != 0) {
strcpy(message, "This function must have no arguments"); returntrue;
} else returnfalse;
} // end of bsonget_def_prec_init
longlong bsonget_def_prec(UDF_INIT *initid, UDF_ARGS *args, uchar *, uchar *)
{ return (longlong)GetJsonDefPrec();
} // end of bsonget_def_prec
/*********************************************************************************/ /* Set the value of JsonGrpSize. */ /*********************************************************************************/
my_bool bsonset_grp_size_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ if (args->arg_count != 1 || args->arg_type[0] != INT_RESULT) {
strcpy(message, "This function must have 1 integer argument"); returntrue;
} else returnfalse;
JsonGrpSize = (uint)n; return (longlong)GetJsonGroupSize();
} // end of bsonset_grp_size
/*********************************************************************************/ /* Get the value of JsonGrpSize. */ /*********************************************************************************/
my_bool bsonget_grp_size_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ if (args->arg_count != 0) {
strcpy(message, "This function must have no arguments"); returntrue;
} else returnfalse;
} // end of bsonget_grp_size_init
longlong bsonget_grp_size(UDF_INIT *initid, UDF_ARGS *args, uchar *, uchar *)
{ return (longlong)GetJsonGroupSize();
} // end of bsonget_grp_size
/*********************************************************************************/ /* Make a Json array from values coming from rows. */ /*********************************************************************************/
my_bool bson_array_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, n = GetJsonGroupSize();
if (args->arg_count != 1) {
strcpy(message, "This function can only accept 1 argument"); returntrue;
} elseif (IsArgJson(args, 0) == 3) {
strcpy(message, "This function does not support Jbin arguments"); returntrue;
} else
CalcLen(args, false, reslen, memlen);
if (!g->Xchk) { if (CheckMemory(g, initid, args, 1, !g->Xchk)) {
PUSH_WARNING("CheckMemory error");
*error = 1; goto err;
} else// Sarea may have been reallocated
bnx.Reset();
void bson_test_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_test_deinit
/*********************************************************************************/ /* Locate a value in a Json tree. */ /*********************************************************************************/
my_bool bsonlocate_init(UDF_INIT* initid, UDF_ARGS* args, char* message) { unsignedlong reslen, memlen, more = 1000;
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required"); returntrue;
} elseif (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item"); returntrue;
} elseif (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (rank)"); returntrue;
} // endifs args
CalcLen(args, false, reslen, memlen);
// TODO: calculate this if (IsArgJson(args, 0) == 3)
more = 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bsonlocate_init
void bsonlocate_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bsonlocate_deinit
/*********************************************************************************/ /* Locate all occurences of a value in a Json tree. */ /*********************************************************************************/
my_bool bson_locate_all_init(UDF_INIT* initid, UDF_ARGS* args, char* message) { unsignedlong reslen, memlen, more = 1000;
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required"); returntrue;
} elseif (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item"); returntrue;
} elseif (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (Depth)"); returntrue;
} // endifs
CalcLen(args, false, reslen, memlen);
// TODO: calculate this if (IsArgJson(args, 0) == 3)
more = 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bson_locate_all_init
void bson_locate_all_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_locate_all_deinit
/*********************************************************************************/ /* Check whether the document contains a value or item. */ /*********************************************************************************/
my_bool bson_contains_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, more = 1024; int n = IsArgJson(args, 0);
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required"); returntrue;
} elseif (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item"); returntrue;
} elseif (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (index)"); returntrue;
} elseif (args->arg_count > 3) { if (args->arg_type[3] == INT_RESULT && args->args[3])
more += (unsignedlong)*(longlong*)args->args[3]; else
strcpy(message, "Fourth argument is not an integer (memory)");
err: if (g->Mrr) *error = 1; return0LL;
} // end of bsoncontains_path
void bsoncontains_path_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bsoncontains_path_deinit
/*********************************************************************************/ /* Merge two arrays or objects. */ /*********************************************************************************/
my_bool bson_item_merge_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments"); returntrue;
} elsefor (int i = 0; i < 2; i++) if (!IsArgJson(args, i) && args->arg_type[i] != STRING_RESULT) {
snprintf(message, MYSQL_ERRMSG_SIZE, "Argument %d must be a json item", i); returntrue;
} // endif type
CalcLen(args, false, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
void bson_item_merge_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_item_merge_deinit
/*********************************************************************************/ /* Get a Json item from a Json document. */ /*********************************************************************************/
my_bool bson_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, more; int n = IsArgJson(args, 0);
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments"); returntrue;
} elseif (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item"); returntrue;
} elseif (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a string (jpath)"); returntrue;
} else
CalcLen(args, false, reslen, memlen);
if (n == 2 && args->args[0]) { char fn[_MAX_PATH]; long fl;
memcpy(fn, args->args[0], args->lengths[0]);
fn[args->lengths[0]] = 0;
fl = GetFileLength(fn);
more = fl * 3;
} elseif (n != 3) {
more = args->lengths[0] * 3;
} else
more = 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bson_get_item_init
void bson_get_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_get_item_deinit
/*********************************************************************************/ /* Get a string value from a Json item. */ /*********************************************************************************/
my_bool bsonget_string_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, more = 1024; int n = IsArgJson(args, 0);
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required"); returntrue;
} elseif (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item"); returntrue;
} elseif (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a string (jpath)"); returntrue;
} elseif (args->arg_count > 2) { if (args->arg_type[2] == INT_RESULT && args->args[2])
more += (unsignedlong)*(longlong*)args->args[2]; else
strcpy(message, "Third argument is not an integer (memory)");
void bsonget_string_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bsonget_string_deinit
/*********************************************************************************/ /* Get an integer value from a Json item. */ /*********************************************************************************/
my_bool bsonget_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, more;
if (args->arg_count != 2) {
strcpy(message, "This function must have 2 arguments"); returntrue;
} elseif (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item"); returntrue;
} elseif (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a (jpath) string"); returntrue;
} else
CalcLen(args, false, reslen, memlen);
// TODO: calculate this
more = (IsArgJson(args, 0) != 3) ? 1000 : 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bsonget_int_init
void bsonget_int_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bsonget_int_deinit
/*********************************************************************************/ /* Get a double value from a Json item. */ /*********************************************************************************/
my_bool bsonget_real_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, more;
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required"); returntrue;
} elseif (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item"); returntrue;
} elseif (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a (jpath) string"); returntrue;
} elseif (args->arg_count > 2) { if (args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (decimals)"); returntrue;
} else
initid->decimals = (uint)*(longlong*)args->args[2];
} else
initid->decimals = 15;
CalcLen(args, false, reslen, memlen);
// TODO: calculate this
more = (IsArgJson(args, 0) != 3) ? 1000 : 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bsonget_real_init
if (args->arg_count < 2) { if (IsArgJson(args, 0) != 3) {
strcpy(message, "This function must have at least 2 arguments or one binary"); returntrue;
} // endif args
} // endif count
CalcLen(args, false, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// Is this a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
if (args->arg_count == 1) { // This should be coming from bbin_locate_all
jar = jvp; // This is the array of paths
jvp = top; // And this is the document
} elseif(!bnx.IsJson(jvp)) {
PUSH_WARNING("First argument is not a JSON document"); goto fin;
} elseif (args->arg_count == 2) { // Check whether this is an array of paths
jar = bnx.MakeValue(args, 1, true);
if (jar && jar->Type != TYPE_JAR)
jar = NULL;
} // endif arg_count
if (jar) { // Do the deletion in reverse order for(int i = bnx.GetArraySize(jar) - 1; i >= 0; i--) {
path = bnx.GetString(bnx.GetArrayValue(jar, i));
/*********************************************************************************/ /* Set Json items of a Json document according to path. */ /*********************************************************************************/
my_bool bson_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, more = 0; int n = IsArgJson(args, 0);
if (!(args->arg_count % 2)) {
strcpy(message, "This function must have an odd number of arguments"); returntrue;
} elseif (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item"); returntrue;
} else
CalcLen(args, false, reslen, memlen);
if (n == 2 && args->args[0]) { char fn[_MAX_PATH]; long fl;
void bson_update_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_update_item_deinit
/*********************************************************************************/ /* Returns a json file as a json string. */ /*********************************************************************************/
my_bool bson_file_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, fl, more = 1024;
if (args->arg_count < 1 || args->arg_count > 4) {
strcpy(message, "This function only accepts 1 to 4 arguments"); returntrue;
} elseif (args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a string (file name)"); returntrue;
} // endif's args[0]
for (unsignedint i = 1; i < args->arg_count; i++) { if (!(args->arg_type[i] == INT_RESULT || args->arg_type[i] == STRING_RESULT)) {
snprintf(message, MYSQL_ERRMSG_SIZE, "Argument %d is not an integer or a string (pretty or path)", i); returntrue;
} // endif arg_type
// Take care of eventual memory argument if (args->arg_type[i] == INT_RESULT && args->args[i])
more += (ulong)*(longlong*)args->args[i];
for (unsignedint i = 1; i < args->arg_count; i++) if (args->arg_type[i] == INT_RESULT && *(longlong*)args->args[i] < 4) {
pretty = (int) * (longlong*)args->args[i]; break;
} // endif type
// Parse the json file and allocate its tree structure if (!(jsp = bnx.ParseJsonFile(g, fn, pty, len))) {
PUSH_WARNING(g->Message); goto fin;
} // endif jsp
if (pty == 3)
PUSH_WARNING("File pretty format cannot be determined"); elseif (pretty != 3 && pty != pretty)
PUSH_WARNING("File pretty format doesn't match the specified pretty value"); elseif (pretty == 3)
pretty = pty;
// Check whether a path was specified if (bnx.CheckPath(g, args, jsp, jvp, 1)) {
PUSH_WARNING(g->Message); goto fin;
} elseif (jvp)
jsp = jvp;
if (!(str = bnx.Serialize(g, jsp, NULL, 0)))
PUSH_WARNING(g->Message);
} else if (!(str = GetJsonFile(g, fn)))
PUSH_WARNING(g->Message);
if (initid->const_item) // Keep result of constant function
g->Xchk = str;
void bson_file_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_file_deinit
/*********************************************************************************/ /* Make a json file from a json item. */ /*********************************************************************************/
my_bool bfile_make_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen;
if (args->arg_count < 1 || args->arg_count > 3) {
strcpy(message, "Wrong number of arguments"); returntrue;
} elseif (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item"); returntrue;
} // endif
CalcLen(args, false, reslen, memlen);
memlen = memlen + 5000; // To take care of not pretty files return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bfile_make_init
if (args->arg_count != 3) {
strcpy(message, "This function must have 3 arguments"); returntrue;
} elseif (args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third Argument must be an integer (LRECL)"); returntrue;
} elsefor (int i = 0; i < 2; i++) if (args->arg_type[i] != STRING_RESULT) {
snprintf(message, MYSQL_ERRMSG_SIZE, "Arguments %d must be a string (file name)", i+1); returntrue;
} // endif args
CalcLen(args, false, reslen, memlen); return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bfile_convert_init
if (args->arg_count != 2 && args->arg_count != 3) {
strcpy(message, "This function must have 2 or 3 arguments"); returntrue;
} elseif (args->arg_count == 3 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third Argument must be an integer (LRECL)"); returntrue;
} elsefor (int i = 0; i < 2; i++) if (args->arg_type[i] != STRING_RESULT) {
snprintf(message, MYSQL_ERRMSG_SIZE, "Arguments %d must be a string (file name)", i + 1); returntrue;
} // endif args
CalcLen(args, false, reslen, memlen);
memlen = memlen * M;
memlen += (args->arg_count == 3) ? (ulong)*(longlong*)args->args[2] : 1024; return JsonInit(initid, args, message, false, reslen, memlen);
} // end of bfile_bjson_init
// if (!(str = bnx.Serialize(g, bvp, bsp->Filename, bsp->Pretty))) if (!(str = bnx.Serialize(g, bvp, NULL, 0)))
str = strcpy(result, g->Message);
// Keep result of constant function
g->Xchk = (initid->const_item) ? str : NULL;
} else { // *error = 1;
str = strcpy(result, "Argument is not a Jbin tree");
} // endif
} else
str = (char*)g->Xchk;
*res_length = strlen(str); return str;
} // end of bson_serialize
void bson_serialize_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_serialize_deinit
/*********************************************************************************/ /* Make and return a binary Json array containing all the parameters. */ /* Note: jvp must be set before arp because it can be a binary argument. */ /*********************************************************************************/
my_bool bbin_make_array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen;
CalcLen(args, false, reslen, memlen); return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bbin_make_array_init
void bbin_make_array_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_make_array_deinit
/*********************************************************************************/ /* Add one value to a Json array. */ /*********************************************************************************/
my_bool bbin_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments"); returntrue;
} else
CalcLen(args, false, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
void bbin_array_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_array_add_deinit
/*********************************************************************************/ /* Add one or several values to a Bson array. */ /*********************************************************************************/
my_bool bbin_array_add_values_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
{ return bson_array_add_values_init(initid, args, message);
} // end of bbin_array_add_values_init
return (char*)bsp;
} // end of bbin_array_add_values
void bbin_array_add_values_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_array_add_values_deinit
/*********************************************************************************/ /* Make a Json array from values coming from rows. */ /*********************************************************************************/
my_bool bbin_array_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ return bson_array_grp_init(initid, args, message);
} // end of bbin_array_grp_init
void bbin_array_grp_clear(UDF_INIT *initid, uchar *a, uchar *b)
{
bson_array_grp_clear(initid, a, b);
} // end of bbin_array_grp_clear
void bbin_array_grp_add(UDF_INIT *initid, UDF_ARGS *args, uchar *a, uchar *b)
{
bson_array_grp_add(initid, args, a, b);
} // end of bbin_array_grp_add
void bbin_array_grp_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_array_grp_deinit
/*********************************************************************************/ /* Make a Json object from values coming from rows. */ /*********************************************************************************/
my_bool bbin_object_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ return bson_object_grp_init(initid, args, message);
} // end of bbin_object_grp_init
void bbin_object_grp_clear(UDF_INIT *initid, uchar *a, uchar *b)
{
bson_object_grp_clear(initid, a, b);
} // end of bbin_object_grp_clear
void bbin_object_grp_add(UDF_INIT *initid, UDF_ARGS *args, uchar *a, uchar *b)
{
bson_object_grp_add(initid, args, a, b);
} // end of bbin_object_grp_add
if (!bsp) { if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
BJNX bnx(g);
PBVAL jvp, objp;
if ((objp = bnx.NewVal(TYPE_JOB))) { for (uint i = 0; i < args->arg_count; i++) if (!bnx.IsValueNull(jvp = bnx.MakeValue(args, i)))
bnx.SetKeyValue(objp, jvp, bnx.MakeKey(args, i));
if (!bsp) { if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
BJNX bnx(g);
PBVAL objp;
if ((objp = bnx.NewVal(TYPE_JOB))) { for (uint i = 0; i < args->arg_count; i += 2)
bnx.SetKeyValue(objp, bnx.MakeValue(args, i + 1), MakePSZ(g, args, i));
void bbin_object_key_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_object_key_deinit
/*********************************************************************************/ /* Add or replace a value in a Json Object. */ /*********************************************************************************/
my_bool bbin_object_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments"); returntrue;
} elseif (!IsArgJson(args, 0)) {
strcpy(message, "First argument must be a json item"); returntrue;
} else
CalcLen(args, true, reslen, memlen, true);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bbin_object_add_init
void bbin_object_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_object_add_deinit
/*********************************************************************************/ /* Delete a value from a Json array. */ /*********************************************************************************/
my_bool bbin_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ return bson_array_delete_init(initid, args, message);
} // end of bbin_array_delete_init
void bbin_array_delete_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_array_delete_deinit
/*********************************************************************************/ /* Delete a value from a Json object. */ /*********************************************************************************/
my_bool bbin_object_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have 2 or 3 arguments"); returntrue;
} elseif (!IsArgJson(args, 0)) {
strcpy(message, "First argument must be a json item"); returntrue;
} elseif (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument must be a key string"); returntrue;
} else
CalcLen(args, true, reslen, memlen, true);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bbin_object_delete_init
if (jsp->Type == TYPE_JOB) {
jarp = bnx.GetKeyList(jsp);
} else {
PUSH_WARNING("First argument is not an object"); if (g->Mrr) *error = 1;
} // endif jsp type
// In case of error unchanged argument will be returned
bsp = bnx.MakeBinResult(args, top, initid->max_length);
bsp->Jsp = (PJSON)jarp;
} // endif CheckMemory
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
void bbin_object_values_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_object_values_deinit
/*********************************************************************************/ /* Get a Json item from a Json document. */ /*********************************************************************************/
my_bool bbin_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ return bson_get_item_init(initid, args, message);
} // end of bbin_get_item_init
/*********************************************************************************/ /* Set Json items of a Json document according to path. */ /*********************************************************************************/
my_bool bbin_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ return bson_set_item_init(initid, args, message);
} // end of bbin_set_item_init
if (args->arg_count == 1) { // This should be coming from bbin_locate_all
jar = jvp; // This is the array of paths
jvp = top; // And this is the document
} elseif(!bnx.IsJson(jvp)) {
PUSH_WARNING("First argument is not a JSON document"); goto fin;
} elseif (args->arg_count == 2) { // Check whether this is an array of paths
jar = bnx.MakeValue(args, 1, true);
if (jar && jar->Type != TYPE_JAR)
jar = NULL;
} // endif arg_count
if (jar) { // Do the deletion in reverse order for(int i = bnx.GetArraySize(jar) - 1; i >= 0; i--) {
path = bnx.GetString(bnx.GetArrayValue(jar, i));
void bbin_file_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_file_deinit
/*********************************************************************************/ /* Locate all occurences of a value in a Json tree. */ /*********************************************************************************/
my_bool bbin_locate_all_init(UDF_INIT* initid, UDF_ARGS* args, char* message) { return bson_locate_all_init(initid, args, message);
} // end of bbin_locate_all_init
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.