Commit dc8f914c authored by Olivier Bertrand's avatar Olivier Bertrand

Remove based enum not accepted by most gcc compilers

parent dae4bd0b
......@@ -21,8 +21,6 @@
#include "plgdbsem.h"
#include "bson.h"
#define ARGS MY_MIN(24,(int)len-i),s+MY_MAX(i-3,0)
#if defined(__WIN__)
#define EL "\r\n"
#else
......@@ -89,43 +87,14 @@ char* NextChr(PSZ s, char sep) {
/***********************************************************************/
/* BDOC constructor. */
/***********************************************************************/
BDOC::BDOC(void) : jp(NULL), base(NULL), s(NULL), len(0)
BDOC::BDOC(void *base) : BJSON(base, NULL)
{
jp = NULL;
s = NULL;
len = 0;
pty[0] = pty[1] = pty[2] = true;
} // end of BDOC constructor
/***********************************************************************/
/* Program for sub-allocating Bson structures. */
/***********************************************************************/
void* BDOC::BsonSubAlloc(PGLOBAL g, size_t size) {
PPOOLHEADER pph; /* Points on area header. */
void* memp = g->Sarea;
size = ((size + 3) / 4) * 4; /* Round up size to multiple of 4 */
pph = (PPOOLHEADER)memp;
xtrc(16, "SubAlloc in %p size=%zd used=%zd free=%zd\n",
memp, size, pph->To_Free, pph->FreeBlk);
if (size > pph->FreeBlk) { /* Not enough memory left in pool */
sprintf(g->Message,
"Not enough memory for request of %zd (used=%zd free=%zd)",
size, pph->To_Free, pph->FreeBlk);
xtrc(1, "BsonSubAlloc: %s\n", g->Message);
throw(1234);
} /* endif size OS32 code */
// Do the suballocation the simplest way
memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block */
pph->To_Free += size; /* New offset of pool free block */
pph->FreeBlk -= size; /* New size of pool free block */
xtrc(16, "Done memp=%p used=%zd free=%zd\n",
memp, pph->To_Free, pph->FreeBlk);
return memp;
} /* end of BsonSubAlloc */
/***********************************************************************/
/* Parse a json string. */
/* Note: when pretty is not known, the caller set pretty to 3. */
......@@ -133,9 +102,10 @@ void* BDOC::BsonSubAlloc(PGLOBAL g, size_t size) {
PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) {
int i, pretty = (ptyp) ? *ptyp : 3;
bool b = false;
PBVAL bvp = NULL;
xtrc(1, "ParseJson: s=%.10s len=%zd\n", s, len);
s = js;
len = lng;
xtrc(1, "BDOC::ParseJson: s=%.10s len=%zd\n", s, len);
if (!s || !len) {
strcpy(g->Message, "Void JSON object");
......@@ -147,30 +117,26 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) {
if (s[0] == '[' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n')))
pty[0] = false;
s = js;
len = lng;
try {
bvp = (PBVAL)PlugSubAlloc(g, NULL, sizeof(BVAL));
bvp->Type = TYPE_UNKNOWN;
base = bvp;
Bvp = SubAllocVal(g);
Bvp->Type = TYPE_UNKNOWN;
for (i = 0; i < len; i++)
switch (s[i]) {
case '[':
if (bvp->Type != TYPE_UNKNOWN)
bvp->To_Val = ParseAsArray(g, i, pretty, ptyp);
if (Bvp->Type != TYPE_UNKNOWN)
Bvp->To_Val = ParseAsArray(g, i, pretty, ptyp);
else
bvp->To_Val = ParseArray(g, ++i);
Bvp->To_Val = ParseArray(g, ++i);
bvp->Type = TYPE_JAR;
Bvp->Type = TYPE_JAR;
break;
case '{':
if (bvp->Type != TYPE_UNKNOWN) {
bvp->To_Val = ParseAsArray(g, i, pretty, ptyp);
bvp->Type = TYPE_JAR;
} else if ((bvp->To_Val = ParseObject(g, ++i)))
bvp->Type = TYPE_JOB;
if (Bvp->Type != TYPE_UNKNOWN) {
Bvp->To_Val = ParseAsArray(g, i, pretty, ptyp);
Bvp->Type = TYPE_JAR;
} else if ((Bvp->To_Val = ParseObject(g, ++i)))
Bvp->Type = TYPE_JOB;
else
throw 2;
......@@ -181,7 +147,7 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) {
case '\r':
break;
case ',':
if (bvp->Type != TYPE_UNKNOWN && (pretty == 1 || pretty == 3)) {
if (Bvp->Type != TYPE_UNKNOWN && (pretty == 1 || pretty == 3)) {
if (comma)
*comma = true;
......@@ -201,18 +167,18 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) {
} // endif b
default:
if (bvp->Type != TYPE_UNKNOWN) {
bvp->To_Val = ParseAsArray(g, i, pretty, ptyp);
bvp->Type = TYPE_JAR;
} else if ((bvp->To_Val = MakeOff(base, ParseValue(g, i))))
bvp->Type = TYPE_JVAL;
if (Bvp->Type != TYPE_UNKNOWN) {
Bvp->To_Val = ParseAsArray(g, i, pretty, ptyp);
Bvp->Type = TYPE_JAR;
} else if ((Bvp->To_Val = MOF(ParseValue(g, i))))
Bvp->Type = TYPE_JVAL;
else
throw 4;
break;
}; // endswitch s[i]
if (bvp->Type == TYPE_UNKNOWN)
if (Bvp->Type == TYPE_UNKNOWN)
sprintf(g->Message, "Invalid Json string '%.*s'", MY_MIN((int)len, 50), s);
else if (ptyp && pretty == 3) {
*ptyp = 3; // Not recognized pretty
......@@ -228,13 +194,13 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) {
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
bvp = NULL;
Bvp = NULL;
} catch (const char* msg) {
strcpy(g->Message, msg);
bvp = NULL;
Bvp = NULL;
} // end catch
return bvp;
return Bvp;
} // end of ParseJson
/***********************************************************************/
......@@ -280,7 +246,7 @@ OFFSET BDOC::ParseArray(PGLOBAL g, int& i) {
throw 1;
} // endif level
return MakeOff(base, vlp);
return MOF(firstvlp);
case '\n':
if (!b)
pty[0] = pty[1] = false;
......@@ -294,7 +260,7 @@ OFFSET BDOC::ParseArray(PGLOBAL g, int& i) {
throw 1;
} else if (lastvlp) {
vlp = ParseValue(g, i);
lastvlp->Next = MakeOff(base, vlp);
lastvlp->Next = MOF(vlp);
lastvlp = vlp;
} else
firstvlp = lastvlp = ParseValue(g, i);
......@@ -305,25 +271,12 @@ OFFSET BDOC::ParseArray(PGLOBAL g, int& i) {
if (b) {
// Case of Pretty == 0
return MakeOff(base, vlp);
return MOF(firstvlp);
} // endif b
throw ("Unexpected EOF in array");
} // end of ParseArray
/***********************************************************************/
/* Sub-allocate and initialize a BPAIR. */
/***********************************************************************/
PBPR BDOC::SubAllocPair(PGLOBAL g, OFFSET key)
{
PBPR bpp = (PBPR)BsonSubAlloc(g, sizeof(BPAIR));
bpp->Key = key;
bpp->Vlp = 0;
bpp->Next = 0;
return bpp;
} // end of SubAllocPair
/***********************************************************************/
/* Parse a JSON Object. */
/***********************************************************************/
......@@ -342,7 +295,7 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) {
bpp = SubAllocPair(g, key);
if (lastbpp) {
lastbpp->Next = MakeOff(base, bpp);
lastbpp->Next = MOF(bpp);
lastbpp = bpp;
} else
firstbpp = lastbpp = bpp;
......@@ -356,7 +309,7 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) {
break;
case ':':
if (level == 1) {
lastbpp->Vlp = MakeOff(base, ParseValue(g, ++i));
lastbpp->Vlp = MOF(ParseValue(g, ++i));
level = 2;
} else {
sprintf(g->Message, "Unexpected ':' near %.*s", ARGS);
......@@ -378,7 +331,7 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) {
throw 2;
} // endif level
return MakeOff(base, firstbpp);
return MOF(firstbpp);
case '\n':
pty[0] = pty[1] = false;
case '\r':
......@@ -395,20 +348,6 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) {
throw 2;
} // end of ParseObject
/***********************************************************************/
/* Sub-allocate and initialize a BVAL. */
/***********************************************************************/
PBVAL BDOC::SubAllocVal(PGLOBAL g)
{
PBVAL bvp = (PBVAL)BsonSubAlloc(g, sizeof(BVAL));
bvp->To_Val = 0;
bvp->Nd = 0;
bvp->Type = TYPE_UNKNOWN;
bvp->Next = 0;
return bvp;
} // end of SubAllocVal
/***********************************************************************/
/* Parse a JSON Value. */
/***********************************************************************/
......@@ -505,7 +444,7 @@ OFFSET BDOC::ParseString(PGLOBAL g, int& i) {
case '"':
p[n++] = 0;
PlugSubAlloc(g, NULL, n);
return MakeOff(base, p);
return MOF(p);
case '\\':
if (++i < len) {
if (s[i] == 'u') {
......@@ -634,7 +573,7 @@ void BDOC::ParseNumeric(PGLOBAL g, int& i, PBVAL vlp) {
double* dvp = (double*)PlugSubAlloc(g, NULL, sizeof(double));
*dvp = dv;
vlp->To_Val = MakeOff(base, dvp);
vlp->To_Val = MOF(dvp);
vlp->Type = TYPE_DBL;
} else {
vlp->F = (float)dv;
......@@ -643,13 +582,13 @@ void BDOC::ParseNumeric(PGLOBAL g, int& i, PBVAL vlp) {
vlp->Nd = nd;
} else {
long long iv = strtoll(buf, NULL, 10);
longlong iv = strtoll(buf, NULL, 10);
if (iv > INT_MAX32 || iv < INT_MIN32) {
long long *llp = (long long*)PlugSubAlloc(g, NULL, sizeof(long long));
longlong *llp = (longlong*)PlugSubAlloc(g, NULL, sizeof(longlong));
*llp = iv;
vlp->To_Val = MakeOff(base, llp);
vlp->To_Val = MOF(llp);
vlp->Type = TYPE_BINT;
} else {
vlp->N = (int)iv;
......@@ -668,12 +607,11 @@ void BDOC::ParseNumeric(PGLOBAL g, int& i, PBVAL vlp) {
} // end of ParseNumeric
/***********************************************************************/
/* Serialize a JSON document tree: */
/* Serialize a BJSON document tree: */
/***********************************************************************/
PSZ BDOC::Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty) {
PSZ str = NULL;
bool b = false, err = true;
JOUT* jp;
FILE* fs = NULL;
g->Message[0] = 0;
......@@ -712,7 +650,7 @@ PSZ BDOC::Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty) {
err |= SerializeObject(bvp->To_Val);
break;
case TYPE_JVAL:
err = SerializeValue((PBVAL)MakePtr(base, bvp->To_Val));
err = SerializeValue(MVP(bvp->To_Val));
break;
default:
strcpy(g->Message, "Invalid json tree");
......@@ -750,7 +688,7 @@ PSZ BDOC::Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty) {
/***********************************************************************/
bool BDOC::SerializeArray(OFFSET arp, bool b) {
bool first = true;
PBVAL vp = (PBVAL)MakePtr(base, arp);
PBVAL vp = MVP(arp);
if (b) {
if (jp->Prty()) {
......@@ -764,7 +702,7 @@ bool BDOC::SerializeArray(OFFSET arp, bool b) {
} else if (jp->WriteChr('['))
return true;
for (vp; vp; vp = (PBVAL)MakePtr(base, vp->Next)) {
for (vp; vp; vp = MVP(vp->Next)) {
if (first)
first = false;
else if ((!b || jp->Prty()) && jp->WriteChr(','))
......@@ -780,7 +718,7 @@ bool BDOC::SerializeArray(OFFSET arp, bool b) {
if (SerializeValue(vp))
return true;
} // endfor i
} // endfor vp
if (b && jp->Prty() == 1 && jp->WriteStr(EL))
return true;
......@@ -793,22 +731,22 @@ bool BDOC::SerializeArray(OFFSET arp, bool b) {
/***********************************************************************/
bool BDOC::SerializeObject(OFFSET obp) {
bool first = true;
PBPR prp = (PBPR)MakePtr(base, obp);
PBPR prp = MPP(obp);
if (jp->WriteChr('{'))
return true;
for (prp; prp; prp = (PBPR)MakePtr(base, prp->Next)) {
for (prp; prp; prp = MPP(prp->Next)) {
if (first)
first = false;
else if (jp->WriteChr(','))
return true;
if (jp->WriteChr('"') ||
jp->WriteStr((const char*)MakePtr(base, prp->Key)) ||
jp->WriteStr(MZP(prp->Key)) ||
jp->WriteChr('"') ||
jp->WriteChr(':') ||
SerializeValue((PBVAL)MakePtr(base, prp->Vlp)))
SerializeValue(MVP(prp->Vlp)))
return true;
} // endfor i
......@@ -831,18 +769,18 @@ bool BDOC::SerializeValue(PBVAL jvp) {
return jp->WriteStr(jvp->B ? "true" : "false");
case TYPE_STRG:
case TYPE_DTM:
return jp->Escape((const char*)MakePtr(base, jvp->To_Val));
return jp->Escape(MZP(jvp->To_Val));
case TYPE_INTG:
sprintf(buf, "%d", jvp->N);
return jp->WriteStr(buf);
case TYPE_BINT:
sprintf(buf, "%lld", *(long long*)MakePtr(base, jvp->To_Val));
sprintf(buf, "%lld", *(longlong*)MakePtr(Base, jvp->To_Val));
return jp->WriteStr(buf);
case TYPE_FLOAT:
sprintf(buf, "%.*f", jvp->Nd, jvp->F);
return jp->WriteStr(buf);
case TYPE_DBL:
sprintf(buf, "%.*lf", jvp->Nd, *(double*)MakePtr(base, jvp->To_Val));
sprintf(buf, "%.*lf", jvp->Nd, *(double*)MakePtr(Base, jvp->To_Val));
return jp->WriteStr(buf);
case TYPE_NULL:
return jp->WriteStr("null");
......@@ -854,84 +792,139 @@ bool BDOC::SerializeValue(PBVAL jvp) {
return true;
} // end of SerializeValue
#if 0
/* -------------------------- Class JOBJECT -------------------------- */
/* --------------------------- Class BJSON --------------------------- */
/***********************************************************************/
/* Program for sub-allocating Bjson structures. */
/***********************************************************************/
void* BJSON::BsonSubAlloc(PGLOBAL g, size_t size)
{
PPOOLHEADER pph; /* Points on area header. */
void* memp = g->Sarea;
size = ((size + 3) / 4) * 4; /* Round up size to multiple of 4 */
pph = (PPOOLHEADER)memp;
xtrc(16, "SubAlloc in %p size=%zd used=%zd free=%zd\n",
memp, size, pph->To_Free, pph->FreeBlk);
if (size > pph->FreeBlk) { /* Not enough memory left in pool */
sprintf(g->Message,
"Not enough memory for request of %zd (used=%zd free=%zd)",
size, pph->To_Free, pph->FreeBlk);
xtrc(1, "BsonSubAlloc: %s\n", g->Message);
throw(1234);
} /* endif size OS32 code */
// Do the suballocation the simplest way
memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block */
pph->To_Free += size; /* New offset of pool free block */
pph->FreeBlk -= size; /* New size of pool free block */
xtrc(16, "Done memp=%p used=%zd free=%zd\n",
memp, pph->To_Free, pph->FreeBlk);
return memp;
} /* end of BsonSubAlloc */
/* ------------------------ Bobject functions ------------------------ */
/***********************************************************************/
/* Sub-allocate and initialize a BPAIR. */
/***********************************************************************/
PBPR BJSON::SubAllocPair(PGLOBAL g, OFFSET key, OFFSET val)
{
PBPR bpp = (PBPR)BsonSubAlloc(g, sizeof(BPAIR));
bpp->Key = key;
bpp->Vlp = val;
bpp->Next = 0;
return bpp;
} // end of SubAllocPair
/***********************************************************************/
/* Return the number of pairs in this object. */
/***********************************************************************/
int JOBJECT::GetSize(bool b) {
int BJSON::GetObjectSize(PBPR bop, bool b)
{
int n = 0;
for (PJPR jpp = First; jpp; jpp = jpp->Next)
for (PBPR brp = bop; brp; brp = MPP(brp->Next))
// If b return only non null pairs
if (!b || jpp->Val && !jpp->Val->IsNull())
if (!b || (brp->Vlp && (MVP(brp->Vlp))->Type != TYPE_NULL))
n++;
return n;
} // end of GetSize
} // end of GetObjectSize
/***********************************************************************/
/* Add a new pair to an Object. */
/* Add a new pair to an Object and return it. */
/***********************************************************************/
PJPR JOBJECT::AddPair(PGLOBAL g, PCSZ key) {
PJPR jpp = (PJPR)PlugSubAlloc(g, NULL, sizeof(JPAIR));
PBPR BJSON::AddPair(PGLOBAL g, PBPR bop, PSZ key, OFFSET val)
{
PBPR brp, nrp = SubAllocPair(g, MOF(key), val);
jpp->Key = key;
jpp->Next = NULL;
jpp->Val = NULL;
if (bop) {
for (brp = bop; brp->Next; brp = MPP(brp->Next));
if (Last)
Last->Next = jpp;
else
First = jpp;
brp->Next = MOF(nrp);
} else
bop = nrp;
Last = jpp;
return jpp;
return bop;
} // end of AddPair
/***********************************************************************/
/* Return all keys as an array. */
/* Return all object keys as an array. */
/***********************************************************************/
PJAR JOBJECT::GetKeyList(PGLOBAL g) {
PJAR jarp = new(g) JARRAY();
PBVAL BJSON::GetKeyList(PGLOBAL g, PBPR bop)
{
PBVAL bvp, lvp, fvp = NULL;
for (PJPR jpp = First; jpp; jpp = jpp->Next)
jarp->AddArrayValue(g, new(g) JVALUE(g, jpp->Key));
for (PBPR brp = bop; brp; brp = MPP(brp->Next))
if (fvp) {
bvp = SubAllocVal(g, brp->Key, TYPE_STRG);
lvp->Next = MOF(bvp);
lvp = bvp;
} else
lvp = fvp = SubAllocVal(g, brp->Key, TYPE_STRG);
jarp->InitArray(g);
return jarp;
return fvp;
} // end of GetKeyList
/***********************************************************************/
/* Return all values as an array. */
/* Return all object values as an array. */
/***********************************************************************/
PJAR JOBJECT::GetValList(PGLOBAL g) {
PJAR jarp = new(g) JARRAY();
PBVAL BJSON::GetObjectValList(PGLOBAL g, PBPR bop)
{
PBVAL bvp, lvp, fvp = NULL;
for (PJPR jpp = First; jpp; jpp = jpp->Next)
jarp->AddArrayValue(g, jpp->Val);
for (PBPR brp = bop; brp; brp = MPP(brp->Next))
if (fvp) {
bvp = DupVal(g, MVP(brp->Vlp));
lvp->Next = MOF(bvp);
lvp = bvp;
} else
lvp = fvp = DupVal(g, MVP(brp->Vlp));
jarp->InitArray(g);
return jarp;
} // end of GetValList
return fvp;
} // end of GetObjectValList
/***********************************************************************/
/* Get the value corresponding to the given key. */
/***********************************************************************/
PJVAL JOBJECT::GetKeyValue(const char* key) {
for (PJPR jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key))
return jp->Val;
PBVAL BJSON::GetKeyValue(PBPR bop, PSZ key)
{
for (PBPR brp = bop; brp; brp = MPP(brp->Next))
if (!strcmp(MZP(brp->Key), key))
return MVP(brp->Vlp);
return NULL;
} // end of GetValue;
} // end of GetKeyValue;
/***********************************************************************/
/* Return the text corresponding to all keys (XML like). */
/***********************************************************************/
PSZ JOBJECT::GetText(PGLOBAL g, PSTRG text) {
if (First) {
PSZ BJSON::GetObjectText(PGLOBAL g, PBPR bop, PSTRG text) {
if (bop) {
bool b;
if (!text) {
......@@ -944,7 +937,8 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSTRG text) {
b = false;
} // endif text
if (b && !First->Next && !strcmp(First->Key, "$date")) {
#if 0
if (b && !bop->Next && !strcmp(MZP(bop->Key), "$date")) {
int i;
PSZ s;
......@@ -964,228 +958,211 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSTRG text) {
} // endif text
} else for (PJPR jp = First; jp; jp = jp->Next) {
jp->Val->GetText(g, text);
} else
#endif // 0
if (jp->Next)
for (PBPR brp = bop; brp; brp = MPP(brp->Next)) {
GetValueText(g, MVP(brp->Vlp), text);
if (brp->Next)
text->Append(' ');
} // endfor jp
} // endfor brp
if (b) {
text->Trim();
return text->GetStr();
} // endif b
} // endif First
} // endif bop
return NULL;
} // end of GetText;
} // end of GetObjectText;
/***********************************************************************/
/* Merge two objects. */
/* Set or add a value corresponding to the given key. */
/***********************************************************************/
bool JOBJECT::Merge(PGLOBAL g, PJSON jsp) {
if (jsp->GetType() != TYPE_JOB) {
strcpy(g->Message, "Second argument is not an object");
return true;
} // endif Type
PBPR BJSON::SetKeyValue(PGLOBAL g, PBPR bop, OFFSET bvp, PSZ key)
{
PBPR brp = bop, prp = NULL;
if (brp) {
for (brp = bop; brp; brp = MPP(brp->Next))
if (!strcmp(MZP(brp->Key), key)) {
brp->Vlp = bvp;
break;
} else
prp = brp;
PJOB jobp = (PJOB)jsp;
if (!brp)
prp->Vlp = MOF(SubAllocPair(g, MOF(key), bvp));
for (PJPR jpp = jobp->First; jpp; jpp = jpp->Next)
SetKeyValue(g, jpp->Val, jpp->Key);
} else
bop = SubAllocPair(g, MOF(key), bvp);
return false;
} // end of Marge;
// Return the first pair of this object
return bop;
} // end of SetKeyValue
/***********************************************************************/
/* Set or add a value corresponding to the given key. */
/* Merge two objects. */
/***********************************************************************/
void JOBJECT::SetKeyValue(PGLOBAL g, PJVAL jvp, PCSZ key) {
PJPR jp;
for (jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key)) {
jp->Val = jvp;
break;
} // endif key
PBPR BJSON::MergeObject(PGLOBAL g, PBPR bop1, PBPR bop2)
{
if (bop1)
for (PBPR brp = bop2; brp; brp = MPP(brp->Next))
SetKeyValue(g, bop1, brp->Vlp, MZP(brp->Key));
if (!jp) {
jp = AddPair(g, key);
jp->Val = jvp;
} // endif jp
else
bop1 = bop2;
} // end of SetValue
return bop1;
} // end of MergeObject;
/***********************************************************************/
/* Delete a value corresponding to the given key. */
/***********************************************************************/
void JOBJECT::DeleteKey(PCSZ key) {
PJPR jp, * pjp = &First;
PBPR BJSON::DeleteKey(PBPR bop, PCSZ key)
{
PBPR brp, pbrp = NULL;
for (brp = bop; brp; brp = MPP(brp->Next))
if (!strcmp(MZP(brp->Key), key)) {
if (pbrp) {
pbrp->Next = brp->Next;
return bop;
} else
return MPP(brp->Next);
for (jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key)) {
*pjp = jp->Next;
break;
} else
pjp = &jp->Next;
pbrp = brp;
return bop;
} // end of DeleteKey
/***********************************************************************/
/* True if void or if all members are nulls. */
/***********************************************************************/
bool JOBJECT::IsNull(void) {
for (PJPR jp = First; jp; jp = jp->Next)
if (!jp->Val->IsNull())
bool BJSON::IsObjectNull(PBPR bop)
{
for (PBPR brp = bop; brp; brp = MPP(brp->Next))
if (brp->Vlp && (MVP(brp->Vlp))->Type != TYPE_NULL)
return false;
return true;
} // end of IsNull
} // end of IsObjectNull
/* -------------------------- Class JARRAY --------------------------- */
/***********************************************************************/
/* JARRAY constructor. */
/***********************************************************************/
JARRAY::JARRAY(void) : JSON() {
Type = TYPE_JAR;
Size = 0;
Alloc = 0;
First = Last = NULL;
Mvals = NULL;
} // end of JARRAY constructor
/* ------------------------- Barray functions ------------------------ */
/***********************************************************************/
/* Return the number of values in this object. */
/***********************************************************************/
int JARRAY::GetSize(bool b) {
if (b) {
// Return only non null values
int n = 0;
for (PJVAL jvp = First; jvp; jvp = jvp->Next)
if (!jvp->IsNull())
n++;
int BJSON::GetArraySize(PBVAL bap, bool b)
{
int n = 0;
return n;
} else
return Size;
for (PBVAL bvp = bap; bvp; bvp = MVP(bvp->Next))
// If b, return only non null values
if (!b || bvp->Type != TYPE_NULL)
n++;
} // end of GetSize
return n;
} // end of GetArraySize
/***********************************************************************/
/* Make the array of values from the values list. */
/* Get the Nth value of an Array. */
/***********************************************************************/
void JARRAY::InitArray(PGLOBAL g) {
int i;
PJVAL jvp, * pjvp = &First;
for (Size = 0, jvp = First; jvp; jvp = jvp->Next)
if (!jvp->Del)
Size++;
if (Size > Alloc) {
// No need to realloc after deleting values
Mvals = (PJVAL*)PlugSubAlloc(g, NULL, Size * sizeof(PJVAL));
Alloc = Size;
} // endif Size
for (i = 0, jvp = First; jvp; jvp = jvp->Next)
if (!jvp->Del) {
Mvals[i++] = jvp;
pjvp = &jvp->Next;
Last = jvp;
} else
*pjvp = jvp->Next;
PBVAL BJSON::GetArrayValue(PBVAL bap, int n)
{
int i = 0;
} // end of InitArray
for (PBVAL bvp = bap; bvp; bvp = MVP(bvp->Next))
if (i == n)
return bvp;
else
i++;
/***********************************************************************/
/* Get the Nth value of an Array. */
/***********************************************************************/
PJVAL JARRAY::GetArrayValue(int i) {
if (Mvals && i >= 0 && i < Size)
return Mvals[i];
else
return NULL;
} // end of GetValue
return NULL;
} // end of GetArrayValue
/***********************************************************************/
/* Add a Value to the Array Value list. */
/***********************************************************************/
PJVAL JARRAY::AddArrayValue(PGLOBAL g, PJVAL jvp, int* x) {
if (!jvp)
jvp = new(g) JVALUE;
PBVAL BJSON::AddArrayValue(PGLOBAL g, PBVAL bap, PBVAL nvp, int* x)
{
if (!nvp)
nvp = SubAllocVal(g);
if (x) {
if (bap) {
int i = 0, n = *x;
PJVAL jp, * jpp = &First;
PBVAL bvp;
for (jp = First; jp && i < n; i++, jp = *(jpp = &jp->Next));
(*jpp) = jvp;
if (!(jvp->Next = jp))
Last = jvp;
} else {
if (!First)
First = jvp;
else if (Last == First)
First->Next = Last = jvp;
else
Last->Next = jvp;
for (bvp = bap; bvp; bvp = MVP(bvp->Next), i++)
if (!bvp->Next || (x && i == n)) {
nvp->Next = bvp->Next;
bvp->Next = MOF(nvp);
break;
} // endif Next
Last = jvp;
Last->Next = NULL;
} // endif x
} else
bap = nvp;
return jvp;
} // end of AddValue
return bap;
} // end of AddArrayValue
/***********************************************************************/
/* Merge two arrays. */
/***********************************************************************/
bool JARRAY::Merge(PGLOBAL g, PJSON jsp) {
if (jsp->GetType() != TYPE_JAR) {
strcpy(g->Message, "Second argument is not an array");
return true;
} // endif Type
PJAR arp = (PJAR)jsp;
PBVAL BJSON::MergeArray(PGLOBAL g, PBVAL bap1, PBVAL bap2)
{
if (bap1) {
for (PBVAL bvp = bap2; bvp; bvp = MVP(bvp->Next))
AddArrayValue(g, bap1, bvp);
for (int i = 0; i < arp->size(); i++)
AddArrayValue(g, arp->GetArrayValue(i));
return bap1;
} else
return bap2;
InitArray(g);
return false;
} // end of Merge
} // end of MergeArray
/***********************************************************************/
/* Set the nth Value of the Array Value list. */
/* Set the nth Value of the Array Value list or add it. */
/***********************************************************************/
bool JARRAY::SetArrayValue(PGLOBAL g, PJVAL jvp, int n) {
int i = 0;
PJVAL jp, * jpp = &First;
PBVAL BJSON::SetArrayValue(PGLOBAL g, PBVAL bap, PBVAL nvp, int n)
{
PBVAL bvp = bap, pvp = NULL;
if (bvp) {
for (int i = 0; bvp; i++, bvp = MVP(bvp->Next))
if (i == n) {
bvp->To_Val = nvp->To_Val;
bvp->Nd = nvp->Nd;
bvp->Type = nvp->Type;
return bap;
} else
pvp = bvp;
} // endif bap
if (!bvp) {
bvp = DupVal(g, nvp);
for (jp = First; i < n; i++, jp = *(jpp = &jp->Next))
if (!jp)
*jpp = jp = new(g) JVALUE;
if (pvp)
pvp->Next = MOF(bvp);
else
bap = bvp;
} // endif bvp
*jpp = jvp;
jvp->Next = (jp ? jp->Next : NULL);
return false;
return bap;
} // end of SetValue
/***********************************************************************/
/* Return the text corresponding to all values. */
/***********************************************************************/
PSZ JARRAY::GetText(PGLOBAL g, PSTRG text) {
if (First) {
PSZ BJSON::GetArrayText(PGLOBAL g, PBVAL bap, PSTRG text) {
if (bap) {
bool b;
PJVAL jp;
if (!text) {
text = new(g) STRING(g, 256);
......@@ -1197,12 +1174,12 @@ PSZ JARRAY::GetText(PGLOBAL g, PSTRG text) {
text->Append('(');
b = false;
}
} // endif text
for (jp = First; jp; jp = jp->Next) {
jp->GetText(g, text);
for (PBVAL bvp = bap; bvp; bvp = MVP(bvp->Next)) {
GetValueText(g, bvp, text);
if (jp->Next)
if (bvp->Next)
text->Append(", ");
else if (!b)
text->Append(')');
......@@ -1222,30 +1199,89 @@ PSZ JARRAY::GetText(PGLOBAL g, PSTRG text) {
/***********************************************************************/
/* Delete a Value from the Arrays Value list. */
/***********************************************************************/
bool JARRAY::DeleteValue(int n) {
PJVAL jvp = GetArrayValue(n);
PBVAL BJSON::DeleteValue(PBVAL bap, int n)
{
PBVAL bvp = bap, pvp = NULL;
if (jvp) {
jvp->Del = true;
return false;
} else
return true;
if (bvp)
for (int i = 0; bvp; i++, bvp = MVP(bvp->Next))
if (i == n) {
if (pvp)
pvp->Next = bvp->Next;
else
bap = bvp;
break;
} // endif i
return bap;
} // end of DeleteValue
/***********************************************************************/
/* True if void or if all members are nulls. */
/***********************************************************************/
bool JARRAY::IsNull(void) {
for (int i = 0; i < Size; i++)
if (!Mvals[i]->IsNull())
bool BJSON::IsArrayNull(PBVAL bap)
{
for (PBVAL bvp = bap; bvp; bvp = MVP(bvp->Next))
if (bvp->Type != TYPE_NULL)
return false;
return true;
} // end of IsNull
/* -------------------------- Class JVALUE- -------------------------- */
/* ------------------------- Bvalue functions ------------------------ */
/***********************************************************************/
/* Sub-allocate and clear a BVAL. */
/***********************************************************************/
PBVAL BJSON::SubAllocVal(PGLOBAL g)
{
PBVAL bvp = (PBVAL)BsonSubAlloc(g, sizeof(BVAL));
bvp->To_Val = 0;
bvp->Nd = 0;
bvp->Type = TYPE_UNKNOWN;
bvp->Next = 0;
return bvp;
} // end of SubAllocVal
/***********************************************************************/
/* Sub-allocate and initialize a BVAL as string. */
/***********************************************************************/
PBVAL BJSON::SubAllocVal(PGLOBAL g, OFFSET toval, JTYP type, short nd)
{
PBVAL bvp = (PBVAL)BsonSubAlloc(g, sizeof(BVAL));
bvp->To_Val = toval;
bvp->Nd = nd;
bvp->Type = type;
bvp->Next = 0;
return bvp;
} // end of SubAllocVal
/***********************************************************************/
/* Allocate a BVALUE with a given string or numeric value. */
/***********************************************************************/
PBVAL BJSON::SubAllocVal(PGLOBAL g, PVAL valp)
{
PBVAL vlp = SubAllocVal(g);
SetValue(g, vlp, valp);
vlp->Next = NULL;
return vlp;
} // end of SubAllocVal
/***********************************************************************/
/* Sub-allocate and initialize a BVAL from another BVAL. */
/***********************************************************************/
PBVAL BJSON::DupVal(PGLOBAL g, PBVAL bvlp) {
PBVAL bvp = (PBVAL)BsonSubAlloc(g, sizeof(BVAL));
*bvp = *bvlp;
bvp->Next = 0;
return bvp;
} // end of DupVal
#if 0
/***********************************************************************/
/* Constructor for a JVALUE. */
/***********************************************************************/
......@@ -1276,7 +1312,6 @@ JVALUE::JVALUE(PJSON jsp) : JSON() {
Type = TYPE_JVAL;
} // end of JVALUE constructor
#if 0
/***********************************************************************/
/* Constructor for a JVALUE with a given string or numeric value. */
/***********************************************************************/
......@@ -1289,18 +1324,7 @@ JVALUE::JVALUE(PGLOBAL g, PVL vlp) : JSON() {
} // end of JVALUE constructor
#endif // 0
/***********************************************************************/
/* Constructor for a JVALUE with a given string or numeric value. */
/***********************************************************************/
JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON() {
Jsp = NULL;
//Val = NULL;
SetValue(g, valp);
Next = NULL;
Del = false;
Type = TYPE_JVAL;
} // end of JVALUE constructor
#if 0
/***********************************************************************/
/* Constructor for a given string. */
/***********************************************************************/
......@@ -1339,13 +1363,31 @@ JTYP JVALUE::GetValType(void) {
return DataType;
} // end of GetValType
#endif // 0
/***********************************************************************/
/* Return the size of value's value. */
/***********************************************************************/
int BJSON::GetSize(PBVAL vlp, bool b)
{
switch (vlp->Type) {
case TYPE_JAR:
return GetArraySize(MVP(vlp->To_Val));
case TYPE_JOB:
return GetObjectSize(MPP(vlp->To_Val));
default:
return 1;
} // enswitch Type
} // end of GetSize
/***********************************************************************/
/* Return the Value's Object value. */
/***********************************************************************/
PJOB JVALUE::GetObject(void) {
if (DataType == TYPE_JSON && Jsp->GetType() == TYPE_JOB)
return (PJOB)Jsp;
PBPR BJSON::GetObject(PBVAL vlp)
{
if (vlp->Type == TYPE_JOB)
return MPP(vlp->To_Val);
return NULL;
} // end of GetObject
......@@ -1353,24 +1395,41 @@ PJOB JVALUE::GetObject(void) {
/***********************************************************************/
/* Return the Value's Array value. */
/***********************************************************************/
PJAR JVALUE::GetArray(void) {
if (DataType == TYPE_JSON && Jsp->GetType() == TYPE_JAR)
return (PJAR)Jsp;
PBVAL BJSON::GetArray(PBVAL vlp)
{
if (vlp->Type == TYPE_JAR)
return MVP(vlp->To_Val);
return NULL;
} // end of GetArray
/***********************************************************************/
/* Return the Value's as a Value class. */
/* Return the Value's as a Value struct. */
/***********************************************************************/
PVAL JVALUE::GetValue(PGLOBAL g) {
PVAL valp = NULL;
PVAL BJSON::GetValue(PGLOBAL g, PBVAL vp)
{
double d;
PVAL valp;
PBVAL vlp = vp->Type == TYPE_JVAL ? MVP(vp->To_Val) : vp;
if (DataType != TYPE_JSON)
if (DataType == TYPE_STRG)
valp = AllocateValue(g, Strp, DataType, Nd);
else
valp = AllocateValue(g, &LLn, DataType, Nd);
switch (vlp->Type) {
case TYPE_STRG:
case TYPE_DBL:
case TYPE_BINT:
valp = AllocateValue(g, MP(vlp->To_Val), vlp->Type, vlp->Nd);
break;
case TYPE_INTG:
case TYPE_BOOL:
valp = AllocateValue(g, vlp, vlp->Type);
break;
case TYPE_FLOAT:
d = (double)vlp->F;
valp = AllocateValue(g, &d, TYPE_DOUBLE, vlp->Nd);
break;
default:
valp = NULL;
break;
} // endswitch Type
return valp;
} // end of GetValue
......@@ -1378,16 +1437,30 @@ PVAL JVALUE::GetValue(PGLOBAL g) {
/***********************************************************************/
/* Return the Value's Integer value. */
/***********************************************************************/
int JVALUE::GetInteger(void) {
int n;
int BJSON::GetInteger(PBVAL vp) {
int n;
PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
switch (DataType) {
case TYPE_INTG: n = N; break;
case TYPE_DBL: n = (int)F; break;
switch (vlp->Type) {
case TYPE_INTG:
n = vlp->N;
break;
case TYPE_FLOAT:
n = (int)vlp->F;
break;
case TYPE_DTM:
case TYPE_STRG: n = atoi(Strp); break;
case TYPE_BOOL: n = (B) ? 1 : 0; break;
case TYPE_BINT: n = (int)LLn; break;
case TYPE_STRG:
n = atoi(MZP(vlp->To_Val));
break;
case TYPE_BOOL:
n = (vlp->B) ? 1 : 0;
break;
case TYPE_BINT:
n = (int)*(longlong*)MP(vlp->To_Val);
break;
case TYPE_DBL:
n = (int)*(double*)MP(vlp->To_Val);
break;
default:
n = 0;
} // endswitch Type
......@@ -1398,16 +1471,30 @@ int JVALUE::GetInteger(void) {
/***********************************************************************/
/* Return the Value's Big integer value. */
/***********************************************************************/
long long JVALUE::GetBigint(void) {
long long lln;
longlong BJSON::GetBigint(PBVAL vp) {
longlong lln;
PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
switch (DataType) {
case TYPE_BINT: lln = LLn; break;
case TYPE_INTG: lln = (long long)N; break;
case TYPE_DBL: lln = (long long)F; break;
switch (vlp->Type) {
case TYPE_BINT:
lln = *(longlong*)MP(vlp->To_Val);
break;
case TYPE_INTG:
lln = (longlong)vlp->N;
break;
case TYPE_FLOAT:
lln = (longlong)vlp->F;
break;
case TYPE_DBL:
lln = (longlong)*(double*)MP(vlp->To_Val);
break;
case TYPE_DTM:
case TYPE_STRG: lln = atoll(Strp); break;
case TYPE_BOOL: lln = (B) ? 1 : 0; break;
case TYPE_STRG:
lln = atoll(MZP(vlp->To_Val));
break;
case TYPE_BOOL:
lln = (vlp->B) ? 1 : 0;
break;
default:
lln = 0;
} // endswitch Type
......@@ -1418,16 +1505,31 @@ long long JVALUE::GetBigint(void) {
/***********************************************************************/
/* Return the Value's Double value. */
/***********************************************************************/
double JVALUE::GetFloat(void) {
double BJSON::GetDouble(PBVAL vp)
{
double d;
PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
switch (DataType) {
case TYPE_DBL: d = F; break;
case TYPE_BINT: d = (double)LLn; break;
case TYPE_INTG: d = (double)N; break;
switch (vlp->Type) {
case TYPE_DBL:
d = *(double*)MP(vlp->To_Val);
break;
case TYPE_BINT:
d = (double)*(longlong*)MP(vlp->To_Val);
break;
case TYPE_INTG:
d = (double)vlp->N;
break;
case TYPE_FLOAT:
d = (double)vlp->F;
break;
case TYPE_DTM:
case TYPE_STRG: d = atof(Strp); break;
case TYPE_BOOL: d = (B) ? 1.0 : 0.0; break;
case TYPE_STRG:
d = atof(MZP(vlp->To_Val));
break;
case TYPE_BOOL:
d = (vlp->B) ? 1.0 : 0.0;
break;
default:
d = 0.0;
} // endswitch Type
......@@ -1438,47 +1540,53 @@ double JVALUE::GetFloat(void) {
/***********************************************************************/
/* Return the Value's String value. */
/***********************************************************************/
PSZ JVALUE::GetString(PGLOBAL g, char* buff) {
PSZ BJSON::GetString(PGLOBAL g, PBVAL vp, char* buff)
{
char buf[32];
char* p = (buff) ? buff : buf;
PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
switch (DataType) {
switch (vlp->Type) {
case TYPE_DTM:
case TYPE_STRG:
p = Strp;
p = MZP(vlp->To_Val);
break;
case TYPE_INTG:
sprintf(p, "%d", N);
sprintf(p, "%d", vlp->N);
break;
case TYPE_FLOAT:
sprintf(p, "%.*f", vlp->Nd, vlp->F);
break;
case TYPE_BINT:
sprintf(p, "%lld", LLn);
sprintf(p, "%lld", *(longlong*)MP(vlp->To_Val));
break;
case TYPE_DBL:
sprintf(p, "%.*lf", Nd, F);
sprintf(p, "%.*lf", vlp->Nd, *(double*)MP(vlp->To_Val));
break;
case TYPE_BOOL:
p = (char*)((B) ? "true" : "false");
p = (PSZ)((vlp->B) ? "true" : "false");
break;
case TYPE_NULL:
p = (char*)"null";
p = (PSZ)"null";
break;
default:
p = NULL;
} // endswitch Type
return (p == buf) ? (char*)PlugDup(g, buf) : p;
return (p == buf) ? (PSZ)PlugDup(g, buf) : p;
} // end of GetString
/***********************************************************************/
/* Return the Value's String value. */
/***********************************************************************/
PSZ JVALUE::GetText(PGLOBAL g, PSTRG text) {
if (DataType == TYPE_JSON)
return Jsp->GetText(g, text);
PSZ BJSON::GetValueText(PGLOBAL g, PBVAL vlp, PSTRG text) {
if (vlp->Type == TYPE_JOB)
return GetObjectText(g, MPP(vlp->To_Val), text);
else if (vlp->Type == TYPE_JAR)
return GetArrayText(g, MVP(vlp->To_Val), text);
char buff[32];
PSZ s = (DataType == TYPE_NULL) ? NULL : GetString(g, buff);
PSZ s = (vlp->Type == TYPE_NULL) ? NULL : GetString(g, vlp, buff);
if (s)
text->Append(s);
......@@ -1488,60 +1596,81 @@ PSZ JVALUE::GetText(PGLOBAL g, PSTRG text) {
return NULL;
} // end of GetText
void JVALUE::SetValue(PJSON jsp) {
if (DataType == TYPE_JSON && jsp->GetType() == TYPE_JVAL) {
Jsp = jsp->GetJsp();
Nd = ((PJVAL)jsp)->Nd;
DataType = ((PJVAL)jsp)->DataType;
// Val = ((PJVAL)jsp)->GetVal();
} else {
Jsp = jsp;
DataType = TYPE_JSON;
} // endif Type
void BJSON::SetValueObj(PBVAL vlp, PBPR bop)
{
vlp->To_Val = MOF(bop);
vlp->Type = TYPE_JOB;
} // end of SetValueObj;
void BJSON::SetValueArr(PBVAL vlp, PBVAL bap)
{
vlp->To_Val = MOF(bap);
vlp->Type = TYPE_JAR;
} // end of SetValue;
void JVALUE::SetValue(PGLOBAL g, PVAL valp) {
//if (!Val)
// Val = AllocVal(g, TYPE_VAL);
void BJSON::SetValueVal(PBVAL vlp, PBVAL vp)
{
vlp->To_Val = vp->To_Val;
vlp->Nd = vp->Nd;
vlp->Type = vp->Type;
} // end of SetValue;
void BJSON::SetValue(PGLOBAL g, PBVAL vlp, PVAL valp)
{
if (!valp || valp->IsNull()) {
DataType = TYPE_NULL;
vlp->Type = TYPE_NULL;
} else switch (valp->GetType()) {
case TYPE_DATE:
if (((DTVAL*)valp)->IsFormatted())
Strp = valp->GetCharValue();
vlp->To_Val = MOF(valp->GetCharValue());
else {
char buf[32];
Strp = PlugDup(g, valp->GetCharString(buf));
vlp->To_Val = MOF(PlugDup(g, valp->GetCharString(buf)));
} // endif Formatted
DataType = TYPE_DTM;
vlp->Type = TYPE_DTM;
break;
case TYPE_STRING:
Strp = valp->GetCharValue();
DataType = TYPE_STRG;
vlp->To_Val = MOF(valp->GetCharValue());
vlp->Type = TYPE_STRG;
break;
case TYPE_DOUBLE:
case TYPE_DECIM:
F = valp->GetFloatValue();
vlp->Nd = (IsTypeNum(valp->GetType())) ? valp->GetValPrec() : 0;
if (IsTypeNum(valp->GetType()))
Nd = valp->GetValPrec();
if (vlp->Nd <= 6) {
vlp->F = (float)valp->GetFloatValue();
vlp->Type = TYPE_FLOAT;
} else {
double *dp = (double*)PlugSubAlloc(g, NULL, sizeof(double));
*dp = valp->GetFloatValue();
vlp->To_Val = MOF(dp);
vlp->Type = TYPE_DBL;
} // endif Nd
DataType = TYPE_DBL;
break;
case TYPE_TINY:
B = valp->GetTinyValue() != 0;
DataType = TYPE_BOOL;
vlp->B = valp->GetTinyValue() != 0;
vlp->Type = TYPE_BOOL;
case TYPE_INT:
N = valp->GetIntValue();
DataType = TYPE_INTG;
vlp->N = valp->GetIntValue();
vlp->Type = TYPE_INTG;
break;
case TYPE_BIGINT:
LLn = valp->GetBigintValue();
DataType = TYPE_BINT;
if (valp->GetBigintValue() >= INT_MIN32 &&
valp->GetBigintValue() <= INT_MAX32) {
vlp->N = valp->GetIntValue();
vlp->Type = TYPE_INTG;
} else {
longlong* llp = (longlong*)PlugSubAlloc(g, NULL, sizeof(longlong));
*llp = valp->GetBigintValue();
vlp->To_Val = MOF(llp);
vlp->Type = TYPE_BINT;
} // endif BigintValue
break;
default:
sprintf(g->Message, "Unsupported typ %d\n", valp->GetType());
......@@ -1553,49 +1682,76 @@ void JVALUE::SetValue(PGLOBAL g, PVAL valp) {
/***********************************************************************/
/* Set the Value's value as the given integer. */
/***********************************************************************/
void JVALUE::SetInteger(PGLOBAL g, int n) {
N = n;
DataType = TYPE_INTG;
void BJSON::SetInteger(PBVAL vlp, int n)
{
vlp->N = n;
vlp->Type = TYPE_INTG;
} // end of SetInteger
/***********************************************************************/
/* Set the Value's Boolean value as a tiny integer. */
/***********************************************************************/
void JVALUE::SetBool(PGLOBAL g, bool b) {
B = b;
DataType = TYPE_BOOL;
void BJSON::SetBool(PBVAL vlp, bool b)
{
vlp->B = b;
vlp->Type = TYPE_BOOL;
} // end of SetTiny
/***********************************************************************/
/* Set the Value's value as the given big integer. */
/***********************************************************************/
void JVALUE::SetBigint(PGLOBAL g, long long ll) {
LLn = ll;
DataType = TYPE_BINT;
void BJSON::SetBigint(PGLOBAL g, PBVAL vlp, longlong ll)
{
if (ll >= INT_MIN32 && ll <= INT_MAX32) {
vlp->N = (int)ll;
vlp->Type = TYPE_INTG;
} else {
longlong* llp = (longlong*)PlugSubAlloc(g, NULL, sizeof(longlong));
*llp = ll;
vlp->To_Val = MOF(llp);
vlp->Type = TYPE_BINT;
} // endif ll
} // end of SetBigint
/***********************************************************************/
/* Set the Value's value as the given DOUBLE. */
/***********************************************************************/
void JVALUE::SetFloat(PGLOBAL g, double f) {
F = f;
Nd = 6;
DataType = TYPE_DBL;
void BJSON::SetFloat(PBVAL vlp, double f) {
vlp->F = (float)f;
vlp->Nd = 6;
vlp->Type = TYPE_FLOAT;
} // end of SetFloat
/***********************************************************************/
/* Set the Value's value as the given string. */
/***********************************************************************/
void JVALUE::SetString(PGLOBAL g, PSZ s, int ci) {
Strp = s;
Nd = ci;
DataType = TYPE_STRG;
void BJSON::SetString(PBVAL vlp, PSZ s, int ci) {
vlp->To_Val = MOF(s);
vlp->Nd = ci;
vlp->Type = TYPE_STRG;
} // end of SetString
/***********************************************************************/
/* True when its JSON or normal value is null. */
/***********************************************************************/
bool JVALUE::IsNull(void) {
return (DataType == TYPE_JSON) ? Jsp->IsNull() : DataType == TYPE_NULL;
} // end of IsNull
#endif // 0
bool BJSON::IsValueNull(PBVAL vlp) {
bool b;
switch (vlp->Type) {
case TYPE_NULL:
b = true;
break;
case TYPE_JOB:
b = IsObjectNull(MPP(vlp->To_Val));
break;
case TYPE_JAR:
b = IsArrayNull(MVP(vlp->To_Val));
break;
default:
b = false;
} // endswitch Type
return b;
} // end of IsNull
......@@ -16,20 +16,25 @@
#define X
#endif
#define ARGS MY_MIN(24,(int)len-i),s+MY_MAX(i-3,0)
#define MOF(X) MakeOff(Base, X)
#define MP(X) MakePtr(Base, X)
#define MPP(X) (PBPR)MakePtr(Base, X)
#define MVP(X) (PBVAL)MakePtr(Base, X)
#define MZP(X) (PSZ)MakePtr(Base, X)
#define LLN(X) *(longlong*)MakePtr(Base, X)
#define DBL(X) *(double*)MakePtr(Base, X)
class BDOC;
class BOUT;
//class JSON;
class BJSON;
typedef class BDOC* PBDOC;
//typedef class BJSON* PBSON;
// BSON size should be equal on Linux and Windows
#define BMX 255
typedef uint OFFSET;
typedef class BJSON* PBJSON;
typedef uint OFFSET;
/***********************************************************************/
/* Structure JVALUE. */
/* Structure BVAL. Binary representation of a JVALUE. */
/***********************************************************************/
typedef struct _jvalue {
union {
......@@ -39,12 +44,12 @@ typedef struct _jvalue {
bool B; // A boolean value True or false (0)
};
short Nd; // Number of decimals
JTYP Type; // The value type
short Type; // The value type
OFFSET Next; // Offset to the next value in array
} BVAL, *PBVAL; // end of struct BVALUE
/***********************************************************************/
/* Structure JPAIR. The pairs of a json Object. */
/* Structure BPAIR. The pairs of a json Object. */
/***********************************************************************/
typedef struct _jpair {
OFFSET Key; // Offset to this pair key name
......@@ -52,26 +57,6 @@ typedef struct _jpair {
OFFSET Next; // Offset to the next pair in object
} BPAIR, *PBPR; // end of struct BPAIR
#if 0
/***********************************************************************/
/* Structure used to return binary json to Json UDF functions. */
/* (should be moved to jsonudf.h). */
/***********************************************************************/
typedef struct _JsonBin {
char Msg[BMX + 1];
char *Filename;
PGLOBAL G;
int Pretty;
ulong Reslen;
my_bool Changed;
PBSON Top;
PBSON Jsp;
PBJN Bsp;
} BJSON, *PBJN ; // end of struct BJSON
PBJN JbinAlloc(PGLOBAL g, UDF_ARGS* args, ulong len, PJSON jsp);
#endif // 0
char* NextChr(PSZ s, char sep);
char* GetJsonNull(void);
const char* GetFmt(int type, bool un);
......@@ -79,15 +64,84 @@ const char* GetFmt(int type, bool un);
DllExport bool IsNum(PSZ s);
/***********************************************************************/
/* Class JDOC. The class for parsing and serializing json documents. */
/* Class BJSON. The class handling all BJSON operations. */
/***********************************************************************/
class BDOC : public BLOCK {
class BJSON : public BLOCK {
public:
BDOC(void);
// Constructor
BJSON(void* base, PBVAL vp = NULL) { Base = base; Bvp = vp; }
void *BsonSubAlloc(PGLOBAL g, size_t size);
PBPR SubAllocPair(PGLOBAL g, OFFSET key);
void* GetBase(void) { return Base; }
// SubAlloc functions
void* BsonSubAlloc(PGLOBAL g, size_t size);
PBPR SubAllocPair(PGLOBAL g, OFFSET key, OFFSET val = 0);
PBVAL SubAllocVal(PGLOBAL g);
PBVAL SubAllocVal(PGLOBAL g, OFFSET toval, JTYP type = TYPE_UNKNOWN, short nd = 0);
PBVAL SubAllocVal(PGLOBAL g, PVAL valp);
PBVAL DupVal(PGLOBAL g, PBVAL bvp);
// Array functions
int GetArraySize(PBVAL bap, bool b = false);
PBVAL GetArrayValue(PBVAL bap, int i);
PSZ GetArrayText(PGLOBAL g, PBVAL bap, PSTRG text);
PBVAL MergeArray(PGLOBAL g, PBVAL bap1,PBVAL bap2);
PBVAL DeleteValue(PBVAL bap, int n);
PBVAL AddArrayValue(PGLOBAL g, PBVAL bap, PBVAL nvp = NULL, int* x = NULL);
PBVAL SetArrayValue(PGLOBAL g, PBVAL bap, PBVAL nvp, int n);
bool IsArrayNull(PBVAL bap);
// Object functions
int GetObjectSize(PBPR bop, bool b = false);
PSZ GetObjectText(PGLOBAL g, PBPR bop, PSTRG text);
PBPR MergeObject(PGLOBAL g, PBPR bop1, PBPR bop2);
PBPR AddPair(PGLOBAL g, PBPR bop, PSZ key, OFFSET val = 0);
PBVAL GetKeyValue(PBPR bop, PSZ key);
PBVAL GetKeyList(PGLOBAL g, PBPR bop);
PBVAL GetObjectValList(PGLOBAL g, PBPR bop);
PBPR SetKeyValue(PGLOBAL g, PBPR bop, OFFSET bvp, PSZ key);
PBPR DeleteKey(PBPR bop, PCSZ k);
bool IsObjectNull(PBPR bop);
// Value functions
int GetSize(PBVAL vlp, bool b = false);
PBPR GetObject(PBVAL vlp);
PBVAL GetArray(PBVAL vlp);
//PJSON GetJsp(void) { return (DataType == TYPE_JSON ? Jsp : NULL); }
PSZ GetValueText(PGLOBAL g, PBVAL vlp, PSTRG text);
//inline PJSON GetJson(void) { return (DataType == TYPE_JSON ? Jsp : this); }
PSZ GetString(PGLOBAL g, PBVAL vp, char* buff = NULL);
int GetInteger(PBVAL vp);
long long GetBigint(PBVAL vp);
double GetDouble(PBVAL vp);
PVAL GetValue(PGLOBAL g, PBVAL vp);
void SetValueObj(PBVAL vlp, PBPR bop);
void SetValueArr(PBVAL vlp, PBVAL bap);
void SetValueVal(PBVAL vlp, PBVAL vp);
void SetValue(PGLOBAL g, PBVAL vlp, PVAL valp);
void SetString(PBVAL vlp, PSZ s, int ci = 0);
void SetInteger(PBVAL vlp, int n);
void SetBigint(PGLOBAL g, PBVAL vlp, longlong ll);
void SetFloat(PBVAL vlp, double f);
void SetBool(PBVAL vlp, bool b);
bool IsValueNull(PBVAL vlp);
// Members
PBVAL Bvp;
void* Base;
protected:
// Default constructor not to be used
BJSON(void) {}
}; // end of class BJSON
/***********************************************************************/
/* Class JDOC. The class for parsing and serializing json documents. */
/***********************************************************************/
class BDOC : public BJSON {
public:
BDOC(void *);
PBVAL ParseJson(PGLOBAL g, char* s, size_t n, int* prty = NULL, bool* b = NULL);
PSZ Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty);
......@@ -98,72 +152,21 @@ class BDOC : public BLOCK {
OFFSET ParseString(PGLOBAL g, int& i);
void ParseNumeric(PGLOBAL g, int& i, PBVAL bvp);
OFFSET ParseAsArray(PGLOBAL g, int& i, int pretty, int* ptyp);
bool SerializeArray(OFFSET arp, bool b);
bool SerializeObject(OFFSET obp);
bool SerializeValue(PBVAL vp);
bool SerializeArray(OFFSET arp, bool b);
bool SerializeObject(OFFSET obp);
bool SerializeValue(PBVAL vp);
// Members used when parsing and serializing
private:
JOUT* jp; // Used with serialize
void* base; // The base for making offsets or pointers
char* s; // The Json string to parse
int len; // The Json string length
bool pty[3]; // Used to guess what pretty is
// Default constructor not to be used
BDOC(void) {}
}; // end of class BDOC
#if 0
/***********************************************************************/
/* Class BJSON. The class handling all BSON operations. */
/***********************************************************************/
class BJSON : public BLOCK {
public:
// Constructor
BJSON(PBVAL vp, void* base) { Vlp = vp; Base = base; }
// Array functions
int GetSize(bool b);
PBVAL GetArrayValue(int i);
PSZ GetText(PGLOBAL g, PSTRG text);
bool Merge(PGLOBAL g, PBVAL jsp);
bool DeleteValue(int n);
PBVAL AddArrayValue(PGLOBAL g, PBVAL jvp = NULL, int* x = NULL);
bool SetArrayValue(PGLOBAL g, PBVAL jvp, int i);
// Object functions
int GetObjectSize(PBPR prp, bool b);
PSZ GetObjectText(PGLOBAL g, PBPR prp, PSTRG text);
bool MergeObject(PGLOBAL g, PBPR prp);
PJPR AddPair(PGLOBAL g, PCSZ key);
PJVAL GetKeyValue(const char* key);
PJAR GetKeyList(PGLOBAL g);
PJAR GetValList(PGLOBAL g);
void SetKeyValue(PGLOBAL g, PBVAL jvp, PCSZ key);
void DeleteKey(PCSZ k);
// Value functions
PBPR GetObject(void);
PBVAL GetArray(void);
PJSON GetJsp(void) { return (DataType == TYPE_JSON ? Jsp : NULL); }
PSZ GetValueText(PGLOBAL g, PSTRG text);
inline PJSON GetJson(void) { return (DataType == TYPE_JSON ? Jsp : this); }
PSZ GetString(PGLOBAL g, char* buff = NULL);
int GetInteger(void);
long long GetBigint(void);
double GetFloat(void);
PVAL GetValue(PGLOBAL g);
void SetValue(PJSON jsp);
void SetValue(PGLOBAL g, PVAL valp);
void SetString(PGLOBAL g, PSZ s, int ci = 0);
void SetInteger(PGLOBAL g, int n);
void SetBigint(PGLOBAL g, longlong ll);
void SetFloat(PGLOBAL g, double f);
void SetBool(PGLOBAL g, bool b);
// Members
PBVAL Vlp;
void* Base;
}; // end of class BJSON
/***********************************************************************/
/* Class JOBJECT: contains a list of value pairs. */
/***********************************************************************/
......
......@@ -15,10 +15,7 @@
#define X
#endif
// Required by some compilers
enum JTYP : short;
enum JTYP : short {
enum JTYP {
TYPE_NULL = TYPE_VOID,
TYPE_STRG = TYPE_STRING,
TYPE_DBL = TYPE_DOUBLE,
......@@ -48,9 +45,6 @@ typedef class JVALUE *PJVAL;
typedef class JOBJECT *PJOB;
typedef class JARRAY *PJAR;
// BSON size should be equal on Linux and Windows
#define BMX 255
typedef struct BSON *PBSON;
typedef struct JPAIR *PJPR;
//typedef struct VAL *PVL;
......@@ -63,39 +57,6 @@ struct JPAIR {
PJPR Next; // To the next pair
}; // end of struct JPAIR
#if 0
/***********************************************************************/
/* Structure VAL (string, int, float, bool or null) */
/***********************************************************************/
struct VAL {
union {
char *Strp; // Ptr to a string
int N; // An integer value
long long LLn; // A big integer value
double F; // A float value
bool B; // True or false
};
int Nd; // Decimal number
JTYP Type; // The value type
}; // end of struct VAL
#endif // 0
/***********************************************************************/
/* Structure used to return binary json to Json UDF functions. */
/***********************************************************************/
struct BSON {
char Msg[BMX + 1];
char *Filename;
PGLOBAL G;
int Pretty;
ulong Reslen;
my_bool Changed;
PJSON Top;
PJSON Jsp;
PBSON Bsp;
}; // end of struct BSON
PBSON JbinAlloc(PGLOBAL g, UDF_ARGS* args, ulong len, PJSON jsp);
//PVL AllocVal(PGLOBAL g, JTYP type);
char *NextChr(PSZ s, char sep);
char *GetJsonNull(void);
......
......@@ -63,7 +63,7 @@ static PJSNX JsnxNew(PGLOBAL g, PJSON jsp, int type, int len)
return jsx;
} /* end of JsnxNew */
/* ----------------------------------- JSNX ------------------------------------ */
/* ----------------------------------- JSNX ------------------------------------ */
/*********************************************************************************/
/* JSNX public constructor. */
......@@ -1186,6 +1186,7 @@ static my_bool JsonSubSet(PGLOBAL g)
pph->To_Free = (g->Saved_Size) ? g->Saved_Size : (size_t)sizeof(POOLHEADER);
pph->FreeBlk = g->Sarea_Size - pph->To_Free;
g->Saved_Size = 0;
return FALSE;
} /* end of JsonSubSet */
......@@ -6558,3 +6559,1476 @@ long long countin(UDF_INIT *initid, UDF_ARGS *args, char *result,
free(str2);
return n;
} // end of countin
/* --------------------------- New Testing BJSON Stuff --------------------------*/
/*********************************************************************************/
/* SubAlloc a new BJNX class with protection against memory exhaustion. */
/*********************************************************************************/
static PBJNX BjnxNew(PGLOBAL g, PBVAL vlp, int type, int len) {
PBJNX bjnx;
try {
bjnx = new(g) BJNX(g, vlp, type, len);
} catch (...) {
if (trace(1023))
htrc("%s\n", g->Message);
PUSH_WARNING(g->Message);
bjnx = NULL;
} // end try/catch
return bjnx;
} /* end of BjnxNew */
/* ----------------------------------- BSNX ------------------------------------ */
/*********************************************************************************/
/* BSNX public constructor. */
/*********************************************************************************/
BJNX::BJNX(PGLOBAL g, PBVAL row, int type, int len, int prec, my_bool wr)
: BDOC(g->Sarea)
{
Row = row;
Bvalp = NULL;
Jpnp = NULL;
Jp = NULL;
Nodes = NULL;
Value = AllocateValue(g, type, len, prec);
MulVal = NULL;
Jpath = NULL;
Buf_Type = type;
Long = len;
Prec = prec;
Nod = 0;
Xnod = -1;
K = 0;
I = -1;
Imax = 9;
B = 0;
Xpd = false;
Parsed = false;
Found = false;
Wr = wr;
Jb = false;
} // end of BJNX constructor
/*********************************************************************************/
/* SetJpath: set and parse the json path. */
/*********************************************************************************/
my_bool BJNX::SetJpath(PGLOBAL g, char* path, my_bool jb) {
// Check Value was allocated
if (!Value)
return true;
Value->SetNullable(true);
Jpath = path;
// Parse the json path
Parsed = false;
Nod = 0;
Jb = jb;
return ParseJpath(g);
} // end of SetJpath
/*********************************************************************************/
/* Analyse array processing options. */
/*********************************************************************************/
my_bool BJNX::SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm) {
int n = (int)strlen(p);
my_bool dg = true, b = false;
PJNODE jnp = &Nodes[i];
if (*p) {
if (p[n - 1] == ']') {
p[--n] = 0;
} else if (!IsNum(p)) {
// Wrong array specification
sprintf(g->Message, "Invalid array specification %s", p);
return true;
} // endif p
} else
b = true;
// To check whether a numeric Rank was specified
dg = IsNum(p);
if (!n) {
// Default specifications
if (jnp->Op != OP_EXP) {
if (Wr) {
// Force append
jnp->Rank = INT_MAX32;
jnp->Op = OP_LE;
} else if (Jb) {
// Return a Json item
jnp->Op = OP_XX;
} else if (b) {
// Return 1st value (B is the index base)
jnp->Rank = B;
jnp->Op = OP_LE;
} else if (!Value->IsTypeNum()) {
jnp->CncVal = AllocateValue(g, PlugDup(g, ", "), TYPE_STRING);
jnp->Op = OP_CNC;
} else
jnp->Op = OP_ADD;
} // endif OP
} else if (dg) {
// Return nth value
jnp->Rank = atoi(p) - B;
jnp->Op = OP_EQ;
} else if (Wr) {
sprintf(g->Message, "Invalid specification %s in a write path", p);
return true;
} else if (n == 1) {
// Set the Op value;
switch (*p) {
case '+': jnp->Op = OP_ADD; break;
case 'x': jnp->Op = OP_MULT; break;
case '>': jnp->Op = OP_MAX; break;
case '<': jnp->Op = OP_MIN; break;
case '!': jnp->Op = OP_SEP; break; // Average
case '#': jnp->Op = OP_NUM; break;
case '*': // Expand this array
strcpy(g->Message, "Expand not supported by this function");
return true;
default:
sprintf(g->Message, "Invalid function specification %c", *p);
return true;
} // endswitch *p
} else if (*p == '"' && p[n - 1] == '"') {
// This is a concat specification
jnp->Op = OP_CNC;
if (n > 2) {
// Set concat intermediate string
p[n - 1] = 0;
if (trace(1))
htrc("Concat string=%s\n", p + 1);
jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING);
} // endif n
} else {
strcpy(g->Message, "Wrong array specification");
return true;
} // endif's
// For calculated arrays, a local Value must be used
switch (jnp->Op) {
case OP_NUM:
jnp->Valp = AllocateValue(g, TYPE_INT);
break;
case OP_ADD:
case OP_MULT:
case OP_SEP:
if (!IsTypeChar(Buf_Type))
jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
else
jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2);
break;
case OP_MIN:
case OP_MAX:
jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
break;
case OP_CNC:
if (IsTypeChar(Buf_Type))
jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
else
jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
break;
default:
break;
} // endswitch Op
if (jnp->Valp)
MulVal = AllocateValue(g, jnp->Valp);
return false;
} // end of SetArrayOptions
/*********************************************************************************/
/* Parse the eventual passed Jpath information. */
/* This information can be specified in the Fieldfmt column option when */
/* creating the table. It permits to indicate the position of the node */
/* corresponding to that column. */
/*********************************************************************************/
my_bool BJNX::ParseJpath(PGLOBAL g) {
char* p, * p1 = NULL, * p2 = NULL, * pbuf = NULL;
int i;
my_bool a, mul = false;
if (Parsed)
return false; // Already done
else if (!Jpath)
// Jpath = Name;
return true;
if (trace(1))
htrc("ParseJpath %s\n", SVP(Jpath));
if (!(pbuf = PlgDBDup(g, Jpath)))
return true;
if (*pbuf == '$') pbuf++;
if (*pbuf == '.') pbuf++;
if (*pbuf == '[') p1 = pbuf++;
// Estimate the required number of nodes
for (i = 0, p = pbuf; (p = NextChr(p, '.')); i++, p++)
Nod++; // One path node found
if (!(Nodes = (PJNODE)PlgDBSubAlloc(g, NULL, (++Nod) * sizeof(JNODE))))
return true;
memset(Nodes, 0, (Nod) * sizeof(JNODE));
// Analyze the Jpath for this column
for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) {
a = (p1 != NULL);
p1 = strchr(p, '[');
p2 = strchr(p, '.');
if (!p2)
p2 = p1;
else if (p1) {
if (p1 < p2)
p2 = p1;
else if (p1 == p2 + 1)
*p2++ = 0; // Old syntax .[
else
p1 = NULL;
} // endif p1
if (p2)
*p2++ = 0;
// Jpath must be explicit
if (a || *p == 0 || *p == '[' || IsNum(p)) {
// Analyse intermediate array processing
if (SetArrayOptions(g, p, i, Nodes[i - 1].Key))
return true;
} else if (*p == '*') {
if (Wr) {
sprintf(g->Message, "Invalid specification %c in a write path", *p);
return true;
} else // Return JSON
Nodes[i].Op = OP_XX;
} else {
Nodes[i].Key = p;
Nodes[i].Op = OP_EXIST;
} // endif's
} // endfor i, p
Nod = i;
MulVal = AllocateValue(g, Value);
if (trace(1))
for (i = 0; i < Nod; i++)
htrc("Node(%d) Key=%s Op=%d Rank=%d\n",
i, SVP(Nodes[i].Key), Nodes[i].Op, Nodes[i].Rank);
Parsed = true;
return false;
} // end of ParseJpath
/*********************************************************************************/
/* MakeJson: Serialize the json item and set value to it. */
/*********************************************************************************/
PVAL BJNX::MakeJson(PGLOBAL g, PBVAL bvp) {
if (Value->IsTypeNum()) {
strcpy(g->Message, "Cannot make Json for a numeric value");
Value->Reset();
} else if (bvp->Type != TYPE_JAR && bvp->Type != TYPE_JOB) {
strcpy(g->Message, "Target is not an array or object");
Value->Reset();
} else
Value->SetValue_psz(Serialize(g, bvp, NULL, 0));
return Value;
} // end of MakeJson
/*********************************************************************************/
/* SetValue: Set a value from a JVALUE contains. */
/*********************************************************************************/
void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp) {
if (vlp) {
vp->SetNull(false);
if (Jb) {
vp->SetValue_psz(Serialize(g, vlp, NULL, 0));
} else switch (vlp->Type) {
case TYPE_DTM:
case TYPE_STRG:
vp->SetValue_psz(GetString(g, vlp));
break;
case TYPE_INTG:
case TYPE_BINT:
vp->SetValue(GetInteger(vlp));
break;
case TYPE_DBL:
if (vp->IsTypeNum())
vp->SetValue(GetDouble(vlp));
else // Get the proper number of decimals
vp->SetValue_psz(GetString(g, vlp));
break;
case TYPE_BOOL:
if (vp->IsTypeNum())
vp->SetValue(GetInteger(vlp) ? 1 : 0);
else
vp->SetValue_psz(GetString(g, vlp));
break;
case TYPE_JAR:
vp->SetValue_psz(GetArrayText(g, MVP(vlp->To_Val), NULL));
break;
case TYPE_JOB:
vp->SetValue_psz(GetObjectText(g, MPP(vlp->To_Val), NULL));
break;
case TYPE_NULL:
vp->SetNull(true);
default:
vp->Reset();
} // endswitch Type
} else {
vp->SetNull(true);
vp->Reset();
} // endif val
} // end of SetJsonValue
/*********************************************************************************/
/* GetJson: */
/*********************************************************************************/
PBVAL BJNX::GetJson(PGLOBAL g) {
return GetRowValue(g, Row, 0);
} // end of GetJson
/*********************************************************************************/
/* ReadValue: */
/*********************************************************************************/
void BJNX::ReadValue(PGLOBAL g) {
Value->SetValue_pval(GetColumnValue(g, Row, 0));
} // end of ReadValue
/*********************************************************************************/
/* GetColumnValue: */
/*********************************************************************************/
PVAL BJNX::GetColumnValue(PGLOBAL g, PBVAL row, int i) {
PBVAL vlp = GetRowValue(g, row, i);
SetJsonValue(g, Value, vlp);
return Value;
} // end of GetColumnValue
/*********************************************************************************/
/* GetRowValue: */
/*********************************************************************************/
PBVAL BJNX::GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b) {
my_bool expd = false;
PBVAL bap;
PBVAL vlp = NULL;
for (; i < Nod && row; i++) {
if (Nodes[i].Op == OP_NUM) {
Value->SetValue(row->Type == TYPE_JAR ? GetArraySize(MVP(row->To_Val)) : 1);
vlp = SubAllocVal(g, Value);
return vlp;
} else if (Nodes[i].Op == OP_XX) {
Jb = b;
// return DupVal(g, row);
return row; // or last line ???
} else switch (row->Type) {
case TYPE_JOB:
if (!Nodes[i].Key) {
// Expected Array was not there
if (Nodes[i].Op == OP_LE) {
if (i < Nod - 1)
continue;
else
vlp = row; // DupVal(g, row) ???
} else {
strcpy(g->Message, "Unexpected object");
vlp = NULL;
} //endif Op
} else
vlp = GetKeyValue(MPP(row->To_Val), Nodes[i].Key);
break;
case TYPE_JAR:
bap = MVP(row->To_Val);
if (!Nodes[i].Key) {
if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
vlp = GetArrayValue(bap, Nodes[i].Rank);
else if (Nodes[i].Op == OP_EXP)
return (PBVAL)ExpandArray(g, bap, i);
else
return SubAllocVal(g, CalculateArray(g, bap, i));
} else {
// Unexpected array, unwrap it as [0]
vlp = GetArrayValue(bap, 0);
i--;
} // endif's
break;
case TYPE_JVAL:
vlp = row;
break;
default:
sprintf(g->Message, "Invalid row JSON type %d", row->Type);
vlp = NULL;
} // endswitch Type
row = vlp;
} // endfor i
return vlp;
} // end of GetRowValue
/*********************************************************************************/
/* ExpandArray: */
/*********************************************************************************/
PVAL BJNX::ExpandArray(PGLOBAL g, PBVAL arp, int n)
{
strcpy(g->Message, "Expand cannot be done by this function");
return NULL;
} // end of ExpandArray
/*********************************************************************************/
/* CalculateArray: NIY */
/*********************************************************************************/
PVAL BJNX::CalculateArray(PGLOBAL g, PBVAL bap, int n)
{
#if 0
int i, ars = GetArraySize(bap), nv = 0;
bool err;
OPVAL op = Nodes[n].Op;
PVAL val[2], vp = Nodes[n].Valp;
PBVAL bvrp, bvp;
BVAL bval;
vp->Reset();
xtrc(1,"CalculateArray size=%d op=%d\n", ars, op);
for (i = 0; i < ars; i++) {
bvrp = GetArrayValue(bap, i);
xtrc(1, "i=%d nv=%d\n", i, nv);
if (!IsValueNull(bvrp) || (op == OP_CNC && GetJsonNull())) {
if (IsValueNull(bvrp)) {
SetString(bvrp, GetJsonNull(), 0);
bvp = bvrp;
} else if (n < Nod - 1 && bvrp->GetJson()) {
bval.SetValue(g, GetColumnValue(g, jvrp->GetJson(), n + 1));
bvp = &bval;
} else
jvp = jvrp;
if (trace(1))
htrc("jvp=%s null=%d\n",
jvp->GetString(g), jvp->IsNull() ? 1 : 0);
if (!nv++) {
SetJsonValue(g, vp, jvp);
continue;
} else
SetJsonValue(g, MulVal, jvp);
if (!MulVal->IsNull()) {
switch (op) {
case OP_CNC:
if (Nodes[n].CncVal) {
val[0] = Nodes[n].CncVal;
err = vp->Compute(g, val, 1, op);
} // endif CncVal
val[0] = MulVal;
err = vp->Compute(g, val, 1, op);
break;
// case OP_NUM:
case OP_SEP:
val[0] = Nodes[n].Valp;
val[1] = MulVal;
err = vp->Compute(g, val, 2, OP_ADD);
break;
default:
val[0] = Nodes[n].Valp;
val[1] = MulVal;
err = vp->Compute(g, val, 2, op);
} // endswitch Op
if (err)
vp->Reset();
if (trace(1)) {
char buf(32);
htrc("vp='%s' err=%d\n",
vp->GetCharString(&buf), err ? 1 : 0);
} // endif trace
} // endif Zero
} // endif jvrp
} // endfor i
if (op == OP_SEP) {
// Calculate average
MulVal->SetValue(nv);
val[0] = vp;
val[1] = MulVal;
if (vp->Compute(g, val, 2, OP_DIV))
vp->Reset();
} // endif Op
return vp;
#else
strcpy(g->Message, "Calculate array NIY");
return NULL;
#endif
} // end of CalculateArray
/*********************************************************************************/
/* CheckPath: Checks whether the path exists in the document. */
/*********************************************************************************/
my_bool BJNX::CheckPath(PGLOBAL g) {
PBVAL val = NULL;
PBVAL row = Row;
for (int i = 0; i < Nod && row; i++) {
val = NULL;
if (Nodes[i].Op == OP_NUM || Nodes[i].Op == OP_XX) {
} else switch (row->Type) {
case TYPE_JOB:
if (Nodes[i].Key)
val = GetKeyValue(MPP(row->To_Val), Nodes[i].Key);
break;
case TYPE_JAR:
if (!Nodes[i].Key)
if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
val = GetArrayValue(MVP(row->To_Val), Nodes[i].Rank);
break;
case TYPE_JVAL:
val = MVP(row->To_Val);
break;
default:
sprintf(g->Message, "Invalid row JSON type %d", row->Type);
} // endswitch Type
// if (i < Nod - 1)
// if (!(row = (val) ? val->GetJsp() : NULL))
// val = NULL;
row = val;
} // endfor i
return (val != NULL);
} // end of CheckPath
/***********************************************************************/
/* GetRow: Set the complete path of the object to be set. */
/***********************************************************************/
PBVAL BJNX::GetRow(PGLOBAL g) {
PBVAL val = NULL;
PBVAL arp;
PBVAL nwr, row = Row;
for (int i = 0; i < Nod - 1 && row; i++) {
if (Nodes[i].Op == OP_XX)
break;
else switch (row->Type) {
case TYPE_JOB:
if (!Nodes[i].Key)
// Expected Array was not there, wrap the value
continue;
val = GetKeyValue(MPP(row->To_Val), Nodes[i].Key);
break;
case TYPE_JAR:
arp = MVP(row->To_Val);
if (!Nodes[i].Key) {
if (Nodes[i].Op == OP_EQ)
val = GetArrayValue(arp, Nodes[i].Rank);
else
val = GetArrayValue(arp, Nodes[i].Rx);
} else {
// Unexpected array, unwrap it as [0]
val = GetArrayValue(arp, 0);
i--;
} // endif Nodes
break;
case TYPE_JVAL:
val = MVP(row->To_Val);
break;
default:
sprintf(g->Message, "Invalid row JSON type %d", row->Type);
val = NULL;
} // endswitch Type
if (val) {
row = val;
} else {
// Construct missing objects
for (i++; row && i < Nod; i++) {
if (Nodes[i].Op == OP_XX)
break;
// else if (!Nodes[i].Key)
// Construct intermediate array
// nwr = SubAllocVal(g);
// else
// nwr = SubAllocPair(g);
// Construct new row
nwr = SubAllocVal(g);
if (row->Type == TYPE_JOB) {
SetKeyValue(g, MPP(row->To_Val), MOF(nwr), Nodes[i - 1].Key);
} else if (row->Type == TYPE_JAR) {
AddArrayValue(g, MVP(row->To_Val), nwr);
} else {
strcpy(g->Message, "Wrong type when writing new row");
nwr = NULL;
} // endif's
row = nwr;
} // endfor i
break;
} // endelse
} // endfor i
return row;
} // end of GetRow
/***********************************************************************/
/* WriteValue: */
/***********************************************************************/
my_bool BJNX::WriteValue(PGLOBAL g, PBVAL jvalp) {
PBPR objp = NULL;
PBVAL arp = NULL;
PBVAL jvp = NULL;
PBVAL row = GetRow(g);
if (!row)
return true;
switch (row->Type) {
case TYPE_JOB: objp = MPP(row->To_Val); break;
case TYPE_JAR: arp = MVP(row->To_Val); break;
case TYPE_JVAL: jvp = MVP(row->To_Val); break;
default:
strcpy(g->Message, "Invalid target type");
return true;
} // endswitch Type
if (arp) {
if (!Nodes[Nod - 1].Key) {
if (Nodes[Nod - 1].Op == OP_EQ)
SetArrayValue(g, arp, jvalp, Nodes[Nod - 1].Rank);
else
AddArrayValue(g, arp, jvalp);
} // endif Key
} else if (objp) {
if (Nodes[Nod - 1].Key)
SetKeyValue(g, objp, MOF(jvalp), Nodes[Nod - 1].Key);
} else if (jvp)
SetValueVal(jvp, jvalp);
return false;
} // end of WriteValue
/*********************************************************************************/
/* Locate a value in a JSON tree: */
/*********************************************************************************/
PSZ BJNX::Locate(PGLOBAL g, PBVAL jsp, PBVAL jvp, int k) {
PSZ str = NULL;
my_bool b = false, err = true;
g->Message[0] = 0;
if (!jsp) {
strcpy(g->Message, "Null json tree");
return NULL;
} // endif jsp
try {
// Write to the path string
Jp = new(g) JOUTSTR(g);
Jp->WriteChr('$');
Bvalp = jvp;
K = k;
switch (jsp->Type) {
case TYPE_JAR:
err = LocateArray(g, MVP(jsp->To_Val));
break;
case TYPE_JOB:
err = LocateObject(g, MPP(jsp->To_Val));
break;
case TYPE_JVAL:
err = LocateValue(g, MVP(jsp->To_Val));
break;
default:
err = true;
} // endswitch Type
if (err) {
if (!g->Message[0])
strcpy(g->Message, "Invalid json tree");
} else if (Found) {
Jp->WriteChr('\0');
PlugSubAlloc(g, NULL, Jp->N);
str = Jp->Strp;
} // endif's
} catch (int n) {
if (trace(1))
htrc("Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
} catch (const char* msg) {
strcpy(g->Message, msg);
} // end catch
return str;
} // end of Locate
/*********************************************************************************/
/* Locate in a JSON Array. */
/*********************************************************************************/
my_bool BJNX::LocateArray(PGLOBAL g, PBVAL jarp) {
char s[16];
int n = GetArraySize(jarp);
size_t m = Jp->N;
for (int i = 0; i < n && !Found; i++) {
Jp->N = m;
sprintf(s, "[%d]", i + B);
if (Jp->WriteStr(s))
return true;
if (LocateValue(g, GetArrayValue(jarp, i)))
return true;
} // endfor i
return false;
} // end of LocateArray
/*********************************************************************************/
/* Locate in a JSON Object. */
/*********************************************************************************/
my_bool BJNX::LocateObject(PGLOBAL g, PBPR jobp) {
size_t m;
if (Jp->WriteChr('.'))
return true;
m = Jp->N;
for (PBPR pair = jobp; pair && !Found; pair = MPP(pair->Next)) {
Jp->N = m;
if (Jp->WriteStr(MZP(pair->Key)))
return true;
if (LocateValue(g, MVP(pair->Vlp)))
return true;
} // endfor i
return false;
} // end of LocateObject
/*********************************************************************************/
/* Locate a JSON Value. */
/*********************************************************************************/
my_bool BJNX::LocateValue(PGLOBAL g, PBVAL jvp)
{
if (CompareTree(g, Bvalp, jvp))
Found = (--K == 0);
else if (jvp->Type == TYPE_JAR)
return LocateArray(g, GetArray(jvp));
else if (jvp->Type == TYPE_JOB)
return LocateObject(g, GetObject(jvp));
return false;
} // end of LocateValue
/*********************************************************************************/
/* Locate all occurrences of a value in a JSON tree: */
/*********************************************************************************/
PSZ BJNX::LocateAll(PGLOBAL g, PBVAL jsp, PBVAL bvp, int mx)
{
PSZ str = NULL;
my_bool b = false, err = true;
PJPN jnp;
if (!jsp) {
strcpy(g->Message, "Null json tree");
return NULL;
} // endif jsp
try {
jnp = (PJPN)PlugSubAlloc(g, NULL, sizeof(JPN) * mx);
memset(jnp, 0, sizeof(JPN) * mx);
g->Message[0] = 0;
// Write to the path string
Jp = new(g)JOUTSTR(g);
Bvalp = bvp;
Imax = mx - 1;
Jpnp = jnp;
Jp->WriteChr('[');
switch (jsp->Type) {
case TYPE_JAR:
err = LocateArrayAll(g, MVP(jsp->To_Val));
break;
case TYPE_JOB:
err = LocateObjectAll(g, MPP(jsp->To_Val));
break;
case TYPE_JVAL:
err = LocateValueAll(g, MVP(jsp->To_Val));
break;
default:
err = LocateValueAll(g, jsp);
} // endswitch Type
if (!err) {
if (Jp->N > 1)
Jp->N--;
Jp->WriteChr(']');
Jp->WriteChr('\0');
PlugSubAlloc(g, NULL, Jp->N);
str = Jp->Strp;
} else if (!g->Message[0])
strcpy(g->Message, "Invalid json tree");
} catch (int n) {
xtrc(1, "Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
} catch (const char* msg) {
strcpy(g->Message, msg);
} // end catch
return str;
} // end of LocateAll
/*********************************************************************************/
/* Locate in a JSON Array. */
/*********************************************************************************/
my_bool BJNX::LocateArrayAll(PGLOBAL g, PBVAL jarp)
{
int i = 0;
if (I < Imax) {
Jpnp[++I].Type = TYPE_JAR;
for (PBVAL vp = jarp; vp; vp = MVP(vp->Next)) {
Jpnp[I].N = i;
if (LocateValueAll(g, GetArrayValue(jarp, i)))
return true;
i++;
} // endfor i
I--;
} // endif I
return false;
} // end of LocateArrayAll
/*********************************************************************************/
/* Locate in a JSON Object. */
/*********************************************************************************/
my_bool BJNX::LocateObjectAll(PGLOBAL g, PBPR jobp)
{
if (I < Imax) {
Jpnp[++I].Type = TYPE_JOB;
for (PBPR pair = jobp; pair; pair = MPP(pair->Next)) {
Jpnp[I].Key = MZP(pair->Key);
if (LocateValueAll(g, MVP(pair->Vlp)))
return true;
} // endfor i
I--;
} // endif I
return false;
} // end of LocateObjectAll
/*********************************************************************************/
/* Locate a JSON Value. */
/*********************************************************************************/
my_bool BJNX::LocateValueAll(PGLOBAL g, PBVAL jvp) {
if (CompareTree(g, Bvalp, jvp))
return AddPath();
else if (jvp->Type == TYPE_JAR)
return LocateArrayAll(g, GetArray(jvp));
else if (jvp->Type == TYPE_JOB)
return LocateObjectAll(g, GetObject(jvp));
return false;
} // end of LocateValueAll
/*********************************************************************************/
/* Compare two JSON trees. */
/*********************************************************************************/
my_bool BJNX::CompareTree(PGLOBAL g, PBVAL jp1, PBVAL jp2)
{
if (!jp1 || !jp2 || jp1->Type != jp2->Type || GetSize(jp1) != GetSize(jp2))
return false;
my_bool found = true;
if (jp1->Type == TYPE_JAR) {
for (int i = 0; found && i < GetArraySize(jp1); i++)
found = (CompareValues(g, GetArrayValue(jp1, i), GetArrayValue(jp2, i)));
} else if (jp1->Type == TYPE_JOB) {
PBPR p1 = MPP(jp1->To_Val), p2 = MPP(jp2->To_Val);
// Keys can be differently ordered
for (; found && p1 && p2; p1 = MPP(p1->Next))
found = CompareValues(g, MVP(p1->Vlp), GetKeyValue(p2, MZP(p1->Key)));
} else if (jp1->Type == TYPE_JVAL) {
found = CompareTree(g, MVP(jp1->To_Val), (MVP(jp2->To_Val)));
} else
found = CompareValues(g, jp1, jp2);
return found;
} // end of CompareTree
/*********************************************************************************/
/* Compare two VAL values and return true if they are equal. */
/*********************************************************************************/
my_bool BJNX::CompareValues(PGLOBAL g, PBVAL v1, PBVAL v2)
{
my_bool b = false;
if (v1 && v2)
switch (v1->Type) {
case TYPE_JAR:
if (v2->Type == TYPE_JAR)
b = CompareTree(g, MVP(v1->To_Val), MVP(v2->To_Val));
break;
case TYPE_STRG:
if (v2->Type == TYPE_STRG) {
if (v1->Nd || v2->Nd) // Case insensitive
b = (!stricmp(MZP(v1->To_Val), MZP(v2->To_Val)));
else
b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
} // endif Type
break;
case TYPE_DTM:
if (v2->Type == TYPE_DTM)
b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
break;
case TYPE_INTG:
if (v2->Type == TYPE_INTG)
b = (v1->N == v2->N);
else if (v2->Type == TYPE_BINT)
b = ((longlong)v1->N == LLN(v2->To_Val));
break;
case TYPE_BINT:
if (v2->Type == TYPE_INTG)
b = (LLN(v1->To_Val) == (longlong)v2->N);
else if (v2->Type == TYPE_BINT)
b = (LLN(v1->To_Val) == LLN(v2->To_Val));
break;
case TYPE_FLOAT:
if (v2->Type == TYPE_FLOAT)
b = (v1->F == v2->F);
else if (v2->Type == TYPE_DBL)
b = ((double)v1->F == DBL(v2->To_Val));
break;
case TYPE_DBL:
if (v2->Type == TYPE_DBL)
b = (DBL(v1->To_Val) == DBL(v2->To_Val));
else if (v2->Type == TYPE_FLOAT)
b = (DBL(v1->To_Val) == (double)v2->F);
break;
case TYPE_BOOL:
if (v2->Type == TYPE_BOOL)
b = (v1->B == v2->B);
break;
case TYPE_NULL:
b = (v2->Type == TYPE_NULL);
break;
default:
break;
} // endswitch Type
else
b = (!v1 && !v2);
return b;
} // end of CompareValues
/*********************************************************************************/
/* Add the found path to the list. */
/*********************************************************************************/
my_bool BJNX::AddPath(void) {
char s[16];
if (Jp->WriteStr("\"$"))
return true;
for (int i = 0; i <= I; i++) {
if (Jpnp[i].Type == TYPE_JAR) {
sprintf(s, "[%d]", Jpnp[i].N + B);
if (Jp->WriteStr(s))
return true;
} else {
if (Jp->WriteChr('.'))
return true;
if (Jp->WriteStr(Jpnp[i].Key))
return true;
} // endif's
} // endfor i
if (Jp->WriteStr("\","))
return true;
return false;
} // end of AddPath
/*********************************************************************************/
/* Make a BVAL value from the passed argument. */
/*********************************************************************************/
static PBVAL MakeBinValue(PGLOBAL g, UDF_ARGS* args, uint i) {
char* sap = (args->arg_count > i) ? args->args[i] : NULL;
int n, len;
int ci;
longlong bigint;
void* Base = g->Sarea; // Required by MOF
BDOC doc(Base);
PBVAL bp;
PBVAL bvp = doc.SubAllocVal(g);
if (sap) switch (args->arg_type[i]) {
case STRING_RESULT:
if ((len = args->lengths[i])) {
if ((n = IsJson(args, i)) < 3)
sap = MakePSZ(g, args, i);
if (n) {
if (n == 2) {
if (!(sap = GetJsonFile(g, sap))) {
PUSH_WARNING(g->Message);
return NULL;
} // endif sap
len = strlen(sap);
} // endif 2
if (!(bp = doc.ParseJson(g, sap, strlen(sap))))
PUSH_WARNING(g->Message);
bvp = bp;
} else {
// Check whether this string is a valid json string
JsonMemSave(g);
if (!(bvp = doc.ParseJson(g, sap, strlen(sap)))) {
// Recover suballocated memory
JsonSubSet(g);
ci = (strnicmp(args->attributes[i], "ci", 2)) ? 0 : 1;
bvp = doc.SubAllocVal(g, MOF(sap), TYPE_STRG, ci);
} else
g->Saved_Size = 0;
} // endif n
} // endif len
break;
case INT_RESULT:
bigint = *(longlong*)sap;
if ((bigint == 0LL && !strcmp(args->attributes[i], "FALSE")) ||
(bigint == 1LL && !strcmp(args->attributes[i], "TRUE")))
doc.SetBool(bvp, (bool)bigint);
else
doc.SetBigint(g, bvp, bigint);
break;
case REAL_RESULT:
doc.SetFloat(bvp, *(double*)sap);
break;
case DECIMAL_RESULT:
doc.SetFloat(bvp, atof(MakePSZ(g, args, i)));
break;
case TIME_RESULT:
case ROW_RESULT:
default:
bvp = NULL;
break;
} // endswitch arg_type
return bvp;
} // end of MakeBinValue
/*********************************************************************************/
/* Test BJSON parse and serialize. */
/*********************************************************************************/
my_bool json_test_bson_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
unsigned long reslen, memlen, more = 1000;
if (args->arg_count == 0) {
strcpy(message, "At least 1 argument required (json)");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of json_test_bson_init
char* json_test_bson(UDF_INIT* initid, UDF_ARGS* args, char* result,
unsigned long* res_length, char* is_null, char* error) {
char* str = NULL, * sap = NULL, * fn = NULL;
int pretty = 1;
PBVAL bvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
BDOC doc(g);
if (g->N) {
str = (char*)g->Activityp;
goto err;
} else if (initid->const_item)
g->N = 1;
try {
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, !g->Xchk)) {
PUSH_WARNING("CheckMemory error");
*error = 1;
goto err;
} else if (!(bvp = MakeBinValue(g, args, 0))) {
PUSH_WARNING(g->Message);
goto err;
} // endif bvp
if (g->Mrr) { // First argument is a constant
g->Xchk = bvp;
JsonMemSave(g);
} // endif Mrr
} else
bvp = (PBVAL)g->Xchk;
for (uint i = 1; i < args->arg_count; i++)
if (args->arg_type[i] == STRING_RESULT)
fn = args->args[i];
else if (args->arg_type[i] == INT_RESULT)
pretty = (int)*(longlong*)args->args[i];
// Serialize the parse tree
str = doc.Serialize(g, bvp, fn, pretty);
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)str;
} catch (int n) {
xtrc(1, "json_test_bson: error %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
*error = 1;
str = NULL;
} catch (const char* msg) {
strcpy(g->Message, msg);
PUSH_WARNING(g->Message);
*error = 1;
str = NULL;
} // end catch
err:
if (!str) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(str);
return str;
} // end of json_test_bson
void json_test_bson_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_test_bson_deinit
/*********************************************************************************/
/* Locate a value in a Json tree. */
/*********************************************************************************/
my_bool jsonlocate_bson_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
unsigned long reslen, memlen, more = 1000;
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (rank)");
return true;
} // endifs args
CalcLen(args, false, reslen, memlen);
// TODO: calculate this
if (IsJson(args, 0) == 3)
more = 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of jsonlocate_bson_init
char* jsonlocate_bson(UDF_INIT* initid, UDF_ARGS* args, char* result,
unsigned long* res_length, char* is_null, char* error) {
char* path = NULL;
int k;
PBVAL bvp, bvp2;
PBJNX bnxp;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (g->Activityp) {
path = (char*)g->Activityp;
*res_length = strlen(path);
return path;
} else {
*res_length = 0;
*is_null = 1;
return NULL;
} // endif Activityp
} else if (initid->const_item)
g->N = 1;
try {
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, !g->Xchk)) {
PUSH_WARNING("CheckMemory error");
*error = 1;
goto err;
} else
bvp = MakeBinValue(g, args, 0);
if (!bvp) {
PUSH_WARNING("First argument is not a valid JSON item");
goto err;
} // endif bvp
if (g->Mrr) { // First argument is a constant
g->Xchk = bvp;
JsonMemSave(g);
} // endif Mrr
} else
bvp = (PBVAL)g->Xchk;
// The item to locate
bvp2 = MakeBinValue(g, args, 1);
k = (args->arg_count > 2) ? (int)*(long long*)args->args[2] : 1;
bnxp = new(g) BJNX(g, bvp, TYPE_STRING);
path = bnxp->Locate(g, bvp, bvp2, k);
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)path;
} catch (int n) {
xtrc(1, "Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
*error = 1;
path = NULL;
} catch (const char* msg) {
strcpy(g->Message, msg);
PUSH_WARNING(g->Message);
*error = 1;
path = NULL;
} // end catch
err:
if (!path) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(path);
return path;
} // end of jsonlocate_bson
void jsonlocate_bson_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of jsonlocate_bson_deinit
/*********************************************************************************/
/* Locate all occurences of a value in a Json tree. */
/*********************************************************************************/
my_bool json_locate_all_bson_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
{
unsigned long reslen, memlen, more = 1000;
if (args->arg_count < 2) {
strcpy(message, "At least 2 arguments required");
return true;
} else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
strcpy(message, "Third argument is not an integer (Depth)");
return true;
} // endifs
CalcLen(args, false, reslen, memlen);
// TODO: calculate this
if (IsJson(args, 0) == 3)
more = 0;
return JsonInit(initid, args, message, true, reslen, memlen, more);
} // end of json_locate_all_bson_init
char* json_locate_all_bson(UDF_INIT* initid, UDF_ARGS* args, char* result,
unsigned long* res_length, char* is_null, char* error)
{
char *path = NULL;
int mx = 10;
PBVAL bvp, bvp2;
PBJNX bnxp;
PGLOBAL g = (PGLOBAL)initid->ptr;
if (g->N) {
if (g->Activityp) {
path = (char*)g->Activityp;
*res_length = strlen(path);
return path;
} else {
*error = 1;
*res_length = 0;
*is_null = 1;
return NULL;
} // endif Activityp
} else if (initid->const_item)
g->N = 1;
try {
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true)) {
PUSH_WARNING("CheckMemory error");
*error = 1;
goto err;
} else
bvp = MakeBinValue(g, args, 0);
if (!bvp) {
PUSH_WARNING("First argument is not a valid JSON item");
goto err;
} // endif bvp
if (g->Mrr) { // First argument is a constant
g->Xchk = bvp;
JsonMemSave(g);
} // endif Mrr
} else
bvp = (PBVAL)g->Xchk;
// The item to locate
bvp2 = MakeBinValue(g, args, 1);
if (args->arg_count > 2)
mx = (int)*(long long*)args->args[2];
bnxp = new(g) BJNX(g, bvp, TYPE_STRING);
path = bnxp->LocateAll(g, bvp, bvp2, mx);
if (initid->const_item)
// Keep result of constant function
g->Activityp = (PACTIVITY)path;
} catch (int n) {
xtrc(1, "Exception %d: %s\n", n, g->Message);
PUSH_WARNING(g->Message);
*error = 1;
path = NULL;
} catch (const char* msg) {
strcpy(g->Message, msg);
PUSH_WARNING(g->Message);
*error = 1;
path = NULL;
} // end catch
err:
if (!path) {
*res_length = 0;
*is_null = 1;
} else
*res_length = strlen(path);
return path;
} // end of json_locate_all_bson
void json_locate_all_bson_deinit(UDF_INIT* initid) {
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_locate_all_bson_deinit
/******************** tabjson H Declares Source Code File (.H) *******************/
/* Name: jsonudf.h Version 1.3 */
/* Name: jsonudf.h Version 1.4 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2015-2017 */
/* (C) Copyright to the author Olivier BERTRAND 2015-2020 */
/* */
/* This file contains the JSON UDF function and class declares. */
/*********************************************************************************/
......@@ -15,6 +15,27 @@
#define UDF_EXEC_ARGS \
UDF_INIT*, UDF_ARGS*, char*, unsigned long*, char*, char*
// BSON size should be equal on Linux and Windows
#define BMX 255
typedef struct BSON* PBSON;
/***********************************************************************/
/* Structure used to return binary json to Json UDF functions. */
/***********************************************************************/
struct BSON {
char Msg[BMX + 1];
char *Filename;
PGLOBAL G;
int Pretty;
ulong Reslen;
my_bool Changed;
PJSON Top;
PJSON Jsp;
PBSON Bsp;
}; // end of struct BSON
PBSON JbinAlloc(PGLOBAL g, UDF_ARGS* args, ulong len, PJSON jsp);
/*********************************************************************************/
/* The JSON tree node. Can be an Object or an Array. */
/*********************************************************************************/
......@@ -29,8 +50,6 @@ typedef struct _jnode {
} JNODE, *PJNODE;
typedef class JSNX *PJSNX;
typedef class JOUTPATH *PJTP;
typedef class JOUTALL *PJTA;
extern "C" {
DllExport my_bool jsonvalue_init(UDF_INIT*, UDF_ARGS*, char*);
......@@ -368,3 +387,90 @@ class JUP : public BLOCK {
int k, recl;
}; // end of class JUP
/* --------------------------- New Testing BJSON Stuff --------------------------*/
typedef class BJNX* PBJNX;
/*********************************************************************************/
/* Class BJNX: BJSON access methods. */
/*********************************************************************************/
class BJNX : public BDOC {
public:
// Constructors
BJNX(PGLOBAL g, PBVAL row, int type, int len = 64, int prec = 0, my_bool wr = false);
// Implementation
int GetPrecision(void) { return Prec; }
PVAL GetValue(void) { return Value; }
// Methods
my_bool SetJpath(PGLOBAL g, char* path, my_bool jb = false);
my_bool ParseJpath(PGLOBAL g);
void ReadValue(PGLOBAL g);
PBVAL GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b = true);
PBVAL GetJson(PGLOBAL g);
my_bool CheckPath(PGLOBAL g);
my_bool WriteValue(PGLOBAL g, PBVAL jvalp);
char* Locate(PGLOBAL g, PBVAL jsp, PBVAL jvp, int k = 1);
char* LocateAll(PGLOBAL g, PBVAL jsp, PBVAL jvp, int mx = 10);
protected:
my_bool SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm);
PVAL GetColumnValue(PGLOBAL g, PBVAL row, int i);
PVAL ExpandArray(PGLOBAL g, PBVAL arp, int n);
PVAL CalculateArray(PGLOBAL g, PBVAL arp, int n);
PVAL MakeJson(PGLOBAL g, PBVAL bvp);
void SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp);
PBVAL GetRow(PGLOBAL g);
my_bool CompareValues(PGLOBAL g, PBVAL v1, PBVAL v2);
my_bool LocateArray(PGLOBAL g, PBVAL jarp);
my_bool LocateObject(PGLOBAL g, PBPR jobp);
my_bool LocateValue(PGLOBAL g, PBVAL jvp);
my_bool LocateArrayAll(PGLOBAL g, PBVAL jarp);
my_bool LocateObjectAll(PGLOBAL g, PBPR jobp);
my_bool LocateValueAll(PGLOBAL g, PBVAL jvp);
my_bool CompareTree(PGLOBAL g, PBVAL jp1, PBVAL jp2);
my_bool AddPath(void);
// Default constructor not to be used
BJNX(void) {}
// Members
PBVAL Row;
PBVAL Bvalp;
PJPN Jpnp;
JOUTSTR* Jp;
JNODE* Nodes; // The intermediate objects
PVAL Value;
PVAL MulVal; // To value used by multiple column
char* Jpath; // The json path
int Buf_Type;
int Long;
int Prec;
int Nod; // The number of intermediate objects
int Xnod; // Index of multiple values
int K; // Kth item to locate
int I; // Index of JPN
int Imax; // Max number of JPN's
int B; // Index base
my_bool Xpd; // True for expandable column
my_bool Parsed; // True when parsed
my_bool Found; // Item found by locate
my_bool Wr; // Write mode
my_bool Jb; // Must return json item
}; // end of class BJNX
extern "C" {
DllExport my_bool json_test_bson_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char* json_test_bson(UDF_EXEC_ARGS);
DllExport void json_test_bson_deinit(UDF_INIT*);
DllExport my_bool jsonlocate_bson_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char* jsonlocate_bson(UDF_EXEC_ARGS);
DllExport void jsonlocate_bson_deinit(UDF_INIT*);
DllExport my_bool json_locate_all_bson_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char* json_locate_all_bson(UDF_EXEC_ARGS);
DllExport void json_locate_all_bson_deinit(UDF_INIT*);
} // extern "C"
......@@ -1596,6 +1596,7 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
if (Value->IsTypeNum()) {
strcpy(g->Message, "Cannot make Json for a numeric column");
Value->Reset();
#if 0
} else if (Value->GetType() == TYPE_BIN) {
if ((unsigned)Value->GetClen() >= sizeof(BSON)) {
ulong len = Tjp->Lrecl ? Tjp->Lrecl : 500;
......@@ -1607,6 +1608,7 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
strcpy(g->Message, "Column size too small");
Value->SetValue_char(NULL, 0);
} // endif Clen
#endif 0
} else
Value->SetValue_psz(Serialize(g, jsp, NULL, 0));
......
......@@ -197,7 +197,7 @@ const char *GetFormatType(int type)
case TYPE_DOUBLE: c = "F"; break;
case TYPE_DATE: c = "D"; break;
case TYPE_TINY: c = "T"; break;
case TYPE_DECIM: c = "M"; break;
case TYPE_DECIM: c = "F"; break;
case TYPE_BIN: c = "B"; break;
case TYPE_PCHAR: c = "P"; break;
} // endswitch type
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment