diff options
author | Olivier Bertrand <bertrandop@gmail.com> | 2020-11-25 17:42:01 +0100 |
---|---|---|
committer | Olivier Bertrand <bertrandop@gmail.com> | 2020-11-25 17:42:01 +0100 |
commit | b656d3d333f6d8a28407e5e4b636cd142d757595 (patch) | |
tree | c52c3eb9ff5d5fff8a1baec96b4c36e5bf3a9485 /storage/connect | |
parent | dc8f914c383366d11b6a995ba184b99d5ec663cf (diff) | |
download | mariadb-git-b656d3d333f6d8a28407e5e4b636cd142d757595.tar.gz |
Desesperatly trying to stop compiling failures
Diffstat (limited to 'storage/connect')
-rw-r--r-- | storage/connect/bson.cpp | 20 | ||||
-rw-r--r-- | storage/connect/bson.h | 2 | ||||
-rw-r--r-- | storage/connect/bsonudf.cpp | 1507 | ||||
-rw-r--r-- | storage/connect/bsonudf.h | 98 | ||||
-rw-r--r-- | storage/connect/json.h | 1 | ||||
-rw-r--r-- | storage/connect/jsonudf.cpp | 1502 | ||||
-rw-r--r-- | storage/connect/jsonudf.h | 121 |
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" |