diff options
author | Olivier Bertrand <bertrandop@gmail.com> | 2020-11-25 12:56:45 +0100 |
---|---|---|
committer | Olivier Bertrand <bertrandop@gmail.com> | 2020-11-25 12:56:45 +0100 |
commit | dc8f914c383366d11b6a995ba184b99d5ec663cf (patch) | |
tree | 8af9316330bfe009952248317a6f68addcaced84 | |
parent | dae4bd0b36b83cc50d827c62f02ed1b8b1aa2045 (diff) | |
download | mariadb-git-dc8f914c383366d11b6a995ba184b99d5ec663cf.tar.gz |
Remove based enum not accepted by most gcc compilers
-rw-r--r-- | storage/connect/bson.cpp | 1016 | ||||
-rw-r--r-- | storage/connect/bson.h | 187 | ||||
-rw-r--r-- | storage/connect/json.h | 41 | ||||
-rw-r--r-- | storage/connect/jsonudf.cpp | 1476 | ||||
-rw-r--r-- | storage/connect/jsonudf.h | 114 | ||||
-rw-r--r-- | storage/connect/tabjson.cpp | 2 | ||||
-rw-r--r-- | storage/connect/value.cpp | 2 |
7 files changed, 2270 insertions, 568 deletions
diff --git a/storage/connect/bson.cpp b/storage/connect/bson.cpp index 86825f5808e..2f380752c0d 100644 --- a/storage/connect/bson.cpp +++ b/storage/connect/bson.cpp @@ -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,53 +87,25 @@ 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. */ /***********************************************************************/ 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,26 +271,13 @@ 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. */ /***********************************************************************/ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) { @@ -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': @@ -396,20 +349,6 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) { } // 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. */ /***********************************************************************/ PBVAL BDOC::ParseValue(PGLOBAL g, int& i) { @@ -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 @@ fin: 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 @@ fin: 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 @@ err: } // 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,31 +1199,90 @@ 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. */ /***********************************************************************/ JVALUE::JVALUE(PJSON jsp) : JSON() { @@ -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 diff --git a/storage/connect/bson.h b/storage/connect/bson.h index 7cf0820dc7a..9f5f44d073c 100644 --- a/storage/connect/bson.h +++ b/storage/connect/bson.h @@ -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,73 +152,22 @@ protected: 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. */ /***********************************************************************/ class JOBJECT : public JSON { diff --git a/storage/connect/json.h b/storage/connect/json.h index c5251af01a9..5ba4d7b3dbd 100644 --- a/storage/connect/json.h +++ b/storage/connect/json.h @@ -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); diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp index c9f0ea9239a..0012b3d6bdd 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -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 + diff --git a/storage/connect/jsonudf.h b/storage/connect/jsonudf.h index 46bac66b607..886f380d426 100644 --- a/storage/connect/jsonudf.h +++ b/storage/connect/jsonudf.h @@ -1,7 +1,7 @@ /******************** 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 @@ public: 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" diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index a9aeadd7bf4..336b0f371ca 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -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)); diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index bca6d26d1e9..e710fefc624 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -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 |