mariadb/storage/connect/jsonudf.cpp
Olivier Bertrand e049f92392 Squashed commit of connect/10.0:
commit ac275d0b4ad (connect/10.0)
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Wed Mar 27 12:46:20 2019 +0100

    Comment out unrecognized command line options: Modified CMakeLists.txt

commit 592f1f75ad6
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Tue Mar 26 19:52:33 2019 +0100

    Replace Command not recognized by CMake modified: CMakeLists.txt

commit 00f72199b16
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Tue Mar 26 18:15:08 2019 +0100

    - Fix MDEV-15793: Server crash in PlugCloseFile with sql_mode=''
      Fixed by replacing sprinf by snprintf in ShowValue to avoid
      buffer overflow. It nows always use a buffer and returns int.
      modified:   storage/connect/tabdos.cpp
      modified:   storage/connect/tabfmt.cpp
      modified:   storage/connect/value.cpp
      modified:   storage/connect/value.h

    - Fix MDEV-18292: CONNECT Engine JDBC not able to issue
      simple UPDATE statement from trigger or stored procedure
      Was not fixed when the same table was called several times
      with different modes. Fixed by checking if a new statement
      is compatible in the start_stmt function. It nows do the
      same checks than external_lock.
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/ha_connect.h

    - typo
      modified:   storage/connect/user_connect.cc

    - Fix GetTableName that returned wrong value under Windows
      modified:   storage/connect/ha_connect.cc

    - Fix MDEV-13136: enhance CREATE SERVER MyServerName
      FOREIGN DATA WRAPPER to work with CONNECT engine
      modified:   storage/connect/tabjdbc.cpp

    - Add a function to retrieve User variable value (DEVELOPMENT only)
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/jsonudf.cpp
      modified:   storage/connect/jsonudf.h
      modified:   storage/connect/tabjdbc.cpp

    - Fix MDEV-18192: CONNECT Engine JDBC not able to issue
      simple UPDATE statement from trigger or stored procedure
      modified:   storage/connect/tabext.cpp
      modified:   storage/connect/tabext.h
      modified:   storage/connect/tabjdbc.cpp

    - Enable CONNECT tables to have triggers
      Update version number
      modified:   storage/connect/ha_connect.cc

    - Make user and password defined in CREATE TABLE have precedence on
      the ones specified in a Federated Server.
      modified:   storage/connect/tabjdbc.cpp

    - JSONColumns: Copy locally constant strings to fix error in OEM modules
      modified:   storage/connect/tabjson.cpp

commit 99de7f4e486
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Sun Jan 27 15:16:15 2019 +0100

    - Fix MDEV-18192: CONNECT Engine JDBC not able to issue
      simple UPDATE statement from trigger or stored procedure
      modified:   storage/connect/tabext.cpp
      modified:   storage/connect/tabext.h
      modified:   storage/connect/tabjdbc.cpp

    - Enable CONNECT tables to have triggers
      Update version number
      modified:   storage/connect/ha_connect.cc

    - Make user and password defined in CREATE TABLE have precedence on
      the ones specified in a Federated Server.
      modified:   storage/connect/tabjdbc.cpp

    - JSONColumns: Copy locally constant strings to fix error in OEM modules
      modified:   storage/connect/tabjson.cpp
2019-04-26 16:49:25 +02:00

5900 lines
155 KiB
C++

