/****************** jsonudf C++ Program Source Code File (.CPP) ******************/ /* PROGRAM NAME: jsonudf Version 1.8 */ /* (C) Copyright to the author Olivier BERTRAND 2015-2019 */ /* This program are the JSON 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 <m_string.h>
/*********************************************************************************/ /* SubAlloc a new JSNX class with protection against memory exhaustion. */ /*********************************************************************************/ static PJSNX JsnxNew(PGLOBAL g, PJSON jsp, int type, int len)
{
PJSNX jsx;
/*********************************************************************************/ /* 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 JSNX::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
/*********************************************************************************/ /* SetValue: Set a value from a JVALUE contains. */ /*********************************************************************************/ void JSNX::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val)
{ if (val) {
vp->SetNull(false);
if (Jb) {
vp->SetValue_psz(Serialize(g, val->GetJsp(), NULL, 0));
Jb = false;
} elseswitch (val->GetValType()) { case TYPE_DTM: case TYPE_STRG:
vp->SetValue_psz(val->GetString(g)); break; case TYPE_INTG:
vp->SetValue(val->GetInteger()); break; case TYPE_BINT:
vp->SetValue(val->GetBigint()); break; case TYPE_DBL: if (vp->IsTypeNum())
vp->SetValue(val->GetFloat()); else// Get the proper number of decimals
vp->SetValue_psz(val->GetString(g));
break; case TYPE_BOOL: if (vp->IsTypeNum())
vp->SetValue(val->GetInteger() ? 1 : 0); else
vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false"));
break; case TYPE_JAR:
vp->SetValue_psz(val->GetArray()->GetText(g, NULL)); break; case TYPE_JOB:
vp->SetValue_psz(val->GetObject()->GetText(g, NULL)); break; case TYPE_NULL:
vp->SetNull(true); /* falls through */ default:
vp->Reset();
} // endswitch Type
} else {
vp->SetNull(true);
vp->Reset();
} // endif val
} // end of SetJsonValue
/*********************************************************************************/ /* MakeJson: Serialize the json item and set value to it. */ /*********************************************************************************/
PJVAL JSNX::MakeJson(PGLOBAL g, PJSON jsp, int n)
{
Jb = false;
if (Value->IsTypeNum()) {
snprintf(g->Message, sizeof(g->Message), "Cannot make Json for a numeric value"); return NULL;
} elseif (jsp->GetType() != TYPE_JAR && jsp->GetType() != TYPE_JOB) {
snprintf(g->Message, sizeof(g->Message), "Target is not an array or object"); return NULL;
} elseif (n < Nod -1) { if (jsp->GetType() == TYPE_JAR) { int ars = jsp->GetSize(false);
PJNODE jnp = &Nodes[n];
PJAR jarp = new(g) JARRAY;
Jb = true; returnnew(g) JVALUE(jsp);
} // end of MakeJson
/*********************************************************************************/ /* GetJson: */ /*********************************************************************************/
PJVAL JSNX::GetJson(PGLOBAL g)
{ return GetRowValue(g, Row, 0);
} // end of GetJson
/*********************************************************************************/ /* ReadValue: */ /*********************************************************************************/ void JSNX::ReadValue(PGLOBAL g)
{
Value->SetValue_pval(GetColumnValue(g, Row, 0));
} // end of ReadValue
/*********************************************************************************/ /* GetColumnValue: */ /*********************************************************************************/
PVAL JSNX::GetColumnValue(PGLOBAL g, PJSON row, int i)
{
PJVAL val = NULL;
val = GetRowValue(g, row, i);
SetJsonValue(g, Value, val); return Value;
} // end of GetColumnValue
/*********************************************************************************/ /* GetRowValue: */ /*********************************************************************************/
PJVAL JSNX::GetRowValue(PGLOBAL g, PJSON row, int i, my_bool b)
{
PJAR arp;
PJVAL val = NULL;
for (; i < Nod && row; i++) { if (Nodes[i].Op == OP_NUM) {
Value->SetValue(row->GetType() == TYPE_JAR ? ((PJAR)row)->size() : 1);
val = new(g) JVALUE(g, Value); return val;
} elseif (Nodes[i].Op == OP_XX) { return MakeJson(g, row, i);
} elseswitch (row->GetType()) { case TYPE_JOB: if (!Nodes[i].Key) { // Expected Array was not there if (Nodes[i].Op == OP_LE) { if (i < Nod-1) continue; else
val = new(g)JVALUE(row);
} else {
snprintf(g->Message, sizeof(g->Message), "Unexpected object");
val = NULL;
} //endif Op
} else
val = ((PJOB)row)->GetKeyValue(Nodes[i].Key);
break; case TYPE_JAR:
arp = (PJAR)row;
if (!Nodes[i].Key) { if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
val = arp->GetArrayValue(Nodes[i].Rank); elseif (Nodes[i].Op == OP_EXP) return (PJVAL)ExpandArray(g, arp, i); else returnnew(g) JVALUE(g, CalculateArray(g, arp, i));
} else { // Unexpected array, unwrap it as [0]
val = arp->GetArrayValue(0);
i--;
} // endif's
break; case TYPE_JVAL:
val = (PJVAL)row; break; default:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->GetType());
val = NULL;
} // endswitch Type
if (i < Nod-1) if (!(row = (val) ? val->GetJsp() : NULL))
val = NULL; // row = (val) ? val->GetJson() : NULL;
} // endfor i
// SetJsonValue(g, Value, val); return val;
} // end of GetRowValue
/*********************************************************************************/ /* ExpandArray: */ /*********************************************************************************/
PVAL JSNX::ExpandArray(PGLOBAL g, PJAR 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 JSNX::GetCalcValue(PGLOBAL g, PJAR jap, 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;
PJVAL 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;
if (op == OP_SEP) { // Calculate average
mulval->SetValue(nv);
val[0] = vp;
val[1] = mulval;
if (vp->Compute(g, val, 2, OP_DIV))
vp->Reset();
} // endif Op
return vp;
} // end of CalculateArray
/*********************************************************************************/ /* CheckPath: Checks whether the path exists in the document. */ /*********************************************************************************/
my_bool JSNX::CheckPath(PGLOBAL g)
{
PJVAL val= NULL;
PJSON 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->GetType()) { case TYPE_JOB: if (Nodes[i].Key)
val = ((PJOB)row)->GetKeyValue(Nodes[i].Key);
break; case TYPE_JAR: if (!Nodes[i].Key) if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
val = ((PJAR)row)->GetArrayValue(Nodes[i].Rank);
break; case TYPE_JVAL:
val = (PJVAL)row; break; default:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->GetType());
} // endswitch Type
if (i < Nod-1) if (!(row = (val) ? val->GetJsp() : NULL))
val = NULL;
} // endfor i
return (val != NULL);
} // end of CheckPath
/***********************************************************************/ /* GetRow: Set the complete path of the object to be set. */ /***********************************************************************/
PJSON JSNX::GetRow(PGLOBAL g)
{
PJVAL val = NULL;
PJAR arp;
PJSON nwr, row = Row;
for (int i = 0; i < Nod - 1 && row; i++) { if (Nodes[i].Op == OP_XX) break; elseswitch (row->GetType()) { case TYPE_JOB: if (!Nodes[i].Key) // Expected Array was not there, wrap the value continue;
val = ((PJOB)row)->GetKeyValue(Nodes[i].Key); break; case TYPE_JAR:
arp = (PJAR)row;
if (!Nodes[i].Key) { if (Nodes[i].Op == OP_EQ)
val = arp->GetArrayValue(Nodes[i].Rank); else
val = arp->GetArrayValue(Nodes[i].Rx);
} else { // Unexpected array, unwrap it as [0]
val = arp->GetArrayValue(0);
i--;
} // endif Nodes
break; case TYPE_JVAL:
val = (PJVAL)row; break; default:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->GetType());
val = NULL;
} // endswitch Type
if (val) {
row = val->GetJson();
} else { // Construct missing objects for (i++; row && i < Nod; i++) { if (Nodes[i].Op == OP_XX) break; elseif (!Nodes[i].Key) // Construct intermediate array
nwr = new(g)JARRAY; else
nwr = new(g)JOBJECT;
if (row->GetType() == TYPE_JOB) {
((PJOB)row)->SetKeyValue(g, new(g)JVALUE(nwr), Nodes[i-1].Key);
} elseif (row->GetType() == TYPE_JAR) {
((PJAR)row)->AddArrayValue(g, new(g)JVALUE(nwr));
((PJAR)row)->InitArray(g);
} else {
snprintf(g->Message, sizeof(g->Message), "Wrong type when writing new row");
nwr = NULL;
} // endif's
/*********************************************************************************/ /* Locate all occurrences of a value in a JSON tree: */ /*********************************************************************************/
PSZ JSNX::LocateAll(PGLOBAL g, PJSON jsp, PJVAL jvp, int mx)
{
PSZ str = NULL;
my_bool err = true;
PJPN jnp;
if (((PJVAL)jp1)->DataType == TYPE_JSON && ((PJVAL)jp2)->DataType == TYPE_JSON)
found = CompareTree(g, jp1->GetJsp(), jp2->GetJsp()); else
found = CompareValues(((PJVAL)jp1), ((PJVAL)jp2));
} elseif (jp1->GetType() == TYPE_JAR) { for (int i = 0; found && i < jp1->size(); i++)
found = (CompareTree(g, jp1->GetArrayValue(i), jp2->GetArrayValue(i)));
for (; found && p1 && p2; p1 = p1->Next, p2 = p2->Next)
found = CompareTree(g, p1->Val, p2->Val);
} else
found = false;
return found;
} // end of CompareTree
/*********************************************************************************/ /* Compare two VAL values and return true if they are equal. */ /*********************************************************************************/
my_bool JSNX::CompareValues(PJVAL v1, PJVAL v2)
{
my_bool b = false;
switch (v1->DataType) { case TYPE_STRG: if (v2->DataType == TYPE_STRG) { if (v1->Nd || v2->Nd) // Case insensitive
b = (!stricmp(v1->Strp, v2->Strp)); else
b = (!strcmp(v1->Strp, v2->Strp));
} // endif Type
break; case TYPE_DTM: if (v2->DataType == TYPE_DTM)
b = (!strcmp(v1->Strp, v2->Strp));
break; case TYPE_INTG: if (v2->DataType == TYPE_INTG)
b = (v1->N == v2->N); elseif (v2->DataType == TYPE_BINT)
b = (v1->N == v2->LLn);
break; case TYPE_BINT: if (v2->DataType == TYPE_INTG)
b = (v1->LLn == v2->N); elseif (v2->DataType == TYPE_BINT)
b = (v1->LLn == v2->LLn);
break; case TYPE_DBL: if (v2->DataType == TYPE_DBL)
b = (v1->F == v2->F);
break; case TYPE_BOOL: if (v2->DataType == TYPE_BOOL)
b = (v1->B == v2->B);
break; case TYPE_NULL: if (v2->DataType == TYPE_NULL)
b = true;
break; default: break;
} // endswitch Type
return b;
} // end of CompareValues
/*********************************************************************************/ /* Add the found path to the list. */ /*********************************************************************************/
my_bool JSNX::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);
/*********************************************************************************/ /* Set the BSON chain as changed. */ /*********************************************************************************/ staticvoid SetChanged(PBSON bsp)
{ if (bsp->Bsp)
SetChanged(bsp->Bsp);
bsp->Changed = true;
} /* end of SetChanged */
/*********************************************************************************/ /* Replaces GetJsonGrpSize not usable when CONNECT is not installed. */ /*********************************************************************************/
uint GetJsonGroupSize(void)
{ return (JsonGrpSize) ? JsonGrpSize : GetJsonGrpSize();
} // end of GetJsonGroupSize
/*********************************************************************************/ /* Program for SubSet re-initialization of the memory pool. */ /*********************************************************************************/
my_bool JsonSubSet(PGLOBAL g, my_bool b)
{
PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
/*********************************************************************************/ /* 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 */
/*********************************************************************************/ /* SubAlloc a new JSON item with protection against memory exhaustion. */ /*********************************************************************************/ static PJSON JsonNew(PGLOBAL g, JTYP type)
{
PJSON jsp = NULL;
try { switch (type) { case TYPE_JAR:
jsp = new(g) JARRAY; break; case TYPE_JOB:
jsp = new(g) JOBJECT; break; default: break;
} // endswitch type
} catch (...) { if (trace(1023))
htrc("%s\n", g->Message);
PUSH_WARNING(g->Message);
} // end try/catch
return jsp;
} /* end of JsonNew */
/*********************************************************************************/ /* SubAlloc a new JValue with protection against memory exhaustion. */ /*********************************************************************************/ static PJVAL JvalNew(PGLOBAL g, JTYP type, void *vp)
{
PJVAL jvp = NULL;
try { if (!vp)
jvp = new (g) JVALUE; elseswitch (type) { case TYPE_JSON: case TYPE_JVAL: case TYPE_JAR: case TYPE_JOB:
jvp = new(g) JVALUE((PJSON)vp); break; // case TYPE_VAL: // jvp = new(g) JVALUE(g, (PVAL)vp); // break; case TYPE_DTM: case TYPE_STRG:
jvp = new(g) JVALUE(g, (PCSZ)vp); break; default: break;
} // endswitch type
} catch (...) { if (trace(1023))
htrc("%s\n", g->Message);
PUSH_WARNING(g->Message);
} // end try/catch
return jvp;
} /* end of JvalNew */
/*********************************************************************************/ /* Allocate and initialise the memory area. */ /*********************************************************************************/
my_bool JsonInit(UDF_INIT *initid, UDF_ARGS *args, char *message, my_bool mbn, unsignedlong reslen, unsignedlong memlen, unsignedlong more)
{
PGLOBAL g = PlugInit(NULL, (size_t)memlen + more + 500); // +500 to avoid CheckMem
if (!g) {
strcpy(message, "Allocation error"); returntrue;
} elseif (g->Sarea_Size == 0) {
strcpy(message, g->Message);
g = PlugExit(g); returntrue;
} // endif g
/*********************************************************************************/ /* Check if a path was specified and set jvp according to it. */ /*********************************************************************************/ static my_bool CheckPath(PGLOBAL g, UDF_ARGS *args, PJSON jsp, PJVAL& 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) {
PJSNX jsx = new(g)JSNX(g, jsp, TYPE_STRING);
if (jsx->SetJpath(g, path)) returntrue;
if (!(jvp = jsx->GetJson(g))) {
snprintf(g->Message, sizeof(g->Message), "No sub-item at '%s'", path); returntrue;
} // endif jvp
/*********************************************************************************/ /* Make the result according to the first argument type. */ /*********************************************************************************/ staticchar *MakeResult(PGLOBAL g, UDF_ARGS *args, PJSON top, uint n = 2)
{ char *str;
if (IsJson(args, 0) == 2) { // Make the change in the json file 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, MakePSZ(g, args, 0), pretty))
PUSH_WARNING(g->Message);
/*********************************************************************************/ /* Make the binary result according to the first argument type. */ /*********************************************************************************/ static PBSON MakeBinResult(PGLOBAL g, UDF_ARGS *args, PJSON top, ulong len, int n = 2)
{
PBSON bsnp = JbinAlloc(g, args, len, top);
if (!bsnp) return NULL;
if (IsJson(args, 0) == 2) { int pretty = 0;
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
/*********************************************************************************/ /* 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 IsJson(UDF_ARGS *args, uint i, bool b)
{ 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, "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, "Jbin_", 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, "Jfile_", 6)) {
n = 2; // arg is a json file name
} elseif (b) { char *sap;
PGLOBAL g = PlugInit(NULL, (size_t)args->lengths[i] * M + 1024);
// JsonSubSet(g);
sap = MakePSZ(g, args, i);
if (ParseJson(g, sap, strlen(sap)))
n = 4;
JsonFreeMem(g);
} // endif's
return n;
} // end of IsJson
/*********************************************************************************/ /* GetMemPtr: returns the memory pointer used by this argument. */ /*********************************************************************************/ static PGLOBAL GetMemPtr(PGLOBAL g, UDF_ARGS *args, uint i)
{ return (IsJson(args, i) == 3) ? ((PBSON)args->args[i])->G : g;
} // end of GetMemPtr
/*********************************************************************************/ /* 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
/*********************************************************************************/ /* Calculate the reslen and memlen needed by a function. */ /*********************************************************************************/
my_bool CalcLen(UDF_ARGS *args, my_bool obj, unsignedlong& reslen, unsignedlong& memlen, my_bool mod)
{ char fn[_MAX_PATH]; unsignedlong i, k, m, n; long fl = 0, j = -1;
reslen = args->arg_count + 2;
// Calculate the result max length for (i = 0; i < args->arg_count; i++) {
n = IsJson(args, i);
if (obj) { if (!(k = args->attribute_lengths[i]))
k = strlen(args->attributes[i]);
reslen += (k + 3); // For quotes and :
} // endif obj
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: default: // What should we do here ? break;
} // endswitch arg_type
} // endfor i
// Calculate the amount of memory needed
memlen = MEMFIX + sizeof(JOUTSTR) + reslen;
for (i = 0; i < args->arg_count; i++) {
n = IsJson(args, i);
memlen += (args->lengths[i] + sizeof(JVALUE));
if (obj) { if (!(k = args->attribute_lengths[i]))
k = strlen(args->attributes[i]);
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: default: // What should we do here ? break;
} // endswitch arg_type
} // endfor i
returnfalse;
} // end of CalcLen
/*********************************************************************************/ /* Check if the calculated memory is enough. */ /*********************************************************************************/
my_bool CheckMemory(PGLOBAL g, UDF_INIT *initid, UDF_ARGS *args, uint n,
my_bool m, my_bool obj, my_bool mod)
{ unsignedlong rl, ml;
my_bool b = false;
n = MY_MIN(n, args->arg_count);
for (uint i = 0; i < n; i++) if (IsJson(args, i) == 2 ||
(b = (m && !i && args->arg_type[0] == STRING_RESULT && !IsJson(args, 0)))) { if (CalcLen(args, obj, rl, ml, mod)) returntrue; elseif (b) {
ulong len; char *p = args->args[0];
// Is this a file name? if (p && !strchr("[{ \t\r\n", *p) && (len = GetFileLength(p)))
ml += len * (M + 1); else
ml += args->lengths[0] * M;
JsonSubSet(g); returnfalse;
} // end of CheckMemory
/*********************************************************************************/ /* Make a zero terminated string from the passed argument. */ /*********************************************************************************/
PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i)
{ if (args->arg_count > (unsigned)i && args->args[i]) { int n = args->lengths[i];
PSZ s = (PSZ)PlgDBSubAlloc(g, NULL, n + 1);
if (s) {
memcpy(s, args->args[i], n);
s[n] = 0;
} else
PUSH_WARNING(g->Message);
return s;
} else return NULL;
} // end of MakePSZ
/*********************************************************************************/ /* Make a valid key from the passed argument. */ /*********************************************************************************/ static PCSZ MakeKey(PGLOBAL g, 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 (IsJson(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 (PCSZ) "Key";
if (!b) { if ((p = (PSZ)PlgDBSubAlloc(g, NULL, n + 1))) {
memcpy(p, s, n);
p[n] = 0;
} else
PUSH_WARNING(g->Message);
if (hFile == INVALID_HANDLE_VALUE) {
DWORD rc = GetLastError();
if (!(*g->Message))
snprintf(g->Message, sizeof(g->Message), MSG(OPEN_MODE_ERROR), "map", (int)rc, fn);
return NULL;
} // endif hFile
/*******************************************************************************/ /* Get the file size. */ /*******************************************************************************/
len = (size_t)mm.lenL;
if (mm.lenH)
len += ((size_t)mm.lenH * 0x000000001LL);
memory = (char *)mm.memory;
if (!len) { // Empty or deleted file
CloseFileHandle(hFile); return NULL;
} // endif len
break; case REAL_RESULT:
jvp->SetFloat(g, *(double*)sap); break; case DECIMAL_RESULT:
jvp->SetFloat(g, atof(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. */ /*********************************************************************************/ static PJVAL MakeTypedValue(PGLOBAL g, UDF_ARGS *args, uint i,
JTYP type, PJSON *top = NULL)
{ char *sap;
PJSON jsp;
PJVAL jvp = MakeValue(g, args, i, top);
// 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 json_make_array
void json_make_array_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_make_array_deinit
/*********************************************************************************/ /* Add one or several values to a Json array. */ /*********************************************************************************/
my_bool json_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 (!IsJson(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 (IsJson(args, 0) > 1)
initid->const_item = 0;
void json_array_add_values_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_array_add_values_deinit
/*********************************************************************************/ /* Add one value to a Json array. */ /*********************************************************************************/
my_bool json_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 (!IsJson(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 (IsJson(args, 0) > 1)
initid->const_item = 0;
void json_array_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_array_add_deinit
/*********************************************************************************/ /* Delete a value from a Json array. */ /*********************************************************************************/
my_bool json_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 (IsJson(args, 0) > 1)
initid->const_item = 0;
void jsonsum_real_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jsonsum_real_deinit
/*********************************************************************************/ /* Returns the average of big integer values from a Json array. */ /*********************************************************************************/
my_bool jsonavg_real_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ return jsonsum_real_init(initid, args, message);
} // end of jsonavg_real_init
double jsonavg_real(UDF_INIT *initid, UDF_ARGS *args, uchar *is_null, uchar *error)
{ double n = 0.0;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) { if (!g->Activityp) {
*is_null = 1; return0.0;
} else return *(double*)g->Activityp;
if (!g->Xchk) { if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
PJOB objp;
if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) { for (uint i = 0; i < args->arg_count; i += 2)
objp->SetKeyValue(g, MakeValue(g, 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 json_object_key
void json_object_key_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_object_key_deinit
/*********************************************************************************/ /* Add or replace a value in a Json Object. */ /*********************************************************************************/
my_bool json_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 (!IsJson(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 (IsJson(args, 0) > 1)
initid->const_item = 0;
void json_object_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_object_add_deinit
/*********************************************************************************/ /* Delete a value from a Json object. */ /*********************************************************************************/
my_bool json_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 (!IsJson(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 (IsJson(args, 0) > 1)
initid->const_item = 0;
void json_object_values_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_object_values_deinit
/*********************************************************************************/ /* Set the value of JsonGrpSize. */ /*********************************************************************************/
my_bool jsonset_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 jsonset_grp_size
/*********************************************************************************/ /* Get the value of JsonGrpSize. */ /*********************************************************************************/
my_bool jsonget_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 jsonget_grp_size_init
longlong jsonget_grp_size(UDF_INIT *initid, UDF_ARGS *args, uchar *, uchar *)
{ return (longlong)GetJsonGroupSize();
} // end of jsonget_grp_size
/*********************************************************************************/ /* Make a Json array from values coming from rows. */ /*********************************************************************************/
my_bool json_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 (IsJson(args, 0) == 3) {
strcpy(message, "This function does not support Jbin arguments"); returntrue;
} else
CalcLen(args, false, reslen, memlen);
PlugSubSet(g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JOB);
g->N = GetJsonGroupSize();
} // end of json_object_grp_clear
void json_object_grp_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_object_grp_deinit
/*********************************************************************************/ /* Merge two arrays or objects. */ /*********************************************************************************/
my_bool json_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;
} elseif (!IsJson(args, 0)) {
strcpy(message, "First argument must be a json item"); returntrue;
} elseif (!IsJson(args, 1)) {
strcpy(message, "Second argument must be a json item"); 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 (IsJson(args, 0) > 1)
initid->const_item = 0;
void json_item_merge_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_item_merge_deinit
/*********************************************************************************/ /* Get a Json item from a Json document. */ /*********************************************************************************/
my_bool json_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, more; int n = IsJson(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 json_get_item_init
void json_get_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_get_item_deinit
/*********************************************************************************/ /* Get a string value from a Json item. */ /*********************************************************************************/
my_bool jsonget_string_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, more = 1024; int n = IsJson(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 jsonget_string_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jsonget_string_deinit
/*********************************************************************************/ /* Get an integer value from a Json item. */ /*********************************************************************************/
my_bool jsonget_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 (!IsJson(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 = (IsJson(args, 0) != 3) ? 1000 : 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of jsonget_int_init
void jsonget_int_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jsonget_int_deinit
/*********************************************************************************/ /* Get a double value from a Json item. */ /*********************************************************************************/
my_bool jsonget_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 (!IsJson(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 = (IsJson(args, 0) != 3) ? 1000 : 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of jsonget_real_init
void jsonget_real_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jsonget_real_deinit
/*********************************************************************************/ /* Locate a value in a Json tree. */ /*********************************************************************************/
my_bool jsonlocate_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 (!IsJson(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;
} elseif (args->arg_count > 3)
{ if (args->arg_type[3] != INT_RESULT) {
strcpy(message, "Fourth argument is not an integer (memory)"); returntrue;
} else
more += (ulong)*(longlong*)args->args[2];
}
CalcLen(args, false, reslen, memlen);
// TODO: calculate this if (IsJson(args, 0) == 3)
more = 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of jsonlocate_init
void jsonlocate_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jsonlocate_deinit
/*********************************************************************************/ /* Locate all occurences of a value in a Json tree. */ /*********************************************************************************/
my_bool json_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 (!IsJson(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;
} elseif (args->arg_count > 3)
{ if (args->arg_type[3] != INT_RESULT) {
strcpy(message, "Fourth argument is not an integer (memory)"); returntrue;
} else
more += (ulong)*(longlong*)args->args[2];
}
CalcLen(args, false, reslen, memlen);
// TODO: calculate this if (IsJson(args, 0) == 3)
more = 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of json_locate_all_init
void json_locate_all_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_locate_all_deinit
/*********************************************************************************/ /* Check whether the document contains a value or item. */ /*********************************************************************************/
my_bool jsoncontains_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, more = 1024; int n = IsJson(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)");
/*********************************************************************************/ /* Set Json items of a Json document according to path. */ /*********************************************************************************/
my_bool json_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, more = 0; int n = IsJson(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 json_update_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_update_item_deinit
/*********************************************************************************/ /* Returns a json file as a json string. */ /*********************************************************************************/
my_bool json_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];
void json_file_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_file_deinit
/*********************************************************************************/ /* Make a json file from a json item. */ /*********************************************************************************/
my_bool jfile_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 (!IsJson(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 jfile_make_init
if ((p = jvp->GetString(g))) { if (!strchr("[{ \t\r\n", *p)) { // Is this a file name? if (!(p = GetJsonFile(g, p))) {
PUSH_WARNING(g->Message); goto fin;
} else
fn = jvp->GetString(g);
void jbin_array_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_array_deinit
/*********************************************************************************/ /* Add one or several values to a Json array. */ /*********************************************************************************/
my_bool jbin_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
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jbin_array_add_values_init
return (char*)bsp;
} // end of jbin_array_add_values
void jbin_array_add_values_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_array_add_values_deinit
/*********************************************************************************/ /* Add one value to a Json array. */ /*********************************************************************************/
my_bool jbin_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 (!IsJson(args, 0)) { // strcpy(message, "First argument must be a json item"); // return true;
} else
CalcLen(args, false, reslen, memlen, true);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jbin_array_add_init
char *jbin_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result, unsignedlong *res_length, uchar *is_null, uchar *error)
{ int n = 2;
PJSON top = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (bsp && !bsp->Changed) { // This constant function was recalled
*res_length = sizeof(BSON); return (char*)bsp;
} // endif bsp
if (!CheckMemory(g, initid, args, 2, false, false, true)) { int *x = NULL;
uint n = 2; // PJSON jsp;
PJVAL jvp;
PJAR arp;
if (jvp->GetValType() != TYPE_JAR) { if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) {
arp->AddArrayValue(gb, (PJVAL)JvalNew(gb, TYPE_JVAL, jvp));
jvp->SetValue(arp);
if (!top)
top = arp;
} // endif arp
} else
arp = jvp->GetArray();
arp->AddArrayValue(gb, MakeValue(gb, args, 1), x);
arp->InitArray(gb);
} else {
PUSH_WARNING("First argument target is not an array"); // if (g->Mrr) *error = 1; (only if no path)
} // endif jvp
} // endif CheckMemory
// In case of error unchanged argument will be returned
bsp = MakeBinResult(g, args, top, initid->max_length, n);
if (initid->const_item) // Keep result of constant function
g->Xchk = bsp;
void jbin_array_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_array_add_deinit
/*********************************************************************************/ /* Delete a value from a Json array. */ /*********************************************************************************/
my_bool jbin_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);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jbin_array_delete_init
if (!bsp || bsp->Changed) { if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
PJOB objp;
if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) { for (uint i = 0; i < args->arg_count; i += 2)
objp->SetKeyValue(g, MakeValue(g, args, i + 1), MakePSZ(g, args, i));
void jbin_object_key_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_object_key_deinit
/*********************************************************************************/ /* Add or replace a value in a Json Object. */ /*********************************************************************************/
my_bool jbin_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 (!IsJson(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 jbin_object_add_init
void jbin_object_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_object_add_deinit
/*********************************************************************************/ /* Delete a value from a Json object. */ /*********************************************************************************/
my_bool jbin_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 (!IsJson(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 jbin_object_delete_init
if ((p = jvp->GetString(g))) { if (!(jsp = ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message); return NULL;
} // endif jsp
} else
jsp = jvp->GetJson();
if (jsp->GetType() == TYPE_JOB) {
jarp = ((PJOB)jsp)->GetKeyList(g);
} else {
PUSH_WARNING("First argument is not an object"); if (g->Mrr) *error = 1;
} // endif jsp type
void jbin_object_list_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_object_list_deinit
/*********************************************************************************/ /* Get a Json item from a Json document. */ /*********************************************************************************/
my_bool jbin_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ return json_get_item_init(initid, args, message);
} // end of jbin_get_item_init
void jbin_get_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_get_item_deinit
/*********************************************************************************/ /* Merge two arrays or objects. */ /*********************************************************************************/
my_bool jbin_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;
} elseif (!IsJson(args, 0)) {
strcpy(message, "First argument must be a json item"); returntrue;
} elseif (!IsJson(args, 1)) {
strcpy(message, "Second argument must be a json item"); returntrue;
} else
CalcLen(args, false, reslen, memlen, true);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jbin_item_merge_init
/*********************************************************************************/ /* Set Json items of a Json document according to path. */ /*********************************************************************************/
my_bool jbin_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen, more = 0; int n = IsJson(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 jbin_update_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_update_item_deinit
/*********************************************************************************/ /* Returns a json file as a json item. */ /*********************************************************************************/
my_bool jbin_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;
} // endifs
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];
} // endfor i
initid->maybe_null = 1;
CalcLen(args, false, reslen, memlen); if (args->args[0])
fl = GetFileLength(args->args[0]); else
fl = 100; // What can be done here?
reslen += fl;
more += fl * M; //memlen += more; return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of jbin_file_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 jfile_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 jfile_bjson_init
/*********************************************************************************/ /* JUP public constructor. */ /*********************************************************************************/
JUP::JUP(PGLOBAL g) {
fs = NULL;
s = buff = NULL;
len = 0;
k = recl = 0;
i = 0;
} // end of JUP constructor
/*********************************************************************************/ /* Copy a json file to another with pretty = 0. */ /*********************************************************************************/ char* JUP::UnprettyJsonFile(PGLOBAL g, char *fn, char *outfn, int lrecl) { char *ret = NULL;
HANDLE hFile;
MEMMAP mm;
if (hFile == INVALID_HANDLE_VALUE) {
DWORD rc = GetLastError();
if (!(*g->Message))
snprintf(g->Message, sizeof(g->Message), MSG(OPEN_MODE_ERROR), "map", (int)rc, fn);
return NULL;
} // endif hFile
/*******************************************************************************/ /* Get the file size (assuming file is smaller than 4 GB) */ /*******************************************************************************/ if (!mm.lenL && !mm.lenH) { // Empty or deleted file
CloseFileHandle(hFile); return NULL;
} else {
len = (size_t)mm.lenL;
if (mm.lenH)
len += ((size_t)mm.lenH * 0x000000001LL);
} // endif size
if (!mm.memory) {
CloseFileHandle(hFile);
snprintf(g->Message, sizeof(g->Message), MSG(MAP_VIEW_ERROR), fn, GetLastError()); return NULL;
} else
s = (char*)mm.memory;
CloseFileHandle(hFile); // Not used anymore
/*********************************************************************************/ /* Parse the json file and allocate its tree structure. */ /*********************************************************************************/ if (!(fs = fopen(outfn, "wb"))) {
snprintf(g->Message, sizeof(g->Message), MSG(OPEN_MODE_ERROR)": %s", "w", (int)errno, outfn, strerror(errno));
CloseMemMap(mm.memory, len); return NULL;
} // endif fs
g->Message[0] = 0;
if (!unPretty(g, lrecl))
ret = outfn;
CloseMemMap(mm.memory, len);
fclose(fs); return ret;
} // end of UnprettyJsonFile
/***********************************************************************/ /* Translate a json file to pretty = 0. */ /***********************************************************************/ bool JUP::unPretty(PGLOBAL g, int lrecl) { bool go, next, rc = false;
if (trace(1))
htrc("UnPretty: s=%.10s len=%zd lrecl=%d\n", s, len, lrecl);
if (!s || !len) {
snprintf(g->Message, sizeof(g->Message), "Void JSON file"); returntrue;
} elseif (*s != '[') { // strcpy(g->Message, "JSON file is not an array");
s = strchr(s, '['); // return true;
} // endif s
i = 1;
go = next = true;
try { // Allocate the record
buff = (char*)PlugSubAlloc(g, NULL, (size_t)lrecl + 3);
recl = lrecl;
do { for (k = 0; go && i < len; i++) switch (s[i]) { case'{':
buff[k++] = s[i++];
CopyObject(g); break; case'[': throw"JSON file is not an array of objects"; break; case' ': case'\t': case'\n': case'\r': break; case',':
go = false; break; case']':
go = next = false; break; default:
snprintf(g->Message, sizeof(g->Message), "Unexpected '%c' near %.*s", s[i], ARGS); throw4; break;
}; // endswitch s[i]
// Write the record #ifdef __win_
buff[k++] = '\r'; #endif
buff[k++] = '\n';
buff[k] = 0;
/*********************************************************************************/ /* Utility function returning a user variable value. */ /*********************************************************************************/
my_bool uvar_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ unsignedlong reslen, memlen;
if (args->arg_count != 1) {
strcpy(message, "Unique argument must be a user variable name"); returntrue;
} else
CalcLen(args, false, reslen, memlen, true);
initid->maybe_null = true; return JsonInit(initid, args, message, true, reslen, memlen, 2048);
} // end of uvar_init
char *uvar(UDF_INIT *initid, UDF_ARGS *args, char *result, unsignedlong *res_length, uchar *is_null, uchar *)
{ char *str, varname[256];
PGLOBAL g = (PGLOBAL)initid->ptr; int n = MY_MIN(args->lengths[0], sizeof(varname) - 1);
void uvar_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of uvar_deinit #endif// DEVELOPMENT
/*********************************************************************************/ /* Returns the distinct number of B occurences in A. */ /*********************************************************************************/
my_bool countin_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ if (args->arg_count != 2) {
strcpy(message, "This function must have 2 arguments"); returntrue;
} elseif (args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be string"); returntrue;
} elseif (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a string"); returntrue;
} // endif args
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.