summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Bertrand <bertrandop@gmail.com>2020-11-25 17:42:01 +0100
committerOlivier Bertrand <bertrandop@gmail.com>2020-11-25 17:42:01 +0100
commitb656d3d333f6d8a28407e5e4b636cd142d757595 (patch)
treec52c3eb9ff5d5fff8a1baec96b4c36e5bf3a9485
parentdc8f914c383366d11b6a995ba184b99d5ec663cf (diff)
downloadmariadb-git-b656d3d333f6d8a28407e5e4b636cd142d757595.tar.gz
Desesperatly trying to stop compiling failures
-rw-r--r--storage/connect/bson.cpp20
-rw-r--r--storage/connect/bson.h2
-rw-r--r--storage/connect/bsonudf.cpp1507
-rw-r--r--storage/connect/bsonudf.h98
-rw-r--r--storage/connect/json.h1
-rw-r--r--storage/connect/jsonudf.cpp1502
-rw-r--r--storage/connect/jsonudf.h121
7 files changed, 1655 insertions, 1596 deletions
diff --git a/storage/connect/bson.cpp b/storage/connect/bson.cpp
index 2f380752c0d..61e5eb9fe16 100644
--- a/storage/connect/bson.cpp
+++ b/storage/connect/bson.cpp
@@ -135,10 +135,10 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) {
if (Bvp->Type != TYPE_UNKNOWN) {
Bvp->To_Val = ParseAsArray(g, i, pretty, ptyp);
Bvp->Type = TYPE_JAR;
- } else if ((Bvp->To_Val = ParseObject(g, ++i)))
+ } else {
+ Bvp->To_Val = ParseObject(g, ++i);
Bvp->Type = TYPE_JOB;
- else
- throw 2;
+ } // endif Type
break;
case ' ':
@@ -300,7 +300,7 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) {
} else
firstbpp = lastbpp = bpp;
- level = 1;
+ level = 2;
} else {
sprintf(g->Message, "misplaced string near %.*s", ARGS);
throw 2;
@@ -308,9 +308,9 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) {
break;
case ':':
- if (level == 1) {
+ if (level == 2) {
lastbpp->Vlp = MOF(ParseValue(g, ++i));
- level = 2;
+ level = 3;
} else {
sprintf(g->Message, "Unexpected ':' near %.*s", ARGS);
throw 2;
@@ -318,15 +318,15 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) {
break;
case ',':
- if (level < 2) {
+ if (level < 3) {
sprintf(g->Message, "Unexpected ',' near %.*s", ARGS);
throw 2;
} else
- level = 0;
+ level = 1;
break;
case '}':
- if (level < 2) {
+ if (!(level == 0 || level == 3)) {
sprintf(g->Message, "Unexpected '}' near %.*s", ARGS);
throw 2;
} // endif level
@@ -1248,7 +1248,7 @@ PBVAL BJSON::SubAllocVal(PGLOBAL g)
/***********************************************************************/
/* Sub-allocate and initialize a BVAL as string. */
/***********************************************************************/
-PBVAL BJSON::SubAllocVal(PGLOBAL g, OFFSET toval, JTYP type, short nd)
+PBVAL BJSON::SubAllocVal(PGLOBAL g, OFFSET toval, int type, short nd)
{
PBVAL bvp = (PBVAL)BsonSubAlloc(g, sizeof(BVAL));
diff --git a/storage/connect/bson.h b/storage/connect/bson.h
index 9f5f44d073c..bffda8ea316 100644
--- a/storage/connect/bson.h
+++ b/storage/connect/bson.h
@@ -77,7 +77,7 @@ public:
void* BsonSubAlloc(PGLOBAL g, size_t size);
PBPR SubAllocPair(PGLOBAL g, OFFSET key, OFFSET val = 0);
PBVAL SubAllocVal(PGLOBAL g);
- PBVAL SubAllocVal(PGLOBAL g, OFFSET toval, JTYP type = TYPE_UNKNOWN, short nd = 0);
+ PBVAL SubAllocVal(PGLOBAL g, OFFSET toval, int type = TYPE_UNKNOWN, short nd = 0);
PBVAL SubAllocVal(PGLOBAL g, PVAL valp);
PBVAL DupVal(PGLOBAL g, PBVAL bvp);
diff --git a/storage/connect/bsonudf.cpp b/storage/connect/bsonudf.cpp
new file mode 100644
index 00000000000..bbb279ce6ce
--- /dev/null
+++ b/storage/connect/bsonudf.cpp
@@ -0,0 +1,1507 @@
+/****************** bsonudf C++ Program Source Code File (.CPP) ******************/
+/* PROGRAM NAME: bsonudf Version 1.0 */
+/* (C) Copyright to the author Olivier BERTRAND 2020 */
+/* This program are the BSON 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 "bsonudf.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 9
+
+/* --------------------------------- JSON UDF ---------------------------------- */
+
+/*********************************************************************************/
+/* Program for saving the status of the memory pools. */
+/*********************************************************************************/
+inline void JsonMemSave(PGLOBAL g) {
+ g->Saved_Size = ((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 */
+
+/* --------------------------- New Testing BJSON Stuff --------------------------*/
+
+/*********************************************************************************/
+/* SubAlloc a new BJNX class with protection against memory exhaustion. */
+/*********************************************************************************/
+static PBJNX BjnxNew(PGLOBAL g, PBVAL vlp, int type, int len) {
+ PBJNX bjnx;
+
+ try {
+ bjnx = new(g) BJNX(g, vlp, type, len);
+ } catch (...) {
+ if (trace(1023))
+ htrc("%s\n", g->Message);
+
+ PUSH_WARNING(g->Message);
+ bjnx = NULL;
+ } // end try/catch
+
+ return bjnx;
+} /* end of BjnxNew */
+
+/* ----------------------------------- BSNX ------------------------------------ */
+
+/*********************************************************************************/
+/* BSNX public constructor. */
+/*********************************************************************************/
+BJNX::BJNX(PGLOBAL g, PBVAL row, int type, int len, int prec, my_bool wr)
+ : BDOC(g->Sarea) {
+ Row = row;
+ Bvalp = NULL;
+ Jpnp = NULL;
+ Jp = NULL;
+ Nodes = NULL;
+ Value = AllocateValue(g, type, len, prec);
+ MulVal = NULL;
+ Jpath = NULL;
+ Buf_Type = type;
+ Long = len;
+ Prec = prec;
+ Nod = 0;
+ Xnod = -1;
+ K = 0;
+ I = -1;
+ Imax = 9;
+ B = 0;
+ Xpd = false;
+ Parsed = false;
+ Found = false;
+ Wr = wr;
+ Jb = false;
+} // end of BJNX constructor
+
+/*********************************************************************************/
+/* SetJpath: set and parse the json path. */
+/*********************************************************************************/
+my_bool BJNX::SetJpath(PGLOBAL g, char* path, my_bool jb) {
+ // Check Value was allocated
+ if (!Value)
+ 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 BJNX::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 BJNX::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 BJNX::MakeJson(PGLOBAL g, PBVAL bvp) {
+ if (Value->IsTypeNum()) {
+ strcpy(g->Message, "Cannot make Json for a numeric value");
+ Value->Reset();
+ } else if (bvp->Type != TYPE_JAR && bvp->Type != TYPE_JOB) {
+ strcpy(g->Message, "Target is not an array or object");
+ Value->Reset();
+ } else
+ Value->SetValue_psz(Serialize(g, bvp, NULL, 0));
+
+ return Value;
+} // end of MakeJson
+
+/*********************************************************************************/
+/* SetValue: Set a value from a JVALUE contains. */
+/*********************************************************************************/
+void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp) {
+ if (vlp) {
+ vp->SetNull(false);
+
+ if (Jb) {
+ vp->SetValue_psz(Serialize(g, vlp, NULL, 0));
+ } else switch (vlp->Type) {
+ case TYPE_DTM:
+ case TYPE_STRG:
+ vp->SetValue_psz(GetString(g, vlp));
+ break;
+ case TYPE_INTG:
+ case TYPE_BINT:
+ vp->SetValue(GetInteger(vlp));
+ break;
+ case TYPE_DBL:
+ if (vp->IsTypeNum())
+ vp->SetValue(GetDouble(vlp));
+ else // Get the proper number of decimals
+ vp->SetValue_psz(GetString(g, vlp));
+
+ break;
+ case TYPE_BOOL:
+ if (vp->IsTypeNum())
+ vp->SetValue(GetInteger(vlp) ? 1 : 0);
+ else
+ vp->SetValue_psz(GetString(g, vlp));
+
+ break;
+ case TYPE_JAR:
+ vp->SetValue_psz(GetArrayText(g, MVP(vlp->To_Val), NULL));
+ break;
+ case TYPE_JOB:
+ vp->SetValue_psz(GetObjectText(g, MPP(vlp->To_Val), NULL));
+ break;
+ case TYPE_NULL:
+ vp->SetNull(true);
+ default:
+ vp->Reset();
+ } // endswitch Type
+
+ } else {
+ vp->SetNull(true);
+ vp->Reset();
+ } // endif val
+
+} // end of SetJsonValue
+
+/*********************************************************************************/
+/* GetJson: */
+/*********************************************************************************/
+PBVAL BJNX::GetJson(PGLOBAL g) {
+ return GetRowValue(g, Row, 0);
+} // end of GetJson
+
+/*********************************************************************************/
+/* ReadValue: */
+/*********************************************************************************/
+void BJNX::ReadValue(PGLOBAL g) {
+ Value->SetValue_pval(GetColumnValue(g, Row, 0));
+} // end of ReadValue
+
+/*********************************************************************************/
+/* GetColumnValue: */
+/*********************************************************************************/
+PVAL BJNX::GetColumnValue(PGLOBAL g, PBVAL row, int i) {
+ PBVAL vlp = GetRowValue(g, row, i);
+
+ SetJsonValue(g, Value, vlp);
+ return Value;
+} // end of GetColumnValue
+
+/*********************************************************************************/
+/* GetRowValue: */
+/*********************************************************************************/
+PBVAL BJNX::GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b) {
+ my_bool expd = false;
+ PBVAL bap;
+ PBVAL vlp = NULL;
+
+ for (; i < Nod && row; i++) {
+ if (Nodes[i].Op == OP_NUM) {
+ Value->SetValue(row->Type == TYPE_JAR ? GetArraySize(MVP(row->To_Val)) : 1);
+ vlp = SubAllocVal(g, Value);
+ return vlp;
+ } else if (Nodes[i].Op == OP_XX) {
+ Jb = b;
+ // return DupVal(g, row);
+ return row; // or last line ???
+ } else switch (row->Type) {
+ case TYPE_JOB:
+ if (!Nodes[i].Key) {
+ // Expected Array was not there
+ if (Nodes[i].Op == OP_LE) {
+ if (i < Nod - 1)
+ continue;
+ else
+ vlp = row; // DupVal(g, row) ???
+
+ } else {
+ strcpy(g->Message, "Unexpected object");
+ vlp = NULL;
+ } //endif Op
+
+ } else
+ vlp = GetKeyValue(MPP(row->To_Val), Nodes[i].Key);
+
+ break;
+ case TYPE_JAR:
+ bap = MVP(row->To_Val);
+
+ if (!Nodes[i].Key) {
+ if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
+ vlp = GetArrayValue(bap, Nodes[i].Rank);
+ else if (Nodes[i].Op == OP_EXP)
+ return (PBVAL)ExpandArray(g, bap, i);
+ else
+ return SubAllocVal(g, CalculateArray(g, bap, i));
+
+ } else {
+ // Unexpected array, unwrap it as [0]
+ vlp = GetArrayValue(bap, 0);
+ i--;
+ } // endif's
+
+ break;
+ case TYPE_JVAL:
+ vlp = row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->Type);
+ vlp = NULL;
+ } // endswitch Type
+
+ row = vlp;
+ } // endfor i
+
+ return vlp;
+} // end of GetRowValue
+
+/*********************************************************************************/
+/* ExpandArray: */
+/*********************************************************************************/
+PVAL BJNX::ExpandArray(PGLOBAL g, PBVAL arp, int n) {
+ strcpy(g->Message, "Expand cannot be done by this function");
+ return NULL;
+} // end of ExpandArray
+
+/*********************************************************************************/
+/* CalculateArray: NIY */
+/*********************************************************************************/
+PVAL BJNX::CalculateArray(PGLOBAL g, PBVAL bap, int n) {
+#if 0
+ int i, ars = GetArraySize(bap), nv = 0;
+ bool err;
+ OPVAL op = Nodes[n].Op;
+ PVAL val[2], vp = Nodes[n].Valp;
+ PBVAL bvrp, bvp;
+ BVAL bval;
+
+ vp->Reset();
+ xtrc(1, "CalculateArray size=%d op=%d\n", ars, op);
+
+ for (i = 0; i < ars; i++) {
+ bvrp = GetArrayValue(bap, i);
+ xtrc(1, "i=%d nv=%d\n", i, nv);
+
+ if (!IsValueNull(bvrp) || (op == OP_CNC && GetJsonNull())) {
+ if (IsValueNull(bvrp)) {
+ SetString(bvrp, GetJsonNull(), 0);
+ bvp = bvrp;
+ } else if (n < Nod - 1 && bvrp->GetJson()) {
+ bval.SetValue(g, GetColumnValue(g, jvrp->GetJson(), n + 1));
+ bvp = &bval;
+ } 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);
+ continue;
+ } else
+ SetJsonValue(g, MulVal, jvp);
+
+ 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;
+#else
+ strcpy(g->Message, "Calculate array NIY");
+ return NULL;
+#endif
+} // end of CalculateArray
+
+/*********************************************************************************/
+/* CheckPath: Checks whether the path exists in the document. */
+/*********************************************************************************/
+my_bool BJNX::CheckPath(PGLOBAL g) {
+ PBVAL val = NULL;
+ PBVAL row = Row;
+
+ for (int i = 0; i < Nod && row; i++) {
+ val = NULL;
+
+ if (Nodes[i].Op == OP_NUM || Nodes[i].Op == OP_XX) {
+ } else switch (row->Type) {
+ case TYPE_JOB:
+ if (Nodes[i].Key)
+ val = GetKeyValue(MPP(row->To_Val), Nodes[i].Key);
+
+ break;
+ case TYPE_JAR:
+ if (!Nodes[i].Key)
+ if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
+ val = GetArrayValue(MVP(row->To_Val), Nodes[i].Rank);
+
+ break;
+ case TYPE_JVAL:
+ val = MVP(row->To_Val);
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->Type);
+ } // endswitch Type
+
+// if (i < Nod - 1)
+// if (!(row = (val) ? val->GetJsp() : NULL))
+// val = NULL;
+
+ row = val;
+ } // endfor i
+
+ return (val != NULL);
+} // end of CheckPath
+
+/***********************************************************************/
+/* GetRow: Set the complete path of the object to be set. */
+/***********************************************************************/
+PBVAL BJNX::GetRow(PGLOBAL g) {
+ PBVAL val = NULL;
+ PBVAL arp;
+ PBVAL nwr, row = Row;
+
+ for (int i = 0; i < Nod - 1 && row; i++) {
+ if (Nodes[i].Op == OP_XX)
+ break;
+ else switch (row->Type) {
+ case TYPE_JOB:
+ if (!Nodes[i].Key)
+ // Expected Array was not there, wrap the value
+ continue;
+
+ val = GetKeyValue(MPP(row->To_Val), Nodes[i].Key);
+ break;
+ case TYPE_JAR:
+ arp = MVP(row->To_Val);
+
+ if (!Nodes[i].Key) {
+ if (Nodes[i].Op == OP_EQ)
+ val = GetArrayValue(arp, Nodes[i].Rank);
+ else
+ val = GetArrayValue(arp, Nodes[i].Rx);
+
+ } else {
+ // Unexpected array, unwrap it as [0]
+ val = GetArrayValue(arp, 0);
+ i--;
+ } // endif Nodes
+
+ break;
+ case TYPE_JVAL:
+ val = MVP(row->To_Val);
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->Type);
+ val = NULL;
+ } // endswitch Type
+
+ if (val) {
+ row = val;
+ } else {
+ // Construct missing objects
+ for (i++; row && i < Nod; i++) {
+ if (Nodes[i].Op == OP_XX)
+ break;
+ // else if (!Nodes[i].Key)
+ // Construct intermediate array
+ // nwr = SubAllocVal(g);
+ // else
+ // nwr = SubAllocPair(g);
+
+ // Construct new row
+ nwr = SubAllocVal(g);
+
+ if (row->Type == TYPE_JOB) {
+ SetKeyValue(g, MPP(row->To_Val), MOF(nwr), Nodes[i - 1].Key);
+ } else if (row->Type == TYPE_JAR) {
+ AddArrayValue(g, MVP(row->To_Val), nwr);
+ } 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 BJNX::WriteValue(PGLOBAL g, PBVAL jvalp) {
+ PBPR objp = NULL;
+ PBVAL arp = NULL;
+ PBVAL jvp = NULL;
+ PBVAL row = GetRow(g);
+
+ if (!row)
+ return true;
+
+ switch (row->Type) {
+ case TYPE_JOB: objp = MPP(row->To_Val); break;
+ case TYPE_JAR: arp = MVP(row->To_Val); break;
+ case TYPE_JVAL: jvp = MVP(row->To_Val); 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)
+ SetArrayValue(g, arp, jvalp, Nodes[Nod - 1].Rank);
+ else
+ AddArrayValue(g, arp, jvalp);
+
+ } // endif Key
+
+ } else if (objp) {
+ if (Nodes[Nod - 1].Key)
+ SetKeyValue(g, objp, MOF(jvalp), Nodes[Nod - 1].Key);
+
+ } else if (jvp)
+ SetValueVal(jvp, jvalp);
+
+ return false;
+} // end of WriteValue
+
+/*********************************************************************************/
+/* Locate a value in a JSON tree: */
+/*********************************************************************************/
+PSZ BJNX::Locate(PGLOBAL g, PBVAL jsp, PBVAL 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('$');
+ Bvalp = jvp;
+ K = k;
+
+ switch (jsp->Type) {
+ case TYPE_JAR:
+ err = LocateArray(g, MVP(jsp->To_Val));
+ break;
+ case TYPE_JOB:
+ err = LocateObject(g, MPP(jsp->To_Val));
+ break;
+ case TYPE_JVAL:
+ err = LocateValue(g, MVP(jsp->To_Val));
+ 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 BJNX::LocateArray(PGLOBAL g, PBVAL jarp) {
+ char s[16];
+ int n = GetArraySize(jarp);
+ size_t m = Jp->N;
+
+ for (int i = 0; i < n && !Found; i++) {
+ Jp->N = m;
+ sprintf(s, "[%d]", i + B);
+
+ if (Jp->WriteStr(s))
+ return true;
+
+ if (LocateValue(g, GetArrayValue(jarp, i)))
+ return true;
+
+ } // endfor i
+
+ return false;
+} // end of LocateArray
+
+/*********************************************************************************/
+/* Locate in a JSON Object. */
+/*********************************************************************************/
+my_bool BJNX::LocateObject(PGLOBAL g, PBPR jobp) {
+ size_t m;
+
+ if (Jp->WriteChr('.'))
+ return true;
+
+ m = Jp->N;
+
+ for (PBPR pair = jobp; pair && !Found; pair = MPP(pair->Next)) {
+ Jp->N = m;
+
+ if (Jp->WriteStr(MZP(pair->Key)))
+ return true;
+
+ if (LocateValue(g, MVP(pair->Vlp)))
+ return true;
+
+ } // endfor i
+
+ return false;
+} // end of LocateObject
+
+/*********************************************************************************/
+/* Locate a JSON Value. */
+/*********************************************************************************/
+my_bool BJNX::LocateValue(PGLOBAL g, PBVAL jvp) {
+ if (CompareTree(g, Bvalp, jvp))
+ Found = (--K == 0);
+ else if (jvp->Type == TYPE_JAR)
+ return LocateArray(g, GetArray(jvp));
+ else if (jvp->Type == TYPE_JOB)
+ return LocateObject(g, GetObject(jvp));
+
+ return false;
+} // end of LocateValue
+
+/*********************************************************************************/
+/* Locate all occurrences of a value in a JSON tree: */
+/*********************************************************************************/
+PSZ BJNX::LocateAll(PGLOBAL g, PBVAL jsp, PBVAL bvp, int mx) {
+ PSZ str = NULL;
+ my_bool 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);
+ Bvalp = bvp;
+ Imax = mx - 1;
+ Jpnp = jnp;
+ Jp->WriteChr('[');
+
+ switch (jsp->Type) {
+ case TYPE_JAR:
+ err = LocateArrayAll(g, MVP(jsp->To_Val));
+ break;
+ case TYPE_JOB:
+ err = LocateObjectAll(g, MPP(jsp->To_Val));
+ break;
+ case TYPE_JVAL:
+ err = LocateValueAll(g, MVP(jsp->To_Val));
+ break;
+ default:
+ err = LocateValueAll(g, jsp);
+ } // 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) {
+ xtrc(1, "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 BJNX::LocateArrayAll(PGLOBAL g, PBVAL jarp) {
+ int i = 0;
+
+ if (I < Imax) {
+ Jpnp[++I].Type = TYPE_JAR;
+
+ for (PBVAL vp = jarp; vp; vp = MVP(vp->Next)) {
+ Jpnp[I].N = i;
+
+ if (LocateValueAll(g, GetArrayValue(jarp, i)))
+ return true;
+
+ i++;
+ } // endfor i
+
+ I--;
+ } // endif I
+
+ return false;
+} // end of LocateArrayAll
+
+/*********************************************************************************/
+/* Locate in a JSON Object. */
+/*********************************************************************************/
+my_bool BJNX::LocateObjectAll(PGLOBAL g, PBPR jobp) {
+ if (I < Imax) {
+ Jpnp[++I].Type = TYPE_JOB;
+
+ for (PBPR pair = jobp; pair; pair = MPP(pair->Next)) {
+ Jpnp[I].Key = MZP(pair->Key);
+
+ if (LocateValueAll(g, MVP(pair->Vlp)))
+ return true;
+
+ } // endfor i
+
+ I--;
+ } // endif I
+
+ return false;
+} // end of LocateObjectAll
+
+/*********************************************************************************/
+/* Locate a JSON Value. */
+/*********************************************************************************/
+my_bool BJNX::LocateValueAll(PGLOBAL g, PBVAL jvp) {
+ if (CompareTree(g, Bvalp, jvp))
+ return AddPath();
+ else if (jvp->Type == TYPE_JAR)
+ return LocateArrayAll(g, GetArray(jvp));
+ else if (jvp->Type == TYPE_JOB)
+ return LocateObjectAll(g, GetObject(jvp));
+
+ return false;
+} // end of LocateValueAll
+
+/*********************************************************************************/
+/* Compare two JSON trees. */
+/*********************************************************************************/
+my_bool BJNX::CompareTree(PGLOBAL g, PBVAL jp1, PBVAL jp2) {
+ if (!jp1 || !jp2 || jp1->Type != jp2->Type || GetSize(jp1) != GetSize(jp2))
+ return false;
+
+ my_bool found = true;
+
+ if (jp1->Type == TYPE_JAR) {
+ for (int i = 0; found && i < GetArraySize(jp1); i++)
+ found = (CompareValues(g, GetArrayValue(jp1, i), GetArrayValue(jp2, i)));
+
+ } else if (jp1->Type == TYPE_JOB) {
+ PBPR p1 = MPP(jp1->To_Val), p2 = MPP(jp2->To_Val);
+
+ // Keys can be differently ordered
+ for (; found && p1 && p2; p1 = MPP(p1->Next))
+ found = CompareValues(g, MVP(p1->Vlp), GetKeyValue(p2, MZP(p1->Key)));
+
+ } else if (jp1->Type == TYPE_JVAL) {
+ found = CompareTree(g, MVP(jp1->To_Val), (MVP(jp2->To_Val)));
+ } else
+ found = CompareValues(g, jp1, jp2);
+
+ return found;
+} // end of CompareTree
+
+/*********************************************************************************/
+/* Compare two VAL values and return true if they are equal. */
+/*********************************************************************************/
+my_bool BJNX::CompareValues(PGLOBAL g, PBVAL v1, PBVAL v2) {
+ my_bool b = false;
+
+ if (v1 && v2)
+ switch (v1->Type) {
+ case TYPE_JAR:
+ if (v2->Type == TYPE_JAR)
+ b = CompareTree(g, MVP(v1->To_Val), MVP(v2->To_Val));
+
+ break;
+ case TYPE_STRG:
+ if (v2->Type == TYPE_STRG) {
+ if (v1->Nd || v2->Nd) // Case insensitive
+ b = (!stricmp(MZP(v1->To_Val), MZP(v2->To_Val)));
+ else
+ b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
+
+ } // endif Type
+
+ break;
+ case TYPE_DTM:
+ if (v2->Type == TYPE_DTM)
+ b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
+
+ break;
+ case TYPE_INTG:
+ if (v2->Type == TYPE_INTG)
+ b = (v1->N == v2->N);
+ else if (v2->Type == TYPE_BINT)
+ b = ((longlong)v1->N == LLN(v2->To_Val));
+
+ break;
+ case TYPE_BINT:
+ if (v2->Type == TYPE_INTG)
+ b = (LLN(v1->To_Val) == (longlong)v2->N);
+ else if (v2->Type == TYPE_BINT)
+ b = (LLN(v1->To_Val) == LLN(v2->To_Val));
+
+ break;
+ case TYPE_FLOAT:
+ if (v2->Type == TYPE_FLOAT)
+ b = (v1->F == v2->F);
+ else if (v2->Type == TYPE_DBL)
+ b = ((double)v1->F == DBL(v2->To_Val));
+
+ break;
+ case TYPE_DBL:
+ if (v2->Type == TYPE_DBL)
+ b = (DBL(v1->To_Val) == DBL(v2->To_Val));
+ else if (v2->Type == TYPE_FLOAT)
+ b = (DBL(v1->To_Val) == (double)v2->F);
+
+ break;
+ case TYPE_BOOL:
+ if (v2->Type == TYPE_BOOL)
+ b = (v1->B == v2->B);
+
+ break;
+ case TYPE_NULL:
+ b = (v2->Type == TYPE_NULL);
+ break;
+ default:
+ break;
+ } // endswitch Type
+
+ else
+ b = (!v1 && !v2);
+
+ return b;
+} // end of CompareValues
+
+/*********************************************************************************/
+/* Add the found path to the list. */
+/*********************************************************************************/
+my_bool BJNX::AddPath(void) {
+ char s[16];
+
+ if (Jp->WriteStr("\"$"))
+ 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
+
+/*********************************************************************************/
+/* Make a BVAL value from the passed argument. */
+/*********************************************************************************/
+static PBVAL MakeBinValue(PGLOBAL g, UDF_ARGS* args, uint i) {
+ char* sap = (args->arg_count > i) ? args->args[i] : NULL;
+ int n, len;
+ int ci;
+ longlong bigint;
+ void* Base = g->Sarea; // Required by MOF
+ BDOC doc(Base);
+ PBVAL bp;
+ PBVAL bvp = doc.SubAllocVal(g);
+
+ 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 == 2) {
+ if (!(sap = GetJsonFile(g, sap))) {
+ PUSH_WARNING(g->Message);
+ return NULL;
+ } // endif sap
+
+ len = strlen(sap);
+ } // endif 2
+
+ if (!(bp = doc.ParseJson(g, sap, strlen(sap))))
+ PUSH_WARNING(g->Message);
+
+ bvp = bp;
+ } else {
+ // Check whether this string is a valid json string
+ JsonMemSave(g);
+
+ if (!(bvp = doc.ParseJson(g, sap, strlen(sap)))) {
+ // Recover suballocated memory
+ JsonSubSet(g);
+ ci = (strnicmp(args->attributes[i], "ci", 2)) ? 0 : 1;
+ bvp = doc.SubAllocVal(g, MOF(sap), TYPE_STRG, ci);
+ } else
+ g->Saved_Size = 0;
+
+ } // endif n
+
+ } // endif len
+
+ break;
+ case INT_RESULT:
+ bigint = *(longlong*)sap;
+
+ if ((bigint == 0LL && !strcmp(args->attributes[i], "FALSE")) ||
+ (bigint == 1LL && !strcmp(args->attributes[i], "TRUE")))
+ doc.SetBool(bvp, (bool)bigint);
+ else
+ doc.SetBigint(g, bvp, bigint);
+
+ break;
+ case REAL_RESULT:
+ doc.SetFloat(bvp, *(double*)sap);
+ break;
+ case DECIMAL_RESULT:
+ doc.SetFloat(bvp, atof(MakePSZ(g, args, i)));
+ break;
+ case TIME_RESULT:
+ case ROW_RESULT:
+ default:
+ bvp = NULL;
+ break;
+ } // endswitch arg_type
+
+ return bvp;
+} // end of MakeBinValue
+
+/*********************************************************************************/
+/* Test BJSON parse and serialize. */
+/*********************************************************************************/
+my_bool json_test_bson_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
+ unsigned long reslen, memlen, more = 1000;
+
+ if (args->arg_count == 0) {
+ strcpy(message, "At least 1 argument required (json)");
+ 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);
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of json_test_bson_init
+
+char* json_test_bson(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long* res_length, char* is_null, char* error) {
+ char* str = NULL, * sap = NULL, * fn = NULL;
+ int pretty = 1;
+ PBVAL bvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ BDOC doc(g);
+
+ 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, !g->Xchk)) {
+ PUSH_WARNING("CheckMemory error");
+ *error = 1;
+ goto err;
+ } else if (!(bvp = MakeBinValue(g, args, 0))) {
+ PUSH_WARNING(g->Message);
+ goto err;
+ } // endif bvp
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = bvp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ bvp = (PBVAL)g->Xchk;
+
+ for (uint i = 1; i < args->arg_count; i++)
+ if (args->arg_type[i] == STRING_RESULT)
+ fn = args->args[i];
+ else if (args->arg_type[i] == INT_RESULT)
+ pretty = (int)*(longlong*)args->args[i];
+
+ // Serialize the parse tree
+ str = doc.Serialize(g, bvp, fn, pretty);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)str;
+
+ } catch (int n) {
+ xtrc(1, "json_test_bson: error %d: %s\n", n, g->Message);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ str = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ str = NULL;
+ } // end catch
+
+err:
+ if (!str) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of json_test_bson
+
+void json_test_bson_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_test_bson_deinit
+
+/*********************************************************************************/
+/* Locate a value in a Json tree. */
+/*********************************************************************************/
+my_bool jsonlocate_bson_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;
+ } // endifs args
+
+ 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_bson_init
+
+char* jsonlocate_bson(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long* res_length, char* is_null, char* error) {
+ char* path = NULL;
+ int k;
+ PBVAL bvp, bvp2;
+ PBJNX bnxp;
+ 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
+ bvp = MakeBinValue(g, args, 0);
+
+ if (!bvp) {
+ PUSH_WARNING("First argument is not a valid JSON item");
+ goto err;
+ } // endif bvp
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = bvp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ bvp = (PBVAL)g->Xchk;
+
+ // The item to locate
+ bvp2 = MakeBinValue(g, args, 1);
+
+ k = (args->arg_count > 2) ? (int)*(long long*)args->args[2] : 1;
+
+ bnxp = new(g) BJNX(g, bvp, TYPE_STRING);
+ path = bnxp->Locate(g, bvp, bvp2, k);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)path;
+
+ } catch (int n) {
+ xtrc(1, "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_bson
+
+void jsonlocate_bson_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jsonlocate_bson_deinit
+
+/*********************************************************************************/
+/* Locate all occurences of a value in a Json tree. */
+/*********************************************************************************/
+my_bool json_locate_all_bson_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;
+ } // endifs
+
+ 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_bson_init
+
+char* json_locate_all_bson(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long* res_length, char* is_null, char* error) {
+ char* path = NULL;
+ int mx = 10;
+ PBVAL bvp, bvp2;
+ PBJNX bnxp;
+ 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
+ bvp = MakeBinValue(g, args, 0);
+
+ if (!bvp) {
+ PUSH_WARNING("First argument is not a valid JSON item");
+ goto err;
+ } // endif bvp
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = bvp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ bvp = (PBVAL)g->Xchk;
+
+ // The item to locate
+ bvp2 = MakeBinValue(g, args, 1);
+
+ if (args->arg_count > 2)
+ mx = (int)*(long long*)args->args[2];
+
+ bnxp = new(g) BJNX(g, bvp, TYPE_STRING);
+ path = bnxp->LocateAll(g, bvp, bvp2, mx);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)path;
+
+ } catch (int n) {
+ xtrc(1, "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_bson
+
+void json_locate_all_bson_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_locate_all_bson_deinit
+
diff --git a/storage/connect/bsonudf.h b/storage/connect/bsonudf.h
new file mode 100644
index 00000000000..6687d4c1640
--- /dev/null
+++ b/storage/connect/bsonudf.h
@@ -0,0 +1,98 @@
+/******************** tabjson H Declares Source Code File (.H) *******************/
+/* Name: bsonudf.h Version 1.0 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2020 */
+/* */
+/* This file contains the BSON UDF function and class declares. */
+/*********************************************************************************/
+#pragma once
+#include "jsonudf.h"
+#include "bson.h"
+
+/* --------------------------- New Testing BJSON Stuff --------------------------*/
+
+typedef class BJNX* PBJNX;
+
+/*********************************************************************************/
+/* Class BJNX: BJSON access methods. */
+/*********************************************************************************/
+class BJNX : public BDOC {
+public:
+ // Constructors
+ BJNX(PGLOBAL g, PBVAL row, int type, int len = 64, int prec = 0, my_bool wr = false);
+
+ // Implementation
+ int GetPrecision(void) { return Prec; }
+ PVAL GetValue(void) { return Value; }
+
+ // Methods
+ my_bool SetJpath(PGLOBAL g, char* path, my_bool jb = false);
+ my_bool ParseJpath(PGLOBAL g);
+ void ReadValue(PGLOBAL g);
+ PBVAL GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b = true);
+ PBVAL GetJson(PGLOBAL g);
+ my_bool CheckPath(PGLOBAL g);
+ my_bool WriteValue(PGLOBAL g, PBVAL jvalp);
+ char* Locate(PGLOBAL g, PBVAL jsp, PBVAL jvp, int k = 1);
+ char* LocateAll(PGLOBAL g, PBVAL jsp, PBVAL jvp, int mx = 10);
+
+protected:
+ my_bool SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm);
+ PVAL GetColumnValue(PGLOBAL g, PBVAL row, int i);
+ PVAL ExpandArray(PGLOBAL g, PBVAL arp, int n);
+ PVAL CalculateArray(PGLOBAL g, PBVAL arp, int n);
+ PVAL MakeJson(PGLOBAL g, PBVAL bvp);
+ void SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp);
+ PBVAL GetRow(PGLOBAL g);
+ my_bool CompareValues(PGLOBAL g, PBVAL v1, PBVAL v2);
+ my_bool LocateArray(PGLOBAL g, PBVAL jarp);
+ my_bool LocateObject(PGLOBAL g, PBPR jobp);
+ my_bool LocateValue(PGLOBAL g, PBVAL jvp);
+ my_bool LocateArrayAll(PGLOBAL g, PBVAL jarp);
+ my_bool LocateObjectAll(PGLOBAL g, PBPR jobp);
+ my_bool LocateValueAll(PGLOBAL g, PBVAL jvp);
+ my_bool CompareTree(PGLOBAL g, PBVAL jp1, PBVAL jp2);
+ my_bool AddPath(void);
+
+ // Default constructor not to be used
+ BJNX(void) {}
+
+ // Members
+ PBVAL Row;
+ PBVAL Bvalp;
+ PJPN Jpnp;
+ JOUTSTR *Jp;
+ JNODE *Nodes; // The intermediate objects
+ PVAL Value;
+ PVAL MulVal; // To value used by multiple column
+ char *Jpath; // The json path
+ int Buf_Type;
+ int Long;
+ int Prec;
+ int Nod; // The number of intermediate objects
+ int Xnod; // Index of multiple values
+ int K; // Kth item to locate
+ int I; // Index of JPN
+ int Imax; // Max number of JPN's
+ int B; // Index base
+ my_bool Xpd; // True for expandable column
+ my_bool Parsed; // True when parsed
+ my_bool Found; // Item found by locate
+ my_bool Wr; // Write mode
+ my_bool Jb; // Must return json item
+}; // end of class BJNX
+
+extern "C" {
+ DllExport my_bool json_test_bson_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* json_test_bson(UDF_EXEC_ARGS);
+ DllExport void json_test_bson_deinit(UDF_INIT*);
+
+ DllExport my_bool jsonlocate_bson_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* jsonlocate_bson(UDF_EXEC_ARGS);
+ DllExport void jsonlocate_bson_deinit(UDF_INIT*);
+
+ DllExport my_bool json_locate_all_bson_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* json_locate_all_bson(UDF_EXEC_ARGS);
+ DllExport void json_locate_all_bson_deinit(UDF_INIT*);
+} // extern "C"
+
diff --git a/storage/connect/json.h b/storage/connect/json.h
index 5ba4d7b3dbd..3a026f5df22 100644
--- a/storage/connect/json.h
+++ b/storage/connect/json.h
@@ -5,6 +5,7 @@
/* */
/* This file contains the JSON classes declares. */
/***********************************************************************/
+#pragma once
#include <mysql_com.h>
#include "value.h"
#include "xobject.h"
diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp
index 0012b3d6bdd..cb29b9f5d6c 100644
--- a/storage/connect/jsonudf.cpp
+++ b/storage/connect/jsonudf.cpp
@@ -27,12 +27,6 @@
#endif
#define M 9
-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,
@@ -1180,7 +1174,7 @@ static uint GetJsonGroupSize(void)
/*********************************************************************************/
/* Program for SubSet re-initialization of the memory pool. */
/*********************************************************************************/
-static my_bool JsonSubSet(PGLOBAL g)
+my_bool JsonSubSet(PGLOBAL g)
{
PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
@@ -1277,10 +1271,8 @@ static PJVAL JvalNew(PGLOBAL g, JTYP type, void *vp)
/*********************************************************************************/
/* 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)
+my_bool JsonInit(UDF_INIT *initid, UDF_ARGS *args, char *message, my_bool mbn,
+ unsigned long reslen, unsigned long memlen, unsigned long more)
{
PGLOBAL g = PlugInit(NULL, (size_t)memlen + more + 500); // +500 to avoid CheckMem
@@ -1443,7 +1435,7 @@ static int *GetIntArgPtr(PGLOBAL g, UDF_ARGS *args, uint& n)
/*********************************************************************************/
/* Returns not 0 if the argument is a JSON item or file name. */
/*********************************************************************************/
-static int IsJson(UDF_ARGS *args, uint i, bool b)
+int IsJson(UDF_ARGS *args, uint i, bool b)
{
int n = 0;
@@ -1510,9 +1502,8 @@ static long GetFileLength(char *fn)
/*********************************************************************************/
/* 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)
+my_bool CalcLen(UDF_ARGS *args, my_bool obj, unsigned long& reslen,
+ unsigned long& memlen, my_bool mod)
{
char fn[_MAX_PATH];
unsigned long i, k, m, n;
@@ -1629,8 +1620,8 @@ static my_bool CalcLen(UDF_ARGS *args, my_bool obj,
/*********************************************************************************/
/* 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)
+my_bool CheckMemory(PGLOBAL g, UDF_INIT *initid, UDF_ARGS *args, uint n,
+ my_bool m, my_bool obj, my_bool mod)
{
unsigned long rl, ml;
my_bool b = false;
@@ -1682,7 +1673,7 @@ static my_bool CheckMemory(PGLOBAL g, UDF_INIT *initid, UDF_ARGS *args, uint n,
/*********************************************************************************/
/* Make a zero terminated string from the passed argument. */
/*********************************************************************************/
-static PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i)
+PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i)
{
if (args->arg_count > (unsigned)i && args->args[i]) {
int n = args->lengths[i];
@@ -1807,7 +1798,7 @@ static PJSON ParseJsonFile(PGLOBAL g, char *fn, int *pretty, size_t& len)
/*********************************************************************************/
/* Return a json file contains. */
/*********************************************************************************/
-static char *GetJsonFile(PGLOBAL g, char *fn)
+char *GetJsonFile(PGLOBAL g, char *fn)
{
char *str;
int h, n, len;
@@ -6559,1476 +6550,3 @@ long long countin(UDF_INIT *initid, UDF_ARGS *args, char *result,
free(str2);
return n;
} // end of countin
-
-/* --------------------------- New Testing BJSON Stuff --------------------------*/
-
-/*********************************************************************************/
-/* SubAlloc a new BJNX class with protection against memory exhaustion. */
-/*********************************************************************************/
-static PBJNX BjnxNew(PGLOBAL g, PBVAL vlp, int type, int len) {
- PBJNX bjnx;
-
- try {
- bjnx = new(g) BJNX(g, vlp, type, len);
- } catch (...) {
- if (trace(1023))
- htrc("%s\n", g->Message);
-
- PUSH_WARNING(g->Message);
- bjnx = NULL;
- } // end try/catch
-
- return bjnx;
-} /* end of BjnxNew */
-
-/* ----------------------------------- BSNX ------------------------------------ */
-
-/*********************************************************************************/
-/* BSNX public constructor. */
-/*********************************************************************************/
-BJNX::BJNX(PGLOBAL g, PBVAL row, int type, int len, int prec, my_bool wr)
- : BDOC(g->Sarea)
-{
- Row = row;
- Bvalp = NULL;
- Jpnp = NULL;
- Jp = NULL;
- Nodes = NULL;
- Value = AllocateValue(g, type, len, prec);
- MulVal = NULL;
- Jpath = NULL;
- Buf_Type = type;
- Long = len;
- Prec = prec;
- Nod = 0;
- Xnod = -1;
- K = 0;
- I = -1;
- Imax = 9;
- B = 0;
- Xpd = false;
- Parsed = false;
- Found = false;
- Wr = wr;
- Jb = false;
-} // end of BJNX constructor
-
-/*********************************************************************************/
-/* SetJpath: set and parse the json path. */
-/*********************************************************************************/
-my_bool BJNX::SetJpath(PGLOBAL g, char* path, my_bool jb) {
- // Check Value was allocated
- if (!Value)
- 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 BJNX::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 BJNX::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 BJNX::MakeJson(PGLOBAL g, PBVAL bvp) {
- if (Value->IsTypeNum()) {
- strcpy(g->Message, "Cannot make Json for a numeric value");
- Value->Reset();
- } else if (bvp->Type != TYPE_JAR && bvp->Type != TYPE_JOB) {
- strcpy(g->Message, "Target is not an array or object");
- Value->Reset();
- } else
- Value->SetValue_psz(Serialize(g, bvp, NULL, 0));
-
- return Value;
-} // end of MakeJson
-
-/*********************************************************************************/
-/* SetValue: Set a value from a JVALUE contains. */
-/*********************************************************************************/
-void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp) {
- if (vlp) {
- vp->SetNull(false);
-
- if (Jb) {
- vp->SetValue_psz(Serialize(g, vlp, NULL, 0));
- } else switch (vlp->Type) {
- case TYPE_DTM:
- case TYPE_STRG:
- vp->SetValue_psz(GetString(g, vlp));
- break;
- case TYPE_INTG:
- case TYPE_BINT:
- vp->SetValue(GetInteger(vlp));
- break;
- case TYPE_DBL:
- if (vp->IsTypeNum())
- vp->SetValue(GetDouble(vlp));
- else // Get the proper number of decimals
- vp->SetValue_psz(GetString(g, vlp));
-
- break;
- case TYPE_BOOL:
- if (vp->IsTypeNum())
- vp->SetValue(GetInteger(vlp) ? 1 : 0);
- else
- vp->SetValue_psz(GetString(g, vlp));
-
- break;
- case TYPE_JAR:
- vp->SetValue_psz(GetArrayText(g, MVP(vlp->To_Val), NULL));
- break;
- case TYPE_JOB:
- vp->SetValue_psz(GetObjectText(g, MPP(vlp->To_Val), NULL));
- break;
- case TYPE_NULL:
- vp->SetNull(true);
- default:
- vp->Reset();
- } // endswitch Type
-
- } else {
- vp->SetNull(true);
- vp->Reset();
- } // endif val
-
-} // end of SetJsonValue
-
-/*********************************************************************************/
-/* GetJson: */
-/*********************************************************************************/
-PBVAL BJNX::GetJson(PGLOBAL g) {
- return GetRowValue(g, Row, 0);
-} // end of GetJson
-
-/*********************************************************************************/
-/* ReadValue: */
-/*********************************************************************************/
-void BJNX::ReadValue(PGLOBAL g) {
- Value->SetValue_pval(GetColumnValue(g, Row, 0));
-} // end of ReadValue
-
-/*********************************************************************************/
-/* GetColumnValue: */
-/*********************************************************************************/
-PVAL BJNX::GetColumnValue(PGLOBAL g, PBVAL row, int i) {
- PBVAL vlp = GetRowValue(g, row, i);
-
- SetJsonValue(g, Value, vlp);
- return Value;
-} // end of GetColumnValue
-
-/*********************************************************************************/
-/* GetRowValue: */
-/*********************************************************************************/
-PBVAL BJNX::GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b) {
- my_bool expd = false;
- PBVAL bap;
- PBVAL vlp = NULL;
-
- for (; i < Nod && row; i++) {
- if (Nodes[i].Op == OP_NUM) {
- Value->SetValue(row->Type == TYPE_JAR ? GetArraySize(MVP(row->To_Val)) : 1);
- vlp = SubAllocVal(g, Value);
- return vlp;
- } else if (Nodes[i].Op == OP_XX) {
- Jb = b;
-// return DupVal(g, row);
- return row; // or last line ???
- } else switch (row->Type) {
- case TYPE_JOB:
- if (!Nodes[i].Key) {
- // Expected Array was not there
- if (Nodes[i].Op == OP_LE) {
- if (i < Nod - 1)
- continue;
- else
- vlp = row; // DupVal(g, row) ???
-
- } else {
- strcpy(g->Message, "Unexpected object");
- vlp = NULL;
- } //endif Op
-
- } else
- vlp = GetKeyValue(MPP(row->To_Val), Nodes[i].Key);
-
- break;
- case TYPE_JAR:
- bap = MVP(row->To_Val);
-
- if (!Nodes[i].Key) {
- if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
- vlp = GetArrayValue(bap, Nodes[i].Rank);
- else if (Nodes[i].Op == OP_EXP)
- return (PBVAL)ExpandArray(g, bap, i);
- else
- return SubAllocVal(g, CalculateArray(g, bap, i));
-
- } else {
- // Unexpected array, unwrap it as [0]
- vlp = GetArrayValue(bap, 0);
- i--;
- } // endif's
-
- break;
- case TYPE_JVAL:
- vlp = row;
- break;
- default:
- sprintf(g->Message, "Invalid row JSON type %d", row->Type);
- vlp = NULL;
- } // endswitch Type
-
- row = vlp;
- } // endfor i
-
- return vlp;
-} // end of GetRowValue
-
-/*********************************************************************************/
-/* ExpandArray: */
-/*********************************************************************************/
-PVAL BJNX::ExpandArray(PGLOBAL g, PBVAL arp, int n)
-{
- strcpy(g->Message, "Expand cannot be done by this function");
- return NULL;
-} // end of ExpandArray
-
-/*********************************************************************************/
-/* CalculateArray: NIY */
-/*********************************************************************************/
-PVAL BJNX::CalculateArray(PGLOBAL g, PBVAL bap, int n)
-{
-#if 0
- int i, ars = GetArraySize(bap), nv = 0;
- bool err;
- OPVAL op = Nodes[n].Op;
- PVAL val[2], vp = Nodes[n].Valp;
- PBVAL bvrp, bvp;
- BVAL bval;
-
- vp->Reset();
- xtrc(1,"CalculateArray size=%d op=%d\n", ars, op);
-
- for (i = 0; i < ars; i++) {
- bvrp = GetArrayValue(bap, i);
- xtrc(1, "i=%d nv=%d\n", i, nv);
-
- if (!IsValueNull(bvrp) || (op == OP_CNC && GetJsonNull())) {
- if (IsValueNull(bvrp)) {
- SetString(bvrp, GetJsonNull(), 0);
- bvp = bvrp;
- } else if (n < Nod - 1 && bvrp->GetJson()) {
- bval.SetValue(g, GetColumnValue(g, jvrp->GetJson(), n + 1));
- bvp = &bval;
- } 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);
- continue;
- } else
- SetJsonValue(g, MulVal, jvp);
-
- 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;
-#else
- strcpy(g->Message, "Calculate array NIY");
- return NULL;
-#endif
-} // end of CalculateArray
-
-/*********************************************************************************/
-/* CheckPath: Checks whether the path exists in the document. */
-/*********************************************************************************/
-my_bool BJNX::CheckPath(PGLOBAL g) {
- PBVAL val = NULL;
- PBVAL row = Row;
-
- for (int i = 0; i < Nod && row; i++) {
- val = NULL;
-
- if (Nodes[i].Op == OP_NUM || Nodes[i].Op == OP_XX) {
- } else switch (row->Type) {
- case TYPE_JOB:
- if (Nodes[i].Key)
- val = GetKeyValue(MPP(row->To_Val), Nodes[i].Key);
-
- break;
- case TYPE_JAR:
- if (!Nodes[i].Key)
- if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
- val = GetArrayValue(MVP(row->To_Val), Nodes[i].Rank);
-
- break;
- case TYPE_JVAL:
- val = MVP(row->To_Val);
- break;
- default:
- sprintf(g->Message, "Invalid row JSON type %d", row->Type);
- } // endswitch Type
-
-// if (i < Nod - 1)
-// if (!(row = (val) ? val->GetJsp() : NULL))
-// val = NULL;
-
- row = val;
- } // endfor i
-
- return (val != NULL);
-} // end of CheckPath
-
-/***********************************************************************/
-/* GetRow: Set the complete path of the object to be set. */
-/***********************************************************************/
-PBVAL BJNX::GetRow(PGLOBAL g) {
- PBVAL val = NULL;
- PBVAL arp;
- PBVAL nwr, row = Row;
-
- for (int i = 0; i < Nod - 1 && row; i++) {
- if (Nodes[i].Op == OP_XX)
- break;
- else switch (row->Type) {
- case TYPE_JOB:
- if (!Nodes[i].Key)
- // Expected Array was not there, wrap the value
- continue;
-
- val = GetKeyValue(MPP(row->To_Val), Nodes[i].Key);
- break;
- case TYPE_JAR:
- arp = MVP(row->To_Val);
-
- if (!Nodes[i].Key) {
- if (Nodes[i].Op == OP_EQ)
- val = GetArrayValue(arp, Nodes[i].Rank);
- else
- val = GetArrayValue(arp, Nodes[i].Rx);
-
- } else {
- // Unexpected array, unwrap it as [0]
- val = GetArrayValue(arp, 0);
- i--;
- } // endif Nodes
-
- break;
- case TYPE_JVAL:
- val = MVP(row->To_Val);
- break;
- default:
- sprintf(g->Message, "Invalid row JSON type %d", row->Type);
- val = NULL;
- } // endswitch Type
-
- if (val) {
- row = val;
- } else {
- // Construct missing objects
- for (i++; row && i < Nod; i++) {
- if (Nodes[i].Op == OP_XX)
- break;
-// else if (!Nodes[i].Key)
- // Construct intermediate array
-// nwr = SubAllocVal(g);
-// else
-// nwr = SubAllocPair(g);
-
- // Construct new row
- nwr = SubAllocVal(g);
-
- if (row->Type == TYPE_JOB) {
- SetKeyValue(g, MPP(row->To_Val), MOF(nwr), Nodes[i - 1].Key);
- } else if (row->Type == TYPE_JAR) {
- AddArrayValue(g, MVP(row->To_Val), nwr);
- } 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 BJNX::WriteValue(PGLOBAL g, PBVAL jvalp) {
- PBPR objp = NULL;
- PBVAL arp = NULL;
- PBVAL jvp = NULL;
- PBVAL row = GetRow(g);
-
- if (!row)
- return true;
-
- switch (row->Type) {
- case TYPE_JOB: objp = MPP(row->To_Val); break;
- case TYPE_JAR: arp = MVP(row->To_Val); break;
- case TYPE_JVAL: jvp = MVP(row->To_Val); 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)
- SetArrayValue(g, arp, jvalp, Nodes[Nod - 1].Rank);
- else
- AddArrayValue(g, arp, jvalp);
-
- } // endif Key
-
- } else if (objp) {
- if (Nodes[Nod - 1].Key)
- SetKeyValue(g, objp, MOF(jvalp), Nodes[Nod - 1].Key);
-
- } else if (jvp)
- SetValueVal(jvp, jvalp);
-
- return false;
-} // end of WriteValue
-
-/*********************************************************************************/
-/* Locate a value in a JSON tree: */
-/*********************************************************************************/
-PSZ BJNX::Locate(PGLOBAL g, PBVAL jsp, PBVAL 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('$');
- Bvalp = jvp;
- K = k;
-
- switch (jsp->Type) {
- case TYPE_JAR:
- err = LocateArray(g, MVP(jsp->To_Val));
- break;
- case TYPE_JOB:
- err = LocateObject(g, MPP(jsp->To_Val));
- break;
- case TYPE_JVAL:
- err = LocateValue(g, MVP(jsp->To_Val));
- 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 BJNX::LocateArray(PGLOBAL g, PBVAL jarp) {
- char s[16];
- int n = GetArraySize(jarp);
- size_t m = Jp->N;
-
- for (int i = 0; i < n && !Found; i++) {
- Jp->N = m;
- sprintf(s, "[%d]", i + B);
-
- if (Jp->WriteStr(s))
- return true;
-
- if (LocateValue(g, GetArrayValue(jarp, i)))
- return true;
-
- } // endfor i
-
- return false;
-} // end of LocateArray
-
-/*********************************************************************************/
-/* Locate in a JSON Object. */
-/*********************************************************************************/
-my_bool BJNX::LocateObject(PGLOBAL g, PBPR jobp) {
- size_t m;
-
- if (Jp->WriteChr('.'))
- return true;
-
- m = Jp->N;
-
- for (PBPR pair = jobp; pair && !Found; pair = MPP(pair->Next)) {
- Jp->N = m;
-
- if (Jp->WriteStr(MZP(pair->Key)))
- return true;
-
- if (LocateValue(g, MVP(pair->Vlp)))
- return true;
-
- } // endfor i
-
- return false;
-} // end of LocateObject
-
-/*********************************************************************************/
-/* Locate a JSON Value. */
-/*********************************************************************************/
-my_bool BJNX::LocateValue(PGLOBAL g, PBVAL jvp)
-{
- if (CompareTree(g, Bvalp, jvp))
- Found = (--K == 0);
- else if (jvp->Type == TYPE_JAR)
- return LocateArray(g, GetArray(jvp));
- else if (jvp->Type == TYPE_JOB)
- return LocateObject(g, GetObject(jvp));
-
- return false;
-} // end of LocateValue
-
-/*********************************************************************************/
-/* Locate all occurrences of a value in a JSON tree: */
-/*********************************************************************************/
-PSZ BJNX::LocateAll(PGLOBAL g, PBVAL jsp, PBVAL bvp, int mx)
-{
- PSZ str = NULL;
- my_bool 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);
- Bvalp = bvp;
- Imax = mx - 1;
- Jpnp = jnp;
- Jp->WriteChr('[');
-
- switch (jsp->Type) {
- case TYPE_JAR:
- err = LocateArrayAll(g, MVP(jsp->To_Val));
- break;
- case TYPE_JOB:
- err = LocateObjectAll(g, MPP(jsp->To_Val));
- break;
- case TYPE_JVAL:
- err = LocateValueAll(g, MVP(jsp->To_Val));
- break;
- default:
- err = LocateValueAll(g, jsp);
- } // 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) {
- xtrc(1, "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 BJNX::LocateArrayAll(PGLOBAL g, PBVAL jarp)
-{
- int i = 0;
-
- if (I < Imax) {
- Jpnp[++I].Type = TYPE_JAR;
-
- for (PBVAL vp = jarp; vp; vp = MVP(vp->Next)) {
- Jpnp[I].N = i;
-
- if (LocateValueAll(g, GetArrayValue(jarp, i)))
- return true;
-
- i++;
- } // endfor i
-
- I--;
- } // endif I
-
- return false;
-} // end of LocateArrayAll
-
-/*********************************************************************************/
-/* Locate in a JSON Object. */
-/*********************************************************************************/
-my_bool BJNX::LocateObjectAll(PGLOBAL g, PBPR jobp)
-{
- if (I < Imax) {
- Jpnp[++I].Type = TYPE_JOB;
-
- for (PBPR pair = jobp; pair; pair = MPP(pair->Next)) {
- Jpnp[I].Key = MZP(pair->Key);
-
- if (LocateValueAll(g, MVP(pair->Vlp)))
- return true;
-
- } // endfor i
-
- I--;
- } // endif I
-
- return false;
-} // end of LocateObjectAll
-
-/*********************************************************************************/
-/* Locate a JSON Value. */
-/*********************************************************************************/
-my_bool BJNX::LocateValueAll(PGLOBAL g, PBVAL jvp) {
- if (CompareTree(g, Bvalp, jvp))
- return AddPath();
- else if (jvp->Type == TYPE_JAR)
- return LocateArrayAll(g, GetArray(jvp));
- else if (jvp->Type == TYPE_JOB)
- return LocateObjectAll(g, GetObject(jvp));
-
- return false;
-} // end of LocateValueAll
-
-/*********************************************************************************/
-/* Compare two JSON trees. */
-/*********************************************************************************/
-my_bool BJNX::CompareTree(PGLOBAL g, PBVAL jp1, PBVAL jp2)
-{
- if (!jp1 || !jp2 || jp1->Type != jp2->Type || GetSize(jp1) != GetSize(jp2))
- return false;
-
- my_bool found = true;
-
- if (jp1->Type == TYPE_JAR) {
- for (int i = 0; found && i < GetArraySize(jp1); i++)
- found = (CompareValues(g, GetArrayValue(jp1, i), GetArrayValue(jp2, i)));
-
- } else if (jp1->Type == TYPE_JOB) {
- PBPR p1 = MPP(jp1->To_Val), p2 = MPP(jp2->To_Val);
-
- // Keys can be differently ordered
- for (; found && p1 && p2; p1 = MPP(p1->Next))
- found = CompareValues(g, MVP(p1->Vlp), GetKeyValue(p2, MZP(p1->Key)));
-
- } else if (jp1->Type == TYPE_JVAL) {
- found = CompareTree(g, MVP(jp1->To_Val), (MVP(jp2->To_Val)));
- } else
- found = CompareValues(g, jp1, jp2);
-
- return found;
-} // end of CompareTree
-
-/*********************************************************************************/
-/* Compare two VAL values and return true if they are equal. */
-/*********************************************************************************/
-my_bool BJNX::CompareValues(PGLOBAL g, PBVAL v1, PBVAL v2)
-{
- my_bool b = false;
-
- if (v1 && v2)
- switch (v1->Type) {
- case TYPE_JAR:
- if (v2->Type == TYPE_JAR)
- b = CompareTree(g, MVP(v1->To_Val), MVP(v2->To_Val));
-
- break;
- case TYPE_STRG:
- if (v2->Type == TYPE_STRG) {
- if (v1->Nd || v2->Nd) // Case insensitive
- b = (!stricmp(MZP(v1->To_Val), MZP(v2->To_Val)));
- else
- b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
-
- } // endif Type
-
- break;
- case TYPE_DTM:
- if (v2->Type == TYPE_DTM)
- b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
-
- break;
- case TYPE_INTG:
- if (v2->Type == TYPE_INTG)
- b = (v1->N == v2->N);
- else if (v2->Type == TYPE_BINT)
- b = ((longlong)v1->N == LLN(v2->To_Val));
-
- break;
- case TYPE_BINT:
- if (v2->Type == TYPE_INTG)
- b = (LLN(v1->To_Val) == (longlong)v2->N);
- else if (v2->Type == TYPE_BINT)
- b = (LLN(v1->To_Val) == LLN(v2->To_Val));
-
- break;
- case TYPE_FLOAT:
- if (v2->Type == TYPE_FLOAT)
- b = (v1->F == v2->F);
- else if (v2->Type == TYPE_DBL)
- b = ((double)v1->F == DBL(v2->To_Val));
-
- break;
- case TYPE_DBL:
- if (v2->Type == TYPE_DBL)
- b = (DBL(v1->To_Val) == DBL(v2->To_Val));
- else if (v2->Type == TYPE_FLOAT)
- b = (DBL(v1->To_Val) == (double)v2->F);
-
- break;
- case TYPE_BOOL:
- if (v2->Type == TYPE_BOOL)
- b = (v1->B == v2->B);
-
- break;
- case TYPE_NULL:
- b = (v2->Type == TYPE_NULL);
- break;
- default:
- break;
- } // endswitch Type
-
- else
- b = (!v1 && !v2);
-
- return b;
-} // end of CompareValues
-
-/*********************************************************************************/
-/* Add the found path to the list. */
-/*********************************************************************************/
-my_bool BJNX::AddPath(void) {
- char s[16];
-
- if (Jp->WriteStr("\"$"))
- 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
-
-/*********************************************************************************/
-/* Make a BVAL value from the passed argument. */
-/*********************************************************************************/
-static PBVAL MakeBinValue(PGLOBAL g, UDF_ARGS* args, uint i) {
- char* sap = (args->arg_count > i) ? args->args[i] : NULL;
- int n, len;
- int ci;
- longlong bigint;
- void* Base = g->Sarea; // Required by MOF
- BDOC doc(Base);
- PBVAL bp;
- PBVAL bvp = doc.SubAllocVal(g);
-
- 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 == 2) {
- if (!(sap = GetJsonFile(g, sap))) {
- PUSH_WARNING(g->Message);
- return NULL;
- } // endif sap
-
- len = strlen(sap);
- } // endif 2
-
- if (!(bp = doc.ParseJson(g, sap, strlen(sap))))
- PUSH_WARNING(g->Message);
-
- bvp = bp;
- } else {
- // Check whether this string is a valid json string
- JsonMemSave(g);
-
- if (!(bvp = doc.ParseJson(g, sap, strlen(sap)))) {
- // Recover suballocated memory
- JsonSubSet(g);
- ci = (strnicmp(args->attributes[i], "ci", 2)) ? 0 : 1;
- bvp = doc.SubAllocVal(g, MOF(sap), TYPE_STRG, ci);
- } else
- g->Saved_Size = 0;
-
- } // endif n
-
- } // endif len
-
- break;
- case INT_RESULT:
- bigint = *(longlong*)sap;
-
- if ((bigint == 0LL && !strcmp(args->attributes[i], "FALSE")) ||
- (bigint == 1LL && !strcmp(args->attributes[i], "TRUE")))
- doc.SetBool(bvp, (bool)bigint);
- else
- doc.SetBigint(g, bvp, bigint);
-
- break;
- case REAL_RESULT:
- doc.SetFloat(bvp, *(double*)sap);
- break;
- case DECIMAL_RESULT:
- doc.SetFloat(bvp, atof(MakePSZ(g, args, i)));
- break;
- case TIME_RESULT:
- case ROW_RESULT:
- default:
- bvp = NULL;
- break;
- } // endswitch arg_type
-
- return bvp;
-} // end of MakeBinValue
-
-/*********************************************************************************/
-/* Test BJSON parse and serialize. */
-/*********************************************************************************/
-my_bool json_test_bson_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
- unsigned long reslen, memlen, more = 1000;
-
- if (args->arg_count == 0) {
- strcpy(message, "At least 1 argument required (json)");
- 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);
-
- return JsonInit(initid, args, message, true, reslen, memlen, more);
-} // end of json_test_bson_init
-
-char* json_test_bson(UDF_INIT* initid, UDF_ARGS* args, char* result,
- unsigned long* res_length, char* is_null, char* error) {
- char* str = NULL, * sap = NULL, * fn = NULL;
- int pretty = 1;
- PBVAL bvp;
- PGLOBAL g = (PGLOBAL)initid->ptr;
- BDOC doc(g);
-
- 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, !g->Xchk)) {
- PUSH_WARNING("CheckMemory error");
- *error = 1;
- goto err;
- } else if (!(bvp = MakeBinValue(g, args, 0))) {
- PUSH_WARNING(g->Message);
- goto err;
- } // endif bvp
-
- if (g->Mrr) { // First argument is a constant
- g->Xchk = bvp;
- JsonMemSave(g);
- } // endif Mrr
-
- } else
- bvp = (PBVAL)g->Xchk;
-
- for (uint i = 1; i < args->arg_count; i++)
- if (args->arg_type[i] == STRING_RESULT)
- fn = args->args[i];
- else if (args->arg_type[i] == INT_RESULT)
- pretty = (int)*(longlong*)args->args[i];
-
- // Serialize the parse tree
- str = doc.Serialize(g, bvp, fn, pretty);
-
- if (initid->const_item)
- // Keep result of constant function
- g->Activityp = (PACTIVITY)str;
-
- } catch (int n) {
- xtrc(1, "json_test_bson: error %d: %s\n", n, g->Message);
- PUSH_WARNING(g->Message);
- *error = 1;
- str = NULL;
- } catch (const char* msg) {
- strcpy(g->Message, msg);
- PUSH_WARNING(g->Message);
- *error = 1;
- str = NULL;
- } // end catch
-
-err:
- if (!str) {
- *res_length = 0;
- *is_null = 1;
- } else
- *res_length = strlen(str);
-
- return str;
-} // end of json_test_bson
-
-void json_test_bson_deinit(UDF_INIT* initid) {
- JsonFreeMem((PGLOBAL)initid->ptr);
-} // end of json_test_bson_deinit
-
-/*********************************************************************************/
-/* Locate a value in a Json tree. */
-/*********************************************************************************/
-my_bool jsonlocate_bson_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;
- } // endifs args
-
- 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_bson_init
-
-char* jsonlocate_bson(UDF_INIT* initid, UDF_ARGS* args, char* result,
- unsigned long* res_length, char* is_null, char* error) {
- char* path = NULL;
- int k;
- PBVAL bvp, bvp2;
- PBJNX bnxp;
- 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
- bvp = MakeBinValue(g, args, 0);
-
- if (!bvp) {
- PUSH_WARNING("First argument is not a valid JSON item");
- goto err;
- } // endif bvp
-
- if (g->Mrr) { // First argument is a constant
- g->Xchk = bvp;
- JsonMemSave(g);
- } // endif Mrr
-
- } else
- bvp = (PBVAL)g->Xchk;
-
- // The item to locate
- bvp2 = MakeBinValue(g, args, 1);
-
- k = (args->arg_count > 2) ? (int)*(long long*)args->args[2] : 1;
-
- bnxp = new(g) BJNX(g, bvp, TYPE_STRING);
- path = bnxp->Locate(g, bvp, bvp2, k);
-
- if (initid->const_item)
- // Keep result of constant function
- g->Activityp = (PACTIVITY)path;
-
- } catch (int n) {
- xtrc(1, "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_bson
-
-void jsonlocate_bson_deinit(UDF_INIT* initid) {
- JsonFreeMem((PGLOBAL)initid->ptr);
-} // end of jsonlocate_bson_deinit
-
-/*********************************************************************************/
-/* Locate all occurences of a value in a Json tree. */
-/*********************************************************************************/
-my_bool json_locate_all_bson_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;
- } // endifs
-
- 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_bson_init
-
-char* json_locate_all_bson(UDF_INIT* initid, UDF_ARGS* args, char* result,
- unsigned long* res_length, char* is_null, char* error)
-{
- char *path = NULL;
- int mx = 10;
- PBVAL bvp, bvp2;
- PBJNX bnxp;
- 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
- bvp = MakeBinValue(g, args, 0);
-
- if (!bvp) {
- PUSH_WARNING("First argument is not a valid JSON item");
- goto err;
- } // endif bvp
-
- if (g->Mrr) { // First argument is a constant
- g->Xchk = bvp;
- JsonMemSave(g);
- } // endif Mrr
-
- } else
- bvp = (PBVAL)g->Xchk;
-
- // The item to locate
- bvp2 = MakeBinValue(g, args, 1);
-
- if (args->arg_count > 2)
- mx = (int)*(long long*)args->args[2];
-
- bnxp = new(g) BJNX(g, bvp, TYPE_STRING);
- path = bnxp->LocateAll(g, bvp, bvp2, mx);
-
- if (initid->const_item)
- // Keep result of constant function
- g->Activityp = (PACTIVITY)path;
-
- } catch (int n) {
- xtrc(1, "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_bson
-
-void json_locate_all_bson_deinit(UDF_INIT* initid) {
- JsonFreeMem((PGLOBAL)initid->ptr);
-} // end of json_locate_all_bson_deinit
-
diff --git a/storage/connect/jsonudf.h b/storage/connect/jsonudf.h
index 886f380d426..2a2b2cac20e 100644
--- a/storage/connect/jsonudf.h
+++ b/storage/connect/jsonudf.h
@@ -5,12 +5,13 @@
/* */
/* This file contains the JSON UDF function and class declares. */
/*********************************************************************************/
+#pragma once
#include "global.h"
#include "plgdbsem.h"
#include "block.h"
#include "osutil.h"
#include "maputil.h"
-#include "bson.h"
+#include "json.h"
#define UDF_EXEC_ARGS \
UDF_INIT*, UDF_ARGS*, char*, unsigned long*, char*, char*
@@ -51,6 +52,28 @@ typedef struct _jnode {
typedef class JSNX *PJSNX;
+/*********************************************************************************/
+/* The JSON tree node. Can be an Object or an Array. */
+/*********************************************************************************/
+bool IsNum(PSZ s);
+char *NextChr(PSZ s, char sep);
+char *GetJsonNull(void);
+uint GetJsonGrpSize(void);
+my_bool JsonSubSet(PGLOBAL g);
+my_bool CalcLen(UDF_ARGS* args, my_bool obj, unsigned long& reslen,
+ unsigned long& memlen, my_bool mod = false);
+my_bool JsonInit(UDF_INIT* initid, UDF_ARGS* args, char* message, my_bool mbn,
+ unsigned long reslen, unsigned long memlen,
+ unsigned long more = 0);
+my_bool CheckMemory(PGLOBAL g, UDF_INIT* initid, UDF_ARGS* args, uint n,
+ my_bool m, my_bool obj = false, my_bool mod = false);
+PSZ MakePSZ(PGLOBAL g, UDF_ARGS* args, int i);
+int IsJson(UDF_ARGS* args, uint i, bool b = false);
+char *GetJsonFile(PGLOBAL g, char* fn);
+
+/*********************************************************************************/
+/* The JSON UDF functions. */
+/*********************************************************************************/
extern "C" {
DllExport my_bool jsonvalue_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *jsonvalue(UDF_EXEC_ARGS);
@@ -272,16 +295,16 @@ extern "C" {
DllExport my_bool countin_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport long long countin(UDF_EXEC_ARGS);
-} // extern "C"
+} // extern "C"
/*********************************************************************************/
/* Structure JPN. Used to make the locate path. */
/*********************************************************************************/
typedef struct _jpn {
- enum JTYP Type;
- PCSZ Key;
- int N;
+ int Type;
+ PCSZ Key;
+ int N;
} JPN, *PJPN;
/*********************************************************************************/
@@ -386,91 +409,3 @@ public:
uint i;
int k, recl;
}; // end of class JUP
-
-
-/* --------------------------- New Testing BJSON Stuff --------------------------*/
-
-typedef class BJNX* PBJNX;
-
-/*********************************************************************************/
-/* Class BJNX: BJSON access methods. */
-/*********************************************************************************/
-class BJNX : public BDOC {
-public:
- // Constructors
- BJNX(PGLOBAL g, PBVAL row, int type, int len = 64, int prec = 0, my_bool wr = false);
-
- // Implementation
- int GetPrecision(void) { return Prec; }
- PVAL GetValue(void) { return Value; }
-
- // Methods
- my_bool SetJpath(PGLOBAL g, char* path, my_bool jb = false);
- my_bool ParseJpath(PGLOBAL g);
- void ReadValue(PGLOBAL g);
- PBVAL GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b = true);
- PBVAL GetJson(PGLOBAL g);
- my_bool CheckPath(PGLOBAL g);
- my_bool WriteValue(PGLOBAL g, PBVAL jvalp);
- char* Locate(PGLOBAL g, PBVAL jsp, PBVAL jvp, int k = 1);
- char* LocateAll(PGLOBAL g, PBVAL jsp, PBVAL jvp, int mx = 10);
-
-protected:
- my_bool SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm);
- PVAL GetColumnValue(PGLOBAL g, PBVAL row, int i);
- PVAL ExpandArray(PGLOBAL g, PBVAL arp, int n);
- PVAL CalculateArray(PGLOBAL g, PBVAL arp, int n);
- PVAL MakeJson(PGLOBAL g, PBVAL bvp);
- void SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp);
- PBVAL GetRow(PGLOBAL g);
- my_bool CompareValues(PGLOBAL g, PBVAL v1, PBVAL v2);
- my_bool LocateArray(PGLOBAL g, PBVAL jarp);
- my_bool LocateObject(PGLOBAL g, PBPR jobp);
- my_bool LocateValue(PGLOBAL g, PBVAL jvp);
- my_bool LocateArrayAll(PGLOBAL g, PBVAL jarp);
- my_bool LocateObjectAll(PGLOBAL g, PBPR jobp);
- my_bool LocateValueAll(PGLOBAL g, PBVAL jvp);
- my_bool CompareTree(PGLOBAL g, PBVAL jp1, PBVAL jp2);
- my_bool AddPath(void);
-
- // Default constructor not to be used
- BJNX(void) {}
-
- // Members
- PBVAL Row;
- PBVAL Bvalp;
- PJPN Jpnp;
- JOUTSTR* Jp;
- JNODE* Nodes; // The intermediate objects
- PVAL Value;
- PVAL MulVal; // To value used by multiple column
- char* Jpath; // The json path
- int Buf_Type;
- int Long;
- int Prec;
- int Nod; // The number of intermediate objects
- int Xnod; // Index of multiple values
- int K; // Kth item to locate
- int I; // Index of JPN
- int Imax; // Max number of JPN's
- int B; // Index base
- my_bool Xpd; // True for expandable column
- my_bool Parsed; // True when parsed
- my_bool Found; // Item found by locate
- my_bool Wr; // Write mode
- my_bool Jb; // Must return json item
-}; // end of class BJNX
-
-extern "C" {
-DllExport my_bool json_test_bson_init(UDF_INIT*, UDF_ARGS*, char*);
-DllExport char* json_test_bson(UDF_EXEC_ARGS);
-DllExport void json_test_bson_deinit(UDF_INIT*);
-
-DllExport my_bool jsonlocate_bson_init(UDF_INIT*, UDF_ARGS*, char*);
-DllExport char* jsonlocate_bson(UDF_EXEC_ARGS);
-DllExport void jsonlocate_bson_deinit(UDF_INIT*);
-
-DllExport my_bool json_locate_all_bson_init(UDF_INIT*, UDF_ARGS*, char*);
-DllExport char* json_locate_all_bson(UDF_EXEC_ARGS);
-DllExport void json_locate_all_bson_deinit(UDF_INIT*);
-} // extern "C"