mariadb/storage/connect/bsonudf.cpp
Mikhail Chalov 2ff01e763e Fix insecure use of strcpy, strcat and sprintf in Connect
Old style C functions `strcpy()`, `strcat()` and `sprintf()` are vulnerable to
security issues due to lacking memory boundary checks. Replace these in the
Connect storage engine with safe new and/or custom functions such as
`snprintf()` `safe_strcpy()` and `safe_strcat()`.

With this change FlawFinder and other static security analyzers report 287
fewer findings.

All new code of the whole pull request, including one or several files that are
either new files or modified ones, are contributed under the BSD-new license. I
am contributing on behalf of my employer Amazon Web Services, Inc.
2023-05-12 15:37:00 +01:00

6221 lines
162 KiB
C++

/****************** bsonudf C++ Program Source Code File (.CPP) ******************/
/* PROGRAM NAME: bsonudf Version 1.0 */
/* (C) Copyright to the author Olivier BERTRAND 2020 - 2021 */
/* This program are the BSON User Defined Functions. */
/*********************************************************************************/
/*********************************************************************************/
/* Include relevant sections of the MariaDB header file. */
/*********************************************************************************/
#include <my_global.h>
#include <mysqld.h>
#include <mysql.h>
#include <sql_error.h>
#include <stdio.h>
#include <cassert>
#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 6
int JsonDefPrec = -1;
int GetDefaultPrec(void);
int IsArgJson(UDF_ARGS* args, uint i);
void SetChanged(PBSON bsp);
int GetJsonDefPrec(void);
static PBSON BbinAlloc(PGLOBAL g, ulong len, PBVAL jsp);
/* --------------------------------- JSON UDF ---------------------------------- */
/*********************************************************************************/
/* Replaces GetJsonGrpSize not usable when CONNECT is not installed. */
/*********************************************************************************/
int GetJsonDefPrec(void) {
return (JsonDefPrec < 0) ? GetDefaultPrec() : JsonDefPrec;
} /* end of GetJsonDefPrec */
/*********************************************************************************/
/* Program for saving the status of the memory pools. */
/*********************************************************************************/
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;
g = PlugExit(g);
} /* end of JsonFreeMem */
/*********************************************************************************/
/* Allocate and initialize a BSON structure. */
/*********************************************************************************/
static PBSON BbinAlloc(PGLOBAL g, ulong len, PBVAL jsp)
{
PBSON bsp = (PBSON)PlgDBSubAlloc(g, NULL, sizeof(BSON));
if (bsp) {
snprintf(bsp->Msg, sizeof(bsp->Msg), "Binary Json");
bsp->Msg[BMX] = 0;
bsp->Filename = NULL;
bsp->G = g;
bsp->Pretty = 2;
bsp->Reslen = len;
bsp->Changed = false;
bsp->Top = bsp->Jsp = (PJSON)jsp;
bsp->Bsp = NULL;
} else
PUSH_WARNING(g->Message);
return bsp;
} /* end of BbinAlloc */
/* --------------------------- 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) : BDOC(g)
{
Row = NULL;
Bvalp = NULL;
Jpnp = NULL;
Jp = NULL;
Nodes = NULL;
Value = NULL;
//MulVal = NULL;
Jpath = NULL;
Buf_Type = TYPE_STRING;
Long = len;
Prec = 0;
Nod = 0;
Xnod = -1;
K = 0;
I = -1;
Imax = 9;
B = 0;
Xpd = false;
Parsed = false;
Found = false;
Wr = false;
Jb = false;
Changed = false;
Throw = false;
} // end of BJNX constructor
/*********************************************************************************/
/* BSNX public constructor. */
/*********************************************************************************/
BJNX::BJNX(PGLOBAL g, PBVAL row, int type, int len, int prec, my_bool wr) : BDOC(g)
{
Row = row;
Bvalp = NULL;
Jpnp = NULL;
Jp = NULL;
Nodes = NULL;
Value = AllocateValue(g, type, len, prec);
//MulVal = NULL;
Jpath = NULL;
Buf_Type = type;
Long = len;
Prec = prec;
Nod = 0;
Xnod = -1;
K = 0;
I = -1;
Imax = 9;
B = 0;
Xpd = false;
Parsed = false;
Found = false;
Wr = wr;
Jb = false;
Changed = false;
Throw = false;
} // end of BJNX constructor
/*********************************************************************************/
/* SetJpath: set and parse the json path. */
/*********************************************************************************/
my_bool BJNX::SetJpath(PGLOBAL g, char* path, my_bool jb)
{
// Check Value was allocated
if (Value)
Value->SetNullable(true);
Jpath = path;
// Parse the json path
Parsed = false;
Nod = 0;
Jb = jb;
return ParseJpath(g);
} // end of SetJpath
/*********************************************************************************/
/* Analyse array processing options. */
/*********************************************************************************/
my_bool BJNX::SetArrayOptions(PGLOBAL g, char* p, int i, 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
snprintf(g->Message, sizeof(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) {
snprintf(g->Message, sizeof(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 '*': jnp->Op = OP_EXP; break;
default:
snprintf(g->Message, sizeof(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 {
snprintf(g->Message, sizeof(g->Message), "Wrong array specification");
return true;
} // endif's
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;
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) {
snprintf(g->Message, sizeof(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
/*********************************************************************************/
/* Make a valid key from the passed argument. */
/*********************************************************************************/
PSZ BJNX::MakeKey(UDF_ARGS *args, int i)
{
if (args->arg_count > (unsigned)i) {
int j = 0, n = args->attribute_lengths[i];
my_bool b; // true if attribute is zero terminated
PSZ p;
PCSZ s = args->attributes[i];
if (s && *s && (n || *s == '\'')) {
if ((b = (!n || !s[n])))
n = strlen(s);
if (IsArgJson(args, i))
j = (int)(strchr(s, '_') - s + 1);
if (j && n > j) {
s += j;
n -= j;
} else if (*s == '\'' && s[n-1] == '\'') {
s++;
n -= 2;
b = false;
} // endif *s
if (n < 1)
return NewStr((PSZ)"Key");
if (!b) {
p = (PSZ)BsonSubAlloc(n + 1);
memcpy(p, s, n);
p[n] = 0;
return p;
} // endif b
} // endif s
return NewStr((PSZ)s);
} // endif count
return NewStr((PSZ)"Key");
} // end of MakeKey
/*********************************************************************************/
/* MakeJson: Make the Json tree to serialize. */
/*********************************************************************************/
PBVAL BJNX::MakeJson(PGLOBAL g, PBVAL bvp, int n)
{
PBVAL vlp, jvp = bvp;
Jb = false;
if (n < Nod -1) {
if (bvp->Type == TYPE_JAR) {
int ars = GetArraySize(bvp);
PJNODE jnp = &Nodes[n];
jvp = NewVal(TYPE_JAR);
jnp->Op = OP_EQ;
for (int i = 0; i < ars; i++) {
jnp->Rank = i;
vlp = GetRowValue(g, bvp, n);
AddArrayValue(jvp, DupVal(vlp));
} // endfor i
jnp->Op = OP_XX;
jnp->Rank = 0;
} else if(bvp->Type == TYPE_JOB) {
jvp = NewVal(TYPE_JOB);
for (PBPR prp = GetObject(bvp); prp; prp = GetNext(prp)) {
vlp = GetRowValue(g, GetVlp(prp), n + 1);
SetKeyValue(jvp, vlp, MZP(prp->Key));
} // endfor prp
} // endif Type
} // endif n
Jb = true;
return jvp;
} // end of MakeJson
/*********************************************************************************/
/* SetValue: Set a value from a BVALUE contains. */
/*********************************************************************************/
void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp)
{
if (vlp) {
vp->SetNull(false);
if (Jb) {
vp->SetValue_psz(Serialize(g, vlp, NULL, 0));
Jb = false;
} else switch (vlp->Type) {
case TYPE_DTM:
case TYPE_STRG:
vp->SetValue_psz(GetString(vlp));
break;
case TYPE_INTG:
vp->SetValue(GetInteger(vlp));
break;
case TYPE_BINT:
vp->SetValue(GetBigint(vlp));
break;
case TYPE_DBL:
case TYPE_FLOAT:
if (vp->IsTypeNum())
vp->SetValue(GetDouble(vlp));
else // Get the proper number of decimals
vp->SetValue_psz(GetString(vlp));
break;
case TYPE_BOOL:
if (vp->IsTypeNum())
vp->SetValue(GetInteger(vlp) ? 1 : 0);
else
vp->SetValue_psz(GetString(vlp));
break;
case TYPE_JAR:
vp->SetValue_psz(GetArrayText(g, vlp, NULL));
break;
case TYPE_JOB:
vp->SetValue_psz(GetObjectText(g, vlp, NULL));
break;
case TYPE_NULL:
vp->SetNull(true);
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)
{
PBVAL bap;
PBVAL vlp = NULL;
for (; i < Nod && row; i++) {
if (Nodes[i].Op == OP_NUM) {
Value->SetValue(row->Type == TYPE_JAR ? GetArraySize(row) : 1);
vlp = NewVal(Value);
return vlp;
} else if (Nodes[i].Op == OP_XX) {
return MakeJson(g, row, i);
} else if (Nodes[i].Op == OP_EXP) {
PUSH_WARNING("Expand not supported by this function");
return NULL;
} 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 {
snprintf(g->Message, sizeof(g->Message), "Unexpected object");
vlp = NULL;
} //endif Op
} else
vlp = GetKeyValue(row, Nodes[i].Key);
break;
case TYPE_JAR:
bap = row;
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 NewVal(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:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->Type);
vlp = NULL;
} // endswitch Type
row = vlp;
} // endfor i
return vlp;
} // end of GetRowValue
/*********************************************************************************/
/* ExpandArray: */
/*********************************************************************************/
PVAL BJNX::ExpandArray(PGLOBAL g, PBVAL arp, int n)
{
snprintf(g->Message, sizeof(g->Message), "Expand cannot be done by this function");
return NULL;
} // end of ExpandArray
/*********************************************************************************/
/* Get the value used for calculating the array. */
/*********************************************************************************/
PVAL BJNX::GetCalcValue(PGLOBAL g, PBVAL bap, int n)
{
// For calculated arrays, a local Value must be used
int lng = 0;
short type = 0, prec = 0;
bool b = n < Nod - 1;
PVAL valp;
PBVAL vlp, vp;
OPVAL op = Nodes[n].Op;
switch (op) {
case OP_NUM:
type = TYPE_INT;
break;
case OP_ADD:
case OP_MULT:
if (!IsTypeNum(Buf_Type)) {
type = TYPE_INT;
prec = 0;
for (vlp = GetArray(bap); vlp; vlp = GetNext(vlp)) {
vp = (b && IsJson(vlp)) ? GetRowValue(g, vlp, n + 1) : vlp;
switch (vp->Type) {
case TYPE_BINT:
if (type == TYPE_INT)
type = TYPE_BIGINT;
break;
case TYPE_DBL:
case TYPE_FLOAT:
type = TYPE_DOUBLE;
prec = MY_MAX(prec, vp->Nd);
break;
default:
break;
} // endswitch Type
} // endfor vlp
} else {
type = Buf_Type;
prec = GetPrecision();
} // endif Buf_Type
break;
case OP_SEP:
if (IsTypeChar(Buf_Type)) {
type = TYPE_DOUBLE;
prec = 2;
} else {
type = Buf_Type;
prec = GetPrecision();
} // endif Buf_Type
break;
case OP_MIN:
case OP_MAX:
type = Buf_Type;
lng = Long;
prec = GetPrecision();
break;
case OP_CNC:
type = TYPE_STRING;
if (IsTypeChar(Buf_Type)) {
lng = (Long) ? Long : 512;
prec = GetPrecision();
} else
lng = 512;
break;
default:
DBUG_ASSERT(!"Implement new op type support.");
} // endswitch Op
return valp = AllocateValue(g, type, lng, prec);
} // end of GetCalcValue
/*********************************************************************************/
/* CalculateArray */
/*********************************************************************************/
PVAL BJNX::CalculateArray(PGLOBAL g, PBVAL bap, int n)
{
int i, ars = GetArraySize(bap), nv = 0;
bool err;
OPVAL op = Nodes[n].Op;
PVAL val[2], vp = GetCalcValue(g, bap, n);
PVAL mulval = AllocateValue(g, vp);
PBVAL bvrp, bvp;
BVAL bval;
vp->Reset();
xtrc(1, "CalculateArray size=%d op=%d\n", ars, op);
try {
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, NewStr(GetJsonNull()), 0);
bvp = bvrp;
} else if (n < Nod - 1 && IsJson(bvrp)) {
SetValue(&bval, GetColumnValue(g, bvrp, n + 1));
bvp = &bval;
} else
bvp = bvrp;
if (trace(1))
htrc("bvp=%s null=%d\n",
GetString(bvp), IsValueNull(bvp) ? 1 : 0);
if (!nv++) {
SetJsonValue(g, vp, bvp);
continue;
} else
SetJsonValue(g, mulval, bvp);
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] = vp;
val[1] = mulval;
err = vp->Compute(g, val, 2, OP_ADD);
break;
default:
val[0] = vp;
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
} catch (int n) {
xtrc(1, "Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
} catch (const char* msg) {
snprintf(g->Message, sizeof(g->Message), "%s", msg);
} // end catch
return vp;
} // end of CalculateArray
/***********************************************************************/
/* 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 if (Nodes[i].Op == OP_EXP) {
PUSH_WARNING("Expand not supported by this function");
return NULL;
} else switch (row->Type) {
case TYPE_JOB:
if (!Nodes[i].Key)
// Expected Array was not there, wrap the value
continue;
val = GetKeyValue(row, Nodes[i].Key);
break;
case TYPE_JAR:
arp = row;
if (!Nodes[i].Key) {
if (Nodes[i].Op == OP_EQ)
val = GetArrayValue(arp, Nodes[i].Rank);
else
val = GetArrayValue(arp, Nodes[i].Rx);
} else {
// Unexpected array, unwrap it as [0]
val = GetArrayValue(arp, 0);
i--;
} // endif Nodes
break;
case TYPE_JVAL:
val = MVP(row->To_Val);
break;
default:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->Type);
val = NULL;
} // endswitch Type
if (val) {
row = val;
} else {
// Construct missing objects
for (i++; row && i < Nod; i++) {
if (Nodes[i].Op == OP_XX)
break;
// Construct new row
nwr = NewVal();
if (row->Type == TYPE_JOB) {
SetKeyValue(row, MOF(nwr), Nodes[i - 1].Key);
} else if (row->Type == TYPE_JAR) {
AddArrayValue(row, MOF(nwr));
} else {
snprintf(g->Message, sizeof(g->Message), "Wrong type when writing new row");
nwr = NULL;
} // endif's
row = nwr;
} // endfor i
break;
} // endelse
} // endfor i
return row;
} // end of GetRow
/***********************************************************************/
/* WriteValue: */
/***********************************************************************/
my_bool BJNX::WriteValue(PGLOBAL g, PBVAL jvalp)
{
PBVAL objp = NULL;
PBVAL arp = NULL;
PBVAL jvp = NULL;
PBVAL row = GetRow(g);
if (!row)
return true;
switch (row->Type) {
case TYPE_JOB: objp = row; break;
case TYPE_JAR: arp = row; break;
case TYPE_JVAL: jvp = MVP(row->To_Val); break;
default:
snprintf(g->Message, sizeof(g->Message), "Invalid target type");
return true;
} // endswitch Type
if (arp) {
if (!Nodes[Nod - 1].Key) {
if (Nodes[Nod - 1].Op == OP_EQ)
SetArrayValue(arp, jvalp, Nodes[Nod - 1].Rank);
else
AddArrayValue(arp, MOF(jvalp));
} // endif Key
} else if (objp) {
if (Nodes[Nod - 1].Key)
SetKeyValue(objp, MOF(jvalp), Nodes[Nod - 1].Key);
} else if (jvp)
SetValueVal(jvp, jvalp);
return false;
} // end of WriteValue
/*********************************************************************************/
/* GetRowValue: */
/*********************************************************************************/
my_bool BJNX::DeleteItem(PGLOBAL g, PBVAL row)
{
int n = -1;
my_bool b = false;
bool loop;
PBVAL vlp, pvp, rwp;
do {
loop = false;
vlp = NULL;
pvp = rwp = row;
for (int i = 0; i < Nod && rwp; i++) {
if (Nodes[i].Op == OP_XX)
break;
else switch (rwp->Type) {
case TYPE_JOB:
if (!Nodes[i].Key) {
vlp = NULL;
} else
vlp = GetKeyValue(rwp, Nodes[i].Key);
break;
case TYPE_JAR:
if (!Nodes[i].Key) {
if (Nodes[i].Op == OP_EXP) {
if (loop) {
PUSH_WARNING("Only one expand can be handled");
return b;
} // endif loop
n++;
} else
n = Nodes[i].Rank;
vlp = GetArrayValue(rwp, n);
if (GetNext(vlp) && Nodes[i].Op == OP_EXP)
loop = true;
} else
vlp = NULL;
break;
case TYPE_JVAL:
vlp = rwp;
break;
default:
vlp = NULL;
} // endswitch Type
pvp = rwp;
rwp = vlp;
vlp = NULL;
} // endfor i
if (rwp) {
if (Nodes[Nod - 1].Op == OP_XX) {
if (!IsJson(rwp))
rwp->Type = TYPE_NULL;
rwp->To_Val = 0;
} else switch (pvp->Type) {
case TYPE_JOB:
b = DeleteKey(pvp, Nodes[Nod - 1].Key);
break;
case TYPE_JAR:
if (Nodes[Nod - 1].Op == OP_EXP) {
pvp->To_Val = 0;
loop = false;
} else
b = DeleteValue(pvp, n);
break;
default:
break;
} // endswitch Type
} // endif rwp
} while (loop);
return b;
} // end of DeleteItem
/*********************************************************************************/
/* CheckPath: Checks whether the path exists in the document. */
/*********************************************************************************/
my_bool BJNX::CheckPath(PGLOBAL g)
{
PBVAL val = NULL;
PBVAL row = Row;
for (int i = 0; i < Nod && row; i++) {
val = NULL;
if (Nodes[i].Op == OP_NUM || Nodes[i].Op == OP_XX) {
} else switch (row->Type) {
case TYPE_JOB:
if (Nodes[i].Key)
val = GetKeyValue(row, Nodes[i].Key);
break;
case TYPE_JAR:
if (!Nodes[i].Key)
if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
val = GetArrayValue(row, Nodes[i].Rank);
break;
case TYPE_JVAL:
val = row;
break;
default:
snprintf(g->Message, sizeof(g->Message), "Invalid row JSON type %d", row->Type);
} // endswitch Type
if (i < Nod-1)
if (!(row = (IsJson(val)) ? val : NULL))
val = NULL;
} // endfor i
return (val != NULL);
} // end of CheckPath
/*********************************************************************************/
/* Check if a path was specified and set jvp according to it. */
/*********************************************************************************/
my_bool BJNX::CheckPath(PGLOBAL g, UDF_ARGS *args, PBVAL jsp, PBVAL& jvp, int n)
{
for (uint i = n; i < args->arg_count; i++)
if (args->arg_type[i] == STRING_RESULT && args->args[i]) {
// A path to a subset of the json tree is given
char *path = MakePSZ(g, args, i);
if (path) {
Row = jsp;
if (SetJpath(g, path))
return true;
if (!(jvp = GetJson(g))) {
snprintf(g->Message, sizeof(g->Message), "No sub-item at '%s'", path);
return true;
} else
return false;
} else {
snprintf(g->Message, sizeof(g->Message), "Path argument is null");
return true;
} // endif path
} // endif type
jvp = jsp;
return false;
} // end of CheckPath
/*********************************************************************************/
/* Locate a value in a JSON tree: */
/*********************************************************************************/
PSZ BJNX::Locate(PGLOBAL g, PBVAL jsp, PBVAL jvp, int k)
{
PSZ str = NULL;
my_bool err = true;
g->Message[0] = 0;
if (!jsp) {
snprintf(g->Message, sizeof(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, jsp);
break;
case TYPE_JOB:
err = LocateObject(g, jsp);
break;
case TYPE_JVAL:
err = LocateValue(g, MVP(jsp->To_Val));
break;
default:
err = true;
} // endswitch Type
if (err) {
if (!g->Message[0])
snprintf(g->Message, sizeof(g->Message), "Invalid json tree");
} else if (Found) {
Jp->WriteChr('\0');
PlugSubAlloc(g, NULL, Jp->N);
str = Jp->Strp;
} // endif's
} catch (int n) {
xtrc(1, "Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
} catch (const char* msg) {
snprintf(g->Message, sizeof(g->Message), "%s", 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;
snprintf(s, sizeof(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, PBVAL jobp)
{
size_t m;
if (Jp->WriteChr('.'))
return true;
m = Jp->N;
for (PBPR pair = GetObject(jobp); pair && !Found; pair = GetNext(pair)) {
Jp->N = m;
if (Jp->WriteStr(MZP(pair->Key)))
return true;
if (LocateValue(g, GetVlp(pair)))
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, jvp);
else if (jvp->Type == TYPE_JOB)
return LocateObject(g, 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 err = true;
PJPN jnp;
if (!jsp) {
snprintf(g->Message, sizeof(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, jsp);
break;
case TYPE_JOB:
err = LocateObjectAll(g, jsp);
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])
snprintf(g->Message, sizeof(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) {
snprintf(g->Message, sizeof(g->Message), "%s", 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 = GetArray(jarp); vp; vp = GetNext(vp)) {
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, PBVAL jobp)
{
if (I < Imax) {
Jpnp[++I].Type = TYPE_JOB;
for (PBPR pair = GetObject(jobp); pair; pair = GetNext(pair)) {
Jpnp[I].Key = MZP(pair->Key);
if (LocateValueAll(g, GetVlp(pair)))
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, jvp);
else if (jvp->Type == TYPE_JOB)
return LocateObjectAll(g, 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 = GetObject(jp1), p2 = GetObject(jp2);
// Keys can be differently ordered
for (; found && p1 && p2; p1 = GetNext(p1))
found = CompareValues(g, GetVlp(p1), GetKeyValue(jp2, GetKey(p1)));
} 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:
case TYPE_JOB:
if (v2->Type == v1->Type)
b = CompareTree(g, v1, v2);
break;
case TYPE_STRG:
if (v2->Type == TYPE_STRG) {
if (v1->Nd || v2->Nd) // Case insensitive
b = (!stricmp(MZP(v1->To_Val), MZP(v2->To_Val)));
else
b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
} // endif Type
break;
case TYPE_DTM:
if (v2->Type == TYPE_DTM)
b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
break;
case TYPE_INTG:
if (v2->Type == TYPE_INTG)
b = (v1->N == v2->N);
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) {
snprintf(s, sizeof(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 JSON value from the passed argument. */
/*********************************************************************************/
PBVAL BJNX::MakeValue(UDF_ARGS *args, uint i, bool b, PBVAL *top)
{
char *sap = (args->arg_count > i) ? args->args[i] : NULL;
int n, len;
int ci;
long long bigint;
PGLOBAL& g = G;
PBVAL jvp = NewVal();
if (top)
*top = NULL;
if (sap) switch (args->arg_type[i]) {
case STRING_RESULT:
if ((len = args->lengths[i])) {
if ((n = IsArgJson(args, i)) < 3)
sap = MakePSZ(g, args, i);
if (n) {
if (n == 3) {
PBSON bsp = (PBSON)sap;
if (i == 0) {
if (top)
*top = (PBVAL)bsp->Top;
jvp = (PBVAL)bsp->Jsp;
G = bsp->G;
Base = G->Sarea;
} else {
BJNX bnx(bsp->G);
jvp = MoveJson(&bnx, (PBVAL)bsp->Jsp);
} // endelse i
} else {
if (n == 2) {
if (!(sap = GetJsonFile(g, sap))) {
PUSH_WARNING(g->Message);
return jvp;
} // endif sap
len = strlen(sap);
} // endif n
if (!(jvp = ParseJson(g, sap, strlen(sap))))
PUSH_WARNING(g->Message);
else if (top)
*top = jvp;
} // endif's n
} else {
PBVAL bp = NULL;
if (b) {
if (strchr("[{ \t\r\n", *sap)) {
// Check whether this string is a valid json string
JsonMemSave(g);
if (!(bp = ParseJson(g, sap, strlen(sap))))
JsonSubSet(g); // Recover suballocated memory
g->Saved_Size = 0;
} else {
// Perhaps a file name
char* s = GetJsonFile(g, sap);
if (s)
bp = ParseJson(g, s, strlen(s));
} // endif's
} // endif b
if (!bp) {
ci = (strnicmp(args->attributes[i], "ci", 2)) ? 0 : 1;
SetString(jvp, sap, ci);
} else {
if (top)
*top = bp;
jvp = bp;
} // endif bp
} // endif n
} // endif len
break;
case INT_RESULT:
bigint = *(long long*)sap;
if ((bigint == 0LL && !strcmp(args->attributes[i], "FALSE")) ||
(bigint == 1LL && !strcmp(args->attributes[i], "TRUE")))
SetBool(jvp, (char)bigint);
else
SetBigint(jvp, bigint);
break;
case REAL_RESULT:
SetFloat(jvp, *(double*)sap);
break;
case DECIMAL_RESULT:
SetFloat(jvp, MakePSZ(g, args, i));
break;
case TIME_RESULT:
case ROW_RESULT:
default:
break;
} // endswitch arg_type
return jvp;
} // end of MakeValue
/*********************************************************************************/
/* Try making a JSON value of the passed type from the passed argument. */
/*********************************************************************************/
PBVAL BJNX::MakeTypedValue(PGLOBAL g, UDF_ARGS *args, uint i, JTYP type, PBVAL *top)
{
char *sap;
PBVAL jsp;
PBVAL jvp = MakeValue(args, i, false, top);
//if (type == TYPE_JSON) {
// if (jvp->GetValType() >= TYPE_JSON)
// return jvp;
//} else if (jvp->GetValType() == type)
// return jvp;
if (jvp->Type == TYPE_STRG) {
sap = GetString(jvp);
if ((jsp = ParseJson(g, sap, strlen(sap)))) {
if ((type == TYPE_JSON && jsp->Type != TYPE_JVAL) || jsp->Type == type) {
if (top)
*top = jvp;
SetValueVal(jvp, jsp);
} // endif Type
} // endif jsp
} // endif Type
return jvp;
} // end of MakeTypedValue
/*********************************************************************************/
/* Parse a json file. */
/*********************************************************************************/
PBVAL BJNX::ParseJsonFile(PGLOBAL g, char *fn, int& pty, size_t& len)
{
char *memory;
HANDLE hFile;
MEMMAP mm;
PBVAL jsp;
// Create the mapping file object
hFile = CreateFileMap(g, fn, &mm, MODE_READ, false);
if (hFile == INVALID_HANDLE_VALUE) {
DWORD rc = GetLastError();
if (!(*g->Message))
snprintf(g->Message, sizeof(g->Message), MSG(OPEN_MODE_ERROR), "map", (int)rc, fn);
return NULL;
} // endif hFile
// Get the file size
len = (size_t)mm.lenL;
if (mm.lenH)
len += mm.lenH;
memory = (char *)mm.memory;
if (!len) { // Empty or deleted file
CloseFileHandle(hFile);
return NULL;
} // endif len
if (!memory) {
CloseFileHandle(hFile);
snprintf(g->Message, sizeof(g->Message), MSG(MAP_VIEW_ERROR), fn, GetLastError());
return NULL;
} // endif Memory
CloseFileHandle(hFile); // Not used anymore
// Parse the json file and allocate its tree structure
g->Message[0] = 0;
jsp = ParseJson(g, memory, len);
pty = pretty;
CloseMemMap(memory, len);
return jsp;
} // end of ParseJsonFile
/*********************************************************************************/
/* Make the result according to the first argument type. */
/*********************************************************************************/
char *BJNX::MakeResult(UDF_ARGS *args, PBVAL top, uint n)
{
char *str = NULL;
PGLOBAL& g = G;
if (IsArgJson(args, 0) == 2) {
// Make the change in the json file
PSZ fn = MakePSZ(g, args, 0);
if (Changed) {
int pretty = 2;
for (uint i = n; i < args->arg_count; i++)
if (args->arg_type[i] == INT_RESULT) {
pretty = (int)*(longlong*)args->args[i];
break;
} // endif type
if (!Serialize(g, top, fn, pretty))
PUSH_WARNING(g->Message);
Changed = false;
} // endif Changed
str = fn;
} else if (IsArgJson(args, 0) == 3) {
PBSON bsp = (PBSON)args->args[0];
if (bsp->Filename) {
if (Changed) {
// Make the change in the json file
if (!Serialize(g, (PBVAL)top, bsp->Filename, bsp->Pretty))
PUSH_WARNING(g->Message);
Changed = false;
} // endif Changed
str = bsp->Filename;
} else if (!(str = Serialize(g, (PBVAL)top, NULL, 0)))
PUSH_WARNING(g->Message);
} else if (!(str = Serialize(g, top, NULL, 0)))
PUSH_WARNING(g->Message);
return str;
} // end of MakeResult
/*********************************************************************************/
/* Make the binary result according to the first argument type. */
/*********************************************************************************/
PBSON BJNX::MakeBinResult(UDF_ARGS *args, PBVAL top, ulong len, int n)
{
char* filename = NULL;
int pretty = 2;
PBSON bnp = NULL;
if (IsArgJson(args, 0) == 3) {
bnp = (PBSON)args->args[0];
if (bnp->Top != (PJSON)top)
bnp->Top = bnp->Jsp = (PJSON)top;
return bnp;
} // endif 3
if (IsArgJson(args, 0) == 2) {
for (uint i = n; i < args->arg_count; i++)
if (args->arg_type[i] == INT_RESULT) {
pretty = (int)*(longlong*)args->args[i];
break;
} // endif type
filename = (char*)args->args[0];
} // endif 2
if ((bnp = BbinAlloc(G, len, top))) {
bnp->Filename = filename;
bnp->Pretty = pretty;
snprintf(bnp->Msg, sizeof(bnp->Msg), "Json Binary item");
} //endif bnp
return bnp;
} // end of MakeBinResult
/***********************************************************************/
/* Move a Json val block from one area to the current area. */
/***********************************************************************/
PBVAL BJNX::MoveVal(PBVAL vlp)
{
PBVAL nvp = NewVal(vlp->Type);
nvp->Nd = vlp->Nd;
return nvp;
} // end of MovedVal
/***********************************************************************/
/* Move a Json tree from one area to current area. */
/***********************************************************************/
PBVAL BJNX::MoveJson(PBJNX bxp, PBVAL jvp)
{
PBVAL res = NULL;
if (jvp)
switch (jvp->Type) {
case TYPE_JAR:
res = MoveArray(bxp, jvp);
break;
case TYPE_JOB:
res = MoveObject(bxp, jvp);
break;
default:
res = MoveValue(bxp, jvp);
break;
} // endswitch Type
return res;
} // end of MoveJson
/***********************************************************************/
/* Move an array. */
/***********************************************************************/
PBVAL BJNX::MoveArray(PBJNX bxp, PBVAL jap)
{
PBVAL vlp, vmp, jvp = NULL, jarp = MoveVal(jap);
for (vlp = bxp->GetArray(jap); vlp; vlp = bxp->GetNext(vlp)) {
vmp = MoveJson(bxp, vlp);
if (jvp)
jvp->Next = MOF(vmp);
else
jarp->To_Val = MOF(vmp);
jvp = vmp;
} // endfor vlp
return jarp;
} // end of MoveArray
/***********************************************************************/
/* Replace all object pointers by offsets. */
/***********************************************************************/
PBVAL BJNX::MoveObject(PBJNX bxp, PBVAL jop)
{
PBPR mpp, prp, ppp = NULL;
PBVAL vmp, jobp = MoveVal(jop);
for (prp = bxp->GetObject(jop); prp; prp = bxp->GetNext(prp)) {
vmp = MoveJson(bxp, GetVlp(prp));
mpp = NewPair(DupStr(bxp->MZP(prp->Key)));
SetPairValue(mpp, vmp);
if (ppp)
ppp->Vlp.Next = MOF(mpp);
else
jobp->To_Val = MOF(mpp);
ppp = mpp;
} // endfor vlp
return jobp;
} // end of MoffObject
/***********************************************************************/
/* Move a non json value. */
/***********************************************************************/
PBVAL BJNX::MoveValue(PBJNX bxp, PBVAL jvp)
{
double *dp;
PBVAL nvp = MoveVal(jvp);
switch (jvp->Type) {
case TYPE_STRG:
case TYPE_DTM:
nvp->To_Val = DupStr(bxp->MZP(jvp->To_Val));
break;
case TYPE_DBL:
dp = (double*)BsonSubAlloc(sizeof(double));
*dp = bxp->DBL(jvp->To_Val);
nvp->To_Val = MOF(dp);
break;
case TYPE_JVAL:
nvp->To_Val = MOF(MoveJson(bxp, bxp->MVP(jvp->To_Val)));
break;
default:
nvp->To_Val = jvp->To_Val;
break;
} // endswith Type
return nvp;
} // end of MoveValue
/* -----------------------------Utility functions ------------------------------ */
/*********************************************************************************/
/* Returns a pointer to the first integer argument found from the nth argument. */
/*********************************************************************************/
static int *GetIntArgPtr(PGLOBAL g, UDF_ARGS *args, uint& n)
{
int *x = NULL;
for (uint i = n; i < args->arg_count; i++)
if (args->arg_type[i] == INT_RESULT) {
if (args->args[i]) {
if ((x = (int*)PlgDBSubAlloc(g, NULL, sizeof(int))))
*x = (int)*(longlong*)args->args[i];
else
PUSH_WARNING(g->Message);
} // endif args
n = i + 1;
break;
} // endif arg_type
return x;
} // end of GetIntArgPtr
/*********************************************************************************/
/* Returns not 0 if the argument is a JSON item or file name. */
/*********************************************************************************/
int IsArgJson(UDF_ARGS *args, uint i)
{
const char *pat = args->attributes[i];
int n = 0;
if (*pat == '@') {
pat++;
if (*pat == '\'' || *pat == '"')
pat++;
} // endif pat
if (i >= args->arg_count || args->arg_type[i] != STRING_RESULT) {
} else if (!strnicmp(pat, "Bson_", 5) || !strnicmp(pat, "Json_", 5)) {
if (!args->args[i] || strchr("[{ \t\r\n", *args->args[i]))
n = 1; // arg should be is a json item
// else
// n = 2; // A file name may have been returned
} else if (!strnicmp(pat, "Bbin_", 5)) {
if (args->lengths[i] == sizeof(BSON))
n = 3; // arg is a binary json item
// else
// n = 2; // A file name may have been returned
} else if (!strnicmp(pat, "Bfile_", 6) || !strnicmp(pat, "Jfile_", 6)) {
n = 2; // arg is a json file name
#if 0
} else if (args->lengths[i]) {
PGLOBAL g = PlugInit(NULL, (size_t)args->lengths[i] * M + 1024);
char *sap = MakePSZ(g, args, i);
if (ParseJson(g, sap, strlen(sap)))
n = 4;
JsonFreeMem(g);
#endif // 0
} // endif's
return n;
} // end of IsArgJson
/*********************************************************************************/
/* GetFileLength: returns file size in number of bytes. */
/*********************************************************************************/
static long GetFileLength(char *fn)
{
int h;
long len;
h= open(fn, _O_RDONLY);
if (h != -1) {
if ((len = _filelength(h)) < 0)
len = 0;
close(h);
} else
len = 0;
return len;
} // end of GetFileLength
/* ------------------------- Now the new Bin UDF's ----------------------------- */
/*********************************************************************************/
/* Make a Json value containing the parameter. */
/*********************************************************************************/
my_bool bsonvalue_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
{
unsigned long reslen, memlen;
if (args->arg_count > 1) {
strcpy(message, "Cannot accept more than 1 argument");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of bsonvalue_init
char* bsonvalue(UDF_INIT* initid, UDF_ARGS* args, char* result,
unsigned long* res_length, char*, char*)
{
char *str;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, 1, false)) {
BJNX bnx(g);
PBVAL bvp = bnx.MakeValue(args, 0, true);
if (!(str = bnx.Serialize(g, bvp, NULL, 0)))
str = strcpy(result, g->Message);
} else
str = strcpy(result, g->Message);
// Keep result of constant function
g->Xchk = (initid->const_item) ? str : NULL;
} else
str = (char*)g->Xchk;
*res_length = strlen(str);
return str;
} // end of bsonValue
void bsonvalue_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bsonvalue_deinit
/*********************************************************************************/
/* Make a Json array containing all the parameters. */
/* Note: jvp must be set before arp because it can be a binary argument. */
/*********************************************************************************/
my_bool bson_make_array_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
{
unsigned long reslen, memlen;
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of bson_make_array_init
char* bson_make_array(UDF_INIT* initid, UDF_ARGS* args, char* result,
unsigned long* res_length, char*, char*)
{
char* str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, false)) {
BJNX bnx(g);
PBVAL jvp = bnx.MakeValue(args, 0);
PBVAL arp = bnx.NewVal(TYPE_JAR);
for (uint i = 0; i < args->arg_count;) {
bnx.AddArrayValue(arp, jvp);
jvp = bnx.MakeValue(args, ++i);
} // endfor i
if (!(str = bnx.Serialize(g, arp, NULL, 0)))
str = strcpy(result, g->Message);
} else
str = strcpy(result, g->Message);
// Keep result of constant function
g->Xchk = (initid->const_item) ? str : NULL;
} else
str = (char*)g->Xchk;
*res_length = strlen(str);
return str;
} // end of bson_make_array
void bson_make_array_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_make_array_deinit
/*********************************************************************************/
/* Add one or several values to a Bson array. */
/*********************************************************************************/
my_bool bson_array_add_values_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
//} else if (!IsArgJson(args, 0, true)) {
// strcpy(message, "First argument must be a valid json string or item");
// return true;
} else
CalcLen(args, false, reslen, memlen);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements
if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
return false;
} else
return true;
} // end of bson_array_add_values_init
char* bson_array_add_values(UDF_INIT* initid, UDF_ARGS* args, char* result,
unsigned long* res_length, char* is_null, char*) {
char* str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, true)) {
BJNX bnx(g);
PBVAL arp = bnx.MakeValue(args, 0, true);
if (arp->Type != TYPE_JAR) {
PUSH_WARNING("First argument is not an array");
goto fin;
} // endif arp
for (uint i = 1; i < args->arg_count; i++)
bnx.AddArrayValue(arp, bnx.MakeValue(args, i));
bnx.SetChanged(true);
str = bnx.MakeResult(args, arp, INT_MAX);
} // endif CheckMemory
if (!str) {
PUSH_WARNING(g->Message);
str = args->args[0];
} // endif str
// Keep result of constant function
g->Xchk = (g->N) ? str : NULL;
} else
str = (char*)g->Xchk;
fin:
if (!str) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(str);
return str;
} // end of bson_array_add_values
void bson_array_add_values_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_array_add_values_deinit
/*********************************************************************************/
/* Add one value to a Json array. */
/*********************************************************************************/
my_bool bson_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
//} else if (!IsArgJson(args, 0, true)) {
// strcpy(message, "First argument is not a valid Json item");
// return true;
} else
CalcLen(args, false, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements
if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
return false;
} else
return true;
} // end of bson_array_add_init
char *bson_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
str = (char*)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 2, false, false, true)) {
int *x;
uint n = 2;
BJNX bnx(g, NULL, TYPE_STRING);
PBVAL jsp, top;
PBVAL arp, jvp = bnx.MakeValue(args, 0, true, &top);
jsp = jvp;
x = GetIntArgPtr(g, args, n);
if (bnx.CheckPath(g, args, jsp, jvp, 2))
PUSH_WARNING(g->Message);
else if (jvp) {
if (jvp->Type != TYPE_JAR) {
if ((arp = bnx.NewVal(TYPE_JAR))) {
bnx.AddArrayValue(arp, jvp);
if (!top)
top = arp;
} // endif arp
} else
arp = jvp;
if (arp) {
bnx.AddArrayValue(arp, bnx.MakeValue(args, 1), x);
bnx.SetChanged(true);
str = bnx.MakeResult(args, top, n);
} else
PUSH_WARNING(g->Message);
} else {
PUSH_WARNING("Target is not an array");
// if (g->Mrr) *error = 1; (only if no path)
} // endif jvp
} // endif CheckMemory
// In case of error or file, return unchanged argument
if (!str)
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*res_length = 0;
*is_null = 1;
*error = 1;
} else
*res_length = strlen(str);
return str;
} // end of bson_array_add
void bson_array_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_array_add_deinit
/*********************************************************************************/
/* Delete a value from a Json array. */
/*********************************************************************************/
my_bool bson_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else
CalcLen(args, false, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements
if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
return false;
} else
return true;
} // end of bson_array_delete_init
char *bson_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
str = (char*)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 1, false, false, true)) {
int *x;
uint n = 1;
BJNX bnx(g, NULL, TYPE_STRING);
PBVAL arp, top;
PBVAL jvp = bnx.MakeValue(args, 0, true, &top);
if (!(x = GetIntArgPtr(g, args, n)))
PUSH_WARNING("Missing or null array index");
else if (bnx.CheckPath(g, args, jvp, arp, 1))
PUSH_WARNING(g->Message);
else if (arp && arp->Type == TYPE_JAR) {
bnx.DeleteValue(arp, *x);
bnx.SetChanged(true);
str = bnx.MakeResult(args, top, n);
} else {
PUSH_WARNING("First argument target is not an array");
// if (g->Mrr) *error = 1;
} // endif jvp
} // endif CheckMemory
// In case of error or file, return unchanged argument
if (!str)
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of bson_array_delete
void bson_array_delete_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_array_delete_deinit
/*********************************************************************************/
/* Make a Json Object containing all the parameters. */
/*********************************************************************************/
my_bool bson_make_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of bson_make_object_init
char *bson_make_object(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *, char *)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, false, false, true)) {
BJNX bnx(g);
PBVAL objp;
if ((objp = bnx.NewVal(TYPE_JOB))) {
for (uint i = 0; i < args->arg_count; i++)
bnx.SetKeyValue(objp, bnx.MakeValue(args, i), bnx.MakeKey(args, i));
str = bnx.Serialize(g, objp, NULL, 0);
} // endif objp
} // endif CheckMemory
if (!str)
str = strcpy(result, g->Message);
// Keep result of constant function
g->Xchk = (initid->const_item) ? str : NULL;
} else
str = (char*)g->Xchk;
*res_length = strlen(str);
return str;
} // end of bson_make_object
void bson_make_object_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_make_object_deinit
/*********************************************************************************/
/* Make a Json Object containing all not null parameters. */
/*********************************************************************************/
my_bool bson_object_nonull_init(UDF_INIT *initid, UDF_ARGS *args,
char *message)
{
unsigned long reslen, memlen;
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of bson_object_nonull_init
char *bson_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *, char *)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
BJNX bnx(g);
PBVAL jvp, objp;
if ((objp = bnx.NewVal(TYPE_JOB))) {
for (uint i = 0; i < args->arg_count; i++)
if (!bnx.IsValueNull(jvp = bnx.MakeValue(args, i)))
bnx.SetKeyValue(objp, jvp, bnx.MakeKey(args, i));
str = bnx.Serialize(g, objp, NULL, 0);
} // endif objp
} // endif CheckMemory
if (!str)
str = strcpy(result, g->Message);
// Keep result of constant function
g->Xchk = (initid->const_item) ? str : NULL;
} else
str = (char*)g->Xchk;
*res_length = strlen(str);
return str;
} // end of bson_object_nonull
void bson_object_nonull_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_object_nonull_deinit
/*********************************************************************************/
/* Make a Json Object containing all the key/value parameters. */
/*********************************************************************************/
my_bool bson_object_key_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count % 2) {
strcpy(message, "This function must have an even number of arguments");
return true;
} // endif arg_count
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of bson_object_key_init
char *bson_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *, char *)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
BJNX bnx(g);
PBVAL objp;
if ((objp = bnx.NewVal(TYPE_JOB))) {
for (uint i = 0; i < args->arg_count; i += 2)
bnx.SetKeyValue(objp, bnx.MakeValue(args, i + 1), MakePSZ(g, args, i));
str = bnx.Serialize(g, objp, NULL, 0);
} // endif objp
} // endif CheckMemory
if (!str)
str = strcpy(result, g->Message);
// Keep result of constant function
g->Xchk = (initid->const_item) ? str : NULL;
} else
str = (char*)g->Xchk;
*res_length = strlen(str);
return str;
} // end of bson_object_key
void bson_object_key_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_object_key_deinit
/*********************************************************************************/
/* Add or replace a value in a Json Object. */
/*********************************************************************************/
my_bool bson_object_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else if (!IsArgJson(args, 0)) {
strcpy(message, "First argument must be a json item");
return true;
} else
CalcLen(args, true, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements
if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
return false;
} else
return true;
} // end of bson_object_add_init
char *bson_object_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PSZ key;
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
str = (char*)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 2, false, true, true)) {
BJNX bnx(g, NULL, TYPE_STRING);
PBVAL jvp, objp;
PBVAL jsp, top;
jsp = bnx.MakeValue(args, 0, true, &top);
if (bnx.CheckPath(g, args, jsp, jvp, 2))
PUSH_WARNING(g->Message);
else if (jvp && jvp->Type == TYPE_JOB) {
objp = jvp;
jvp = bnx.MakeValue(args, 1);
key = bnx.MakeKey(args, 1);
bnx.SetKeyValue(objp, jvp, key);
bnx.SetChanged(true);
str = bnx.MakeResult(args, top);
} else {
PUSH_WARNING("First argument target is not an object");
// if (g->Mrr) *error = 1; (only if no path)
} // endif jvp
} // endif CheckMemory
// In case of error or file, return unchanged argument
if (!str)
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of bson_object_add
void bson_object_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_object_add_deinit
/*********************************************************************************/
/* Delete a value from a Json object. */
/*********************************************************************************/
my_bool bson_object_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have 2 or 3 arguments");
return true;
} else if (!IsArgJson(args, 0)) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument must be a key string");
return true;
} else
CalcLen(args, true, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements
if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
return false;
} else
return true;
} // end of bson_object_delete_init
char *bson_object_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
str = (char*)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 1, false, true, true)) {
bool chg;
BJNX bnx(g, NULL, TYPE_STRG);
PSZ key;
PBVAL jsp, objp, top;
PBVAL jvp = bnx.MakeValue(args, 0, false, &top);
jsp = jvp;
if (bnx.CheckPath(g, args, jsp, jvp, 2))
PUSH_WARNING(g->Message);
else if (jvp && jvp->Type == TYPE_JOB) {
key = bnx.MakeKey(args, 1);
objp = jvp;
chg = bnx.DeleteKey(objp, key);
bnx.SetChanged(chg);
str = bnx.MakeResult(args, top);
} else {
PUSH_WARNING("First argument target is not an object");
// if (g->Mrr) *error = 1; (only if no path)
} // endif jvp
} // endif CheckMemory
// In case of error or file, return unchanged argument
if (!str)
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of bson_object_delete
void bson_object_delete_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_object_delete_deinit
/*********************************************************************************/
/* Returns an array of the Json object keys. */
/*********************************************************************************/
my_bool bson_object_list_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count != 1) {
strcpy(message, "This function must have 1 argument");
return true;
} else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "Argument must be a json item");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bson_object_list_init
char *bson_object_list(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->N) {
if (!CheckMemory(g, initid, args, 1, true, true)) {
BJNX bnx(g);
PBVAL jarp;
PBVAL jsp = bnx.MakeValue(args, 0, true);
if (jsp->Type == TYPE_JOB) {
jarp = bnx.GetKeyList(jsp);
if (!(str = bnx.Serialize(g, jarp, NULL, 0)))
PUSH_WARNING(g->Message);
} else {
PUSH_WARNING("First argument is not an object");
if (g->Mrr) *error = 1;
} // endif jvp
} // endif CheckMemory
if (initid->const_item) {
// Keep result of constant function
g->Xchk = str;
g->N = 1; // str can be NULL
} // endif const_item
} else
str = (char*)g->Xchk;
if (!str) {
*is_null = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of bson_object_list
void bson_object_list_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_object_list_deinit
/*********************************************************************************/
/* Returns an array of the Json object values. */
/*********************************************************************************/
my_bool bson_object_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count != 1) {
strcpy(message, "This function must have 1 argument");
return true;
} else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "Argument must be a json object");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bson_object_values_init
char *bson_object_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->N) {
if (!CheckMemory(g, initid, args, 1, true, true)) {
BJNX bnx(g);
char *p;
PBVAL jsp, jarp;
PBVAL jvp = bnx.MakeValue(args, 0);
if ((p = bnx.GetString(jvp))) {
if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
return NULL;
} // endif jsp
} else
jsp = jvp;
if (jsp->Type == TYPE_JOB) {
jarp = bnx.GetObjectValList(jsp);
if (!(str = bnx.Serialize(g, jarp, NULL, 0)))
PUSH_WARNING(g->Message);
} else {
PUSH_WARNING("First argument is not an object");
if (g->Mrr) *error = 1;
} // endif jvp
} // endif CheckMemory
if (initid->const_item) {
// Keep result of constant function
g->Xchk = str;
g->N = 1; // str can be NULL
} // endif const_item
} else
str = (char*)g->Xchk;
if (!str) {
*is_null = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of bson_object_values
void bson_object_values_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_object_values_deinit
/*********************************************************************************/
/* Set the value of JsonGrpSize. */
/*********************************************************************************/
my_bool bsonset_def_prec_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
if (args->arg_count != 1 || args->arg_type[0] != INT_RESULT) {
strcpy(message, "This function must have 1 integer argument");
return true;
} else
return false;
} // end of bsonset_def_prec_init
long long bsonset_def_prec(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
{
long long n = *(long long*)args->args[0];
JsonDefPrec = (int)n;
return (long long)GetJsonDefPrec();
} // end of bsonset_def_prec
/*********************************************************************************/
/* Get the value of JsonGrpSize. */
/*********************************************************************************/
my_bool bsonget_def_prec_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
if (args->arg_count != 0) {
strcpy(message, "This function must have no arguments");
return true;
} else
return false;
} // end of bsonget_def_prec_init
long long bsonget_def_prec(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
{
return (long long)GetJsonDefPrec();
} // end of bsonget_def_prec
/*********************************************************************************/
/* Set the value of JsonGrpSize. */
/*********************************************************************************/
my_bool bsonset_grp_size_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
if (args->arg_count != 1 || args->arg_type[0] != INT_RESULT) {
strcpy(message, "This function must have 1 integer argument");
return true;
} else
return false;
} // end of bsonset_grp_size_init
long long bsonset_grp_size(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
{
long long n = *(long long*)args->args[0];
JsonGrpSize = (uint)n;
return (long long)GetJsonGroupSize();
} // end of bsonset_grp_size
/*********************************************************************************/
/* Get the value of JsonGrpSize. */
/*********************************************************************************/
my_bool bsonget_grp_size_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
if (args->arg_count != 0) {
strcpy(message, "This function must have no arguments");
return true;
} else
return false;
} // end of bsonget_grp_size_init
long long bsonget_grp_size(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
{
return (long long)GetJsonGroupSize();
} // end of bsonget_grp_size
/*********************************************************************************/
/* Make a Json array from values coming from rows. */
/*********************************************************************************/
my_bool bson_array_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, n = GetJsonGroupSize();
if (args->arg_count != 1) {
strcpy(message, "This function can only accept 1 argument");
return true;
} else if (IsArgJson(args, 0) == 3) {
strcpy(message, "This function does not support Jbin arguments");
return true;
} else
CalcLen(args, false, reslen, memlen);
reslen *= n;
memlen += ((memlen - MEMFIX) * (n - 1));
if (JsonInit(initid, args, message, false, reslen, memlen))
return true;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBJNX bxp = new(g) BJNX(g);
JsonMemSave(g);
return false;
} // end of bson_array_grp_init
void bson_array_grp_clear(UDF_INIT *initid, char*, char*)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
JsonSubSet(g);
g->Activityp = (PACTIVITY)bxp->NewVal(TYPE_JAR);
g->N = GetJsonGroupSize();
} // end of bson_array_grp_clear
void bson_array_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
PBVAL arp = (PBVAL)g->Activityp;
if (arp && g->N-- > 0)
bxp->AddArrayValue(arp, bxp->MakeValue(args, 0));
} // end of bson_array_grp_add
char *bson_array_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
unsigned long *res_length, char *, char *)
{
char *str;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
PBVAL arp = (PBVAL)g->Activityp;
if (g->N < 0)
PUSH_WARNING("Result truncated to json_grp_size values");
if (!arp || !(str = bxp->Serialize(g, arp, NULL, 0)))
str = strcpy(result, g->Message);
*res_length = strlen(str);
return str;
} // end of bson_array_grp
void bson_array_grp_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_array_grp_deinit
/*********************************************************************************/
/* Make a Json object from values coming from rows. */
/*********************************************************************************/
my_bool bson_object_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, n = GetJsonGroupSize();
if (args->arg_count != 2) {
strcpy(message, "This function requires 2 arguments (key, value)");
return true;
} else if (IsArgJson(args, 0) == 3) {
strcpy(message, "This function does not support Jbin arguments");
return true;
} else
CalcLen(args, true, reslen, memlen);
reslen *= n;
memlen += ((memlen - MEMFIX) * (n - 1));
if (JsonInit(initid, args, message, false, reslen, memlen))
return true;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBJNX bxp = new(g) BJNX(g);
JsonMemSave(g);
return false;
} // end of bson_object_grp_init
void bson_object_grp_clear(UDF_INIT *initid, char*, char*)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
JsonSubSet(g);
g->Activityp = (PACTIVITY)bxp->NewVal(TYPE_JOB);
g->N = GetJsonGroupSize();
} // end of bson_object_grp_clear
void bson_object_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
PBVAL bop = (PBVAL)g->Activityp;
if (g->N-- > 0)
bxp->SetKeyValue(bop, bxp->MakeValue(args, 1), MakePSZ(g, args, 0));
} // end of bson_object_grp_add
char *bson_object_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
unsigned long *res_length, char *, char *)
{
char *str;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
PBVAL bop = (PBVAL)g->Activityp;
if (g->N < 0)
PUSH_WARNING("Result truncated to json_grp_size values");
if (!bop || !(str = bxp->Serialize(g, bop, NULL, 0)))
str = strcpy(result, g->Message);
*res_length = strlen(str);
return str;
} // end of bson_object_grp
void bson_object_grp_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_object_grp_deinit
/*********************************************************************************/
/* Test BJSON parse and serialize. */
/*********************************************************************************/
my_bool bson_test_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 (!IsArgJson(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 bson_test_init
char* bson_test(UDF_INIT* initid, UDF_ARGS* args, char* result,
unsigned long* res_length, char* is_null, char* error) {
char* str = NULL, *fn = NULL;
int pretty = 1;
PBVAL bvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
str = (char*)g->Activityp;
goto err;
} else if (initid->const_item)
g->N = 1;
try {
BJNX bnx(g);
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, !g->Xchk)) {
PUSH_WARNING("CheckMemory error");
*error = 1;
goto err;
} else // Sarea may have been reallocated
bnx.Reset();
bvp = bnx.MakeValue(args, 0, true);
if (bvp->Type == TYPE_NULL) {
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 = bnx.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) {
snprintf(g->Message, sizeof(g->Message), "%s", 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 bson_test
void bson_test_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_test_deinit
/*********************************************************************************/
/* Locate a value in a Json tree. */
/*********************************************************************************/
my_bool bsonlocate_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
unsigned long reslen, memlen, more = 1000;
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!IsArgJson(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 (IsArgJson(args, 0) == 3)
more = 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bsonlocate_init
char* bsonlocate(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;
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 {
BJNX bnx(g);
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, !g->Xchk)) {
PUSH_WARNING("CheckMemory error");
*error = 1;
goto err;
} else {
bnx.Reset(); // Sarea may have been re-allocated
bvp = bnx.MakeValue(args, 0, true);
if (!bvp) {
bnx.GetMsg(g);
PUSH_WARNING(g->Message);
goto err;
} else if (bvp->Type == TYPE_NULL) {
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
} // endif CheckMemory
} else
bvp = (PBVAL)g->Xchk;
// The item to locate
bvp2 = bnx.MakeValue(args, 1, true);
if (bvp2->Type == TYPE_NULL) {
PUSH_WARNING("Invalid second argument");
goto err;
} // endif bvp
k = (args->arg_count > 2) ? (int)*(long long*)args->args[2] : 1;
// bnxp = new(g) BJNX(g, bvp, TYPE_STRING);
path = bnx.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) {
snprintf(g->Message, sizeof(g->Message), "%s", 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 bsonlocate
void bsonlocate_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bsonlocate_deinit
/*********************************************************************************/
/* Locate all occurences of a value in a Json tree. */
/*********************************************************************************/
my_bool bson_locate_all_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
unsigned long reslen, memlen, more = 1000;
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!IsArgJson(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 (IsArgJson(args, 0) == 3)
more = 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bson_locate_all_init
char* bson_locate_all(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;
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 {
BJNX bnx(g);
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
*error = 1;
goto err;
} else
bnx.Reset();
bvp = bnx.MakeValue(args, 0, true);
if (bvp->Type == TYPE_NULL) {
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 = bnx.MakeValue(args, 1, true);
if (bvp2->Type == TYPE_NULL) {
PUSH_WARNING("Invalid second argument");
goto err;
} // endif bvp
if (args->arg_count > 2)
mx = (int)*(long long*)args->args[2];
// bnxp = new(g) BJNX(g, bvp, TYPE_STRING);
path = bnx.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) {
snprintf(g->Message, sizeof(g->Message), "%s", 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 bson_locate_all
void bson_locate_all_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_locate_all_deinit
/*********************************************************************************/
/* Check whether the document contains a value or item. */
/*********************************************************************************/
my_bool bson_contains_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, more = 1024;
int n = IsArgJson(args, 0);
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (index)");
return true;
} else if (args->arg_count > 3) {
if (args->arg_type[3] == INT_RESULT && args->args[3])
more += (unsigned long)*(long long*)args->args[3];
else
strcpy(message, "Fourth argument is not an integer (memory)");
} // endif's
CalcLen(args, false, reslen, memlen);
//memlen += more;
// TODO: calculate this
more += (IsArgJson(args, 0) != 3 ? 1000 : 0);
return JsonInit(initid, args, message, false, reslen, memlen, more);
} // end of bson contains_init
long long bson_contains(UDF_INIT *initid, UDF_ARGS *args, char *, char *error)
{
char isn, res[256];
unsigned long reslen;
isn = 0;
bsonlocate(initid, args, res, &reslen, &isn, error);
return (isn) ? 0LL : 1LL;
} // end of bson_contains
void bson_contains_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_contains_deinit
/*********************************************************************************/
/* Check whether the document contains a path. */
/*********************************************************************************/
my_bool bsoncontains_path_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, more = 1024;
int n = IsArgJson(args, 0);
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a string (path)");
return true;
} else if (args->arg_count > 2) {
if (args->arg_type[2] == INT_RESULT && args->args[2])
more += (unsigned long)*(long long*)args->args[2];
else
strcpy(message, "Third argument is not an integer (memory)");
} // endif's
CalcLen(args, false, reslen, memlen);
//memlen += more;
// TODO: calculate this
more += (IsArgJson(args, 0) != 3 ? 1000 : 0);
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bsoncontains_path_init
long long bsoncontains_path(UDF_INIT *initid, UDF_ARGS *args, char *, char *error)
{
char *p, *path;
long long n;
PBVAL jsp;
PBVAL jvp;
PBJNX bxp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (!g->Activityp) {
return 0LL;
} else
return *(long long*)g->Activityp;
} else if (initid->const_item)
g->N = 1;
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
goto err;
} else {
BJNX bnx(g);
jvp = bnx.MakeValue(args, 0);
if ((p = bnx.GetString(jvp))) {
if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
goto err;
} // endif jsp
} else
jsp = jvp;
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} // endelse CheckMemory
} else
jsp = (PBVAL)g->Xchk;
bxp = new(g) BJNX(g, jsp, TYPE_BIGINT);
path = MakePSZ(g, args, 1);
if (bxp->SetJpath(g, path)) {
PUSH_WARNING(g->Message);
goto err;
} // endif SetJpath
n = (bxp->CheckPath(g)) ? 1LL : 0LL;
if (initid->const_item) {
// Keep result of constant function
long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long));
if (np) {
*np = n;
g->Activityp = (PACTIVITY)np;
} else
PUSH_WARNING(g->Message);
} // endif const_item
return n;
err:
if (g->Mrr) *error = 1;
return 0LL;
} // end of bsoncontains_path
void bsoncontains_path_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bsoncontains_path_deinit
/*********************************************************************************/
/* Merge two arrays or objects. */
/*********************************************************************************/
my_bool bson_item_merge_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else for (int i = 0; i < 2; i++)
if (!IsArgJson(args, i) && args->arg_type[i] != STRING_RESULT) {
sprintf(message, "Argument %d must be a json item", i);
return true;
} // endif type
CalcLen(args, false, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements
if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
return false;
} else
return true;
} // end of bson_item_merge_init
char *bson_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
str = (char*)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 2, false, false, true)) {
JTYP type;
BJNX bnx(g);
PBVAL jvp = NULL, top = NULL;
PBVAL jsp[2] = {NULL, NULL};
for (int i = 0; i < 2; i++) {
jvp = bnx.MakeValue(args, i, true);
if (i) {
if (jvp && (jvp->Type != type)) {
PUSH_WARNING("Argument types mismatch");
goto fin;
} // endif type
} else {
type = (JTYP)jvp->Type;
if (type != TYPE_JAR && type != TYPE_JOB) {
PUSH_WARNING("First argument is not an array or object");
goto fin;
} else
top = jvp;
} // endif i
jsp[i] = jvp;
} // endfor i
if (type == TYPE_JAR)
bnx.MergeArray(jsp[0], jsp[1]);
else
bnx.MergeObject(jsp[0], jsp[1]);
bnx.SetChanged(true);
str = bnx.MakeResult(args, top);
} // endif CheckMemory
// In case of error or file, return unchanged first argument
if (!str)
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*res_length = 0;
*error = 1;
*is_null = 1;
} else
*res_length = strlen(str);
return str;
} // end of bson_item_merge
void bson_item_merge_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_item_merge_deinit
/*********************************************************************************/
/* Get a Json item from a Json document. */
/*********************************************************************************/
my_bool bson_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, more;
int n = IsArgJson(args, 0);
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a string (jpath)");
return true;
} else
CalcLen(args, false, reslen, memlen);
if (n == 2 && args->args[0]) {
char fn[_MAX_PATH];
long fl;
memcpy(fn, args->args[0], args->lengths[0]);
fn[args->lengths[0]] = 0;
fl = GetFileLength(fn);
more = fl * 3;
} else if (n != 3) {
more = args->lengths[0] * 3;
} else
more = 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bson_get_item_init
char *bson_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *)
{
char *path, *str = NULL;
PBVAL jvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
BJNX bnx(g, NULL, TYPE_STRING, initid->max_length);
if (g->N) {
str = (char*)g->Activityp;
goto fin;
} else if (initid->const_item)
g->N = 1;
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true, true)) {
PUSH_WARNING("CheckMemory error");
goto fin;
} else {
bnx.Reset();
jvp = bnx.MakeValue(args, 0, true);
if (g->Mrr) { // First argument is a constant
g->Xchk = jvp;
JsonMemSave(g);
} // endif Mrr
} // endelse CheckMemory
} else
jvp = (PBVAL)g->Xchk;
path = MakePSZ(g, args, 1);
if (bnx.SetJpath(g, path, true)) {
goto fin;
} else
jvp = bnx.GetRowValue(g, jvp, 0);
if (!bnx.IsJson(jvp)) {
snprintf(g->Message, sizeof(g->Message), "Not a Json item");
} else
str = bnx.Serialize(g, jvp, NULL, 0);
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)str;
fin:
if (!str) {
PUSH_WARNING(g->Message);
*is_null = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of bson_get_item
void bson_get_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_get_item_deinit
/*********************************************************************************/
/* Get a string value from a Json item. */
/*********************************************************************************/
my_bool bsonget_string_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, more = 1024;
int n = IsArgJson(args, 0);
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a string (jpath)");
return true;
} else if (args->arg_count > 2) {
if (args->arg_type[2] == INT_RESULT && args->args[2])
more += (unsigned long)*(long long*)args->args[2];
else
strcpy(message, "Third argument is not an integer (memory)");
} // endif's
CalcLen(args, false, reslen, memlen);
//memlen += more;
if (n == 2 && args->args[0]) {
char fn[_MAX_PATH];
long fl;
memcpy(fn, args->args[0], args->lengths[0]);
fn[args->lengths[0]] = 0;
fl = GetFileLength(fn);
more += fl * 3;
} else if (n != 3)
more += args->lengths[0] * 3;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bsonget_string_init
char *bsonget_string(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *)
{
char *p, *path, *str = NULL;
PBVAL jsp, jvp;
PBJNX bxp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
str = (char*)g->Activityp;
goto err;
} else if (initid->const_item)
g->N = 1;
try {
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
goto err;
} else {
BJNX bnx(g);
jvp = bnx.MakeValue(args, 0);
if ((p = bnx.GetString(jvp))) {
if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
goto err;
} // endif jsp
} else
jsp = jvp;
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} // endelse CheckMemory
} else
jsp = (PBVAL)g->Xchk;
path = MakePSZ(g, args, 1);
bxp = new(g) BJNX(g, jsp, TYPE_STRING, initid->max_length);
if (bxp->SetJpath(g, path)) {
PUSH_WARNING(g->Message);
goto err;
} else
bxp->ReadValue(g);
if (!bxp->GetValue()->IsNull())
str = bxp->GetValue()->GetCharValue();
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)str;
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
str = NULL;
} catch (const char *msg) {
snprintf(g->Message, sizeof(g->Message), "%s", msg);
PUSH_WARNING(g->Message);
str = NULL;
} // end catch
err:
if (!str) {
*is_null = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of bsonget_string
void bsonget_string_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bsonget_string_deinit
/*********************************************************************************/
/* Get an integer value from a Json item. */
/*********************************************************************************/
my_bool bsonget_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, more;
if (args->arg_count != 2) {
strcpy(message, "This function must have 2 arguments");
return true;
} else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a (jpath) string");
return true;
} else
CalcLen(args, false, reslen, memlen);
// TODO: calculate this
more = (IsArgJson(args, 0) != 3) ? 1000 : 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bsonget_int_init
long long bsonget_int(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *error)
{
char *p, *path;
long long n;
PBVAL jsp, jvp;
PBJNX bxp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (!g->Activityp) {
*is_null = 1;
return 0LL;
} else
return *(long long*)g->Activityp;
} else if (initid->const_item)
g->N = 1;
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
if (g->Mrr) *error = 1;
*is_null = 1;
return 0LL;
} else {
BJNX bnx(g);
jvp = bnx.MakeValue(args, 0);
if ((p = bnx.GetString(jvp))) {
if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
if (g->Mrr) *error = 1;
*is_null = 1;
return 0;
} // endif jsp
} else
jsp = jvp;
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} // endelse CheckMemory
} else
jsp = (PBVAL)g->Xchk;
path = MakePSZ(g, args, 1);
bxp = new(g) BJNX(g, jsp, TYPE_BIGINT);
if (bxp->SetJpath(g, path)) {
PUSH_WARNING(g->Message);
*is_null = 1;
return 0;
} else
bxp->ReadValue(g);
if (bxp->GetValue()->IsNull()) {
*is_null = 1;
return 0;
} // endif IsNull
n = bxp->GetValue()->GetBigintValue();
if (initid->const_item) {
// Keep result of constant function
long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long));
if (np) {
*np = n;
g->Activityp = (PACTIVITY)np;
} else
PUSH_WARNING(g->Message);
} // endif const_item
return n;
} // end of bsonget_int
void bsonget_int_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bsonget_int_deinit
/*********************************************************************************/
/* Get a double value from a Json item. */
/*********************************************************************************/
my_bool bsonget_real_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, more;
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument is not a (jpath) string");
return true;
} else if (args->arg_count > 2) {
if (args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (decimals)");
return true;
} else
initid->decimals = (uint)*(longlong*)args->args[2];
} else
initid->decimals = 15;
CalcLen(args, false, reslen, memlen);
// TODO: calculate this
more = (IsArgJson(args, 0) != 3) ? 1000 : 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of bsonget_real_init
double bsonget_real(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *error)
{
char *p, *path;
double d;
PBVAL jsp, jvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
BJNX bnx(g);
if (g->N) {
if (!g->Activityp) {
*is_null = 1;
return 0.0;
} else
return *(double*)g->Activityp;
} else if (initid->const_item)
g->N = 1;
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
if (g->Mrr) *error = 1;
*is_null = 1;
return 0.0;
} else {
bnx.Reset();
jvp = bnx.MakeValue(args, 0);
if ((p = bnx.GetString(jvp))) {
if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
*is_null = 1;
return 0.0;
} // endif jsp
} else
jsp = jvp;
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} // endelse CheckMemory
} else
jsp = (PBVAL)g->Xchk;
path = MakePSZ(g, args, 1);
//bxp = new(g) BJNX(g, jsp, TYPE_DOUBLE, 32, jsp->Nd);
if (bnx.SetJpath(g, path)) {
PUSH_WARNING(g->Message);
*is_null = 1;
return 0.0;
} else
jvp = bnx.GetRowValue(g, jsp, 0);
if (!jvp || bnx.IsValueNull(jvp)) {
*is_null = 1;
return 0.0;
} else if (args->arg_count == 2) {
d = atof(bnx.GetString(jvp));
} else
d = bnx.GetDouble(jvp);
if (initid->const_item) {
// Keep result of constant function
double *dp;
if ((dp = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) {
*dp = d;
g->Activityp = (PACTIVITY)dp;
} else {
PUSH_WARNING(g->Message);
*is_null = 1;
return 0.0;
} // endif dp
} // endif const_item
return d;
} // end of jsonget_real
void bsonget_real_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bsonget_real_deinit
/*********************************************************************************/
/* Delete items from a Json document. */
/*********************************************************************************/
my_bool bson_delete_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
if (IsArgJson(args, 0) != 3) {
strcpy(message, "This function must have at least 2 arguments or one binary");
return true;
} // endif args
} // endif count
CalcLen(args, false, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// Is this a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements
if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
return false;
} else
return true;
} // end of bson_delete_item_init
char *bson_delete_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *path, *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
str = (char*)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 1, false, false, true)) {
BJNX bnx(g, NULL, TYPE_STRING);
PBVAL top, jar = NULL;
PBVAL jvp = bnx.MakeValue(args, 0, true, &top);
if (args->arg_count == 1) {
// This should be coming from bbin_locate_all
jar = jvp; // This is the array of paths
jvp = top; // And this is the document
} else if(!bnx.IsJson(jvp)) {
PUSH_WARNING("First argument is not a JSON document");
goto fin;
} else if (args->arg_count == 2) {
// Check whether this is an array of paths
jar = bnx.MakeValue(args, 1, true);
if (jar && jar->Type != TYPE_JAR)
jar = NULL;
} // endif arg_count
if (jar) {
// Do the deletion in reverse order
for(int i = bnx.GetArraySize(jar) - 1; i >= 0; i--) {
path = bnx.GetString(bnx.GetArrayValue(jar, i));
if (bnx.SetJpath(g, path, false)) {
PUSH_WARNING(g->Message);
continue;
} // endif SetJpath
bnx.SetChanged(bnx.DeleteItem(g, jvp));
} // endfor i
} else for (uint i = 1; i < args->arg_count; i++) {
path = MakePSZ(g, args, i);
if (bnx.SetJpath(g, path, false)) {
PUSH_WARNING(g->Message);
continue;
} // endif SetJpath
bnx.SetChanged(bnx.DeleteItem(g, jvp));
} // endfor i
str = bnx.MakeResult(args, top, INT_MAX);
} // endif CheckMemory
if (g->N)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of bson_delete_item
void bson_delete_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_delete_item_deinit
/*********************************************************************************/
/* This function is used by the json_set/insert/update_item functions. */
/*********************************************************************************/
static char *bson_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *path, *str = NULL;
int w;
my_bool b = true;
PBJNX bxp;
PBVAL jsp, jvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Alchecked) {
str = (char*)g->Activityp;
goto fin;
} else if (g->N)
g->Alchecked = 1;
if (!strcmp(result, "$set"))
w = 0;
else if (!strcmp(result, "$insert"))
w = 1;
else if (!strcmp(result, "$update"))
w = 2;
else {
PUSH_WARNING("Logical error, please contact CONNECT developer");
goto fin;
} // endelse
try {
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true, false, true)) {
PUSH_WARNING("CheckMemory error");
throw 1;
} else {
BJNX bnx(g);
jsp = bnx.MakeValue(args, 0, true);
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
JsonMemSave(g);
} // endif Mrr
} // endif CheckMemory
} else
jsp = (PBVAL)g->Xchk;
bxp = new(g)BJNX(g, jsp, TYPE_STRING, initid->max_length, 0, true);
for (uint i = 1; i + 1 < args->arg_count; i += 2) {
jvp = bxp->MakeValue(args, i);
path = MakePSZ(g, args, i + 1);
if (bxp->SetJpath(g, path, false)) {
PUSH_WARNING(g->Message);
continue;
} // endif SetJpath
if (w) {
bxp->ReadValue(g);
b = bxp->GetValue()->IsNull();
b = (w == 1) ? b : !b;
} // endif w
if (b && bxp->WriteValue(g, jvp)) {
PUSH_WARNING(g->Message);
continue;
} // endif SetJpath
bxp->SetChanged(true);
} // endfor i
// In case of error or file, return unchanged argument
if (!(str = bxp->MakeResult(args, jsp, INT_MAX32)))
str = MakePSZ(g, args, 0);
if (g->N)
// Keep result of constant function
g->Activityp = (PACTIVITY)str;
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
str = NULL;
} catch (const char *msg) {
snprintf(g->Message, sizeof(g->Message), "%s", msg);
PUSH_WARNING(g->Message);
str = NULL;
} // end catch
fin:
if (!str) {
*is_null = 1;
*res_length = 0;
} else
*res_length = strlen(str);
return str;
} // end of bson_handle_item
/*********************************************************************************/
/* Set Json items of a Json document according to path. */
/*********************************************************************************/
my_bool bson_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, more = 0;
int n = IsArgJson(args, 0);
if (!(args->arg_count % 2)) {
strcpy(message, "This function must have an odd number of arguments");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else
CalcLen(args, false, reslen, memlen);
if (n == 2 && args->args[0]) {
char fn[_MAX_PATH];
long fl;
memcpy(fn, args->args[0], args->lengths[0]);
fn[args->lengths[0]] = 0;
fl = GetFileLength(fn);
more += fl * 3;
} else if (n != 3)
more += args->lengths[0] * 3;
if (!JsonInit(initid, args, message, true, reslen, memlen, more)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements
if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
g->Alchecked = 0;
return false;
} else
return true;
} // end of bson_set_item_init
char *bson_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$set");
return bson_handle_item(initid, args, result, res_length, is_null, p);
} // end of bson_set_item
void bson_set_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_set_item_deinit
/*********************************************************************************/
/* Insert Json items of a Json document according to path. */
/*********************************************************************************/
my_bool bson_insert_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_set_item_init(initid, args, message);
} // end of bson_insert_item_init
char *bson_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$insert");
return bson_handle_item(initid, args, result, res_length, is_null, p);
} // end of bson_insert_item
void bson_insert_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_insert_item_deinit
/*********************************************************************************/
/* Update Json items of a Json document according to path. */
/*********************************************************************************/
my_bool bson_update_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_set_item_init(initid, args, message);
} // end of bson_update_item_init
char *bson_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$update");
return bson_handle_item(initid, args, result, res_length, is_null, p);
} // end of bson_update_item
void bson_update_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_update_item_deinit
/*********************************************************************************/
/* Returns a json file as a json string. */
/*********************************************************************************/
my_bool bson_file_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, fl, more = 1024;
if (args->arg_count < 1 || args->arg_count > 4) {
strcpy(message, "This function only accepts 1 to 4 arguments");
return true;
} else if (args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a string (file name)");
return true;
} // endif's args[0]
for (unsigned int i = 1; i < args->arg_count; i++) {
if (!(args->arg_type[i] == INT_RESULT || args->arg_type[i] == STRING_RESULT)) {
sprintf(message, "Argument %d is not an integer or a string (pretty or path)", i);
return true;
} // endif arg_type
// Take care of eventual memory argument
if (args->arg_type[i] == INT_RESULT && args->args[i])
more += (ulong)*(longlong*)args->args[i];
} // endfor i
initid->maybe_null = 1;
CalcLen(args, false, reslen, memlen);
if (args->args[0])
fl = GetFileLength(args->args[0]);
else
fl = 100; // What can be done here?
reslen += fl;
if (initid->const_item)
more += fl;
if (args->arg_count > 1)
more += fl * M;
memlen += more;
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bson_file_init
char *bson_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *fn, *str = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
str = (char*)g->Xchk;
goto fin;
} else if (initid->const_item)
g->N = 1;
PlugSubSet(g->Sarea, g->Sarea_Size);
fn = MakePSZ(g, args, 0);
if (args->arg_count > 1) {
int pretty = 3, pty = 3;
size_t len;
PBVAL jsp, jvp = NULL;
BJNX bnx(g);
for (unsigned int i = 1; i < args->arg_count; i++)
if (args->arg_type[i] == INT_RESULT && *(longlong*)args->args[i] < 4) {
pretty = (int) * (longlong*)args->args[i];
break;
} // endif type
// Parse the json file and allocate its tree structure
if (!(jsp = bnx.ParseJsonFile(g, fn, pty, len))) {
PUSH_WARNING(g->Message);
goto fin;
} // endif jsp
if (pty == 3)
PUSH_WARNING("File pretty format cannot be determined");
else if (pretty != 3 && pty != pretty)
PUSH_WARNING("File pretty format doesn't match the specified pretty value");
else if (pretty == 3)
pretty = pty;
// Check whether a path was specified
if (bnx.CheckPath(g, args, jsp, jvp, 1)) {
PUSH_WARNING(g->Message);
goto fin;
} else if (jvp)
jsp = jvp;
if (!(str = bnx.Serialize(g, jsp, NULL, 0)))
PUSH_WARNING(g->Message);
} else
if (!(str = GetJsonFile(g, fn)))
PUSH_WARNING(g->Message);
if (initid->const_item)
// Keep result of constant function
g->Xchk = str;
fin:
if (!str) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(str);
return str;
} // end of bson_file
void bson_file_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_file_deinit
/*********************************************************************************/
/* Make a json file from a json item. */
/*********************************************************************************/
my_bool bfile_make_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 1 || args->arg_count > 3) {
strcpy(message, "Wrong number of arguments");
return true;
} else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} // endif
CalcLen(args, false, reslen, memlen);
memlen = memlen + 5000; // To take care of not pretty files
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bfile_make_init
char *bfile_make(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *)
{
char *p, *str = NULL, *fn = NULL;
int n, pretty = 2;
PBVAL jsp, jvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
BJNX bnx(g);
if (g->N) {
str = (char*)g->Activityp;
goto fin;
} else if (initid->const_item)
g->N = 1;
if ((n = IsArgJson(args, 0)) == 3) {
// Get default file name and pretty
PBSON bsp = (PBSON)args->args[0];
fn = bsp->Filename;
pretty = bsp->Pretty;
} else if ((n = IsArgJson(args, 0)) == 2)
fn = args->args[0];
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
goto fin;
} else
bnx.Reset();
jvp = bnx.MakeValue(args, 0);
if (!n && (p = bnx.GetString(jvp))) {
if (!strchr("[{ \t\r\n", *p)) {
// Is this a file name?
if (!(p = GetJsonFile(g, p))) {
PUSH_WARNING(g->Message);
goto fin;
} else
fn = bnx.GetString(jvp);
} // endif p
if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
PUSH_WARNING(g->Message);
goto fin;
} // endif jsp
bnx.SetValueVal(jvp, jsp);
} // endif p
if (g->Mrr) { // First argument is a constant
g->Xchk = jvp;
JsonMemSave(g);
} // endif Mrr
} else
jvp = (PBVAL)g->Xchk;
for (uint i = 1; i < args->arg_count; i++)
switch (args->arg_type[i]) {
case STRING_RESULT:
fn = MakePSZ(g, args, i);
break;
case INT_RESULT:
pretty = (int)*(longlong*)args->args[i];
break;
default:
PUSH_WARNING("Unexpected argument type in bfile_make");
} // endswitch arg_type
if (fn) {
if (!bnx.Serialize(g, jvp, fn, pretty))
PUSH_WARNING(g->Message);
} else
PUSH_WARNING("Missing file name");
str = fn;
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)str;
fin:
if (!str) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(str);
return str;
} // end of bfile_make
void bfile_make_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bfile_make_deinit
/*********************************************************************************/
/* Convert a prettiest Json file to Pretty=0. */
/*********************************************************************************/
my_bool bfile_convert_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
unsigned long reslen, memlen;
if (args->arg_count != 3) {
strcpy(message, "This function must have 3 arguments");
return true;
} else if (args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third Argument must be an integer (LRECL)");
return true;
} else for (int i = 0; i < 2; i++)
if (args->arg_type[i] != STRING_RESULT) {
sprintf(message, "Arguments %d must be a string (file name)", i+1);
return true;
} // endif args
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bfile_convert_init
char *bfile_convert(UDF_INIT* initid, UDF_ARGS* args, char* result,
unsigned long *res_length, char *is_null, char *error) {
char *str, *fn, *ofn;
int lrecl = (int)*(longlong*)args->args[2];
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g->Sarea, g->Sarea_Size);
fn = MakePSZ(g, args, 0);
ofn = MakePSZ(g, args, 1);
if (!g->Xchk) {
JUP* jup = new(g) JUP(g);
str = jup->UnprettyJsonFile(g, fn, ofn, lrecl);
g->Xchk = str;
} else
str = (char*)g->Xchk;
if (!str) {
PUSH_WARNING(*g->Message ? g->Message : "Unexpected error");
*is_null = 1;
*error = 1;
*res_length = 0;
} else {
strcpy(result, str);
*res_length = strlen(str);
} // endif str
return str;
} // end of bfile_convert
void bfile_convert_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bfile_convert_deinit
/*********************************************************************************/
/* Convert a pretty=0 Json file to binary BJSON. */
/*********************************************************************************/
my_bool bfile_bjson_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
unsigned long reslen, memlen;
if (args->arg_count != 2 && args->arg_count != 3) {
strcpy(message, "This function must have 2 or 3 arguments");
return true;
} else if (args->arg_count == 3 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third Argument must be an integer (LRECL)");
return true;
} else for (int i = 0; i < 2; i++)
if (args->arg_type[i] != STRING_RESULT) {
sprintf(message, "Arguments %d must be a string (file name)", i + 1);
return true;
} // endif args
CalcLen(args, false, reslen, memlen);
memlen = memlen * M;
memlen += (args->arg_count == 3) ? (ulong)*(longlong*)args->args[2] : 1024;
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of bfile_bjson_init
char *bfile_bjson(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char*, char *error) {
char *buf, *str = NULL, fn[_MAX_PATH], ofn[_MAX_PATH];
bool loop;
ssize_t len, newloc;
size_t lrecl, binszp;
PBVAL jsp;
PGLOBAL g = (PGLOBAL)initid->ptr;
BDOC doc(g);
snprintf(fn, sizeof(fn), "%s", MakePSZ(g, args, 0));
snprintf(ofn, sizeof(ofn), "%s", MakePSZ(g, args, 1));
if (args->arg_count == 3)
lrecl = (size_t)*(longlong*)args->args[2];
else
lrecl = 1024;
if (!g->Xchk) {
int msgid = MSGID_OPEN_MODE_STRERROR;
FILE *fout = NULL;
FILE *fin;
if (!(fin = global_fopen(g, msgid, fn, "rt")))
str = strcpy(result, g->Message);
else if (!(fout = global_fopen(g, msgid, ofn, "wb")))
str = strcpy(result, g->Message);
else if ((buf = (char*)malloc(lrecl))) {
try {
do {
loop = false;
PlugSubSet(g->Sarea, g->Sarea_Size);
if (!fgets(buf, lrecl, fin)) {
if (!feof(fin)) {
snprintf(g->Message, sizeof(g->Message), "Error %d reading %zu bytes from %s",
errno, lrecl, fn);
str = strcpy(result, g->Message);
} else
str = strcpy(result, ofn);
} else if ((len = strlen(buf))) {
if ((jsp = doc.ParseJson(g, buf, len))) {
newloc = (size_t)PlugSubAlloc(g, NULL, 0);
binszp = newloc - (size_t)jsp;
if (fwrite(&binszp, sizeof(binszp), 1, fout) != 1) {
snprintf(g->Message, sizeof(g->Message), "Error %d writing %zu bytes to %s",
errno, sizeof(binszp), ofn);
str = strcpy(result, g->Message);
} else if (fwrite(jsp, binszp, 1, fout) != 1) {
snprintf(g->Message, sizeof(g->Message), "Error %d writing %zu bytes to %s",
errno, binszp, ofn);
str = strcpy(result, g->Message);
} else
loop = true;
} else {
str = strcpy(result, g->Message);
} // endif jsp
} else
loop = true;
} while (loop);
} catch (int) {
str = strcpy(result, g->Message);
} catch (const char* msg) {
str = strcpy(result, msg);
} // end catch
free(buf);
} else
str = strcpy(result, "Buffer malloc failed");
if (fin) fclose(fin);
if (fout) fclose(fout);
g->Xchk = str;
} else
str = (char*)g->Xchk;
if (!str) {
if (*g->Message)
str = strcpy(result, g->Message);
else
str = strcpy(result, "Unexpected error");
} // endif str
*res_length = strlen(str);
return str;
} // end of bfile_bjson
void bfile_bjson_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bfile_bjson_deinit
/*********************************************************************************/
/* Serialize a Json document. . */
/*********************************************************************************/
my_bool bson_serialize_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->args[0] && IsArgJson(args, 0) != 3) {
strcpy(message, "Argument must be a Jbin tree");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of bson_serialize_init
char *bson_serialize(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *, char *error)
{
char *str;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (!g->Xchk) {
if (IsArgJson(args, 0) == 3) {
PBSON bsp = (PBSON)args->args[0];
BJNX bnx(bsp->G);
PBVAL bvp = (args->arg_count == 1) ? (PBVAL)bsp->Jsp : (PBVAL)bsp->Top;
// if (!(str = bnx.Serialize(g, bvp, bsp->Filename, bsp->Pretty)))
if (!(str = bnx.Serialize(g, bvp, NULL, 0)))
str = strcpy(result, g->Message);
// Keep result of constant function
g->Xchk = (initid->const_item) ? str : NULL;
} else {
// *error = 1;
str = strcpy(result, "Argument is not a Jbin tree");
} // endif
} else
str = (char*)g->Xchk;
*res_length = strlen(str);
return str;
} // end of bson_serialize
void bson_serialize_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bson_serialize_deinit
/*********************************************************************************/
/* Make and return a binary Json array containing all the parameters. */
/* Note: jvp must be set before arp because it can be a binary argument. */
/*********************************************************************************/
my_bool bbin_make_array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bbin_make_array_init
char *bbin_make_array(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = NULL;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, false)) {
BJNX bnx(g);
PBVAL jvp = bnx.MakeValue(args, 0);
PBVAL arp = bnx.NewVal(TYPE_JAR);
for (uint i = 0; i < args->arg_count;) {
bnx.AddArrayValue(arp, jvp);
jvp = bnx.MakeValue(args, ++i);
} // endfor i
if ((bsp = BbinAlloc(bnx.G, initid->max_length, arp))) {
safe_strcat(bsp->Msg, sizeof(bsp->Msg), " array");
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
} // endif CheckMemory
} else
bsp = (PBSON)g->Xchk;
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_make_array
void bbin_make_array_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_make_array_deinit
/*********************************************************************************/
/* Add one value to a Json array. */
/*********************************************************************************/
my_bool bbin_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else
CalcLen(args, false, reslen, memlen, true);
if (!JsonInit(initid, args, message, true, reslen, memlen)) {
PGLOBAL g = (PGLOBAL)initid->ptr;
// This is a constant function
g->N = (initid->const_item) ? 1 : 0;
// This is to avoid double execution when using prepared statements
if (IsArgJson(args, 0) > 1)
initid->const_item = 0;
return false;
} else
return true;
} // end of bbin_array_add_init
char *bbin_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = NULL;
if (g->Xchk) {
// This constant function was recalled
bsp = (PBSON)g->Xchk;
*res_length = sizeof(BSON);
return (char*)bsp;
} else if (!CheckMemory(g, initid, args, 2, false, false, true)) {
uint n = 2;
int* x = GetIntArgPtr(g, args, n);
BJNX bnx(g, NULL, TYPE_STRING);
PBVAL jarp = NULL, top = NULL, jvp = NULL;
PBVAL jsp = bnx.MakeValue(args, 0, true, &top);
if (bnx.CheckPath(g, args, jsp, jvp, 2))
PUSH_WARNING(g->Message);
else if (jvp && jvp->Type != TYPE_JAR) {
if ((jarp = bnx.NewVal(TYPE_JAR))) {
bnx.AddArrayValue(jarp, jvp);
if (!top)
top = jarp;
} // endif jarp
} else
jarp = jvp;
if (jarp) {
bnx.AddArrayValue(jarp, bnx.MakeValue(args, 1), x);
bnx.SetChanged(true);
bsp = bnx.MakeBinResult(args, top, initid->max_length);
if (initid->const_item)
// Keep result of constant function
g->Xchk = bsp;
} else
PUSH_WARNING(g->Message);
} // endif CheckMemory
if (!bsp) {
*res_length = 0;
*is_null = 1;
*error = 1;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_array_add
void bbin_array_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_array_add_deinit
/*********************************************************************************/
/* Add one or several values to a Bson array. */
/*********************************************************************************/
my_bool bbin_array_add_values_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
{
return bson_array_add_values_init(initid, args, message);
} // end of bbin_array_add_values_init
char* bbin_array_add_values(UDF_INIT* initid, UDF_ARGS* args, char* result,
unsigned long* res_length, char* is_null, char* error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = NULL;
if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, true)) {
uint i = 0;
BJNX bnx(g);
PBVAL arp, top;
PBVAL bvp = bnx.MakeValue(args, 0, true, &top);
if (bvp->Type == TYPE_JAR) {
arp = bvp;
i = 1;
} else // First argument is not an array
arp = bnx.NewVal(TYPE_JAR);
for (; i < args->arg_count; i++)
bnx.AddArrayValue(arp, bnx.MakeValue(args, i));
bnx.SetChanged(true);
bsp = bnx.MakeBinResult(args, top, initid->max_length);
} // endif CheckMemory
// Keep result of constant function
g->Xchk = (g->N) ? bsp : NULL;
} else
bsp = (PBSON)g->Xchk;
if (!bsp) {
*res_length = 0;
*is_null = 1;
*error = 1;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_array_add_values
void bbin_array_add_values_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_array_add_values_deinit
/*********************************************************************************/
/* Make a Json array from values coming from rows. */
/*********************************************************************************/
my_bool bbin_array_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_array_grp_init(initid, args, message);
} // end of bbin_array_grp_init
void bbin_array_grp_clear(UDF_INIT *initid, char *a, char *b)
{
bson_array_grp_clear(initid, a, b);
} // end of bbin_array_grp_clear
void bbin_array_grp_add(UDF_INIT *initid, UDF_ARGS *args, char *a, char *b)
{
bson_array_grp_add(initid, args, a, b);
} // end of bbin_array_grp_add
char *bbin_array_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PBSON bsp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBVAL arp = (PBVAL)g->Activityp;
if (g->N < 0)
PUSH_WARNING("Result truncated to json_grp_size values");
if (arp)
if ((bsp = BbinAlloc(g, initid->max_length, arp))) {
safe_strcat(bsp->Msg, sizeof(bsp->Msg), " array");
}
if (!bsp) {
*res_length = 0;
*is_null = 1;
*error = 1;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_array_grp
void bbin_array_grp_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_array_grp_deinit
/*********************************************************************************/
/* Make a Json object from values coming from rows. */
/*********************************************************************************/
my_bool bbin_object_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_object_grp_init(initid, args, message);
} // end of bbin_object_grp_init
void bbin_object_grp_clear(UDF_INIT *initid, char *a, char *b)
{
bson_object_grp_clear(initid, a, b);
} // end of bbin_object_grp_clear
void bbin_object_grp_add(UDF_INIT *initid, UDF_ARGS *args, char *a, char *b)
{
bson_object_grp_add(initid, args, a, b);
} // end of bbin_object_grp_add
char *bbin_object_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PBSON bsp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBVAL bop = (PBVAL)g->Activityp;
if (g->N < 0)
PUSH_WARNING("Result truncated to json_grp_size values");
if (bop)
if ((bsp = BbinAlloc(g, initid->max_length, bop))) {
safe_strcat(bsp->Msg, sizeof(bsp->Msg), " object");
}
if (!bsp) {
*res_length = 0;
*is_null = 1;
*error = 1;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_object_grp
void bbin_object_grp_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_object_grp_deinit
/*********************************************************************************/
/* Make a Json Object containing all the parameters. */
/*********************************************************************************/
my_bool bbin_make_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, false, reslen, memlen);
} // end of bbin_make_object_init
char *bbin_make_object(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (!bsp) {
if (!CheckMemory(g, initid, args, args->arg_count, true)) {
BJNX bnx(g);
PBVAL objp;
if ((objp = bnx.NewVal(TYPE_JOB))) {
for (uint i = 0; i < args->arg_count; i++)
bnx.SetKeyValue(objp, bnx.MakeValue(args, i), bnx.MakeKey(args, i));
if ((bsp = BbinAlloc(bnx.G, initid->max_length, objp))) {
safe_strcat(bsp->Msg, sizeof(bsp->Msg), " object");
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
} // endif objp
} // endif CheckMemory
} // endif Xchk
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_make_object
void bbin_make_object_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_make_object_deinit
/*********************************************************************************/
/* Make a Json Object containing all not null parameters. */
/*********************************************************************************/
my_bool bbin_object_nonull_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bbin_object_nonull_init
char *bbin_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (!bsp) {
if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
BJNX bnx(g);
PBVAL jvp, objp;
if ((objp = bnx.NewVal(TYPE_JOB))) {
for (uint i = 0; i < args->arg_count; i++)
if (!bnx.IsValueNull(jvp = bnx.MakeValue(args, i)))
bnx.SetKeyValue(objp, jvp, bnx.MakeKey(args, i));
if ((bsp = BbinAlloc(bnx.G, initid->max_length, objp))) {
safe_strcat(bsp->Msg, sizeof(bsp->Msg), " object");
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
} // endif objp
} // endif CheckMemory
} // endif Xchk
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_object_nonull
void bbin_object_nonull_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_object_nonull_deinit
/*********************************************************************************/
/* Make a Json Object containing all the key/value parameters. */
/*********************************************************************************/
my_bool bbin_object_key_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count % 2) {
strcpy(message, "This function must have an even number of arguments");
return true;
} // endif arg_count
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bbin_object_key_init
char *bbin_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (!bsp) {
if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
BJNX bnx(g);
PBVAL objp;
if ((objp = bnx.NewVal(TYPE_JOB))) {
for (uint i = 0; i < args->arg_count; i += 2)
bnx.SetKeyValue(objp, bnx.MakeValue(args, i + 1), MakePSZ(g, args, i));
if ((bsp = BbinAlloc(bnx.G, initid->max_length, objp))) {
safe_strcat(bsp->Msg, sizeof(bsp->Msg), " object");
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
} // endif objp
} // endif CheckMemory
} // endif Xchk
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_object_key
void bbin_object_key_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_object_key_deinit
/*********************************************************************************/
/* Add or replace a value in a Json Object. */
/*********************************************************************************/
my_bool bbin_object_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have at least 2 arguments");
return true;
} else if (!IsArgJson(args, 0)) {
strcpy(message, "First argument must be a json item");
return true;
} else
CalcLen(args, true, reslen, memlen, true);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bbin_object_add_init
char *bbin_object_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = NULL;
if (g->Xchk) {
// This constant function was recalled
bsp = (PBSON)g->Xchk;
*res_length = sizeof(BSON);
return (char*)bsp;
} else if (!CheckMemory(g, initid, args, 2, false, true, true)) {
PSZ key;
BJNX bnx(g, NULL, TYPE_STRING);
PBVAL top;
PBVAL jobp = bnx.MakeValue(args, 0, true, &top);
PBVAL jvp = jobp;
if (bnx.CheckPath(g, args, jvp, jobp, 2))
PUSH_WARNING(g->Message);
else if (jobp && jobp->Type == TYPE_JOB) {
jvp = bnx.MakeValue(args, 1);
key = bnx.MakeKey(args, 1);
bnx.SetKeyValue(jobp, jvp, key);
bnx.SetChanged(true);
} else {
PUSH_WARNING("First argument target is not an object");
// if (g->Mrr) *error = 1; (only if no path)
} // endif jobp
// In case of error unchanged argument will be returned
bsp = bnx.MakeBinResult(args, top, initid->max_length);
if (initid->const_item)
// Keep result of constant function
g->Xchk = bsp;
} // endif CheckMemory
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_object_add
void bbin_object_add_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_object_add_deinit
/*********************************************************************************/
/* Delete a value from a Json array. */
/*********************************************************************************/
my_bool bbin_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_array_delete_init(initid, args, message);
} // end of bbin_array_delete_init
char *bbin_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = NULL;
if (g->Xchk) {
// This constant function was recalled
bsp = (PBSON)g->Xchk;
} else if (!CheckMemory(g, initid, args, 1, false, false, true)) {
int* x;
uint n = 1;
BJNX bnx(g);
PBVAL arp, top;
PBVAL jvp = bnx.MakeValue(args, 0, true, &top);
if (!(x = GetIntArgPtr(g, args, n)))
PUSH_WARNING("Missing or null array index");
else if (bnx.CheckPath(g, args, jvp, arp, 1))
PUSH_WARNING(g->Message);
else if (arp && arp->Type == TYPE_JAR) {
bnx.SetChanged(bnx.DeleteValue(arp, *x));
bsp = bnx.MakeBinResult(args, top, initid->max_length);
} else {
PUSH_WARNING("First argument target is not an array");
// if (g->Mrr) *error = 1;
} // endif jvp
if (g->N)
// Keep result of constant function
g->Xchk = bsp;
} // endif CheckMemory
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_array_delete
void bbin_array_delete_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_array_delete_deinit
/*********************************************************************************/
/* Delete a value from a Json object. */
/*********************************************************************************/
my_bool bbin_object_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "This function must have 2 or 3 arguments");
return true;
} else if (!IsArgJson(args, 0)) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_type[1] != STRING_RESULT) {
strcpy(message, "Second argument must be a key string");
return true;
} else
CalcLen(args, true, reslen, memlen, true);
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of bbin_object_delete_init
char *bbin_object_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = NULL;
if (g->Xchk) {
// This constant function was recalled
bsp = (PBSON)g->Xchk;
*res_length = sizeof(BSON);
return (char*)bsp;
} else if (!CheckMemory(g, initid, args, 1, false, true, true)) {
PCSZ key;
BJNX bnx(g, NULL, TYPE_STRING);
PBVAL top;
PBVAL jobp = bnx.MakeValue(args, 0, true, &top);
if (bnx.CheckPath(g, args, top, jobp, 2))
PUSH_WARNING(g->Message);
else if (jobp && jobp->Type == TYPE_JOB) {
key = bnx.MakeKey(args, 1);
bnx.SetChanged(bnx.DeleteKey(jobp, key));
} else {
PUSH_WARNING("First argument target is not an object");
// if (g->Mrr) *error = 1; (only if no path)
} // endif jvp
// In case of error unchanged argument will be returned
bsp = bnx.MakeBinResult(args, top, initid->max_length);
if (initid->const_item)
// Keep result of constant function
g->Xchk = bsp;
} // endif CheckMemory
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_object_delete
void bbin_object_delete_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_object_delete_deinit
/*********************************************************************************/
/* Returns an array of the Json object keys. */
/*********************************************************************************/
my_bool bbin_object_list_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_object_list_init(initid, args, message);
} // end of bbin_object_list_init
char *bbin_object_list(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (!bsp) {
if (!CheckMemory(g, initid, args, 1, true, true)) {
BJNX bnx(g);
PBVAL top, jarp = NULL;
PBVAL jsp = bnx.MakeValue(args, 0, true, &top);
if (jsp->Type == TYPE_JOB) {
jarp = bnx.GetKeyList(jsp);
} else {
PUSH_WARNING("First argument is not an object");
if (g->Mrr) *error = 1;
} // endif jsp type
// In case of error unchanged argument will be returned
bsp = bnx.MakeBinResult(args, top, initid->max_length);
bsp->Jsp = (PJSON)jarp;
} // endif CheckMemory
// Keep result of constant function
g->Xchk = (initid->const_item) ? bsp : NULL;
} // endif bsp
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_object_list
void bbin_object_list_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_object_list_deinit
/*********************************************************************************/
/* Returns an array of the Json object values. */
/*********************************************************************************/
my_bool bbin_object_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_object_values_init(initid, args, message);
} // end of bbin_object_values_init
char *bbin_object_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = (PBSON)g->Xchk;
if (!bsp) {
if (!CheckMemory(g, initid, args, 1, true, true)) {
BJNX bnx(g);
PBVAL top, jarp = NULL;
PBVAL jvp = bnx.MakeValue(args, 0, true, &top);
if (jvp->Type == TYPE_JOB) {
jarp = bnx.GetObjectValList(jvp);
} else {
PUSH_WARNING("First argument is not an object");
if (g->Mrr) *error = 1;
} // endif jvp
// In case of error unchanged argument will be returned
bsp = bnx.MakeBinResult(args, top, initid->max_length);
bsp->Jsp = (PJSON)jarp;
} // endif CheckMemory
if (initid->const_item) {
// Keep result of constant function
g->Xchk = bsp;
} // endif const_item
} // endif bsp
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_object_values
void bbin_object_values_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_object_values_deinit
/*********************************************************************************/
/* Get a Json item from a Json document. */
/*********************************************************************************/
my_bool bbin_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_get_item_init(initid, args, message);
} // end of bbin_get_item_init
char *bbin_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PBSON bsp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
bsp = (PBSON)g->Xchk;
} else if (!CheckMemory(g, initid, args, 1, true, true)) {
BJNX bnx(g, NULL, TYPE_STRING, initid->max_length);
PBVAL top, jvp = NULL;
PBVAL jsp = bnx.MakeValue(args, 0, true, &top);
if (bnx.CheckPath(g, args, jsp, jvp, 1))
PUSH_WARNING(g->Message);
else if (jvp) {
bsp = bnx.MakeBinResult(args, top, initid->max_length);
bsp->Jsp = (PJSON)jvp;
if (initid->const_item)
// Keep result of constant function
g->Xchk = bsp;
} // endif jvp
} else
PUSH_WARNING("CheckMemory error");
if (!bsp) {
*is_null = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_get_item
void bbin_get_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_get_item_deinit
/*********************************************************************************/
/* Merge two arrays or objects. */
/*********************************************************************************/
my_bool bbin_item_merge_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_item_merge_init(initid, args, message);
} // end of bbin_item_merge_init
char *bbin_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
PBSON bsp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
bsp = (PBSON)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 2, false, false, true)) {
JTYP type;
BJNX bnx(g);
PBVAL jvp = NULL, top = NULL;
PBVAL jsp[2] = {NULL, NULL};
for (int i = 0; i < 2; i++) {
if (i) {
jvp = bnx.MakeValue(args, i, true);
if (jvp && (jvp->Type != type)) {
PUSH_WARNING("Argument types mismatch");
goto fin;
} // endif type
} else {
jvp = bnx.MakeValue(args, i, true, &top);
type = (JTYP)jvp->Type;
if (type != TYPE_JAR && type != TYPE_JOB) {
PUSH_WARNING("First argument is not an array or object");
goto fin;
} // endif type
} // endif i
jsp[i] = jvp;
} // endfor i
if (type == TYPE_JAR)
bnx.MergeArray(jsp[0], jsp[1]);
else
bnx.MergeObject(jsp[0], jsp[1]);
bnx.SetChanged(true);
bsp = bnx.MakeBinResult(args, top, initid->max_length);
} // endif CheckMemory
if (g->N)
// Keep result of constant function
g->Xchk = bsp;
fin:
if (!bsp) {
*res_length = 0;
*error = 1;
*is_null = 1;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_item_merge
void bbin_item_merge_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_item_merge_deinit
/*********************************************************************************/
/* This function is used by the jbin_set/insert/update_item functions. */
/*********************************************************************************/
static char *bbin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *path;
int w;
my_bool b = true;
PBJNX bxp;
PBVAL jsp, jvp, top;
PBSON bsp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Alchecked) {
bsp = (PBSON)g->Activityp;
goto fin;
} else if (g->N)
g->Alchecked = 1;
if (!strcmp(result, "$set"))
w = 0;
else if (!strcmp(result, "$insert"))
w = 1;
else if (!strcmp(result, "$update"))
w = 2;
else {
PUSH_WARNING("Logical error, please contact CONNECT developer");
goto fin;
} // endelse
try {
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true, false, true)) {
throw 1;
} else {
BJNX bnx(g);
jsp = bnx.MakeValue(args, 0, true, &top);
if (g->Mrr) { // First argument is a constant
g->Xchk = jsp;
g->More = (size_t)top;
JsonMemSave(g);
} // endif Mrr
} // endif CheckMemory
} else {
jsp = (PBVAL)g->Xchk;
top = (PBVAL)g->More;
} // endif Xchk
bxp = new(g)BJNX(g, jsp, TYPE_STRING, initid->max_length, 0, true);
for (uint i = 1; i + 1 < args->arg_count; i += 2) {
jvp = bxp->MakeValue(args, i);
path = MakePSZ(g, args, i + 1);
if (bxp->SetJpath(g, path, false))
throw 2;
if (w) {
bxp->ReadValue(g);
b = bxp->GetValue()->IsNull();
b = (w == 1) ? b : !b;
} // endif w
if (b && bxp->WriteValue(g, jvp))
throw 3;
bxp->SetChanged(true);
} // endfor i
if (!(bsp = bxp->MakeBinResult(args, top, initid->max_length)))
throw 4;
if (g->N)
// Keep result of constant function
g->Activityp = (PACTIVITY)bsp;
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
} catch (const char *msg) {
snprintf(g->Message, sizeof(g->Message), "%s", msg);
PUSH_WARNING(g->Message);
} // end catch
fin:
if (!bsp) {
*is_null = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_handle_item
/*********************************************************************************/
/* Set Json items of a Json document according to path. */
/*********************************************************************************/
my_bool bbin_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_set_item_init(initid, args, message);
} // end of bbin_set_item_init
char *bbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$set");
return bbin_handle_item(initid, args, result, res_length, is_null, p);
} // end of bbin_set_item
void bbin_set_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_set_item_deinit
/*********************************************************************************/
/* Insert Json items of a Json document according to path. */
/*********************************************************************************/
my_bool bbin_insert_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_set_item_init(initid, args, message);
} // end of bbin_insert_item_init
char *bbin_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$insert");
return bbin_handle_item(initid, args, result, res_length, is_null, p);
} // end of bbin_insert_item
void bbin_insert_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_insert_item_deinit
/*********************************************************************************/
/* Update Json items of a Json document according to path. */
/*********************************************************************************/
my_bool bbin_update_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_set_item_init(initid, args, message);
} // end of bbin_update_item_init
char *bbin_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$update");
return bbin_handle_item(initid, args, result, res_length, is_null, p);
} // end of bbin_update_item
void bbin_update_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_update_item_deinit
/*********************************************************************************/
/* Delete items from a Json document. */
/*********************************************************************************/
my_bool bbin_delete_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_delete_item_init(initid, args, message);
} // end of bbin_delete_item_init
char *bbin_delete_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *path;
PBSON bsp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->Xchk) {
// This constant function was recalled
bsp = (PBSON)g->Xchk;
goto fin;
} // endif Xchk
if (!CheckMemory(g, initid, args, 1, false, false, true)) {
BJNX bnx(g, NULL, TYPE_STRING);
PBVAL top, jar = NULL;
PBVAL jvp = bnx.MakeValue(args, 0, true, &top);
if (args->arg_count == 1) {
// This should be coming from bbin_locate_all
jar = jvp; // This is the array of paths
jvp = top; // And this is the document
} else if(!bnx.IsJson(jvp)) {
PUSH_WARNING("First argument is not a JSON document");
goto fin;
} else if (args->arg_count == 2) {
// Check whether this is an array of paths
jar = bnx.MakeValue(args, 1, true);
if (jar && jar->Type != TYPE_JAR)
jar = NULL;
} // endif arg_count
if (jar) {
// Do the deletion in reverse order
for(int i = bnx.GetArraySize(jar) - 1; i >= 0; i--) {
path = bnx.GetString(bnx.GetArrayValue(jar, i));
if (bnx.SetJpath(g, path, false)) {
PUSH_WARNING(g->Message);
continue;
} // endif SetJpath
bnx.SetChanged(bnx.DeleteItem(g, jvp));
} // endfor i
} else for (uint i = 1; i < args->arg_count; i++) {
path = MakePSZ(g, args, i);
if (bnx.SetJpath(g, path, false)) {
PUSH_WARNING(g->Message);
continue;
} // endif SetJpath
bnx.SetChanged(bnx.DeleteItem(g, jvp));
} // endfor i
bsp = bnx.MakeBinResult(args, top, initid->max_length);
if (args->arg_count == 1)
// Here Jsp was not a sub-item of top
bsp->Jsp = (PJSON)top;
} // endif CheckMemory
if (g->N)
// Keep result of constant function
g->Xchk = bsp;
fin:
if (!bsp) {
*is_null = 1;
*error = 1;
*res_length = 0;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_delete_item
void bbin_delete_item_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_delete_item_deinit
/*********************************************************************************/
/* Returns a json file as a json binary tree. */
/*********************************************************************************/
my_bool bbin_file_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return bson_file_init(initid, args, message);
} // end of bbin_file_init
char *bbin_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *fn;
int pretty = 3;
size_t len = 0;
PBVAL jsp, jvp = NULL;
PGLOBAL g = (PGLOBAL)initid->ptr;
BJNX bnx(g);
PBSON bsp = (PBSON)g->Xchk;
if (bsp)
goto fin;
fn = MakePSZ(g, args, 0);
for (unsigned int i = 1; i < args->arg_count; i++)
if (args->arg_type[i] == INT_RESULT && *(longlong*)args->args[i] < 4) {
pretty = (int) * (longlong*)args->args[i];
break;
} // endif type
// Parse the json file and allocate its tree structure
if (!(jsp = bnx.ParseJsonFile(g, fn, pretty, len))) {
PUSH_WARNING(g->Message);
*error = 1;
goto fin;
} // endif jsp
// if (pretty == 3)
// PUSH_WARNING("File pretty format cannot be determined");
// else if (pretty == 3)
// pretty = pty;
if ((bsp = BbinAlloc(bnx.G, len, jsp))) {
safe_strcat(bsp->Msg, sizeof(bsp->Msg), " file");
bsp->Filename = fn;
bsp->Pretty = pretty;
} else {
*error = 1;
goto fin;
} // endif bsp
// Check whether a path was specified
if (bnx.CheckPath(g, args, jsp, jvp, 1)) {
PUSH_WARNING(g->Message);
bsp = NULL;
goto fin;
} else if (jvp)
bsp->Jsp = (PJSON)jvp;
if (initid->const_item)
// Keep result of constant function
g->Xchk = bsp;
fin:
if (!bsp) {
*res_length = 0;
*is_null = 1;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_file
void bbin_file_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_file_deinit
/*********************************************************************************/
/* Locate all occurences of a value in a Json tree. */
/*********************************************************************************/
my_bool bbin_locate_all_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
return bson_locate_all_init(initid, args, message);
} // end of bbin_locate_all_init
char* bbin_locate_all(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;
PGLOBAL g = (PGLOBAL)initid->ptr;
PBSON bsp = NULL;
if (g->N) {
if (g->Activityp) {
bsp = (PBSON)g->Activityp;
*res_length = sizeof(BSON);
return (char*)bsp;
} else {
*error = 1;
*res_length = 0;
*is_null = 1;
return NULL;
} // endif Activityp
} else if (initid->const_item)
g->N = 1;
try {
PBVAL top = NULL;
BJNX bnx(g);
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
*error = 1;
goto err;
} else
bnx.Reset();
bvp = bnx.MakeValue(args, 0, true, &top);
if (bvp->Type == TYPE_NULL) {
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;
g->More = (size_t)top;
JsonMemSave(g);
} // endif Mrr
} else {
bvp = (PBVAL)g->Xchk;
top = (PBVAL)g->More;
} // endif Xchk
// The item to locate
bvp2 = bnx.MakeValue(args, 1, true);
if (bvp2->Type == TYPE_NULL) {
PUSH_WARNING("Invalid second argument");
goto err;
} // endif bvp2
if (args->arg_count > 2)
mx = (int)*(long long*)args->args[2];
if ((path = bnx.LocateAll(g, bvp, bvp2, mx))) {
bsp = bnx.MakeBinResult(args, top, initid->max_length);
bsp->Jsp = (PJSON)bnx.ParseJson(g, path, strlen(path));
} // endif path
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)bsp;
} catch (int n) {
xtrc(1, "Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
*error = 1;
path = NULL;
} catch (const char* msg) {
snprintf(g->Message, sizeof(g->Message), "%s", msg);
PUSH_WARNING(g->Message);
*error = 1;
path = NULL;
} // end catch
err:
if (!bsp) {
*res_length = 0;
*is_null = 1;
} else
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bbin_locate_all
void bbin_locate_all_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of bbin_locate_all_deinit