/****************** jsonudf C++ Program Source Code File (.CPP) ******************/
/* PROGRAM NAME: jsonudf Version 1.7 */
/* (C) Copyright to the author Olivier BERTRAND 2015-2018 */
/* This program are the JSON User Defined Functions . */
/*********************************************************************************/
/*********************************************************************************/
/* Include relevant sections of the MariaDB header file. */
/*********************************************************************************/
#include <my_global.h>
#include <mysqld.h>
#include <mysql.h>
#include <sql_error.h>
#include <stdio.h>
#include "jsonudf.h"
#if defined(UNIX) || defined(UNIV_LINUX)
#define _O_RDONLY O_RDONLY
#endif
#define MEMFIX 4096
#if defined(connect_EXPORTS)
#define PUSH_WARNING(M) push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0, M)
#else
#define PUSH_WARNING(M) htrc(M)
#endif
#define M 7
bool IsNum(PSZ s);
char *NextChr(PSZ s, char sep);
char *GetJsonNull(void);
uint GetJsonGrpSize(void);
static int IsJson(UDF_ARGS *args, uint i, bool b = false);
static PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i);
static char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error);
static char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error);
static PJSON JsonNew(PGLOBAL g, JTYP type);
static PJVAL JvalNew(PGLOBAL g, JTYP type, void *vp = NULL);
static PJSNX JsnxNew(PGLOBAL g, PJSON jsp, int type, int len = 64);
static uint JsonGrpSize = 10;
/*********************************************************************************/
/* SubAlloc a new JSNX class with protection against memory exhaustion. */
/*********************************************************************************/
static PJSNX JsnxNew(PGLOBAL g, PJSON jsp, int type, int len)
{
PJSNX jsx;
try {
jsx = new(g) JSNX(g, jsp, type, len);
} catch (...) {
if (trace(1023))
htrc("%s\n", g->Message);
PUSH_WARNING(g->Message);
jsx = NULL;
} // end try/catch
return jsx;
} /* end of JsnxNew */
/* ----------------------------------- JSNX ------------------------------------ */
/*********************************************************************************/
/* JSNX public constructor. */
/*********************************************************************************/
JSNX::JSNX(PGLOBAL g, PJSON row, int type, int len, int prec, my_bool wr)
{
Row = row;
Jvalp = 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;
} // end of JSNX constructor
/*********************************************************************************/
/* SetJpath: set and parse the json path. */
/*********************************************************************************/
my_bool JSNX::SetJpath(PGLOBAL g, char *path, my_bool jb)
{
// Check Value was allocated
if (!Value)
return true;
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 JSNX::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
{
int n = (int)strlen(p);
my_bool dg = true, b = false;
PJNODE jnp = &Nodes[i];
if (*p) {
if (p[n - 1] == ']') {
p[--n] = 0;
} else if (!IsNum(p)) {
// Wrong array specification
sprintf(g->Message, "Invalid array specification %s", p);
return true;
} // endif p
} else
b = true;
// To check whether a numeric Rank was specified
dg = IsNum(p);
if (!n) {
// Default specifications
if (jnp->Op != OP_EXP) {
if (Wr) {
// Force append
jnp->Rank = INT_MAX32;
jnp->Op = OP_LE;
} else if (Jb) {
// Return a Json item
jnp->Op = OP_XX;
} else if (b) {
// Return 1st value (B is the index base)
jnp->Rank = B;
jnp->Op = OP_LE;
} else if (!Value->IsTypeNum()) {
jnp->CncVal = AllocateValue(g, PlugDup(g, ", "), TYPE_STRING);
jnp->Op = OP_CNC;
} else
jnp->Op = OP_ADD;
} // endif OP
} else if (dg) {
// Return nth value
jnp->Rank = atoi(p) - B;
jnp->Op = OP_EQ;
} else if (Wr) {
sprintf(g->Message, "Invalid specification %s in a write path", p);
return true;
} else if (n == 1) {
// Set the Op value;
switch (*p) {
case '+': jnp->Op = OP_ADD; break;
case 'x': jnp->Op = OP_MULT; break;
case '>': jnp->Op = OP_MAX; break;
case '<': jnp->Op = OP_MIN; break;
case '!': jnp->Op = OP_SEP; break; // Average
case '#': jnp->Op = OP_NUM; break;
case '*': // Expand this array
strcpy(g->Message, "Expand not supported by this function");
return true;
default:
sprintf(g->Message, "Invalid function specification %c", *p);
return true;
} // endswitch *p
} else if (*p == '"' && p[n - 1] == '"') {
// This is a concat specification
jnp->Op = OP_CNC;
if (n > 2) {
// Set concat intermediate string
p[n - 1] = 0;
if (trace(1))
htrc("Concat string=%s\n", p + 1);
jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING);
} // endif n
} else {
strcpy(g->Message, "Wrong array specification");
return true;
} // endif's
// For calculated arrays, a local Value must be used
switch (jnp->Op) {
case OP_NUM:
jnp->Valp = AllocateValue(g, TYPE_INT);
break;
case OP_ADD:
case OP_MULT:
case OP_SEP:
if (!IsTypeChar(Buf_Type))
jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
else
jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2);
break;
case OP_MIN:
case OP_MAX:
jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
break;
case OP_CNC:
if (IsTypeChar(Buf_Type))
jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
else
jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
break;
default:
break;
} // endswitch Op
if (jnp->Valp)
MulVal = AllocateValue(g, jnp->Valp);
return false;
} // end of SetArrayOptions
/*********************************************************************************/
/* 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, mul = false;
if (Parsed)
return false; // Already done
else if (!Jpath)
// Jpath = Name;
return true;
if (trace(1))
htrc("ParseJpath %s\n", SVP(Jpath));
if (!(pbuf = PlgDBDup(g, Jpath)))
return true;
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))))
return true;
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 (!p2)
p2 = p1;
else if (p1) {
if (p1 < p2)
p2 = p1;
else if (p1 == p2 + 1)
*p2++ = 0; // Old syntax .[
else
p1 = NULL;
} // endif p1
if (p2)
*p2++ = 0;
// Jpath must be explicit
if (a || *p == 0 || *p == '[' || IsNum(p)) {
// Analyse intermediate array processing
if (SetArrayOptions(g, p, i, Nodes[i-1].Key))
return true;
} else if (*p == '*') {
if (Wr) {
sprintf(g->Message, "Invalid specification %c in a write path", *p);
return true;
} else // Return JSON
Nodes[i].Op = OP_XX;
} else {
Nodes[i].Key = p;
Nodes[i].Op = OP_EXIST;
} // endif's
} // endfor i, p
Nod = i;
MulVal = AllocateValue(g, Value);
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;
return false;
} // end of ParseJpath
/*********************************************************************************/
/* MakeJson: Serialize the json item and set value to it. */
/*********************************************************************************/
PVAL JSNX::MakeJson(PGLOBAL g, PJSON jsp)
{
if (Value->IsTypeNum()) {
strcpy(g->Message, "Cannot make Json for a numeric value");
Value->Reset();
} else if (jsp->GetType() != TYPE_JAR && jsp->GetType() != TYPE_JOB) {
strcpy(g->Message, "Target is not an array or object");
Value->Reset();
} else
Value->SetValue_psz(Serialize(g, jsp, NULL, 0));
return Value;
} // end of MakeJson
/*********************************************************************************/
/* SetValue: Set a value from a JVALUE contains. */
/*********************************************************************************/
void JSNX::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n)
{
if (val) {
vp->SetNull(false);
if (Jb) {
vp->SetValue_psz(Serialize(g, val->GetJsp(), NULL, 0));
} else switch (val->GetValType()) {
case TYPE_STRG:
case TYPE_INTG:
case TYPE_BINT:
case TYPE_DBL:
vp->SetValue_pval(val->GetValue());
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:
SetJsonValue(g, vp, val->GetArray()->GetValue(0), n);
break;
case TYPE_JOB:
// if (!vp->IsTypeNum() || !Strict) {
vp->SetValue_psz(val->GetObject()->GetText(g, NULL));
break;
// } // endif Type
case TYPE_NULL:
vp->SetNull(true);
default:
vp->Reset();
} // endswitch Type
} else {
vp->SetNull(true);
vp->Reset();
} // endif val
} // end of SetJsonValue
/*********************************************************************************/
/* 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)
{
int n = Nod - 1;
PJVAL val = NULL;
val = GetRowValue(g, row, i);
SetJsonValue(g, Value, val, n);
return Value;
} // end of GetColumnValue
/*********************************************************************************/
/* GetRowValue: */
/*********************************************************************************/
PJVAL JSNX::GetRowValue(PGLOBAL g, PJSON row, int i, my_bool b)
{
my_bool expd = false;
PJAR arp;
PJVAL val = NULL;
for (; i < Nod && row; i++) {
if (Nodes[i].Op == OP_NUM) {
Value->SetValue(row->GetType() == TYPE_JAR ? row->size() : 1);
val = new(g) JVALUE(g, Value);
return val;
} else if (Nodes[i].Op == OP_XX) {
Jb = b;
return new(g)JVALUE(row);
} else switch (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 {
strcpy(g->Message, "Unexpected object");
val = NULL;
} //endif Op
} else
val = ((PJOB)row)->GetValue(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->GetValue(Nodes[i].Rank);
else if (Nodes[i].Op == OP_EXP)
return (PJVAL)ExpandArray(g, arp, i);
else
return new(g) JVALUE(g, CalculateArray(g, arp, i));
} else {
// Unexpected array, unwrap it as [0]
val = arp->GetValue(0);
i--;
} // endif's
break;
case TYPE_JVAL:
val = (PJVAL)row;
break;
default:
sprintf(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, n);
return val;
} // end of GetRowValue
/*********************************************************************************/
/* ExpandArray: */
/*********************************************************************************/
PVAL JSNX::ExpandArray(PGLOBAL g, PJAR arp, int n)
{
strcpy(g->Message, "Expand cannot be done by this function");
return NULL;
} // end of ExpandArray
/*********************************************************************************/
/* CalculateArray: */
/*********************************************************************************/
PVAL JSNX::CalculateArray(PGLOBAL g, PJAR arp, int n)
{
int i, ars = arp->size(), nv = 0;
bool err;
OPVAL op = Nodes[n].Op;
PVAL val[2], vp = Nodes[n].Valp;
PJVAL jvrp, jvp;
JVALUE jval;
vp->Reset();
if (trace(1))
htrc("CalculateArray size=%d op=%d\n", ars, op);
for (i = 0; i < ars; i++) {
jvrp = arp->GetValue(i);
if (trace(1))
htrc("i=%d nv=%d\n", i, nv);
if (!jvrp->IsNull() || (op == OP_CNC && GetJsonNull())) {
if (jvrp->IsNull()) {
jvrp->Value = AllocateValue(g, GetJsonNull(), TYPE_STRING);
jvp = jvrp;
} else if (n < Nod - 1 && jvrp->GetJson()) {
jval.SetValue(GetColumnValue(g, jvrp->GetJson(), n + 1));
jvp = &jval;
} else
jvp = jvrp;
if (trace(1))
htrc("jvp=%s null=%d\n",
jvp->GetString(g), jvp->IsNull() ? 1 : 0);
if (!nv++) {
SetJsonValue(g, vp, jvp, n);
continue;
} else
SetJsonValue(g, MulVal, jvp, n);
if (!MulVal->IsNull()) {
switch (op) {
case OP_CNC:
if (Nodes[n].CncVal) {
val[0] = Nodes[n].CncVal;
err = vp->Compute(g, val, 1, op);
} // endif CncVal
val[0] = MulVal;
err = vp->Compute(g, val, 1, op);
break;
// case OP_NUM:
case OP_SEP:
val[0] = Nodes[n].Valp;
val[1] = MulVal;
err = vp->Compute(g, val, 2, OP_ADD);
break;
default:
val[0] = Nodes[n].Valp;
val[1] = MulVal;
err = vp->Compute(g, val, 2, op);
} // endswitch Op
if (err)
vp->Reset();
if (trace(1)) {
char buf(32);
htrc("vp='%s' err=%d\n",
vp->GetCharString(&buf), err ? 1 : 0);
} // endif trace
} // endif Zero
} // endif jvrp
} // endfor i
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) {
} else switch (row->GetType()) {
case TYPE_JOB:
if (Nodes[i].Key)
val = ((PJOB)row)->GetValue(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)->GetValue(Nodes[i].Rank);
break;
case TYPE_JVAL:
val = (PJVAL)row;
break;
default:
sprintf(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;
else switch (row->GetType()) {
case TYPE_JOB:
if (!Nodes[i].Key)
// Expected Array was not there, wrap the value
continue;
val = ((PJOB)row)->GetValue(Nodes[i].Key);
break;
case TYPE_JAR:
arp = (PJAR)row;
if (!Nodes[i].Key) {
if (Nodes[i].Op == OP_EQ)
val = arp->GetValue(Nodes[i].Rank);
else
val = arp->GetValue(Nodes[i].Rx);
} else {
// Unexpected array, unwrap it as [0]
val = arp->GetValue(0);
i--;
} // endif Nodes
break;
case TYPE_JVAL:
val = (PJVAL)row;
break;
default:
sprintf(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;
else if (!Nodes[i].Key)
// Construct intermediate array
nwr = new(g)JARRAY;
else
nwr = new(g)JOBJECT;
if (row->GetType() == TYPE_JOB) {
((PJOB)row)->SetValue(g, new(g)JVALUE(nwr), Nodes[i-1].Key);
} else if (row->GetType() == TYPE_JAR) {
((PJAR)row)->AddValue(g, new(g)JVALUE(nwr));
((PJAR)row)->InitArray(g);
} else {
strcpy(g->Message, "Wrong type when writing new row");
nwr = NULL;
} // endif's
row = nwr;
} // endfor i
break;
} // endelse
} // endfor i
return row;
} // end of GetRow
/***********************************************************************/
/* WriteValue: */
/***********************************************************************/
my_bool JSNX::WriteValue(PGLOBAL g, PJVAL jvalp)
{
PJOB objp = NULL;
PJAR arp = NULL;
PJVAL jvp = NULL;
PJSON row = GetRow(g);
if (!row)
return true;
switch (row->GetType()) {
case TYPE_JOB: objp = (PJOB)row; break;
case TYPE_JAR: arp = (PJAR)row; break;
case TYPE_JVAL: jvp = (PJVAL)row; break;
default:
strcpy(g->Message, "Invalid target type");
return true;
} // endswitch Type
if (arp) {
if (!Nodes[Nod-1].Key) {
if (Nodes[Nod-1].Op == OP_EQ)
arp->SetValue(g, jvalp, Nodes[Nod-1].Rank);
else
arp->AddValue(g, jvalp);
arp->InitArray(g);
} // endif Key
} else if (objp) {
if (Nodes[Nod-1].Key)
objp->SetValue(g, jvalp, Nodes[Nod-1].Key);
} else if (jvp)
jvp->SetValue(jvalp);
return false;
} // end of WriteValue
/*********************************************************************************/
/* Locate a value in a JSON tree: */
/*********************************************************************************/
PSZ JSNX::Locate(PGLOBAL g, PJSON jsp, PJVAL jvp, int k)
{
PSZ str = NULL;
my_bool b = false, err = true;
g->Message[0] = 0;
if (!jsp) {
strcpy(g->Message, "Null json tree");
return NULL;
} // endif jsp
try {
// Write to the path string
Jp = new(g) JOUTSTR(g);
Jp->WriteChr('$');
Jvalp = jvp;
K = k;
switch (jsp->GetType()) {
case TYPE_JAR:
err = LocateArray((PJAR)jsp);
break;
case TYPE_JOB:
err = LocateObject((PJOB)jsp);
break;
case TYPE_JVAL:
err = LocateValue((PJVAL)jsp);
break;
default:
err = true;
} // endswitch Type
if (err) {
if (!g->Message[0])
strcpy(g->Message, "Invalid json tree");
} else if (Found) {
Jp->WriteChr('\0');
PlugSubAlloc(g, NULL, Jp->N);
str = Jp->Strp;
} // endif's
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
} catch (const char *msg) {
strcpy(g->Message, msg);
} // end catch
return str;
} // end of Locate
/*********************************************************************************/
/* Locate in a JSON Array. */
/*********************************************************************************/
my_bool JSNX::LocateArray(PJAR jarp)
{
char s[16];
size_t m = Jp->N;
for (int i = 0; i < jarp->size() && !Found; i++) {
Jp->N = m;
sprintf(s, "[%d]", i + B);
if (Jp->WriteStr(s))
return true;
if (LocateValue(jarp->GetValue(i)))
return true;
} // endfor i
return false;
} // end of LocateArray
/*********************************************************************************/
/* Locate in a JSON Object. */
/*********************************************************************************/
my_bool JSNX::LocateObject(PJOB jobp)
{
size_t m;
if (Jp->WriteChr('.'))
return true;
m = Jp->N;
for (PJPR pair = jobp->First; pair && !Found; pair = pair->Next) {
Jp->N = m;
if (Jp->WriteStr(pair->Key))
return true;
if (LocateValue(pair->Val))
return true;
} // endfor i
return false;
} // end of LocateObject
/*********************************************************************************/
/* Locate a JSON Value. */
/*********************************************************************************/
my_bool JSNX::LocateValue(PJVAL jvp)
{
if (CompareTree(Jvalp, jvp))
Found = (--K == 0);
else if (jvp->GetArray())
return LocateArray(jvp->GetArray());
else if (jvp->GetObject())
return LocateObject(jvp->GetObject());
return false;
} // end of LocateValue
/*********************************************************************************/
/* 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 b = false, err = true;
PJPN jnp;
if (!jsp) {
strcpy(g->Message, "Null json tree");
return NULL;
} // endif jsp
try {
jnp = (PJPN)PlugSubAlloc(g, NULL, sizeof(JPN) * mx);
memset(jnp, 0, sizeof(JPN) * mx);
g->Message[0] = 0;
// Write to the path string
Jp = new(g)JOUTSTR(g);
Jvalp = jvp;
Imax = mx - 1;
Jpnp = jnp;
Jp->WriteChr('[');
switch (jsp->GetType()) {
case TYPE_JAR:
err = LocateArrayAll((PJAR)jsp);
break;
case TYPE_JOB:
err = LocateObjectAll((PJOB)jsp);
break;
case TYPE_JVAL:
err = LocateValueAll((PJVAL)jsp);
break;
default:
err = true;
} // endswitch Type
if (!err) {
if (Jp->N > 1)
Jp->N--;
Jp->WriteChr(']');
Jp->WriteChr('\0');
PlugSubAlloc(g, NULL, Jp->N);
str = Jp->Strp;
} else if (!g->Message[0])
strcpy(g->Message, "Invalid json tree");
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
} catch (const char *msg) {
strcpy(g->Message, msg);
} // end catch
return str;
} // end of LocateAll
/*********************************************************************************/
/* Locate in a JSON Array. */
/*********************************************************************************/
my_bool JSNX::LocateArrayAll(PJAR jarp)
{
if (I < Imax) {
Jpnp[++I].Type = TYPE_JAR;
for (int i = 0; i < jarp->size(); i++) {
Jpnp[I].N = i;
if (LocateValueAll(jarp->GetValue(i)))
return true;
} // endfor i
I--;
} // endif I
return false;
} // end of LocateArrayAll
/*********************************************************************************/
/* Locate in a JSON Object. */
/*********************************************************************************/
my_bool JSNX::LocateObjectAll(PJOB jobp)
{
if (I < Imax) {
Jpnp[++I].Type = TYPE_JOB;
for (PJPR pair = jobp->First; pair; pair = pair->Next) {
Jpnp[I].Key = pair->Key;
if (LocateValueAll(pair->Val))
return true;
} // endfor i
I--;
} // endif I
return false;
} // end of LocateObjectAll
/*********************************************************************************/
/* Locate a JSON Value. */
/*********************************************************************************/
my_bool JSNX::LocateValueAll(PJVAL jvp)
{
if (CompareTree(Jvalp, jvp))
return AddPath();
else if (jvp->GetArray())
return LocateArrayAll(jvp->GetArray());
else if (jvp->GetObject())
return LocateObjectAll(jvp->GetObject());
return false;
} // end of LocateValueAll
/*********************************************************************************/
/* Compare two JSON trees. */
/*********************************************************************************/
my_bool JSNX::CompareTree(PJSON jp1, PJSON jp2)
{
if (!jp1 || !jp2 || jp1->GetType() != jp2->GetType()
|| jp1->size() != jp2->size())
return false;
my_bool found = true;
if (jp1->GetType() == TYPE_JVAL) {
PVAL v1 = jp1->GetValue(), v2 = jp2->GetValue();
if (v1 && v2) {
if (v1->GetType() == v2->GetType())
found = !v1->CompareValue(v2);
else
found = false;
} else
found = CompareTree(jp1->GetJsp(), jp2->GetJsp());
} else if (jp1->GetType() == TYPE_JAR) {
for (int i = 0; found && i < jp1->size(); i++)
found = (CompareTree(jp1->GetValue(i), jp2->GetValue(i)));
} else if (jp1->GetType() == TYPE_JOB) {
PJPR p1 = jp1->GetFirst(), p2 = jp2->GetFirst();
for (; found && p1 && p2; p1 = p1->Next, p2 = p2->Next)
found = CompareTree(p1->Val, p2->Val);
} else
found = false;
return found;
} // end of CompareTree
/*********************************************************************************/
/* Add the found path to the list. */
/*********************************************************************************/
my_bool JSNX::AddPath(void)
{
char s[16];
if (Jp->WriteStr("\"$"))
return true;
for (int i = 0; i <= I; i++) {
if (Jpnp[i].Type == TYPE_JAR) {
sprintf(s, "[%d]", Jpnp[i].N + B);
if (Jp->WriteStr(s))
return true;
} else {
if (Jp->WriteChr('.'))
return true;
if (Jp->WriteStr(Jpnp[i].Key))
return true;
} // endif's
} // endfor i
if (Jp->WriteStr("\","))
return true;
return false;
} // end of AddPath
/* --------------------------------- JSON UDF ---------------------------------- */
// BSON size should be equal on Linux and Windows
#define BMX 255
typedef struct BSON *PBSON;
/*********************************************************************************/
/* Structure used to return binary json. */
/*********************************************************************************/
struct BSON {
char Msg[BMX + 1];
char *Filename;
PGLOBAL G;
int Pretty;
ulong Reslen;
my_bool Changed;
PJSON Top;
PJSON Jsp;
PBSON Bsp;
}; // end of struct BSON
/*********************************************************************************/
/* Allocate and initialize a BSON structure. */
/*********************************************************************************/
static PBSON JbinAlloc(PGLOBAL g, UDF_ARGS *args, ulong len, PJSON jsp)
{
PBSON bsp = (PBSON)PlgDBSubAlloc(g, NULL, sizeof(BSON));
if (bsp) {
strcpy(bsp->Msg, "Binary Json");
bsp->Msg[BMX] = 0;
bsp->Filename = NULL;
bsp->G = g;
bsp->Pretty = 2;
bsp->Reslen = len;
bsp->Changed = false;
bsp->Top = bsp->Jsp = jsp;
bsp->Bsp = (IsJson(args, 0) == 3) ? (PBSON)args->args[0] : NULL;
} else
PUSH_WARNING(g->Message);
return bsp;
} /* end of JbinAlloc */
/*********************************************************************************/
/* Set the BSON chain as changed. */
/*********************************************************************************/
static void SetChanged(PBSON bsp)
{
if (bsp->Bsp)
SetChanged(bsp->Bsp);
bsp->Changed = true;
} /* end of SetChanged */
/*********************************************************************************/
/* Replaces GetJsonGrpSize not usable when CONNECT is not installed. */
/*********************************************************************************/
static uint GetJsonGroupSize(void)
{
return (JsonGrpSize) ? JsonGrpSize : GetJsonGrpSize();
} // end of GetJsonGroupSize
/*********************************************************************************/
/* Program for SubSet re-initialization of the memory pool. */
/*********************************************************************************/
static my_bool JsonSubSet(PGLOBAL g)
{
PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
pph->To_Free = (OFFSET)((g->Createas) ? g->Createas : sizeof(POOLHEADER));
pph->FreeBlk = g->Sarea_Size - pph->To_Free;
return FALSE;
} /* end of JsonSubSet */
/*********************************************************************************/
/* Program for saving the status of the memory pools. */
/*********************************************************************************/
inline void JsonMemSave(PGLOBAL g)
{
g->Createas = (int)((PPOOLHEADER)g->Sarea)->To_Free;
} /* end of JsonMemSave */
/*********************************************************************************/
/* Program for freeing the memory pools. */
/*********************************************************************************/
inline void JsonFreeMem(PGLOBAL g)
{
g->Activityp = NULL;
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;
else switch (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_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 JsonNew */
/*********************************************************************************/
/* Allocate and initialise the memory area. */
/*********************************************************************************/
static my_bool JsonInit(UDF_INIT *initid, UDF_ARGS *args,
char *message, my_bool mbn,
unsigned long reslen, unsigned long memlen,
unsigned long more = 0)
{
PGLOBAL g = PlugInit(NULL, memlen + more + 500); // +500 to avoid CheckMem
if (!g) {
strcpy(message, "Allocation error");
return true;
} else if (g->Sarea_Size == 0) {
strcpy(message, g->Message);
PlugExit(g);
return true;
} // endif g
g->Mrr = (args->arg_count && args->args[0]) ? 1 : 0;
g->More = more;
initid->maybe_null = mbn;
initid->max_length = reslen;
initid->ptr = (char*)g;
return false;
} // end of JsonInit
/*********************************************************************************/
/* 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))
return true;
if (!(jvp = jsx->GetJson(g))) {
sprintf(g->Message, "No sub-item at '%s'", path);
return true;
} // endif jvp
} else {
strcpy(g->Message, "Path argument is null");
return true;
} // endif path
break;
} // endif type
return false;
} // end of CheckPath
/*********************************************************************************/
/* Make the result according to the first argument type. */
/*********************************************************************************/
static char *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);
str = NULL;
} else if (IsJson(args, 0) == 3) {
PBSON bsp = (PBSON)args->args[0];
if (bsp->Filename) {
// Make the change in the json file
if (!Serialize(g, top, bsp->Filename, bsp->Pretty))
PUSH_WARNING(g->Message);
str = bsp->Filename;
} else if (!(str = Serialize(g, top, NULL, 0)))
PUSH_WARNING(g->Message);
SetChanged(bsp);
} else if (!(str = Serialize(g, top, NULL, 0)))
PUSH_WARNING(g->Message);
return str;
} // end of MakeResult
/*********************************************************************************/
/* 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
bsnp->Pretty = pretty;
if (bsnp->Filename = (char*)args->args[0]) {
bsnp->Filename = MakePSZ(g, args, 0);
strncpy(bsnp->Msg, bsnp->Filename, BMX);
} else
strncpy(bsnp->Msg, "null filename", BMX);
} else if (IsJson(args, 0) == 3) {
PBSON bsp = (PBSON)args->args[0];
if (bsp->Filename) {
bsnp->Filename = bsp->Filename;
strncpy(bsnp->Msg, bsp->Filename, BMX);
bsnp->Pretty = bsp->Pretty;
} else
strcpy(bsnp->Msg, "Json Binary item");
} else
strcpy(bsnp->Msg, "Json Binary item");
return bsnp;
} // end of MakeBinResult
/*********************************************************************************/
/* Returns a pointer to the first integer argument found from the nth argument. */
/*********************************************************************************/
static int *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. */
/*********************************************************************************/
static int IsJson(UDF_ARGS *args, uint i, bool b)
{
int n = 0;
if (i >= args->arg_count || args->arg_type[i] != STRING_RESULT) {
} else if (!strnicmp(args->attributes[i], "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
} else if (!strnicmp(args->attributes[i], "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
} else if (!strnicmp(args->attributes[i], "Jfile_", 6)) {
n = 2; // arg is a json file name
} else if (b) {
char *sap;
PGLOBAL g = PlugInit(NULL, 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. */
/*********************************************************************************/
static long 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. */
/*********************************************************************************/
static my_bool CalcLen(UDF_ARGS *args, my_bool obj,
unsigned long& reslen, unsigned long& memlen,
my_bool mod = false)
{
char fn[_MAX_PATH];
unsigned long 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
switch (args->arg_type[i]) {
case STRING_RESULT:
if (n == 2 && args->args[i]) {
if (!mod) {
m = MY_MIN(args->lengths[i], sizeof(fn) - 1);
memcpy(fn, args->args[i], m);
fn[m] = 0;
j = i;
fl = GetFileLength(fn);
reslen += fl;
} else
reslen += args->lengths[i];
} else if (n == 3 && args->args[i])
reslen += ((PBSON)args->args[i])->Reslen;
else if (n == 1)
reslen += args->lengths[i];
else
reslen += (args->lengths[i] + 1) * 2; // Pessimistic !
break;
case INT_RESULT:
reslen += 20;
break;
case REAL_RESULT:
reslen += 31;
break;
case DECIMAL_RESULT:
reslen += (args->lengths[i] + 7); // 6 decimals
break;
case TIME_RESULT:
case ROW_RESULT:
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 += (k + sizeof(JOBJECT) + sizeof(JPAIR));
} else
memlen += sizeof(JARRAY);
switch (args->arg_type[i]) {
case STRING_RESULT:
if (n == 2 && args->args[i]) {
if ((signed)i != j) {
m = MY_MIN(args->lengths[i], sizeof(fn) - 1);
memcpy(fn, args->args[i], m);
fn[m] = 0;
j = -1;
fl = GetFileLength(fn);
} // endif i
memlen += fl * M;
} else if (n == 1) {
if (i == 0)
memlen += sizeof(BSON); // For Jbin functions
memlen += args->lengths[i] * M; // Estimate parse memory
} else if (n == 3)
memlen += sizeof(JVALUE);
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
return false;
} // end of CalcLen
/*********************************************************************************/
/* Check if the calculated memory is enough. */
/*********************************************************************************/
static my_bool CheckMemory(PGLOBAL g, UDF_INIT *initid, UDF_ARGS *args, uint n,
my_bool m, my_bool obj = false, my_bool mod = false)
{
unsigned long 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))
return true;
else if (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;
} // endif b
ml += g->More;
if (ml > g->Sarea_Size) {
FreeSarea(g);
if (AllocSarea(g, ml)) {
char errmsg[MAX_STR];
snprintf(errmsg, sizeof(errmsg) - 1, MSG(WORK_AREA), g->Message);
strcpy(g->Message, errmsg);
return true;
} // endif SareaAlloc
g->Createas = 0;
g->Xchk = NULL;
initid->max_length = rl;
} // endif Size
break;
} // endif IsJson
JsonSubSet(g);
return false;
} // end of CheckMemory
/*********************************************************************************/
/* Make a zero terminated string from the passed argument. */
/*********************************************************************************/
static 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;
} else if (*s == '\'' && s[n-1] == '\'') {
s++;
n -= 2;
b = false;
} // endif *s
if (n < 1)
return "Key";
if (!b) {
if ((p = (PSZ)PlgDBSubAlloc(g, NULL, n + 1))) {
memcpy(p, s, n);
p[n] = 0;
} else
PUSH_WARNING(g->Message);
s = p;
} // endif b
} // endif s
return s;
} // endif count
return "Key";
} // end of MakeKey
/*********************************************************************************/
/* Parse a json file. */
/*********************************************************************************/
static PJSON ParseJsonFile(PGLOBAL g, char *fn, int *pretty, int& len)
{
char *memory;
HANDLE hFile;
MEMMAP mm;
PJSON jsp;
/*******************************************************************************/
/* Create the mapping file object. */
/*******************************************************************************/
hFile = CreateFileMap(g, fn, &mm, MODE_READ, false);
if (hFile == INVALID_HANDLE_VALUE) {
DWORD rc = GetLastError();
if (!(*g->Message))
sprintf(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) */
/*******************************************************************************/
len = mm.lenL;
memory = (char *)mm.memory;
if (!len) { // Empty or deleted file
CloseFileHandle(hFile);
return NULL;
} // endif len
if (!memory) {
CloseFileHandle(hFile);
sprintf(g->Message, MSG(MAP_VIEW_ERROR), fn, GetLastError());
return NULL;
} // endif Memory
CloseFileHandle(hFile); // Not used anymore
/*********************************************************************************/
/* Parse the json file and allocate its tree structure. */
/*********************************************************************************/
g->Message[0] = 0;
jsp = ParseJson(g, memory, len, pretty);
CloseMemMap(memory, len);
return jsp;
} // end of ParseJsonFile
/*********************************************************************************/
/* Return a json file contains. */
/*********************************************************************************/
static char *GetJsonFile(PGLOBAL g, char *fn)
{
char *str;
int h, n, len;
#if defined(UNIX) || defined(UNIV_LINUX)
h= open(fn, O_RDONLY);
#else
h= open(fn, _O_RDONLY, _O_TEXT);
#endif
if (h == -1) {
sprintf(g->Message, "Error %d opening %s", errno, fn);
return NULL;
} // endif h
if ((len = _filelength(h)) < 0) {
sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", fn);
close(h);
return NULL;
} // endif len
if ((str = (char*)PlgDBSubAlloc(g, NULL, len + 1))) {
if ((n = read(h, str, len)) < 0) {
sprintf(g->Message, "Error %d reading %d bytes from %s", errno, len, fn);
return NULL;
} // endif n
str[n] = 0;
close(h);
} // endif str
return str;
} // end of GetJsonFile
/*********************************************************************************/
/* Make a JSON value from the passed argument. */
/*********************************************************************************/
static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, uint i, PJSON *top = NULL)
{
char *sap = (args->arg_count > i) ? args->args[i] : NULL;
int n, len;
short c;
long long bigint;
PJSON jsp;
PJVAL jvp = new(g) JVALUE;
if (top)
*top = NULL;
if (sap) switch (args->arg_type[i]) {
case STRING_RESULT:
if ((len = args->lengths[i])) {
if ((n = IsJson(args, i)) < 3)
sap = MakePSZ(g, args, i);
if (n) {
if (n == 3) {
if (top)
*top = ((PBSON)sap)->Top;
jsp = ((PBSON)sap)->Jsp;
} else {
if (n == 2) {
if (!(sap = GetJsonFile(g, sap))) {
PUSH_WARNING(g->Message);
return jvp;
} // endif sap
len = strlen(sap);
} // endif n
if (!(jsp = ParseJson(g, sap, strlen(sap))))
PUSH_WARNING(g->Message);
else if (top)
*top = jsp;
} // endif's n
if (jsp && jsp->GetType() == TYPE_JVAL)
jvp = (PJVAL)jsp;
else
jvp->SetValue(jsp);
} else {
c = (strnicmp(args->attributes[i], "ci", 2)) ? 0 : 1;
jvp->SetString(g, sap, c);
} // endif n
} // endif len
break;
case INT_RESULT:
bigint = *(long long*)sap;
if ((bigint == 0LL && !strcmp(args->attributes[i], "FALSE")) ||
(bigint == 1LL && !strcmp(args->attributes[i], "TRUE")))
jvp->SetTiny(g, (char)bigint);
else
jvp->SetBigint(g, bigint);
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);
//if (type == TYPE_JSON) {
// if (jvp->GetValType() >= TYPE_JSON)
// return jvp;
//} else if (jvp->GetValType() == type)
// return jvp;
if (jvp->GetValType() == TYPE_STRG) {
sap = jvp->GetString(g);
if ((jsp = ParseJson(g, sap, strlen(sap)))) {
if ((type == TYPE_JSON && jsp->GetType() != TYPE_JVAL) || jsp->GetType() == type) {
if (top)
*top = jsp;
jvp->SetValue(jsp);
} // endif Type
} // endif jsp
} // endif Type
return jvp;
} // end of MakeTypedValue
/*********************************************************************************/
/* Make a Json value containing the parameter. */
/*********************************************************************************/
my_bool jsonvalue_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count > 1) {
strcpy(message, "Cannot accept more than 1 argument");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of jsonvalue_init
char *jsonvalue(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *, char *)
{
char *str;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, 1, false)) {
PJVAL jvp = MakeValue(g, args, 0);
if (!(str = Serialize(g, jvp, NULL, 0)))
str = strcpy(result, g->Message);
} else
str = strcpy(result, g->Message);
// 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 JsonValue
void jsonvalue_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jsonvalue_deinit
/*********************************************************************************/
/* Make a Json array containing all the parameters. */
/*********************************************************************************/
my_bool json_make_array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of json_make_array_init
char *json_make_array(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *, char *)
{
char *str;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, false)) {
PJAR arp = new(g)JARRAY;
for (uint i = 0; i < args->arg_count; i++)
arp->AddValue(g, MakeValue(g, args, i));
arp->InitArray(g);
if (!(str = Serialize(g, arp, NULL, 0)))
str = strcpy(result, g->Message);
} else
str = strcpy(result, g->Message);
// 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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
//} 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;
return false;
} else
return true;
} // end of json_array_add_values_init
char *json_array_add_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, true)) {
PJSON top;
PJAR arp;
PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JAR, &top);
if (jvp->GetValType() != TYPE_JAR) {
arp = new(g)JARRAY;
arp->AddValue(g, jvp);
top = arp;
} else
arp = jvp->GetArray();
for (uint i = 1; i < args->arg_count; i++)
arp->AddValue(g, MakeValue(g, args, i));
arp->InitArray(g);
str = MakeResult(g, args, top, args->arg_count);
} // endif CheckMemory
if (!str) {
PUSH_WARNING(g->Message);
str = args->args[0];
} // endif str
// Keep result of constant function
g->Xchk = (g->N) ? str : NULL;
} else
str = (char*)g->Xchk;
if (!str) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(str);
return str;
} // end of json_array_add_values
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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
//} 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;
return false;
} else
return true;
} // end of json_array_add_init
char *json_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
str = (char*)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 2, false, false, true)) {
int *x;
uint n = 2;
PJSON jsp, top;
PJVAL jvp;
PJAR arp;
jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
jsp = jvp->GetJson();
x = GetIntArgPtr(g, args, n);
if (CheckPath(g, args, jsp, jvp, 2))
PUSH_WARNING(g->Message);
else if (jvp) {
PGLOBAL gb = GetMemPtr(g, args, 0);
if (jvp->GetValType() != TYPE_JAR) {
if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) {
arp->AddValue(gb, JvalNew(gb, TYPE_JVAL, jvp));
jvp->SetValue(arp);
if (!top)
top = arp;
} // endif arp
} else
arp = jvp->GetArray();
if (arp) {
arp->AddValue(gb, MakeValue(gb, args, 1), x);
arp->InitArray(gb);
str = MakeResult(g, args, top, n);
} else
PUSH_WARNING(gb->Message);
} else {
PUSH_WARNING("Target is not an array");
// if (g->Mrr) *error = 1; (only if no path)
} // endif jvp
} // endif CheckMemory
// In case of error or file, return unchanged argument
if (!str)
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*res_length = 0;
*is_null = 1;
*error = 1;
} else
*res_length = strlen(str);
return str;
} // end of json_array_add
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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
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;
return false;
} else
return true;
} // end of json_array_delete_init
char *json_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
str = (char*)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 1, false, false, true)) {
int *x;
uint n = 1;
PJSON top;
PJAR arp;
PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
if (!(x = GetIntArgPtr(g, args, n)))
PUSH_WARNING("Missing or null array index");
else if (CheckPath(g, args, jvp->GetJson(), jvp, 1))
PUSH_WARNING(g->Message);
else if (jvp && jvp->GetValType() == TYPE_JAR) {
arp = jvp->GetArray();
arp->DeleteValue(*x);
arp->InitArray(GetMemPtr(g, args, 0));
str = MakeResult(g, args, top, n);
} else {
PUSH_WARNING("First argument target is not an array");
// if (g->Mrr) *error = 1;
} // endif jvp
} // endif CheckMemory
// In case of error or file, return unchanged argument
if (!str)
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of json_array_delete
void json_array_delete_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_array_delete_deinit
/*********************************************************************************/
/* Sum big integer values from a Json array. */
/*********************************************************************************/
my_bool jsonsum_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, more;
if (args->arg_count != 1) {
strcpy(message, "This function must have 1 argument");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} 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 jsonsum_int_init
long long jsonsum_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
{
long long n = 0LL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (!g->Activityp) {
*is_null = 1;
return 0LL;
} else
return *(long long*)g->Activityp;
} else if (initid->const_item)
g->N = 1;
if (!CheckMemory(g, initid, args, 1, false, false, true)) {
PJVAL jvp = MakeValue(g, args, 0);
if (jvp && jvp->GetValType() == TYPE_JAR) {
PJAR arp = jvp->GetArray();
for (int i = 0; i < arp->size(); i++)
n += arp->GetValue(i)->GetBigint();
} else {
PUSH_WARNING("First argument target is not an array");
} // endif jvp
} else {
*error = 1;
n = -1LL;
} // end of CheckMemory
if (g->N) {
// Keep result of constant function
long long *np;
if ((np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long)))) {
*np = n;
g->Activityp = (PACTIVITY)np;
} else
PUSH_WARNING(g->Message);
} // endif const_item
return n;
} // end of jsonsum_int
void jsonsum_int_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jsonsum_int_deinit
/*********************************************************************************/
/* Sum big integer values from a Json array. */
/*********************************************************************************/
my_bool jsonsum_real_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, more;
if (args->arg_count != 1) {
strcpy(message, "This function must have 1 argument");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} 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 jsonsum_real_init
double jsonsum_real(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
{
double n = 0.0;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (!g->Activityp) {
*is_null = 1;
return 0.0;
} else
return *(double*)g->Activityp;
} else if (initid->const_item)
g->N = 1;
if (!CheckMemory(g, initid, args, 1, false, false, true)) {
PJVAL jvp = MakeValue(g, args, 0);
if (jvp && jvp->GetValType() == TYPE_JAR) {
PJAR arp = jvp->GetArray();
for (int i = 0; i < arp->size(); i++)
n += arp->GetValue(i)->GetFloat();
} else {
PUSH_WARNING("First argument target is not an array");
} // endif jvp
} else {
*error = 1;
n = -1.0;
} // endif CheckMemory
if (g->N) {
// Keep result of constant function
double *np;
if ((np = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) {
*np = n;
g->Activityp = (PACTIVITY)np;
} else {
PUSH_WARNING(g->Message);
*error = 1;
n = -1.0;
} // endif np
} // endif const_item
return n;
} // end of jsonsum_real
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, char *is_null, char *error)
{
double n = 0.0;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (!g->Activityp) {
*is_null = 1;
return 0.0;
} else
return *(double*)g->Activityp;
} else if (initid->const_item)
g->N = 1;
if (!CheckMemory(g, initid, args, 1, false, false, true)) {
PJVAL jvp = MakeValue(g, args, 0);
if (jvp && jvp->GetValType() == TYPE_JAR) {
PJAR arp = jvp->GetArray();
if (arp->size()) {
for (int i = 0; i < arp->size(); i++)
n += arp->GetValue(i)->GetFloat();
n /= arp->size();
} // endif size
} else {
PUSH_WARNING("First argument target is not an array");
} // endif jvp
} else {
*error = 1;
n = -1.0;
} // endif CheckMemory
if (g->N) {
// Keep result of constant function
double *np;
if ((np = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) {
*np = n;
g->Activityp = (PACTIVITY)np;
} else {
*error = 1;
n = -1.0;
} // endif np
} // endif const_item
return n;
} // end of jsonavg_real
void jsonavg_real_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jsonavg_real_deinit
/*********************************************************************************/
/* Make a Json Object containing all the parameters. */
/*********************************************************************************/
my_bool json_make_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of json_make_object_init
char *json_make_object(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *, char *)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, false, false, true)) {
PJOB objp;
if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
for (uint i = 0; i < args->arg_count; i++)
objp->SetValue(g, MakeValue(g, args, i), MakeKey(g, args, i));
str = Serialize(g, objp, NULL, 0);
} // endif objp
} // endif CheckMemory
if (!str)
str = strcpy(result, g->Message);
// 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_object
void json_make_object_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_make_object_deinit
/*********************************************************************************/
/* Make a Json Object containing all not null parameters. */
/*********************************************************************************/
my_bool json_object_nonull_init(UDF_INIT *initid, UDF_ARGS *args,
char *message)
{
unsigned long reslen, memlen;
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of json_object_nonull_init
char *json_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *, char *)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
PJVAL jvp;
PJOB objp;
if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
for (uint i = 0; i < args->arg_count; i++)
if (!(jvp = MakeValue(g, args, i))->IsNull())
objp->SetValue(g, jvp, MakeKey(g, args, i));
str = Serialize(g, objp, NULL, 0);
} // endif objp
} // endif CheckMemory
if (!str)
str = strcpy(result, g->Message);
// 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_nonull
void json_object_nonull_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_object_nonull_deinit
/*********************************************************************************/
/* Make a Json Object containing all the key/value parameters. */
/*********************************************************************************/
my_bool json_object_key_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count % 2) {
strcpy(message, "This function must have an even number of arguments");
return true;
} // endif arg_count
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of json_object_key_init
char *json_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *, char *)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
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->SetValue(g, MakeValue(g, args, i + 1), MakePSZ(g, args, i));
str = Serialize(g, objp, NULL, 0);
} // endif objp
} // endif CheckMemory
if (!str)
str = strcpy(result, g->Message);
// 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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else if (!IsJson(args, 0)) {
strcpy(message, "First argument must be a json item");
return true;
} 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;
return false;
} else
return true;
} // end of json_object_add_init
char *json_object_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PCSZ key;
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
str = (char*)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 2, false, true, true)) {
PJOB jobp;
PJVAL jvp;
PJSON jsp, top;
PGLOBAL gb = GetMemPtr(g, args, 0);
jvp = MakeValue(g, args, 0, &top);
jsp = jvp->GetJson();
if (CheckPath(g, args, jsp, jvp, 2))
PUSH_WARNING(g->Message);
else if (jvp && jvp->GetValType() == TYPE_JOB) {
jobp = jvp->GetObject();
jvp = MakeValue(gb, args, 1);
key = MakeKey(gb, args, 1);
jobp->SetValue(gb, jvp, key);
str = MakeResult(g, args, top);
} else {
PUSH_WARNING("First argument target is not an object");
// if (g->Mrr) *error = 1; (only if no path)
} // endif jvp
} // endif CheckMemory
// In case of error or file, return unchanged argument
if (!str)
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of json_object_add
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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have 2 or 3 arguments");
return true;
} else if (!IsJson(args, 0)) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument must be a key string");
return true;
} 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;
return false;
} else
return true;
} // end of json_object_delete_init
char *json_object_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
str = (char*)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 1, false, true, true)) {
PCSZ key;
PJOB jobp;
PJSON jsp, top;
PJVAL jvp = MakeValue(g, args, 0, &top);
jsp = jvp->GetJson();
if (CheckPath(g, args, jsp, jvp, 2))
PUSH_WARNING(g->Message);
else if (jvp && jvp->GetValType() == TYPE_JOB) {
key = MakeKey(GetMemPtr(g, args, 0), args, 1);
jobp = jvp->GetObject();
jobp->DeleteKey(key);
str = MakeResult(g, args, top);
} else {
PUSH_WARNING("First argument target is not an object");
// if (g->Mrr) *error = 1; (only if no path)
} // endif jvp
} // endif CheckMemory
// In case of error or file, return unchanged argument
if (!str)
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of json_object_delete
void json_object_delete_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_object_delete_deinit
/*********************************************************************************/
/* Returns an array of the Json object keys. */
/*********************************************************************************/
my_bool json_object_list_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count != 1) {
strcpy(message, "This function must have 1 argument");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "Argument must be a json item");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of json_object_list_init
char *json_object_list(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->N) {
if (!CheckMemory(g, initid, args, 1, true, true)) {
char *p;
PJSON jsp;
PJVAL jvp = MakeValue(g, args, 0);
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) {
PJAR jarp = ((PJOB)jsp)->GetKeyList(g);
if (!(str = Serialize(g, jarp, NULL, 0)))
PUSH_WARNING(g->Message);
} else {
PUSH_WARNING("First argument is not an object");
if (g->Mrr) *error = 1;
} // endif jvp
} // endif CheckMemory
if (initid->const_item) {
// Keep result of constant function
g->Xchk = str;
g->N = 1; // str can be NULL
} // endif const_item
} else
str = (char*)g->Xchk;
if (!str) {
*is_null = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of json_object_list
void json_object_list_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_object_list_deinit
/*********************************************************************************/
/* Returns an array of the Json object values. */
/*********************************************************************************/
my_bool json_object_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count != 1) {
strcpy(message, "This function must have 1 argument");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "Argument must be a json object");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of json_object_list_init
char *json_object_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->N) {
if (!CheckMemory(g, initid, args, 1, true, true)) {
char *p;
PJSON jsp;
PJVAL jvp = MakeValue(g, args, 0);
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) {
PJAR jarp = ((PJOB)jsp)->GetValList(g);
if (!(str = Serialize(g, jarp, NULL, 0)))
PUSH_WARNING(g->Message);
} else {
PUSH_WARNING("First argument is not an object");
if (g->Mrr) *error = 1;
} // endif jvp
} // endif CheckMemory
if (initid->const_item) {
// Keep result of constant function
g->Xchk = str;
g->N = 1; // str can be NULL
} // endif const_item
} else
str = (char*)g->Xchk;
if (!str) {
*is_null = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of json_object_values
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");
return true;
} else
return false;
} // end of jsonset_grp_size_init
long long jsonset_grp_size(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
{
long long n = *(long long*)args->args[0];
JsonGrpSize = (uint)n;
return (long long)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");
return true;
} else
return false;
} // end of jsonget_grp_size_init
long long jsonget_grp_size(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
{
return (long long)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)
{
unsigned long reslen, memlen, n = GetJsonGroupSize();
if (args->arg_count != 1) {
strcpy(message, "This function can only accept 1 argument");
return true;
} else if (IsJson(args, 0) == 3) {
strcpy(message, "This function does not support Jbin arguments");
return true;
} else
CalcLen(args, false, reslen, memlen);
reslen *= n;
memlen += ((memlen - MEMFIX) * (n - 1));
if (JsonInit(initid, args, message, false, reslen, memlen))
return true;
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JAR);
g->N = (int)n;
return false;
} // end of json_array_grp_init
void json_array_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PJAR arp = (PJAR)g->Activityp;
if (arp && g->N-- > 0)
arp->AddValue(g, MakeValue(g, args, 0));
} // end of json_array_grp_add
char *json_array_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
unsigned long *res_length, char *, char *)
{
char *str;
PGLOBAL g = (PGLOBAL)initid->ptr;
PJAR arp = (PJAR)g->Activityp;
if (g->N < 0)
PUSH_WARNING("Result truncated to json_grp_size values");
if (arp) {
arp->InitArray(g);
str = Serialize(g, arp, NULL, 0);
} else
str = NULL;
if (!str)
str = strcpy(result, g->Message);
*res_length = strlen(str);
return str;
} // end of json_array_grp
void json_array_grp_clear(UDF_INIT *initid, char*, char*)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JAR);
g->N = GetJsonGroupSize();
} // end of json_array_grp_clear
void json_array_grp_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_array_grp_deinit
/*********************************************************************************/
/* Make a Json object from values coming from rows. */
/*********************************************************************************/
my_bool json_object_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, n = GetJsonGroupSize();
if (args->arg_count != 2) {
strcpy(message, "This function requires 2 arguments (key, value)");
return true;
} else if (IsJson(args, 0) == 3) {
strcpy(message, "This function does not support Jbin arguments");
return true;
} else
CalcLen(args, true, reslen, memlen);
reslen *= n;
memlen += ((memlen - MEMFIX) * (n - 1));
if (JsonInit(initid, args, message, false, reslen, memlen))
return true;
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JOB);
g->N = (int)n;
return false;
} // end of json_object_grp_init
void json_object_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PJOB objp = (PJOB)g->Activityp;
if (g->N-- > 0)
objp->SetValue(g, MakeValue(g, args, 1), MakePSZ(g, args, 0));
} // end of json_object_grp_add
char *json_object_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
unsigned long *res_length, char *, char *)
{
char *str;
PGLOBAL g = (PGLOBAL)initid->ptr;
PJOB objp = (PJOB)g->Activityp;
if (g->N < 0)
PUSH_WARNING("Result truncated to json_grp_size values");
if (!objp || !(str = Serialize(g, objp, NULL, 0)))
str = strcpy(result, g->Message);
*res_length = strlen(str);
return str;
} // end of json_object_grp
void json_object_grp_clear(UDF_INIT *initid, char*, char*)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else if (!IsJson(args, 0)) {
strcpy(message, "First argument must be a json item");
return true;
} else if (!IsJson(args, 1)) {
strcpy(message, "Second argument must be a 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;
return false;
} else
return true;
} // end of json_item_merge_init
char *json_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
str = (char*)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 2, false, false, true)) {
PJSON top = NULL;
PJVAL jvp;
PJSON jsp[2] = {NULL, NULL};
for (int i = 0; i < 2; i++) {
jvp = MakeValue(g, args, i);
if (!i) top = jvp->GetJson();
if (jvp->GetValType() != TYPE_JAR && jvp->GetValType() != TYPE_JOB) {
sprintf(g->Message, "Argument %d is not an array or object", i);
PUSH_WARNING(g->Message);
} else
jsp[i] = jvp->GetJsp();
} // endfor i
if (jsp[0]) {
if (jsp[0]->Merge(GetMemPtr(g, args, 0), jsp[1]))
PUSH_WARNING(GetMemPtr(g, args, 0)->Message);
else
str = MakeResult(g, args, top);
} // endif jsp
} // endif CheckMemory
// In case of error or file, return unchanged argument
if (!str)
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of json_item_merge
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)
{
unsigned long reslen, memlen, more;
int n = IsJson(args, 0);
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a string (jpath)");
return true;
} 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;
} else if (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
char *json_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *)
{
char *path, *str = NULL;
PJSON jsp;
PJVAL jvp;
PJSNX jsx;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
str = (char*)g->Activityp;
goto fin;
} else if (initid->const_item)
g->N = 1;
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true, true)) {
PUSH_WARNING("CheckMemory error");
goto fin;
} // endif CheckMemory
jvp = MakeTypedValue(g, args, 0, TYPE_JSON);
jsp = jvp->GetJson();
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} else
jsp = (PJSON)g->Xchk;
path = MakePSZ(g, args, 1);
jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length);
if (!jsx || jsx->SetJpath(g, path, true)) {
PUSH_WARNING(g->Message);
*is_null = 1;
return NULL;
} // endif SetJpath
jsx->ReadValue(g);
if (!jsx->GetValue()->IsNull())
str = jsx->GetValue()->GetCharValue();
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)str;
fin:
if (!str) {
*is_null = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of json_get_item
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)
{
unsigned long reslen, memlen, more = 1024;
int n = IsJson(args, 0);
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a string (jpath)");
return true;
} else if (args->arg_count > 2) {
if (args->arg_type[2] == INT_RESULT && args->args[2])
more += (unsigned long)*(long long*)args->args[2];
else
strcpy(message, "Third argument is not an integer (memory)");
} // endif's
CalcLen(args, false, reslen, memlen);
//memlen += more;
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;
} else if (n != 3)
more += args->lengths[0] * 3;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of jsonget_string_init
char *jsonget_string(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *)
{
char *p, *path, *str = NULL;
PJSON jsp;
PJSNX jsx;
PJVAL jvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
str = (char*)g->Activityp;
goto err;
} else if (initid->const_item)
g->N = 1;
try {
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
goto err;
} else
jvp = MakeValue(g, args, 0);
if ((p = jvp->GetString(g))) {
if (!(jsp = ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
goto err;
} // endif jsp
} else
jsp = jvp->GetJson();
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} else
jsp = (PJSON)g->Xchk;
path = MakePSZ(g, args, 1);
jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length);
if (!jsx || jsx->SetJpath(g, path)) {
PUSH_WARNING(g->Message);
goto err;
} // endif SetJpath
jsx->ReadValue(g);
if (!jsx->GetValue()->IsNull())
str = jsx->GetValue()->GetCharValue();
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)str;
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
str = NULL;
} catch (const char *msg) {
strcpy(g->Message, msg);
PUSH_WARNING(g->Message);
str = NULL;
} // end catch
err:
if (!str) {
*is_null = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of jsonget_string
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)
{
unsigned long reslen, memlen, more;
if (args->arg_count != 2) {
strcpy(message, "This function must have 2 arguments");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a (jpath) string");
return true;
} 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
long long jsonget_int(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *error)
{
char *p, *path;
long long n;
PJSON jsp;
PJSNX jsx;
PJVAL jvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (!g->Activityp) {
*is_null = 1;
return 0LL;
} else
return *(long long*)g->Activityp;
} else if (initid->const_item)
g->N = 1;
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
if (g->Mrr) *error = 1;
*is_null = 1;
return 0LL;
} else
jvp = MakeValue(g, args, 0);
if ((p = jvp->GetString(g))) {
if (!(jsp = ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
if (g->Mrr) *error = 1;
*is_null = 1;
return 0;
} // endif jsp
} else
jsp = jvp->GetJson();
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} else
jsp = (PJSON)g->Xchk;
path = MakePSZ(g, args, 1);
jsx = JsnxNew(g, jsp, TYPE_BIGINT);
if (!jsx || jsx->SetJpath(g, path)) {
PUSH_WARNING(g->Message);
*is_null = 1;
return 0;
} // endif SetJpath
jsx->ReadValue(g);
if (jsx->GetValue()->IsNull()) {
*is_null = 1;
return 0;
} // endif IsNull
n = jsx->GetValue()->GetBigintValue();
if (initid->const_item) {
// Keep result of constant function
long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long));
if (np) {
*np = n;
g->Activityp = (PACTIVITY)np;
} else
PUSH_WARNING(g->Message);
} // endif const_item
return n;
} // end of jsonget_int
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)
{
unsigned long reslen, memlen, more;
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a (jpath) string");
return true;
} else if (args->arg_count > 2) {
if (args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (decimals)");
return true;
} 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
double jsonget_real(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *error)
{
char *p, *path;
double d;
PJSON jsp;
PJSNX jsx;
PJVAL jvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (!g->Activityp) {
*is_null = 1;
return 0.0;
} else
return *(double*)g->Activityp;
} else if (initid->const_item)
g->N = 1;
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
if (g->Mrr) *error = 1;
*is_null = 1;
return 0.0;
} else
jvp = MakeValue(g, args, 0);
if ((p = jvp->GetString(g))) {
if (!(jsp = ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
*is_null = 1;
return 0.0;
} // endif jsp
} else
jsp = jvp->GetJson();
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} else
jsp = (PJSON)g->Xchk;
path = MakePSZ(g, args, 1);
jsx = JsnxNew(g, jsp, TYPE_DOUBLE);
if (!jsx || jsx->SetJpath(g, path)) {
PUSH_WARNING(g->Message);
*is_null = 1;
return 0.0;
} // endif SetJpath
jsx->ReadValue(g);
if (jsx->GetValue()->IsNull()) {
*is_null = 1;
return 0.0;
} // endif IsNull
d = jsx->GetValue()->GetFloatValue();
if (initid->const_item) {
// Keep result of constant function
double *dp;
if ((dp = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) {
*dp = d;
g->Activityp = (PACTIVITY)dp;
} else {
PUSH_WARNING(g->Message);
*is_null = 1;
return 0.0;
} // endif dp
} // endif const_item
return d;
} // end of jsonget_real
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)
{
unsigned long reslen, memlen, more = 1000;
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (rank)");
return true;
} else if (args->arg_count > 3)
if (args->arg_type[3] != INT_RESULT) {
strcpy(message, "Fourth argument is not an integer (memory)");
return true;
} 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
char *jsonlocate(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *path = NULL;
int k;
PJVAL jvp, jvp2;
PJSON jsp;
PJSNX jsx;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (g->Activityp) {
path = (char*)g->Activityp;
*res_length = strlen(path);
return path;
} else {
*res_length = 0;
*is_null = 1;
return NULL;
} // endif Activityp
} else if (initid->const_item)
g->N = 1;
try {
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, !g->Xchk)) {
PUSH_WARNING("CheckMemory error");
*error = 1;
goto err;
} else
jvp = MakeTypedValue(g, args, 0, TYPE_JSON);
//if ((p = jvp->GetString(g))) {
// if (!(jsp = ParseJson(g, p, strlen(p)))) {
// PUSH_WARNING(g->Message);
// goto err;
// } // endif jsp
//} else
// jsp = jvp->GetJson();
if (!(jsp = jvp->GetJson())) {
PUSH_WARNING("First argument is not a valid JSON item");
goto err;
} // endif jsp
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} else
jsp = (PJSON)g->Xchk;
// The item to locate
jvp2 = MakeValue(g, args, 1);
k = (args->arg_count > 2) ? (int)*(long long*)args->args[2] : 1;
jsx = new(g) JSNX(g, jsp, TYPE_STRING);
path = jsx->Locate(g, jsp, jvp2, k);
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)path;
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
*error = 1;
path = NULL;
} catch (const char *msg) {
strcpy(g->Message, msg);
PUSH_WARNING(g->Message);
*error = 1;
path = NULL;
} // end catch
err:
if (!path) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(path);
return path;
} // end of jsonlocate
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)
{
unsigned long reslen, memlen, more = 1000;
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (Depth)");
return true;
} else if (args->arg_count > 3)
if (args->arg_type[3] != INT_RESULT) {
strcpy(message, "Fourth argument is not an integer (memory)");
return true;
} 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
char *json_locate_all(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *p, *path = NULL;
int mx = 10;
PJVAL jvp, jvp2;
PJSON jsp;
PJSNX jsx;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (g->Activityp) {
path = (char*)g->Activityp;
*res_length = strlen(path);
return path;
} else {
*error = 1;
*res_length = 0;
*is_null = 1;
return NULL;
} // endif Activityp
} else if (initid->const_item)
g->N = 1;
try {
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
*error = 1;
goto err;
} else
jvp = MakeValue(g, args, 0);
if ((p = jvp->GetString(g))) {
if (!(jsp = ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
goto err;
} // endif jsp
} else
jsp = jvp->GetJson();
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} else
jsp = (PJSON)g->Xchk;
// The item to locate
jvp2 = MakeValue(g, args, 1);
if (args->arg_count > 2)
mx = (int)*(long long*)args->args[2];
jsx = new(g) JSNX(g, jsp, TYPE_STRING);
path = jsx->LocateAll(g, jsp, jvp2, mx);
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)path;
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
*error = 1;
path = NULL;
} catch (const char *msg) {
strcpy(g->Message, msg);
PUSH_WARNING(g->Message);
*error = 1;
path = NULL;
} // end catch
err:
if (!path) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(path);
return path;
} // end of json_locate_all
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)
{
unsigned long reslen, memlen, more = 1024;
int n = IsJson(args, 0);
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (index)");
return true;
} else if (args->arg_count > 3) {
if (args->arg_type[3] == INT_RESULT && args->args[3])
more += (unsigned long)*(long long*)args->args[3];
else
strcpy(message, "Fourth argument is not an integer (memory)");
} // endif's
CalcLen(args, false, reslen, memlen);
//memlen += more;
// TODO: calculate this
more += (IsJson(args, 0) != 3 ? 1000 : 0);
return JsonInit(initid, args, message, false, reslen, memlen, more);
} // end of jsoncontains_init
long long jsoncontains(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *p __attribute__((unused)), res[256];
long long n;
unsigned long reslen;
*is_null = 0;
p = jsonlocate(initid, args, res, &reslen, is_null, error);
n = (*is_null) ? 0LL : 1LL;
return n;
} // end of jsoncontains
void jsoncontains_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jsoncontains_deinit
/*********************************************************************************/
/* Check whether the document contains a path. */
/*********************************************************************************/
my_bool jsoncontains_path_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, more = 1024;
int n = IsJson(args, 0);
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a string (path)");
return true;
} else if (args->arg_count > 2) {
if (args->arg_type[2] == INT_RESULT && args->args[2])
more += (unsigned long)*(long long*)args->args[2];
else
strcpy(message, "Third argument is not an integer (memory)");
} // endif's
CalcLen(args, false, reslen, memlen);
//memlen += more;
// TODO: calculate this
more += (IsJson(args, 0) != 3 ? 1000 : 0);
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of jsoncontains_path_init
long long jsoncontains_path(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *p, *path;
long long n;
PJSON jsp;
PJSNX jsx;
PJVAL jvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (!g->Activityp) {
*is_null = 1;
return 0LL;
} else
return *(long long*)g->Activityp;
} else if (initid->const_item)
g->N = 1;
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
goto err;
} else
jvp = MakeValue(g, args, 0);
if ((p = jvp->GetString(g))) {
if (!(jsp = ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
goto err;
} // endif jsp
} else
jsp = jvp->GetJson();
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} else
jsp = (PJSON)g->Xchk;
path = MakePSZ(g, args, 1);
jsx = JsnxNew(g, jsp, TYPE_BIGINT);
if (!jsx || jsx->SetJpath(g, path)) {
PUSH_WARNING(g->Message);
goto err;
} // endif SetJpath
n = (jsx->CheckPath(g)) ? 1LL : 0LL;
if (initid->const_item) {
// Keep result of constant function
long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long));
if (np) {
*np = n;
g->Activityp = (PACTIVITY)np;
} else
PUSH_WARNING(g->Message);
} // endif const_item
return n;
err:
if (g->Mrr) *error = 1;
*is_null = 1;
return 0LL;
} // end of jsoncontains_path
void jsoncontains_path_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jsoncontains_path_deinit
/*********************************************************************************/
/* This function is used by the json_set/insert/update_item functions. */
/*********************************************************************************/
char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *p, *path, *str = NULL;
int w;
my_bool b = true;
PJSON jsp;
PJSNX jsx;
PJVAL jvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
PGLOBAL gb = GetMemPtr(g, args, 0);
if (g->Alchecked) {
str = (char*)g->Activityp;
goto fin;
} else if (g->N)
g->Alchecked = 1;
if (!strcmp(result, "$set"))
w = 0;
else if (!strcmp(result, "$insert"))
w = 1;
else if (!strcmp(result, "$update"))
w = 2;
else {
PUSH_WARNING("Logical error, please contact CONNECT developer");
goto fin;
} // endelse
try {
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true, false, true)) {
PUSH_WARNING("CheckMemory error");
throw 1;
} else
jvp = MakeValue(g, args, 0);
if ((p = jvp->GetString(g))) {
if (!(jsp = ParseJson(g, p, strlen(p)))) {
throw 2;
} // endif jsp
} else
jsp = jvp->GetJson();
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} else
jsp = (PJSON)g->Xchk;
jsx = new(g)JSNX(g, jsp, TYPE_STRING, initid->max_length, 0, true);
for (uint i = 1; i + 1 < args->arg_count; i += 2) {
jvp = MakeValue(gb, args, i);
path = MakePSZ(g, args, i + 1);
if (jsx->SetJpath(g, path, false)) {
PUSH_WARNING(g->Message);
continue;
} // endif SetJpath
if (w) {
jsx->ReadValue(g);
b = jsx->GetValue()->IsNull();
b = (w == 1) ? b : !b;
} // endif w
if (b && jsx->WriteValue(gb, jvp))
PUSH_WARNING(g->Message);
} // endfor i
// In case of error or file, return unchanged argument
if (!(str = MakeResult(g, args, jsp, INT_MAX32)))
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Activityp = (PACTIVITY)str;
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
str = NULL;
} catch (const char *msg) {
strcpy(g->Message, msg);
PUSH_WARNING(g->Message);
str = NULL;
} // end catch
fin:
if (!str) {
*is_null = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of handle_item
/*********************************************************************************/
/* Set Json items of a Json document according to path. */
/*********************************************************************************/
my_bool json_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long 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");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} 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;
} else if (n != 3)
more += args->lengths[0] * 3;
if (!JsonInit(initid, args, message, true, reslen, memlen, more)) {
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;
g->Alchecked = 0;
return false;
} else
return true;
} // end of json_set_item_init
char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$set");
return handle_item(initid, args, result, res_length, is_null, p);
} // end of json_set_item
void json_set_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_set_item_deinit
/*********************************************************************************/
/* Insert Json items of a Json document according to path. */
/*********************************************************************************/
my_bool json_insert_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return json_set_item_init(initid, args, message);
} // end of json_insert_item_init
char *json_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$insert");
return handle_item(initid, args, result, res_length, is_null, p);
} // end of json_insert_item
void json_insert_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_insert_item_deinit
/*********************************************************************************/
/* Update Json items of a Json document according to path. */
/*********************************************************************************/
my_bool json_update_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return json_set_item_init(initid, args, message);
} // end of json_update_item_init
char *json_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$update");
return handle_item(initid, args, result, res_length, is_null, p);
} // end of json_update_item
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)
{
unsigned long reslen, memlen, fl, more = 1024;
if (args->arg_count < 1 || args->arg_count > 4) {
strcpy(message, "This function only accepts 1 to 4 arguments");
return true;
} else if (args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a string (file name)");
return true;
} // endif's args[0]
for (unsigned int i = 1; i < args->arg_count; i++) {
if (!(args->arg_type[i] == INT_RESULT || args->arg_type[i] == STRING_RESULT)) {
sprintf(message, "Argument %d is not an integer or a string (pretty or path)", i);
return true;
} // 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;
if (initid->const_item)
more += fl;
if (args->arg_count > 1)
more += fl * M;
memlen += more;
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of json_file_init
char *json_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str, *fn;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
str = (char*)g->Xchk;
goto fin;
} else if (initid->const_item)
g->N = 1;
PlugSubSet(g->Sarea, g->Sarea_Size);
fn = MakePSZ(g, args, 0);
if (args->arg_count > 1) {
int len, pretty, pty = 3;
PJSON jsp;
PJVAL jvp = NULL;
pretty = (args->arg_type[1] == INT_RESULT) ? (int)*(longlong*)args->args[1]
: (args->arg_count > 2 && args->arg_type[2] == INT_RESULT)
? (int)*(longlong*)args->args[2] : 3;
/*******************************************************************************/
/* Parse the json file and allocate its tree structure. */
/*******************************************************************************/
if (!(jsp = ParseJsonFile(g, fn, &pty, len))) {
PUSH_WARNING(g->Message);
str = NULL;
goto fin;
} // endif jsp
if (pty == 3)
PUSH_WARNING("File pretty format cannot be determined");
else if (pretty != 3 && pty != pretty)
PUSH_WARNING("File pretty format doesn't match the specified pretty value");
else if (pretty == 3)
pretty = pty;
// Check whether a path was specified
if (CheckPath(g, args, jsp, jvp, 1)) {
PUSH_WARNING(g->Message);
str = NULL;
goto fin;
} else if (jvp)
jsp = jvp->GetJson();
if (!(str = 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;
fin:
if (!str) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(str);
return str;
} // end of json_file
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)
{
unsigned long reslen, memlen;
if (args->arg_count < 1 || args->arg_count > 3) {
strcpy(message, "Wrong number of arguments");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} // endif
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jfile_make_init
char *jfile_make(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *)
{
char *p, *str = NULL, *fn = NULL;
int n, pretty = 2;
PJSON jsp;
PJVAL jvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
str = (char*)g->Activityp;
goto fin;
} else if (initid->const_item)
g->N = 1;
if ((n = IsJson(args, 0)) == 3) {
// Get default file name and pretty
PBSON bsp = (PBSON)args->args[0];
fn = bsp->Filename;
pretty = bsp->Pretty;
} else if (n == 2)
fn = args->args[0];
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
goto fin;
} else
jvp = MakeValue(g, args, 0);
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);
} // endif p
if (!(jsp = ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
goto fin;
} // endif jsp
jvp->SetValue(jsp);
} // endif p
if (g->Mrr) { // First argument is a constant
g->Xchk = jvp;
JsonMemSave(g);
} // endif Mrr
} else
jvp = (PJVAL)g->Xchk;
for (uint i = 1; i < args->arg_count; i++)
switch (args->arg_type[i]) {
case STRING_RESULT:
fn = MakePSZ(g, args, i);
break;
case INT_RESULT:
pretty = (int)*(longlong*)args->args[i];
break;
default:
PUSH_WARNING("Unexpected argument type in jfile_make");
} // endswitch arg_type
if (fn) {
if (!Serialize(g, jvp->GetJson(), fn, pretty))
PUSH_WARNING(g->Message);
} else
PUSH_WARNING("Missing file name");
str= fn;
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)str;
fin:
if (!str) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(str);
return str;
} // end of jfile_make
void jfile_make_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jfile_make_deinit
/*********************************************************************************/
/* Make and return a binary Json array containing all the parameters. */
/*********************************************************************************/
my_bool jbin_array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jbin_array_init
char *jbin_array(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (!bsp || bsp->Changed) {
if (!CheckMemory(g, initid, args, args->arg_count, false)) {
PJAR arp;
if ((arp = (PJAR)JsonNew(g, TYPE_JAR)) &&
(bsp = JbinAlloc(g, args, initid->max_length, arp))) {
strcat(bsp->Msg, " array");
for (uint i = 0; i < args->arg_count; i++)
arp->AddValue(g, MakeValue(g, args, i));
arp->InitArray(g);
} // endif arp && bsp
} else
bsp = NULL;
if (!bsp && (bsp = JbinAlloc(g, args, initid->max_length, NULL)))
strncpy(bsp->Msg, g->Message, BMX);
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_array
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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jbin_array_add_values_init
char *jbin_array_add_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (!bsp || bsp->Changed) {
if (!CheckMemory(g, initid, args, args->arg_count, true)) {
PJSON top;
PJAR arp;
PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JAR, &top);
PGLOBAL gb = GetMemPtr(g, args, 0);
if (jvp->GetValType() != TYPE_JAR) {
if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) {
arp->AddValue(gb, jvp);
top = arp;
} // endif arp
} else
arp = jvp->GetArray();
for (uint i = 1; i < args->arg_count; i++)
arp->AddValue(gb, MakeValue(gb, args, i));
arp->InitArray(gb);
if ((bsp = JbinAlloc(g, args, initid->max_length, top))) {
strcat(bsp->Msg, " array");
bsp->Jsp = arp;
} // endif bsp
} else
if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
strncpy(bsp->Msg, g->Message, BMX);
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
//} 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,
unsigned long *res_length, char *is_null, char *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;
jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
// jsp = jvp->GetJson();
x = GetIntArgPtr(g, args, n);
if (CheckPath(g, args, top, jvp, n))
PUSH_WARNING(g->Message);
else if (jvp) {
PGLOBAL gb = GetMemPtr(g, args, 0);
if (jvp->GetValType() != TYPE_JAR) {
if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) {
arp->AddValue(gb, (PJVAL)JvalNew(gb, TYPE_JVAL, jvp));
jvp->SetValue(arp);
if (!top)
top = arp;
} // endif arp
} else
arp = jvp->GetArray();
arp->AddValue(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;
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_array_add
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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else
CalcLen(args, false, reslen, memlen, true);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jbin_array_delete_init
char *jbin_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
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, 1, false, false, true)) {
int *x;
uint n = 1;
PJAR arp;
PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
if (CheckPath(g, args, top, jvp, 1))
PUSH_WARNING(g->Message);
else if (jvp && jvp->GetValType() == TYPE_JAR) {
if ((x = GetIntArgPtr(g, args, n))) {
arp = jvp->GetArray();
arp->DeleteValue(*x);
arp->InitArray(GetMemPtr(g, args, 0));
} else
PUSH_WARNING("Missing or null array index");
} else {
PUSH_WARNING("First argument target is not an array");
// if (g->Mrr) *error = 1;
} // endif jvp
} // endif CheckMemory
// In case of error unchanged argument will be returned
bsp = MakeBinResult(g, args, top, initid->max_length);
if (initid->const_item)
// Keep result of constant function
g->Xchk = bsp;
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_array_delete
void jbin_array_delete_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_array_delete_deinit
/*********************************************************************************/
/* Make a Json Object containing all the parameters. */
/*********************************************************************************/
my_bool jbin_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of jbin_object_init
char *jbin_object(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (!bsp || bsp->Changed) {
if (!CheckMemory(g, initid, args, args->arg_count, true)) {
PJOB objp;
if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
for (uint i = 0; i < args->arg_count; i++)
objp->SetValue(g, MakeValue(g, args, i), MakeKey(g, args, i));
if ((bsp = JbinAlloc(g, args, initid->max_length, objp)))
strcat(bsp->Msg, " object");
} else
bsp = NULL;
} else
if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
strncpy(bsp->Msg, g->Message, BMX);
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_object
void jbin_object_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_object_deinit
/*********************************************************************************/
/* Make a Json Object containing all not null parameters. */
/*********************************************************************************/
my_bool jbin_object_nonull_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jbin_object_nonull_init
char *jbin_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (!bsp || bsp->Changed) {
if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
PJVAL jvp;
PJOB objp;
if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
for (uint i = 0; i < args->arg_count; i++)
if (!(jvp = MakeValue(g, args, i))->IsNull())
objp->SetValue(g, jvp, MakeKey(g, args, i));
if ((bsp = JbinAlloc(g, args, initid->max_length, objp)))
strcat(bsp->Msg, " object");
} else
bsp = NULL;
} else
if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
strncpy(bsp->Msg, g->Message, BMX);
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_object_nonull
void jbin_object_nonull_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_object_nonull_deinit
/*********************************************************************************/
/* Make a Json Object containing all the key/value parameters. */
/*********************************************************************************/
my_bool jbin_object_key_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count % 2) {
strcpy(message, "This function must have an even number of arguments");
return true;
} // endif arg_count
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jbin_object_key_init
char *jbin_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
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->SetValue(g, MakeValue(g, args, i + 1), MakePSZ(g, args, i));
if ((bsp = JbinAlloc(g, args, initid->max_length, objp)))
strcat(bsp->Msg, " object");
} else
bsp = NULL;
} else
if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
strncpy(bsp->Msg, g->Message, BMX);
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_object_key
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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else if (!IsJson(args, 0)) {
strcpy(message, "First argument must be a json item");
return true;
} else
CalcLen(args, true, reslen, memlen, true);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jbin_object_add_init
char *jbin_object_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PJSON top = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (bsp && !bsp->Changed) {
// This constant function was recalled
bsp = (PBSON)g->Xchk;
*res_length = sizeof(BSON);
return (char*)bsp;
} // endif bsp
if (!CheckMemory(g, initid, args, 2, false, true, true)) {
PCSZ key;
PJOB jobp;
PJVAL jvp = MakeValue(g, args, 0, &top);
PJSON jsp = jvp->GetJson();
if (CheckPath(g, args, jsp, jvp, 2))
PUSH_WARNING(g->Message);
else if (jvp && jvp->GetValType() == TYPE_JOB) {
PGLOBAL gb = GetMemPtr(g, args, 0);
jobp = jvp->GetObject();
jvp = MakeValue(gb, args, 1);
key = MakeKey(gb, args, 1);
jobp->SetValue(gb, jvp, key);
} else {
PUSH_WARNING("First argument target is not an object");
// 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);
if (initid->const_item)
// Keep result of constant function
g->Xchk = bsp;
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_object_add
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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have 2 or 3 arguments");
return true;
} else if (!IsJson(args, 0)) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument must be a key string");
return true;
} else
CalcLen(args, true, reslen, memlen, true);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of jbin_object_delete_init
char *jbin_object_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PJSON top = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (bsp && !bsp->Changed) {
// This constant function was recalled
bsp = (PBSON)g->Xchk;
*res_length = sizeof(BSON);
return (char*)bsp;
} // endif bsp
if (!CheckMemory(g, initid, args, 1, false, true, true)) {
PCSZ key;
PJOB jobp;
PJVAL jvp = MakeValue(g, args, 0, &top);
PJSON jsp = jvp->GetJson();
if (CheckPath(g, args, top, jvp, 2))
PUSH_WARNING(g->Message);
else if (jvp && jvp->GetValType() == TYPE_JOB) {
key = MakeKey(g, args, 1);
jobp = jvp->GetObject();
jobp->DeleteKey(key);
} else {
PUSH_WARNING("First argument target is not an object");
// 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);
if (initid->const_item)
// Keep result of constant function
g->Xchk = bsp;
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_object_delete
void jbin_object_delete_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_object_delete_deinit
/*********************************************************************************/
/* Returns an array of the Json object keys. */
/*********************************************************************************/
my_bool jbin_object_list_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return json_object_list_init(initid, args, message);
} // end of jbin_object_list_init
char *jbin_object_list(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PJAR jarp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (!bsp || bsp->Changed) {
if (!CheckMemory(g, initid, args, 1, true, true)) {
char *p;
PJSON jsp;
PJVAL jvp = MakeValue(g, args, 0);
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
} // endif CheckMemory
if ((bsp = JbinAlloc(g, args, initid->max_length, jarp)))
strcat(bsp->Msg, " array");
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_object_list
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
char *jbin_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *path;
PJSON jsp;
PJSNX jsx;
PJVAL jvp;
PBSON bsp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
bsp = (PBSON)g->Activityp;
goto fin;
} else if (initid->const_item)
g->N = 1;
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true, true)) {
PUSH_WARNING("CheckMemory error");
goto fin;
} // endif CheckMemory
jvp = MakeTypedValue(g, args, 0, TYPE_JSON);
jsp = jvp->GetJson();
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} else
jsp = (PJSON)g->Xchk;
path = MakePSZ(g, args, 1);
jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length);
if (!jsx || jsx->SetJpath(g, path, false)) {
PUSH_WARNING(g->Message);
goto fin;
} // endif SetJpath
// Get the json tree
if ((jvp = jsx->GetRowValue(g, jsp, 0, false))) {
jsp = (jvp->GetJsp()) ? jvp->GetJsp() : JvalNew(g, TYPE_VAL, jvp->GetValue());
if ((bsp = JbinAlloc(g, args, initid->max_length, jsp)))
strcat(bsp->Msg, " item");
else
*error = 1;
} // endif jvp
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)bsp;
fin:
if (!bsp) {
*is_null = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_get_item
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)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else if (!IsJson(args, 0)) {
strcpy(message, "First argument must be a json item");
return true;
} else if (!IsJson(args, 1)) {
strcpy(message, "Second 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_item_merge_init
char *jbin_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
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)) {
PJVAL jvp;
PJSON jsp[2] = {NULL, NULL};
PGLOBAL gb = GetMemPtr(g, args, 0);
for (int i = 0; i < 2; i++) {
jvp = MakeValue(g, args, i);
if (!i) top = jvp->GetJson();
if (jvp->GetValType() != TYPE_JAR && jvp->GetValType() != TYPE_JOB) {
sprintf(g->Message, "Argument %d is not an array or object", i);
PUSH_WARNING(g->Message);
} else
jsp[i] = jvp->GetJsp();
} // endfor i
if (jsp[0] && jsp[0]->Merge(gb, jsp[1]))
PUSH_WARNING(gb->Message);
} // endif CheckMemory
// In case of error unchanged first argument will be returned
bsp = MakeBinResult(g, args, top, initid->max_length);
if (initid->const_item)
// Keep result of constant function
g->Xchk = bsp;
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_item_merge
void jbin_item_merge_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_item_merge_deinit
/*********************************************************************************/
/* This function is used by the jbin_set/insert/update functions. */
/*********************************************************************************/
char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *p, *path;
int w;
my_bool b = true;
PJSON jsp;
PJSNX jsx;
PJVAL jvp = NULL;
PBSON bsp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
PGLOBAL gb = GetMemPtr(g, args, 0);
if (g->N) {
bsp = (PBSON)g->Activityp;
goto fin;
} else if (initid->const_item)
g->N = 1;
if (!strcmp(result, "$set"))
w = 0;
else if (!strcmp(result, "$insert"))
w = 1;
else if (!strcmp(result, "$update"))
w = 2;
else {
PUSH_WARNING("Logical error, please contact CONNECT developer");
goto fin;
} // endelse
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true, false, true)) {
PUSH_WARNING("CheckMemory error");
goto fin;
} else
jvp = MakeValue(g, args, 0);
if ((p = jvp->GetString(g))) {
if (!(jsp = ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
goto fin;
} // endif jsp
} else
jsp = jvp->GetJson();
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} else
jsp = (PJSON)g->Xchk;
jsx = new(g)JSNX(g, jsp, TYPE_STRING, initid->max_length, 0, true);
for (uint i = 1; i+1 < args->arg_count; i += 2) {
jvp = MakeValue(gb, args, i);
path = MakePSZ(g, args, i+1);
if (jsx->SetJpath(g, path, false)) {
PUSH_WARNING(g->Message);
continue;
} // endif SetJpath
if (w) {
jsx->ReadValue(g);
b = jsx->GetValue()->IsNull();
b = (w == 1) ? b : !b;
} // endif w
if (b && jsx->WriteValue(gb, jvp))
PUSH_WARNING(g->Message);
} // endfor i
if (!(bsp = MakeBinResult(g, args, jsp, initid->max_length, INT_MAX32)))
*error = 1;
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)bsp;
fin:
if (!bsp) {
*is_null = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bin_handle_item
/*********************************************************************************/
/* Set Json items of a Json document according to path. */
/*********************************************************************************/
my_bool jbin_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long 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");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} 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;
} else if (n != 3)
more = args->lengths[0] * 3;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of jbin_set_item_init
char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$set");
return bin_handle_item(initid, args, result, res_length, is_null, p);
} // end of jbin_set_item
void jbin_set_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_set_item_deinit
/*********************************************************************************/
/* Insert Json items of a Json document according to path. */
/*********************************************************************************/
my_bool jbin_insert_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return json_set_item_init(initid, args, message);
} // end of jbin_insert_item_init
char *jbin_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$insert");
return bin_handle_item(initid, args, result, res_length, is_null, p);
} // end of jbin_insert_item
void jbin_insert_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_insert_item_deinit
/*********************************************************************************/
/* Update Json items of a Json document according to path. */
/*********************************************************************************/
my_bool jbin_update_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return json_set_item_init(initid, args, message);
} // end of jbin_update_item_init
char *jbin_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$update");
return bin_handle_item(initid, args, result, res_length, is_null, p);
} // end of jbin_update_item
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)
{
unsigned long reslen, memlen, fl, more = 1024;
if (args->arg_count < 1 || args->arg_count > 4) {
strcpy(message, "This function only accepts 1 to 4 arguments");
return true;
} else if (args->arg_type[0] != STRING_RESULT || !args->args[0]) {
strcpy(message, "First argument must be a constant string (file name)");
return true;
} else if (args->arg_count > 1 && args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a string (path)");
return true;
} else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (pretty)");
return true;
} else if (args->arg_count > 3) {
if (args->arg_type[3] != INT_RESULT) {
strcpy(message, "Fourth argument is not an integer (memory)");
return true;
} else
more += (ulong)*(longlong*)args->args[3];
} // endifs
initid->maybe_null = 1;
CalcLen(args, false, reslen, memlen);
fl = GetFileLength(args->args[0]);
reslen += fl;
more += fl * M;
//memlen += more;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of jbin_file_init
char *jbin_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *fn;
int pretty, len = 0, pty = 3;
PJSON jsp;
PJVAL jvp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (bsp && !bsp->Changed)
goto fin;
PlugSubSet(g->Sarea, g->Sarea_Size);
g->Xchk = NULL;
fn = MakePSZ(g, args, 0);
pretty = (args->arg_count > 2 && args->args[2]) ? (int)*(longlong*)args->args[2] : 3;
/*********************************************************************************/
/* Parse the json file and allocate its tree structure. */
/*********************************************************************************/
if (!(jsp = ParseJsonFile(g, fn, &pty, len))) {
PUSH_WARNING(g->Message);
*error = 1;
goto fin;
} // endif jsp
if (pty == 3)
PUSH_WARNING("File pretty format cannot be determined");
else if (pretty != 3 && pty != pretty)
PUSH_WARNING("File pretty format doesn't match the specified pretty value");
else if (pretty == 3)
pretty = pty;
if ((bsp = JbinAlloc(g, args, len, jsp))) {
strcat(bsp->Msg, " file");
bsp->Filename = fn;
bsp->Pretty = pretty;
} else {
*error = 1;
goto fin;
} // endif bsp
// Check whether a path was specified
if (CheckPath(g, args, jsp, jvp, 1)) {
PUSH_WARNING(g->Message);
bsp = NULL;
goto fin;
} else if (jvp)
bsp->Jsp = jvp->GetJsp();
if (initid->const_item)
// Keep result of constant function
g->Xchk = bsp;
fin:
if (!bsp) {
*res_length = 0;
*is_null = 1;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of jbin_file
void jbin_file_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jbin_file_deinit
/*********************************************************************************/
/* Serialize a Json document. . */
/*********************************************************************************/
my_bool json_serialize_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count != 1) {
strcpy(message, "This function must have 1 argument");
return true;
} else if (args->args[0] && IsJson(args, 0) != 3) {
strcpy(message, "Argument must be a Jbin tree");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of json_serialize_init
char *json_serialize(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *, char *error)
{
char *str;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (IsJson(args, 0) == 3) {
PBSON bsp = (PBSON)args->args[0];
JsonSubSet(g);
if (!(str = Serialize(g, bsp->Jsp, 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 json_serialize
void json_serialize_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_serialize_deinit
/*********************************************************************************/
/* Utility function returning an environment variable value. */
/*********************************************************************************/
my_bool envar_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
if (args->arg_count != 1) {
strcpy(message, "Unique argument must be an environment variable name");
return true;
} else {
initid->maybe_null = true;
return false;
} // endif count
} // end of envar_init
char *envar(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *)
{
char *str, name[256];
int n = MY_MIN(args->lengths[0], sizeof(name) - 1);
memcpy(name, args->args[0], n);
name[n] = 0;
if (!(str = getenv(name))) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(str);
return str;
} // end of envar
#if defined(DEVELOPMENT)
extern char *GetUserVariable(PGLOBAL g, const uchar *varname);
/*********************************************************************************/
/* Utility function returning a user variable value. */
/*********************************************************************************/
my_bool uvar_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count != 1) {
strcpy(message, "Unique argument must be a user variable name");
return true;
} 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,
unsigned long *res_length, char *is_null, char *)
{
char *str, varname[256];
PGLOBAL g = (PGLOBAL)initid->ptr;
int n = MY_MIN(args->lengths[0], sizeof(varname) - 1);
PlugSubSet(g->Sarea, g->Sarea_Size);
memcpy(varname, args->args[0], n);
varname[n] = 0;
if (!(str = GetUserVariable(g, (const uchar*)&varname))) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(str);
return str;
} // end of uvar
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");
return true;
} else if (args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be string");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a string");
return true;
} // endif args
return false;
} // end of countin_init
long long countin(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *)
{
PSZ str1, str2;
char *s;
long long n = 0;
size_t lg;
lg = (size_t)args->lengths[0];
s = str1 = (PSZ)malloc(lg + 1);
memcpy(str1, args->args[0], lg);
str1[lg] = 0;
lg = (size_t)args->lengths[1];
str2 = (PSZ)malloc(lg + 1);
memcpy(str2, args->args[1], lg);
str2[lg] = 0;
while (s = strstr(s, str2)) {
n++;
s += lg;
} // endwhile
free(str1);
free(str2);
return n;
} // end of countin