diff options
author | Olivier Bertrand <bertrandop@gmail.com> | 2020-12-01 19:30:56 +0100 |
---|---|---|
committer | Olivier Bertrand <bertrandop@gmail.com> | 2020-12-01 19:39:09 +0100 |
commit | 4e8af8a6645136be34649abacb5b31ef64264584 (patch) | |
tree | 6395e9862ab27dc9879b9f68b87cc704458891d0 | |
parent | 950bf6ab53d7b6d5db0e7d986b81fbd5709e98f6 (diff) | |
download | mariadb-git-4e8af8a6645136be34649abacb5b31ef64264584.tar.gz |
- Fix memory leak for the JSON table type
(and continue BSON implementatio)
modified: storage/connect/bson.cpp
modified: storage/connect/bson.h
modified: storage/connect/bsonudf.cpp
modified: storage/connect/connect.cc
modified: storage/connect/global.h
modified: storage/connect/ha_connect.cc
modified: storage/connect/jsonudf.cpp
modified: storage/connect/mycat.cc
modified: storage/connect/plgdbsem.h
modified: storage/connect/plugutil.cpp
modified: storage/connect/tabjson.cpp
modified: storage/connect/tabjson.h
modified: storage/connect/user_connect.cc
- Desesperatly trying to fix xml.test failure
modified: storage/connect/mysql-test/connect/r/xml.result
-rw-r--r-- | storage/connect/bson.cpp | 218 | ||||
-rw-r--r-- | storage/connect/bson.h | 83 | ||||
-rw-r--r-- | storage/connect/bsonudf.cpp | 47 | ||||
-rw-r--r-- | storage/connect/connect.cc | 3 | ||||
-rw-r--r-- | storage/connect/global.h | 2 | ||||
-rw-r--r-- | storage/connect/ha_connect.cc | 23 | ||||
-rw-r--r-- | storage/connect/jsonudf.cpp | 6 | ||||
-rw-r--r-- | storage/connect/mycat.cc | 27 | ||||
-rw-r--r-- | storage/connect/mysql-test/connect/r/xml.result | 4 | ||||
-rw-r--r-- | storage/connect/plgdbsem.h | 3 | ||||
-rw-r--r-- | storage/connect/plugutil.cpp | 9 | ||||
-rw-r--r-- | storage/connect/tabbson.cpp | 2599 | ||||
-rw-r--r-- | storage/connect/tabbson.h | 342 | ||||
-rw-r--r-- | storage/connect/tabjson.cpp | 24 | ||||
-rw-r--r-- | storage/connect/tabjson.h | 2 | ||||
-rw-r--r-- | storage/connect/user_connect.cc | 3 |
16 files changed, 3214 insertions, 181 deletions
diff --git a/storage/connect/bson.cpp b/storage/connect/bson.cpp index 4725b67c06b..e395bd8988d 100644 --- a/storage/connect/bson.cpp +++ b/storage/connect/bson.cpp @@ -87,7 +87,7 @@ char* NextChr(PSZ s, char sep) { /***********************************************************************/ /* BDOC constructor. */ /***********************************************************************/ -BDOC::BDOC(void *base) : BJSON(base, NULL) +BDOC::BDOC(PGLOBAL G) : BJSON(G, NULL) { jp = NULL; s = NULL; @@ -118,25 +118,25 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) { pty[0] = false; try { - Bvp = SubAllocVal(g); + Bvp = NewVal(); 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); + Bvp->To_Val = ParseAsArray(i, pretty, ptyp); else - Bvp->To_Val = ParseArray(g, ++i); + Bvp->To_Val = ParseArray(++i); Bvp->Type = TYPE_JAR; break; case '{': if (Bvp->Type != TYPE_UNKNOWN) { - Bvp->To_Val = ParseAsArray(g, i, pretty, ptyp); + Bvp->To_Val = ParseAsArray(i, pretty, ptyp); Bvp->Type = TYPE_JAR; } else { - Bvp->To_Val = ParseObject(g, ++i); + Bvp->To_Val = ParseObject(++i); Bvp->Type = TYPE_JOB; } // endif Type @@ -168,9 +168,9 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) { default: if (Bvp->Type != TYPE_UNKNOWN) { - Bvp->To_Val = ParseAsArray(g, i, pretty, ptyp); + Bvp->To_Val = ParseAsArray(i, pretty, ptyp); Bvp->Type = TYPE_JAR; - } else if ((Bvp->To_Val = MOF(ParseValue(g, i)))) + } else if ((Bvp->To_Val = MOF(ParseValue(i)))) Bvp->Type = TYPE_JVAL; else throw 4; @@ -193,7 +193,8 @@ 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); + htrc("Exception %d: %s\n", n, G->Message); + GetMsg(g); Bvp = NULL; } catch (const char* msg) { strcpy(g->Message, msg); @@ -206,16 +207,16 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) { /***********************************************************************/ /* Parse several items as being in an array. */ /***********************************************************************/ -OFFSET BDOC::ParseAsArray(PGLOBAL g, int& i, int pretty, int* ptyp) { +OFFSET BDOC::ParseAsArray(int& i, int pretty, int* ptyp) { if (pty[0] && (!pretty || pretty > 2)) { OFFSET jsp; - if ((jsp = ParseArray(g, (i = 0))) && ptyp && pretty == 3) + if ((jsp = ParseArray((i = 0))) && ptyp && pretty == 3) *ptyp = (pty[0]) ? 0 : 3; return jsp; } else - strcpy(g->Message, "More than one item in file"); + strcpy(G->Message, "More than one item in file"); return 0; } // end of ParseAsArray @@ -223,7 +224,7 @@ OFFSET BDOC::ParseAsArray(PGLOBAL g, int& i, int pretty, int* ptyp) { /***********************************************************************/ /* Parse a JSON Array. */ /***********************************************************************/ -OFFSET BDOC::ParseArray(PGLOBAL g, int& i) { +OFFSET BDOC::ParseArray(int& i) { int level = 0; bool b = (!i); PBVAL vlp, firstvlp, lastvlp; @@ -234,7 +235,7 @@ OFFSET BDOC::ParseArray(PGLOBAL g, int& i) { switch (s[i]) { case ',': if (level < 2) { - sprintf(g->Message, "Unexpected ',' near %.*s", ARGS); + sprintf(G->Message, "Unexpected ',' near %.*s", ARGS); throw 1; } else level = 1; @@ -242,7 +243,7 @@ OFFSET BDOC::ParseArray(PGLOBAL g, int& i) { break; case ']': if (level == 1) { - sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS); + sprintf(G->Message, "Unexpected ',]' near %.*s", ARGS); throw 1; } // endif level @@ -256,14 +257,14 @@ OFFSET BDOC::ParseArray(PGLOBAL g, int& i) { break; default: if (level == 2) { - sprintf(g->Message, "Unexpected value near %.*s", ARGS); + sprintf(G->Message, "Unexpected value near %.*s", ARGS); throw 1; } else if (lastvlp) { - vlp = ParseValue(g, i); + vlp = ParseValue(i); lastvlp->Next = MOF(vlp); lastvlp = vlp; } else - firstvlp = lastvlp = ParseValue(g, i); + firstvlp = lastvlp = ParseValue(i); level = (b) ? 1 : 2; break; @@ -280,7 +281,7 @@ OFFSET BDOC::ParseArray(PGLOBAL g, int& i) { /***********************************************************************/ /* Parse a JSON Object. */ /***********************************************************************/ -OFFSET BDOC::ParseObject(PGLOBAL g, int& i) { +OFFSET BDOC::ParseObject(int& i) { OFFSET key; int level = 0; PBPR bpp, firstbpp, lastbpp; @@ -291,8 +292,8 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) { switch (s[i]) { case '"': if (level < 2) { - key = ParseString(g, ++i); - bpp = SubAllocPair(g, key); + key = ParseString(++i); + bpp = SubAllocPair(key); if (lastbpp) { lastbpp->Next = MOF(bpp); @@ -302,24 +303,24 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) { level = 2; } else { - sprintf(g->Message, "misplaced string near %.*s", ARGS); + sprintf(G->Message, "misplaced string near %.*s", ARGS); throw 2; } // endif level break; case ':': if (level == 2) { - lastbpp->Vlp = MOF(ParseValue(g, ++i)); + lastbpp->Vlp = MOF(ParseValue(++i)); level = 3; } else { - sprintf(g->Message, "Unexpected ':' near %.*s", ARGS); + sprintf(G->Message, "Unexpected ':' near %.*s", ARGS); throw 2; } // endif level break; case ',': if (level < 3) { - sprintf(g->Message, "Unexpected ',' near %.*s", ARGS); + sprintf(G->Message, "Unexpected ',' near %.*s", ARGS); throw 2; } else level = 1; @@ -327,7 +328,7 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) { break; case '}': if (!(level == 0 || level == 3)) { - sprintf(g->Message, "Unexpected '}' near %.*s", ARGS); + sprintf(G->Message, "Unexpected '}' near %.*s", ARGS); throw 2; } // endif level @@ -339,20 +340,21 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) { case '\t': break; default: - sprintf(g->Message, "Unexpected character '%c' near %.*s", + sprintf(G->Message, "Unexpected character '%c' near %.*s", s[i], ARGS); throw 2; }; // endswitch s[i] - strcpy(g->Message, "Unexpected EOF in Object"); + strcpy(G->Message, "Unexpected EOF in Object"); throw 2; } // end of ParseObject /***********************************************************************/ /* Parse a JSON Value. */ /***********************************************************************/ -PBVAL BDOC::ParseValue(PGLOBAL g, int& i) { - PBVAL bvp = SubAllocVal(g); +PBVAL BDOC::ParseValue(int& i) +{ + PBVAL bvp = NewVal(); for (; i < len; i++) switch (s[i]) { @@ -369,16 +371,16 @@ PBVAL BDOC::ParseValue(PGLOBAL g, int& i) { suite: switch (s[i]) { case '[': - bvp->To_Val = ParseArray(g, ++i); + bvp->To_Val = ParseArray(++i); bvp->Type = TYPE_JAR; break; case '{': - bvp->To_Val = ParseObject(g, ++i); + bvp->To_Val = ParseObject(++i); bvp->Type = TYPE_JOB; break; case '"': // jvp->Val = AllocVal(g, TYPE_STRG); - bvp->To_Val = ParseString(g, ++i); + bvp->To_Val = ParseString(++i); bvp->Type = TYPE_STRG; break; case 't': @@ -412,7 +414,7 @@ suite: case '-': default: if (s[i] == '-' || isdigit(s[i])) - ParseNumeric(g, i, bvp); + ParseNumeric(i, bvp); else goto err; @@ -421,29 +423,29 @@ suite: return bvp; err: - sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS); + sprintf(G->Message, "Unexpected character '%c' near %.*s", s[i], ARGS); throw 3; } // end of ParseValue /***********************************************************************/ /* Unescape and parse a JSON string. */ /***********************************************************************/ -OFFSET BDOC::ParseString(PGLOBAL g, int& i) { +OFFSET BDOC::ParseString(int& i) { uchar* p; int n = 0; // Be sure of memory availability - if (((size_t)len + 1 - i) > ((PPOOLHEADER)g->Sarea)->FreeBlk) + if (((size_t)len + 1 - i) > ((PPOOLHEADER)G->Sarea)->FreeBlk) throw("ParseString: Out of memory"); // The size to allocate is not known yet - p = (uchar*)PlugSubAlloc(g, NULL, 0); + p = (uchar*)PlugSubAlloc(G, NULL, 0); for (; i < len; i++) switch (s[i]) { case '"': p[n++] = 0; - PlugSubAlloc(g, NULL, n); + PlugSubAlloc(G, NULL, n); return MOF(p); case '\\': if (++i < len) { @@ -514,7 +516,7 @@ throw("Unexpected EOF in String"); /***********************************************************************/ /* Parse a JSON numeric value. */ /***********************************************************************/ -void BDOC::ParseNumeric(PGLOBAL g, int& i, PBVAL vlp) { +void BDOC::ParseNumeric(int& i, PBVAL vlp) { char buf[50]; int n = 0; short nd = 0; @@ -570,7 +572,7 @@ fin: double dv = strtod(buf, NULL); if (nd > 6) { - double* dvp = (double*)PlugSubAlloc(g, NULL, sizeof(double)); + double* dvp = (double*)PlugSubAlloc(G, NULL, sizeof(double)); *dvp = dv; vlp->To_Val = MOF(dvp); @@ -585,7 +587,7 @@ fin: longlong iv = strtoll(buf, NULL, 10); if (iv > INT_MAX32 || iv < INT_MIN32) { - longlong *llp = (longlong*)PlugSubAlloc(g, NULL, sizeof(longlong)); + longlong *llp = (longlong*)PlugSubAlloc(G, NULL, sizeof(longlong)); *llp = iv; vlp->To_Val = MOF(llp); @@ -614,7 +616,7 @@ PSZ BDOC::Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty) { bool b = false, err = true; FILE* fs = NULL; - g->Message[0] = 0; + G->Message[0] = 0; try { if (!bvp) { @@ -664,15 +666,15 @@ PSZ BDOC::Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty) { str = ((JOUTSTR*)jp)->Strp; jp->WriteChr('\0'); PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N); - } else { - if (!g->Message[0]) + } else if (G->Message[0]) strcpy(g->Message, "Error in Serialize"); - - } // endif's + else + GetMsg(g); } catch (int n) { if (trace(1)) - htrc("Exception %d: %s\n", n, g->Message); + htrc("Exception %d: %s\n", n, G->Message); + GetMsg(g); str = NULL; } catch (const char* msg) { strcpy(g->Message, msg); @@ -796,10 +798,10 @@ bool BDOC::SerializeValue(PBVAL jvp) { /***********************************************************************/ /* Program for sub-allocating Bjson structures. */ /***********************************************************************/ -void* BJSON::BsonSubAlloc(PGLOBAL g, size_t size) +void* BJSON::BsonSubAlloc(size_t size) { PPOOLHEADER pph; /* Points on area header. */ - void* memp = g->Sarea; + void* memp = G->Sarea; size = ((size + 3) / 4) * 4; /* Round up size to multiple of 4 */ pph = (PPOOLHEADER)memp; @@ -808,10 +810,10 @@ void* BJSON::BsonSubAlloc(PGLOBAL g, size_t size) memp, size, pph->To_Free, pph->FreeBlk); if (size > pph->FreeBlk) { /* Not enough memory left in pool */ - sprintf(g->Message, + 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); + xtrc(1, "BsonSubAlloc: %s\n", G->Message); throw(1234); } /* endif size OS32 code */ @@ -824,14 +826,29 @@ void* BJSON::BsonSubAlloc(PGLOBAL g, size_t size) return memp; } /* end of BsonSubAlloc */ +/*********************************************************************************/ +/* Program for SubSet re-initialization of the memory pool. */ +/*********************************************************************************/ +void BJSON::SubSet(bool b) +{ + PPOOLHEADER pph = (PPOOLHEADER)G->Sarea; + + pph->To_Free = (G->Saved_Size) ? G->Saved_Size : sizeof(POOLHEADER); + pph->FreeBlk = G->Sarea_Size - pph->To_Free; + + if (b) + G->Saved_Size = 0; + +} /* end of JsonSubSet */ + /* ------------------------ Bobject functions ------------------------ */ /***********************************************************************/ /* Sub-allocate and initialize a BPAIR. */ /***********************************************************************/ -PBPR BJSON::SubAllocPair(PGLOBAL g, OFFSET key, OFFSET val) +PBPR BJSON::SubAllocPair(OFFSET key, OFFSET val) { - PBPR bpp = (PBPR)BsonSubAlloc(g, sizeof(BPAIR)); + PBPR bpp = (PBPR)BsonSubAlloc(sizeof(BPAIR)); bpp->Key = key; bpp->Vlp = val; @@ -857,9 +874,9 @@ int BJSON::GetObjectSize(PBPR bop, bool b) /***********************************************************************/ /* Add a new pair to an Object and return it. */ /***********************************************************************/ -PBPR BJSON::AddPair(PGLOBAL g, PBPR bop, PSZ key, OFFSET val) +PBPR BJSON::AddPair(PBPR bop, PSZ key, OFFSET val) { - PBPR brp, nrp = SubAllocPair(g, key, val); + PBPR brp, nrp = SubAllocPair(key, val); if (bop) { for (brp = bop; brp->Next; brp = MPP(brp->Next)); @@ -874,17 +891,17 @@ PBPR BJSON::AddPair(PGLOBAL g, PBPR bop, PSZ key, OFFSET val) /***********************************************************************/ /* Return all object keys as an array. */ /***********************************************************************/ -PBVAL BJSON::GetKeyList(PGLOBAL g, PBPR bop) +PBVAL BJSON::GetKeyList(PBPR bop) { PBVAL bvp, lvp, fvp = NULL; for (PBPR brp = bop; brp; brp = MPP(brp->Next)) if (fvp) { - bvp = SubAllocVal(g, brp->Key, TYPE_STRG); + bvp = SubAllocVal(brp->Key, TYPE_STRG); lvp->Next = MOF(bvp); lvp = bvp; } else - lvp = fvp = SubAllocVal(g, brp->Key, TYPE_STRG); + lvp = fvp = SubAllocVal(brp->Key, TYPE_STRG); return fvp; } // end of GetKeyList @@ -892,17 +909,17 @@ PBVAL BJSON::GetKeyList(PGLOBAL g, PBPR bop) /***********************************************************************/ /* Return all object values as an array. */ /***********************************************************************/ -PBVAL BJSON::GetObjectValList(PGLOBAL g, PBPR bop) +PBVAL BJSON::GetObjectValList(PBPR bop) { PBVAL bvp, lvp, fvp = NULL; for (PBPR brp = bop; brp; brp = MPP(brp->Next)) if (fvp) { - bvp = DupVal(g, MVP(brp->Vlp)); + bvp = DupVal(MVP(brp->Vlp)); lvp->Next = MOF(bvp); lvp = bvp; } else - lvp = fvp = DupVal(g, MVP(brp->Vlp)); + lvp = fvp = DupVal(MVP(brp->Vlp)); return fvp; } // end of GetObjectValList @@ -981,7 +998,7 @@ PSZ BJSON::GetObjectText(PGLOBAL g, PBPR bop, PSTRG text) { /***********************************************************************/ /* Set or add a value corresponding to the given key. */ /***********************************************************************/ -PBPR BJSON::SetKeyValue(PGLOBAL g, PBPR bop, OFFSET bvp, PSZ key) +PBPR BJSON::SetKeyValue(PBPR bop, OFFSET bvp, PSZ key) { PBPR brp = bop, prp = NULL; @@ -994,10 +1011,10 @@ PBPR BJSON::SetKeyValue(PGLOBAL g, PBPR bop, OFFSET bvp, PSZ key) prp = brp; if (!brp) - prp->Vlp = MOF(SubAllocPair(g, key, bvp)); + prp->Vlp = MOF(SubAllocPair(key, bvp)); } else - bop = SubAllocPair(g, key, bvp); + bop = SubAllocPair(key, bvp); // Return the first pair of this object return bop; @@ -1006,11 +1023,11 @@ PBPR BJSON::SetKeyValue(PGLOBAL g, PBPR bop, OFFSET bvp, PSZ key) /***********************************************************************/ /* Merge two objects. */ /***********************************************************************/ -PBPR BJSON::MergeObject(PGLOBAL g, PBPR bop1, PBPR bop2) +PBPR BJSON::MergeObject(PBPR bop1, PBPR bop2) { if (bop1) for (PBPR brp = bop2; brp; brp = MPP(brp->Next)) - SetKeyValue(g, bop1, brp->Vlp, MZP(brp->Key)); + SetKeyValue(bop1, brp->Vlp, MZP(brp->Key)); else bop1 = bop2; @@ -1087,10 +1104,10 @@ PBVAL BJSON::GetArrayValue(PBVAL bap, int n) /***********************************************************************/ /* Add a Value to the Array Value list. */ /***********************************************************************/ -PBVAL BJSON::AddArrayValue(PGLOBAL g, PBVAL bap, PBVAL nvp, int* x) +PBVAL BJSON::AddArrayValue(PBVAL bap, PBVAL nvp, int* x) { if (!nvp) - nvp = SubAllocVal(g); + nvp = NewVal(); if (bap) { int i = 0, n = (x) ? *x : INT_MAX32; @@ -1112,11 +1129,11 @@ PBVAL BJSON::AddArrayValue(PGLOBAL g, PBVAL bap, PBVAL nvp, int* x) /***********************************************************************/ /* Merge two arrays. */ /***********************************************************************/ -PBVAL BJSON::MergeArray(PGLOBAL g, PBVAL bap1, PBVAL bap2) +PBVAL BJSON::MergeArray(PBVAL bap1, PBVAL bap2) { if (bap1) { for (PBVAL bvp = bap2; bvp; bvp = MVP(bvp->Next)) - AddArrayValue(g, bap1, bvp); + AddArrayValue(bap1, bvp); return bap1; } else @@ -1127,7 +1144,7 @@ PBVAL BJSON::MergeArray(PGLOBAL g, PBVAL bap1, PBVAL bap2) /***********************************************************************/ /* Set the nth Value of the Array Value list or add it. */ /***********************************************************************/ -PBVAL BJSON::SetArrayValue(PGLOBAL g, PBVAL bap, PBVAL nvp, int n) +PBVAL BJSON::SetArrayValue(PBVAL bap, PBVAL nvp, int n) { PBVAL bvp = bap, pvp = NULL; @@ -1144,7 +1161,7 @@ PBVAL BJSON::SetArrayValue(PGLOBAL g, PBVAL bap, PBVAL nvp, int n) } // endif bap if (!bvp) { - bvp = DupVal(g, nvp); + bvp = DupVal(nvp); if (pvp) pvp->Next = MOF(bvp); @@ -1233,47 +1250,56 @@ bool BJSON::IsArrayNull(PBVAL bap) /***********************************************************************/ /* Sub-allocate and clear a BVAL. */ /***********************************************************************/ -PBVAL BJSON::SubAllocVal(PGLOBAL g) +PBVAL BJSON::NewVal(int type) { - PBVAL bvp = (PBVAL)BsonSubAlloc(g, sizeof(BVAL)); + PBVAL bvp = (PBVAL)BsonSubAlloc(sizeof(BVAL)); bvp->To_Val = 0; bvp->Nd = 0; - bvp->Type = TYPE_NULL; + bvp->Type = type; bvp->Next = 0; return bvp; } // end of SubAllocVal /***********************************************************************/ +/* Sub-allocate and initialize a BVAL as type. */ +/***********************************************************************/ +PBVAL BJSON::SubAllocVal(OFFSET toval, int type, short nd) +{ + PBVAL bvp = NewVal(type); + + bvp->To_Val = toval; + bvp->Nd = nd; + return bvp; +} // end of SubAllocVal + +/***********************************************************************/ /* Sub-allocate and initialize a BVAL as string. */ /***********************************************************************/ -PBVAL BJSON::SubAllocVal(PGLOBAL g, OFFSET toval, int type, short nd) +PBVAL BJSON::SubAllocStr(OFFSET toval, short nd) { - PBVAL bvp = (PBVAL)BsonSubAlloc(g, sizeof(BVAL)); + PBVAL bvp = NewVal(TYPE_STRG); 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 BJSON::SubAllocVal(PVAL valp) { - PBVAL vlp = SubAllocVal(g); - SetValue(g, vlp, valp); - vlp->Next = NULL; + PBVAL vlp = NewVal(); + SetValue(vlp, valp); 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)); +PBVAL BJSON::DupVal(PBVAL bvlp) { + PBVAL bvp = NewVal(); *bvp = *bvlp; bvp->Next = 0; @@ -1539,7 +1565,7 @@ double BJSON::GetDouble(PBVAL vp) /***********************************************************************/ /* Return the Value's String value. */ /***********************************************************************/ -PSZ BJSON::GetString(PGLOBAL g, PBVAL vp, char* buff) +PSZ BJSON::GetString(PBVAL vp, char* buff) { char buf[32]; char* p = (buff) ? buff : buf; @@ -1572,7 +1598,7 @@ PSZ BJSON::GetString(PGLOBAL g, PBVAL vp, char* buff) p = NULL; } // endswitch Type - return (p == buf) ? (PSZ)PlugDup(g, buf) : p; + return (p == buf) ? (PSZ)PlugDup(G, buf) : p; } // end of GetString /***********************************************************************/ @@ -1585,7 +1611,7 @@ PSZ BJSON::GetValueText(PGLOBAL g, PBVAL vlp, PSTRG text) { return GetArrayText(g, MVP(vlp->To_Val), text); char buff[32]; - PSZ s = (vlp->Type == TYPE_NULL) ? NULL : GetString(g, vlp, buff); + PSZ s = (vlp->Type == TYPE_NULL) ? NULL : GetString(vlp, buff); if (s) text->Append(s); @@ -1614,7 +1640,7 @@ void BJSON::SetValueVal(PBVAL vlp, PBVAL vp) vlp->Type = vp->Type; } // end of SetValue; -void BJSON::SetValue(PGLOBAL g, PBVAL vlp, PVAL valp) +void BJSON::SetValue(PBVAL vlp, PVAL valp) { if (!valp || valp->IsNull()) { vlp->Type = TYPE_NULL; @@ -1625,7 +1651,7 @@ void BJSON::SetValue(PGLOBAL g, PBVAL vlp, PVAL valp) else { char buf[32]; - vlp->To_Val = MOF(PlugDup(g, valp->GetCharString(buf))); + vlp->To_Val = MOF(PlugDup(G, valp->GetCharString(buf))); } // endif Formatted vlp->Type = TYPE_DTM; @@ -1642,7 +1668,7 @@ void BJSON::SetValue(PGLOBAL g, PBVAL vlp, PVAL valp) vlp->F = (float)valp->GetFloatValue(); vlp->Type = TYPE_FLOAT; } else { - double *dp = (double*)PlugSubAlloc(g, NULL, sizeof(double)); + double *dp = (double*)PlugSubAlloc(G, NULL, sizeof(double)); *dp = valp->GetFloatValue(); vlp->To_Val = MOF(dp); @@ -1663,7 +1689,7 @@ void BJSON::SetValue(PGLOBAL g, PBVAL vlp, PVAL valp) vlp->N = valp->GetIntValue(); vlp->Type = TYPE_INTG; } else { - longlong* llp = (longlong*)PlugSubAlloc(g, NULL, sizeof(longlong)); + longlong* llp = (longlong*)PlugSubAlloc(G, NULL, sizeof(longlong)); *llp = valp->GetBigintValue(); vlp->To_Val = MOF(llp); @@ -1672,7 +1698,7 @@ void BJSON::SetValue(PGLOBAL g, PBVAL vlp, PVAL valp) break; default: - sprintf(g->Message, "Unsupported typ %d\n", valp->GetType()); + sprintf(G->Message, "Unsupported typ %d\n", valp->GetType()); throw(777); } // endswitch Type @@ -1699,13 +1725,13 @@ void BJSON::SetBool(PBVAL vlp, bool b) /***********************************************************************/ /* Set the Value's value as the given big integer. */ /***********************************************************************/ -void BJSON::SetBigint(PGLOBAL g, PBVAL vlp, longlong ll) +void BJSON::SetBigint(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)); + longlong* llp = (longlong*)PlugSubAlloc(G, NULL, sizeof(longlong)); *llp = ll; vlp->To_Val = MOF(llp); diff --git a/storage/connect/bson.h b/storage/connect/bson.h index 284bee1da48..077e71b1413 100644 --- a/storage/connect/bson.h +++ b/storage/connect/bson.h @@ -69,54 +69,64 @@ DllExport bool IsNum(PSZ s); class BJSON : public BLOCK { public: // Constructor - BJSON(void* base, PBVAL vp = NULL) { Base = base; Bvp = vp; } + BJSON(PGLOBAL g, PBVAL vp = NULL) { G = g, Base = G->Sarea; Bvp = vp; } void* GetBase(void) { return Base; } + void SubSet(bool b = false); + void MemSave(void) {G->Saved_Size = ((PPOOLHEADER)G->Sarea)->To_Free;} + void GetMsg(PGLOBAL g) { if (g != G) strcpy(g->Message, G->Message); } // SubAlloc functions - void* BsonSubAlloc(PGLOBAL g, size_t size); - PBPR SubAllocPair(PGLOBAL g, OFFSET key, OFFSET val = 0); - PBPR SubAllocPair(PGLOBAL g, PSZ key, OFFSET val = 0) - {return SubAllocPair(g, MOF(key), val);} - PBVAL SubAllocVal(PGLOBAL g); - PBVAL SubAllocVal(PGLOBAL g, OFFSET toval, int type = TYPE_NULL, short nd = 0); - PBVAL SubAllocVal(PGLOBAL g, PBVAL toval, int type = TYPE_NULL, short nd = 0) - {return SubAllocVal(g, MOF(toval), type, nd);} - PBVAL SubAllocVal(PGLOBAL g, PSZ str, int type = TYPE_STRG, short nd = 0) - {return SubAllocVal(g, MOF(str), type, nd);} - PBVAL SubAllocVal(PGLOBAL g, PVAL valp); - PBVAL DupVal(PGLOBAL g, PBVAL bvp); + void* BsonSubAlloc(size_t size); + PBPR SubAllocPair(OFFSET key, OFFSET val = 0); + PBPR SubAllocPair(PSZ key, OFFSET val = 0) + {return SubAllocPair(MOF(key), val);} + PBVAL NewVal(int type = TYPE_NULL); + PBVAL SubAllocVal(OFFSET toval, int type = TYPE_NULL, short nd = 0); + PBVAL SubAllocVal(PBVAL toval, int type = TYPE_NULL, short nd = 0) + {return SubAllocVal(MOF(toval), type, nd);} + PBVAL SubAllocStr(OFFSET str, short nd = 0); + PBVAL SubAllocStr(PSZ str, short nd = 0) + {return SubAllocStr(MOF(str), nd);} + PBVAL SubAllocVal(PVAL valp); + PBVAL DupVal(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 MergeArray(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); + PBVAL AddArrayValue(PBVAL bap, PBVAL nvp = NULL, int* x = NULL); + PBVAL SetArrayValue(PBVAL bap, PBVAL nvp, int n); bool IsArrayNull(PBVAL bap); // Object functions int GetObjectSize(PBPR bop, bool b = false); + PBPR GetNext(PBPR prp) {return MPP(prp->Next);} 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); + PBPR MergeObject(PBPR bop1, PBPR bop2); + PBPR AddPair(PBPR bop, PSZ key, OFFSET val = 0); + PSZ GetKey(PBPR prp) {return MZP(prp->Key);} + PBVAL GetVal(PBPR prp) {return MVP(prp->Vlp);} 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); + PBVAL GetKeyList(PBPR bop); + PBVAL GetObjectValList(PBPR bop); + PBPR SetKeyValue(PBPR bop, OFFSET bvp, PSZ key); + inline PBPR SetKeyValue(PBPR bop, PBVAL vlp, PSZ key) + {return SetKeyValue(bop, MOF(vlp), key);} PBPR DeleteKey(PBPR bop, PCSZ k); bool IsObjectNull(PBPR bop); // Value functions int GetSize(PBVAL vlp, bool b = false); + PBVAL GetNext(PBVAL vlp) {return MVP(vlp->Next);} 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); + inline PBVAL GetBson(PBVAL bvp) { return IsJson(bvp) ? MVP(bvp->To_Val) : bvp; } + PSZ GetString(PBVAL vp, char* buff = NULL); int GetInteger(PBVAL vp); long long GetBigint(PBVAL vp); double GetDouble(PBVAL vp); @@ -124,17 +134,20 @@ public: 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 SetValue(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 SetBigint(PBVAL vlp, longlong ll); void SetFloat(PBVAL vlp, double f); void SetBool(PBVAL vlp, bool b); + void Clear(PBVAL vlp) { vlp->N = 0; vlp->Nd = 0; vlp->Next = 0; vlp->Type = TYPE_NULL; } bool IsValueNull(PBVAL vlp); + bool IsJson(PBVAL vlp) {return (vlp->Type == TYPE_JAR || vlp->Type == TYPE_JOB);} // Members - PBVAL Bvp; - void* Base; + PGLOBAL G; + PBVAL Bvp; + void *Base; protected: // Default constructor not to be used @@ -146,18 +159,18 @@ protected: /***********************************************************************/ class BDOC : public BJSON { public: - BDOC(void *); + BDOC(PGLOBAL G); 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); protected: - OFFSET ParseArray(PGLOBAL g, int& i); - OFFSET ParseObject(PGLOBAL g, int& i); - PBVAL ParseValue(PGLOBAL g, int& i); - OFFSET ParseString(PGLOBAL g, int& i); - void ParseNumeric(PGLOBAL g, int& i, PBVAL bvp); - OFFSET ParseAsArray(PGLOBAL g, int& i, int pretty, int* ptyp); + OFFSET ParseArray(int& i); + OFFSET ParseObject(int& i); + PBVAL ParseValue(int& i); + OFFSET ParseString(int& i); + void ParseNumeric(int& i, PBVAL bvp); + OFFSET ParseAsArray(int& i, int pretty, int* ptyp); bool SerializeArray(OFFSET arp, bool b); bool SerializeObject(OFFSET obp); bool SerializeValue(PBVAL vp); @@ -166,7 +179,7 @@ protected: JOUT* jp; // Used with serialize char* s; // The Json string to parse int len; // The Json string length - bool pty[3]; // Used to guess what pretty is + bool pty[3]; // Used to guess what pretty is // Default constructor not to be used BDOC(void) {} diff --git a/storage/connect/bsonudf.cpp b/storage/connect/bsonudf.cpp index 95cc8aa7da8..36bec919ffd 100644 --- a/storage/connect/bsonudf.cpp +++ b/storage/connect/bsonudf.cpp @@ -41,7 +41,7 @@ inline void JsonMemSave(PGLOBAL g) { /*********************************************************************************/ inline void JsonFreeMem(PGLOBAL g) { g->Activityp = NULL; - PlugExit(g); + g = PlugExit(g); } /* end of JsonFreeMem */ /* --------------------------- New Testing BJSON Stuff --------------------------*/ @@ -71,8 +71,7 @@ static PBJNX BjnxNew(PGLOBAL g, PBVAL vlp, int type, int len) /*********************************************************************************/ /* BSNX public constructor. */ /*********************************************************************************/ -BJNX::BJNX(PGLOBAL g, PBVAL row, int type, int len, int prec, my_bool wr) - : BDOC(g->Sarea) +BJNX::BJNX(PGLOBAL g, PBVAL row, int type, int len, int prec, my_bool wr) : BDOC(g) { Row = row; Bvalp = NULL; @@ -361,7 +360,7 @@ void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp) } else switch (vlp->Type) { case TYPE_DTM: case TYPE_STRG: - vp->SetValue_psz(GetString(g, vlp)); + vp->SetValue_psz(GetString(vlp)); break; case TYPE_INTG: case TYPE_BINT: @@ -371,14 +370,14 @@ void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp) if (vp->IsTypeNum()) vp->SetValue(GetDouble(vlp)); else // Get the proper number of decimals - vp->SetValue_psz(GetString(g, vlp)); + vp->SetValue_psz(GetString(vlp)); break; case TYPE_BOOL: if (vp->IsTypeNum()) vp->SetValue(GetInteger(vlp) ? 1 : 0); else - vp->SetValue_psz(GetString(g, vlp)); + vp->SetValue_psz(GetString(vlp)); break; case TYPE_JAR: @@ -439,7 +438,7 @@ PBVAL BJNX::GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b) 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); + vlp = SubAllocVal(Value); return vlp; } else if (Nodes[i].Op == OP_XX) { Jb = b; @@ -473,7 +472,7 @@ PBVAL BJNX::GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b) else if (Nodes[i].Op == OP_EXP) return (PBVAL)ExpandArray(g, bap, i); else - return SubAllocVal(g, CalculateArray(g, bap, i)); + return SubAllocVal(CalculateArray(g, bap, i)); } else { // Unexpected array, unwrap it as [0] @@ -701,12 +700,12 @@ PBVAL BJNX::GetRow(PGLOBAL g) // nwr = SubAllocPair(g); // Construct new row - nwr = SubAllocVal(g); + nwr = NewVal(); if (row->Type == TYPE_JOB) { - SetKeyValue(g, MPP(row->To_Val), MOF(nwr), Nodes[i - 1].Key); + SetKeyValue(MPP(row->To_Val), MOF(nwr), Nodes[i - 1].Key); } else if (row->Type == TYPE_JAR) { - AddArrayValue(g, MVP(row->To_Val), nwr); + AddArrayValue(MVP(row->To_Val), nwr); } else { strcpy(g->Message, "Wrong type when writing new row"); nwr = NULL; @@ -748,15 +747,15 @@ my_bool BJNX::WriteValue(PGLOBAL g, PBVAL jvalp) if (arp) { if (!Nodes[Nod - 1].Key) { if (Nodes[Nod - 1].Op == OP_EQ) - SetArrayValue(g, arp, jvalp, Nodes[Nod - 1].Rank); + SetArrayValue(arp, jvalp, Nodes[Nod - 1].Rank); else - AddArrayValue(g, arp, jvalp); + AddArrayValue(arp, jvalp); } // endif Key } else if (objp) { if (Nodes[Nod - 1].Key) - SetKeyValue(g, objp, MOF(jvalp), Nodes[Nod - 1].Key); + SetKeyValue(objp, MOF(jvalp), Nodes[Nod - 1].Key); } else if (jvp) SetValueVal(jvp, jvalp); @@ -1159,8 +1158,8 @@ static PBVAL MakeBinValue(PGLOBAL g, UDF_ARGS* args, uint i) int n, len; int ci; longlong bigint; - BDOC doc(g->Sarea); - PBVAL bp, bvp = doc.SubAllocVal(g); + BDOC doc(g); + PBVAL bp, bvp = doc.NewVal(); if (sap) { if (args->arg_type[i] == STRING_RESULT) { @@ -1209,7 +1208,7 @@ static PBVAL MakeBinValue(PGLOBAL g, UDF_ARGS* args, uint i) (bigint == 1LL && !strcmp(args->attributes[i], "TRUE"))) doc.SetBool(bvp, (bool)bigint); else - doc.SetBigint(g, bvp, bigint); + doc.SetBigint(bvp, bigint); break; case REAL_RESULT: @@ -1256,7 +1255,7 @@ char* bsonvalue(UDF_INIT* initid, UDF_ARGS* args, char* result, if (!g->Xchk) { if (!CheckMemory(g, initid, args, 1, false)) { - BDOC doc(g->Sarea); + BDOC doc(g); PBVAL bvp = MakeBinValue(g, args, 0); if (!(str = doc.Serialize(g, bvp, NULL, 0))) @@ -1297,13 +1296,13 @@ char* bson_make_array(UDF_INIT* initid, UDF_ARGS* args, char* result, if (!g->Xchk) { if (!CheckMemory(g, initid, args, args->arg_count, false)) { - BDOC doc(g->Sarea); + BDOC doc(g); PBVAL bvp = NULL, arp = NULL; for (uint i = 0; i < args->arg_count; i++) - bvp = doc.AddArrayValue(g, bvp, MakeBinValue(g, args, i)); + bvp = doc.AddArrayValue(bvp, MakeBinValue(g, args, i)); - arp = doc.SubAllocVal(g, bvp, TYPE_JAR); + arp = doc.SubAllocVal(bvp, TYPE_JAR); if (!(str = doc.Serialize(g, arp, NULL, 0))) str = strcpy(result, g->Message); @@ -1364,7 +1363,7 @@ char* bson_array_add_values(UDF_INIT* initid, UDF_ARGS* args, char* result, if (!CheckMemory(g, initid, args, args->arg_count, true)) { uint n = 1; bool b = false; - BDOC doc(g->Sarea); + BDOC doc(g); PBVAL bvp = NULL, arp = MakeBinValue(g, args, 0); if (arp->Type == TYPE_JAR) { @@ -1374,10 +1373,10 @@ char* bson_array_add_values(UDF_INIT* initid, UDF_ARGS* args, char* result, n = 0; for (uint i = n; i < args->arg_count; i++) - bvp = doc.AddArrayValue(g, bvp, MakeBinValue(g, args, i)); + bvp = doc.AddArrayValue(bvp, MakeBinValue(g, args, i)); if (!n) - arp = doc.SubAllocVal(g, bvp, TYPE_JAR); + arp = doc.SubAllocVal(bvp, TYPE_JAR); else if (b) doc.SetValueArr(arp, bvp); diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index 2a0f2ed037f..250ff7fa62f 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -73,8 +73,7 @@ PGLOBAL CntExit(PGLOBAL g) g->Activityp = NULL; } // endif Activityp - PlugExit(g); - g= NULL; + g= PlugExit(g); } // endif g return g; diff --git a/storage/connect/global.h b/storage/connect/global.h index 294ad0e1d7b..f09d5250124 100644 --- a/storage/connect/global.h +++ b/storage/connect/global.h @@ -208,7 +208,7 @@ DllExport char *PlugGetMessage(PGLOBAL, int); DllExport short GetLineLength(PGLOBAL); // Console line length #endif // __WIN__ DllExport PGLOBAL PlugInit(LPCSTR, size_t); // Plug global initialization -DllExport int PlugExit(PGLOBAL); // Plug global termination +DllExport PGLOBAL PlugExit(PGLOBAL); // Plug global termination DllExport LPSTR PlugRemoveType(LPSTR, LPCSTR); DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR prefix, LPCSTR name, LPCSTR dir); DllExport BOOL PlugIsAbsolutePath(LPCSTR path); diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index e9b9e5c24aa..4e7dd3ff394 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -170,7 +170,7 @@ #define JSONMAX 10 // JSON Default max grp size extern "C" { - char version[]= "Version 1.07.0002 November 13, 2020"; + char version[]= "Version 1.07.0002 November 30, 2020"; #if defined(__WIN__) char compver[]= "Version 1.07.0002 " __DATE__ " " __TIME__; char slash= '\\'; @@ -230,6 +230,9 @@ char *GetUserVariable(PGLOBAL g, const uchar *varname) PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); PQRYRES VirColumns(PGLOBAL g, bool info); PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info); +#ifdef DEVELOPMENT +PQRYRES BSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info); +#endif // DEVEOPMENT PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info); #if defined(REST_SUPPORT) PQRYRES RESTColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); @@ -4513,7 +4516,10 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn, bool quick) case TAB_VEC: case TAB_REST: case TAB_JSON: - if (options->filename && *options->filename) { +#if defined DEVELOPMENT + case TAB_BSON: +#endif // DEVELOPMENT + if (options->filename && *options->filename) { if (!quick) { char path[FN_REFLEN], dbpath[FN_REFLEN]; @@ -5679,7 +5685,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd, } else if (topt->http) { switch (ttp) { case TAB_JSON: - case TAB_XML: +#ifdef DEVELOPMENT + case TAB_BSON: +#endif // DEVELOPMENT + case TAB_XML: case TAB_CSV: ttp = TAB_REST; break; @@ -5863,6 +5872,9 @@ static int connect_assisted_discovery(handlerton *, THD* thd, case TAB_XML: #endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT case TAB_JSON: +#ifdef DEVELOPMENT + case TAB_BSON: +#endif // DEVELOPMENT dsn= strz(g, create_info->connect_string); if (!fn && !zfn && !mul && !dsn) @@ -6029,6 +6041,11 @@ static int connect_assisted_discovery(handlerton *, THD* thd, case TAB_JSON: qrp= JSONColumns(g, db, dsn, topt, fnc == FNC_COL); break; +#ifdef DEVELOPMENT + case TAB_BSON: + qrp= BSONColumns(g, db, dsn, topt, fnc == FNC_COL); + break; +#endif // DEVELOPMENT #if defined(JAVA_SUPPORT) case TAB_MONGO: url= strz(g, create_info->connect_string); diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp index d993947589f..773828a96dd 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -1178,7 +1178,7 @@ my_bool JsonSubSet(PGLOBAL g) { PPOOLHEADER pph = (PPOOLHEADER)g->Sarea; - pph->To_Free = (g->Saved_Size) ? g->Saved_Size : (size_t)sizeof(POOLHEADER); + pph->To_Free = (g->Saved_Size) ? g->Saved_Size : sizeof(POOLHEADER); pph->FreeBlk = g->Sarea_Size - pph->To_Free; g->Saved_Size = 0; return FALSE; @@ -1198,7 +1198,7 @@ inline void JsonMemSave(PGLOBAL g) inline void JsonFreeMem(PGLOBAL g) { g->Activityp = NULL; - PlugExit(g); + g = PlugExit(g); } /* end of JsonFreeMem */ /*********************************************************************************/ @@ -1281,7 +1281,7 @@ my_bool JsonInit(UDF_INIT *initid, UDF_ARGS *args, char *message, my_bool mbn, return true; } else if (g->Sarea_Size == 0) { strcpy(message, g->Message); - PlugExit(g); + g = PlugExit(g); return true; } // endif g diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc index f8b3dc03aa5..395e1192b45 100644 --- a/storage/connect/mycat.cc +++ b/storage/connect/mycat.cc @@ -16,9 +16,9 @@ /*************** Mycat CC Program Source Code File (.CC) ***************/ /* PROGRAM NAME: MYCAT */ /* ------------- */ -/* Version 1.7 */ +/* Version 1.8 */ /* */ -/* Author: Olivier Bertrand 2012 - 2019 */ +/* Author: Olivier Bertrand 2012 - 2020 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -82,7 +82,11 @@ #endif // JAVA_SUPPORT #include "tabpivot.h" #include "tabvir.h" +#if defined(DEVELOPMENT) +#include "tabbson.h" +#else #include "tabjson.h" +#endif // DEVELOPMENT #include "ha_connect.h" #if defined(XML_SUPPORT) #include "tabxml.h" @@ -157,6 +161,9 @@ TABTYPE GetTypeID(const char *type) : (!stricmp(type, "PIVOT")) ? TAB_PIVOT : (!stricmp(type, "VIR")) ? TAB_VIR : (!stricmp(type, "JSON")) ? TAB_JSON +#if defined(DEVELOPMENT) + : (!stricmp(type, "BSON")) ? TAB_BSON +#endif #if defined(ZIP_SUPPORT) : (!stricmp(type, "ZIP")) ? TAB_ZIP #endif @@ -181,6 +188,9 @@ bool IsFileType(TABTYPE type) case TAB_INI: case TAB_VEC: case TAB_JSON: +#if defined(DEVELOPMENT) + case TAB_BSON: +#endif case TAB_REST: // case TAB_ZIP: isfile= true; @@ -276,6 +286,9 @@ bool IsTypeIndexable(TABTYPE type) case TAB_VEC: case TAB_DBF: case TAB_JSON: +#if defined(DEVELOPMENT) + case TAB_BSON: +#endif idx= true; break; default: @@ -302,6 +315,9 @@ int GetIndexType(TABTYPE type) case TAB_VEC: case TAB_DBF: case TAB_JSON: +#if defined(DEVELOPMENT) + case TAB_BSON: +#endif xtyp= 1; break; case TAB_MYSQL: @@ -445,7 +461,7 @@ PTABDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) case TAB_XML: tdp= new(g) XMLDEF; break; #endif // XML_SUPPORT #if defined(VCT_SUPPORT) - case TAB_VEC: tdp = new(g) VCTDEF; break; + case TAB_VEC: tdp= new(g) VCTDEF; break; #endif // VCT_SUPPORT #if defined(ODBC_SUPPORT) case TAB_ODBC: tdp= new(g) ODBCDEF; break; @@ -466,8 +482,11 @@ PTABDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) case TAB_PIVOT: tdp= new(g) PIVOTDEF; break; case TAB_VIR: tdp= new(g) VIRDEF; break; case TAB_JSON: tdp= new(g) JSONDEF; break; +#if defined(DEVELOPMENT) + case TAB_BSON: tdp= new(g) BSONDEF; break; +#endif #if defined(ZIP_SUPPORT) - case TAB_ZIP: tdp = new(g) ZIPDEF; break; + case TAB_ZIP: tdp= new(g) ZIPDEF; break; #endif // ZIP_SUPPORT #if defined(REST_SUPPORT) case TAB_REST: tdp= new (g) RESTDEF; break; diff --git a/storage/connect/mysql-test/connect/r/xml.result b/storage/connect/mysql-test/connect/r/xml.result index 99739b1ec10..599c35cb1ed 100644 --- a/storage/connect/mysql-test/connect/r/xml.result +++ b/storage/connect/mysql-test/connect/r/xml.result @@ -323,7 +323,7 @@ HEX(c) 3F3F3F3F3F3F3F Warnings: Level Warning Code 1366 -Message Incorrect string value: '\xC3\x81\xC3\x82\xC3\x83...' for column 'c' at row 1 +Message Incorrect string value: '\xC3\x81\xC3\x82\xC3\x83...' for column `test`.`t1`.`c` at row 1 Level Warning Code 1105 Message Out of range value ÃÂÃÄÅÆÇ for column 'c' at row 1 @@ -374,7 +374,7 @@ INSERT INTO t1 VALUES (_cp1251 0xC0C1C2C3); Warnings: Level Warning Code 1105 -Message Com error: Unable to save character to 'iso-8859-1' encoding.
+Message Com error: Impossible d'enregistrer le caractère dans le codage iso-8859-1.
INSERT INTO t1 VALUES ('&<>"\''); SELECT node, hex(node) FROM t1; diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index 1d644cb75c2..dd204d065ed 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -83,7 +83,8 @@ enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */ TAB_ZIP = 27, /* ZIP file info table */ TAB_MONGO = 28, /* Table retrieved from MongoDB */ TAB_REST = 29, /* Table retrieved from Rest */ - TAB_NIY = 30}; /* Table not implemented yet */ + TAB_BSON = 30, /* BSON Table (development) */ + TAB_NIY = 31}; /* Table not implemented yet */ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ TYPE_AM_ROWID = 1, /* ROWID type (special column) */ diff --git a/storage/connect/plugutil.cpp b/storage/connect/plugutil.cpp index 0ab594f5533..479310703eb 100644 --- a/storage/connect/plugutil.cpp +++ b/storage/connect/plugutil.cpp @@ -184,7 +184,7 @@ PGLOBAL PlugInit(LPCSTR Language, size_t worksize) /***********************************************************************/ /* PlugExit: Terminate Plug operations. */ /***********************************************************************/ -int PlugExit(PGLOBAL g) +PGLOBAL PlugExit(PGLOBAL g) { if (g) { PDBUSER dup = PlgGetUser(g); @@ -196,7 +196,7 @@ int PlugExit(PGLOBAL g) delete g; } // endif g - return 0; + return NULL; } // end of PlugExit /***********************************************************************/ @@ -483,9 +483,10 @@ bool AllocSarea(PGLOBAL g, size_t size) #else if (trace(8)) { #endif - if (g->Sarea) + if (g->Sarea) { htrc("Work area of %zd allocated at %p\n", size, g->Sarea); - else + PlugSubSet(g->Sarea, size); + } else htrc("SareaAlloc: %s\n", g->Message); } // endif trace diff --git a/storage/connect/tabbson.cpp b/storage/connect/tabbson.cpp new file mode 100644 index 00000000000..aa2f5957911 --- /dev/null +++ b/storage/connect/tabbson.cpp @@ -0,0 +1,2599 @@ +/************* tabbson C++ Program Source Code File (.CPP) *************/ +/* PROGRAM NAME: tabjson Version 1.0 */ +/* (C) Copyright to the author Olivier BERTRAND 2020 */ +/* This program are the BSON class DB execution routines. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant sections of the MariaDB header file. */ +/***********************************************************************/ +#include <my_global.h> + +/***********************************************************************/ +/* Include application header files: */ +/* global.h is header containing all global declarations. */ +/* plgdbsem.h is header containing the DB application declarations. */ +/* tdbdos.h is header containing the TDBDOS declarations. */ +/* json.h is header containing the JSON classes declarations. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "maputil.h" +#include "filamtxt.h" +#include "tabdos.h" +#include "tabbson.h" +#include "filamap.h" +#if defined(GZ_SUPPORT) +#include "filamgz.h" +#endif // GZ_SUPPORT +#if defined(ZIP_SUPPORT) +#include "filamzip.h" +#endif // ZIP_SUPPORT +#if 0 +#if defined(JAVA_SUPPORT) +#include "jmgfam.h" +#endif // JAVA_SUPPORT +#if defined(CMGO_SUPPORT) +#include "cmgfam.h" +#endif // CMGO_SUPPORT +#endif // 0 +#include "tabmul.h" +#include "checklvl.h" +#include "resource.h" +#include "mycat.h" // for FNC_COL + +/***********************************************************************/ +/* This should be an option. */ +/***********************************************************************/ +#define MAXCOL 200 /* Default max column nb in result */ +//#define TYPE_UNKNOWN 12 /* Must be greater than other types */ + +/***********************************************************************/ +/* External functions. */ +/***********************************************************************/ +USETEMP UseTemp(void); +bool JsonAllPath(void); +int GetDefaultDepth(void); +char *GetJsonNull(void); + +/***********************************************************************/ +/* BSONColumns: construct the result blocks containing the description */ +/* of all the columns of a table contained inside a JSON file. */ +/***********************************************************************/ +PQRYRES BSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) +{ + static int buftyp[] = { TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, + TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING }; + static XFLD fldtyp[] = { FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, + FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT }; + static unsigned int length[] = { 0, 6, 8, 10, 10, 6, 6, 0 }; + int i, n = 0; + int ncol = sizeof(buftyp) / sizeof(int); + PJCL jcp; + BSONDISC* pjdc = NULL; + PQRYRES qrp; + PCOLRES crp; + + if (info) { + length[0] = 128; + length[7] = 256; + goto skipit; + } // endif info + + if (GetIntegerTableOption(g, topt, "Multiple", 0)) { + strcpy(g->Message, "Cannot find column definition for multiple table"); + return NULL; + } // endif Multiple + + pjdc = new(g) BSONDISC(g, length); + + if (!(n = pjdc->GetColumns(g, db, dsn, topt))) + return NULL; + +skipit: + if (trace(1)) + htrc("BSONColumns: n=%d len=%d\n", n, length[0]); + + /*********************************************************************/ + /* Allocate the structures used to refer to the result set. */ + /*********************************************************************/ + qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, + buftyp, fldtyp, length, false, false); + + crp = qrp->Colresp->Next->Next->Next->Next->Next->Next; + crp->Name = PlugDup(g, "Nullable"); + crp->Next->Name = PlugDup(g, "Jpath"); + + if (info || !qrp) + return qrp; + + qrp->Nblin = n; + + /*********************************************************************/ + /* Now get the results into blocks. */ + /*********************************************************************/ + for (i = 0, jcp = pjdc->fjcp; jcp; i++, jcp = jcp->Next) { + if (jcp->Type == TYPE_UNKNOWN) + jcp->Type = TYPE_STRG; // Void column + + crp = qrp->Colresp; // Column Name + crp->Kdata->SetValue(jcp->Name, i); + crp = crp->Next; // Data Type + crp->Kdata->SetValue(jcp->Type, i); + crp = crp->Next; // Type Name + crp->Kdata->SetValue(GetTypeName(jcp->Type), i); + crp = crp->Next; // Precision + crp->Kdata->SetValue(jcp->Len, i); + crp = crp->Next; // Length + crp->Kdata->SetValue(jcp->Len, i); + crp = crp->Next; // Scale (precision) + crp->Kdata->SetValue(jcp->Scale, i); + crp = crp->Next; // Nullable + crp->Kdata->SetValue(jcp->Cbn ? 1 : 0, i); + crp = crp->Next; // Field format + + if (crp->Kdata) + crp->Kdata->SetValue(jcp->Fmt, i); + + } // endfor i + +/*********************************************************************/ +/* Return the result pointer. */ +/*********************************************************************/ + return qrp; +} // end of BSONColumns + +/* -------------------------- Class BSONDISC ------------------------- */ + +/***********************************************************************/ +/* Class used to get the columns of a JSON table. */ +/***********************************************************************/ +BSONDISC::BSONDISC(PGLOBAL g, uint* lg) +{ + length = lg; + jcp = fjcp = pjcp = NULL; + tdp = NULL; + tjnp = NULL; + jpp = NULL; + tjsp = NULL; + jsp = NULL; + bp = NULL; + row = NULL; + sep = NULL; + i = n = bf = ncol = lvl = sz = limit = 0; + all = strfy = false; +} // end of BSONDISC constructor + +int BSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) +{ + char filename[_MAX_PATH]; + bool mgo = (GetTypeID(topt->type) == TAB_MONGO); + PBVAL bdp = NULL; + + lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth()); + lvl = GetIntegerTableOption(g, topt, "Depth", lvl); + sep = GetStringTableOption(g, topt, "Separator", "."); + sz = GetIntegerTableOption(g, topt, "Jsize", 1024); + limit = GetIntegerTableOption(g, topt, "Limit", 10); + strfy = GetBooleanTableOption(g, topt, "Stringify", false); + + /*********************************************************************/ + /* Open the input file. */ + /*********************************************************************/ + tdp = new(g) BSONDEF; + tdp->G = NULL; +#if defined(ZIP_SUPPORT) + tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL); + tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false); +#endif // ZIP_SUPPORT + tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL); + + if (!(tdp->Database = SetPath(g, db))) + return 0; + + tdp->Objname = GetStringTableOption(g, topt, "Object", NULL); + tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0; + tdp->Pretty = GetIntegerTableOption(g, topt, "Pretty", 2); + tdp->Xcol = GetStringTableOption(g, topt, "Expand", NULL); + tdp->Accept = GetBooleanTableOption(g, topt, "Accept", false); + tdp->Uri = (dsn && *dsn ? dsn : NULL); + + if (!tdp->Fn && !tdp->Uri) { + strcpy(g->Message, MSG(MISSING_FNAME)); + return 0; + } // endif Fn + + if (tdp->Fn) { + // We used the file name relative to recorded datapath + PlugSetPath(filename, tdp->Fn, tdp->GetPath()); + tdp->Fn = PlugDup(g, filename); + } // endif Fn + + if (trace(1)) + htrc("File %s objname=%s pretty=%d lvl=%d\n", + tdp->Fn, tdp->Objname, tdp->Pretty, lvl); + + if (tdp->Uri) { +#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) + tdp->Collname = GetStringTableOption(g, topt, "Name", NULL); + tdp->Collname = GetStringTableOption(g, topt, "Tabname", tdp->Collname); + tdp->Schema = GetStringTableOption(g, topt, "Dbname", "test"); + tdp->Options = (PSZ)GetStringTableOption(g, topt, "Colist", "all"); + tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false); + tdp->Driver = (PSZ)GetStringTableOption(g, topt, "Driver", NULL); + tdp->Version = GetIntegerTableOption(g, topt, "Version", 3); + tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper", + (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface"); + tdp->Pretty = 0; +#else // !MONGO_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); + return 0; +#endif // !MONGO_SUPPORT + } // endif Uri + + if (tdp->Pretty == 2) { + tdp->G = g; + + if (tdp->Zipped) { +#if defined(ZIP_SUPPORT) + tjsp = new(g) TDBBSON(g, tdp, new(g) UNZFAM(tdp)); +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return 0; +#endif // !ZIP_SUPPORT + } else + tjsp = new(g) TDBBSON(g, tdp, new(g) MAPFAM(tdp)); + + if (tjsp->MakeDocument(g)) + return 0; + + bp = tjsp->Bp; + bdp = tjsp->GetDoc() ? bp->GetBson(tjsp->GetDoc()) : NULL; + jsp = bdp ? bp->GetArrayValue(bdp, 0) : NULL; + } else { + if (!((tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0)))) { + if (!mgo) { + sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty); + return 0; + } else + tdp->Lrecl = 8192; // Should be enough + + } // endif Lrecl + + // Allocate the parse work memory + tdp->G = PlugInit(NULL, (size_t)tdp->Lrecl * (tdp->Pretty >= 0 ? 6 : 2)); + tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF); + + if (tdp->Zipped) { +#if defined(ZIP_SUPPORT) + tjnp = new(g)TDBBSN(tdp->G, tdp, new(g) UNZFAM(tdp)); +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; +#endif // !ZIP_SUPPORT +#if 0 + } else if (tdp->Uri) { + if (tdp->Driver && toupper(*tdp->Driver) == 'C') { +#if defined(CMGO_SUPPORT) + tjnp = new(g) TDBBSN(G, tdp, new(g) CMGFAM(tdp)); +#else + sprintf(g->Message, "Mongo %s Driver not available", "C"); + return 0; +#endif + } else if (tdp->Driver && toupper(*tdp->Driver) == 'J') { +#if defined(JAVA_SUPPORT) + tjnp = new(g) TDBBSN(G, tdp, new(g) JMGFAM(tdp)); +#else + sprintf(g->Message, "Mongo %s Driver not available", "Java"); + return 0; +#endif + } else { // Driver not specified +#if defined(CMGO_SUPPORT) + tjnp = new(g) TDBBSN(G, tdp, new(g) CMGFAM(tdp)); +#elif defined(JAVA_SUPPORT) + tjnp = new(g) TDBBSN(G, tdp, new(g) JMGFAM(tdp)); +#else + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); + return 0; +#endif + } // endif Driver +#endif // 0 + + } else if (tdp->Pretty >= 0) + tjnp = new(g) TDBBSN(g, tdp, new(g) DOSFAM(tdp)); + else + tjnp = new(g) TDBBSN(g, tdp, new(g) BINFAM(tdp)); + + tjnp->SetMode(MODE_READ); + bp = tjnp->Bp; + + if (tjnp->OpenDB(g)) + return 0; + + switch (tjnp->ReadDB(g)) { + case RC_EF: + strcpy(g->Message, "Void json table"); + case RC_FX: + goto err; + default: + jsp = bp->FindRow(g); + } // endswitch ReadDB + + } // endif pretty + + if (!(row = (jsp) ? bp->GetObject(jsp) : NULL)) { + strcpy(g->Message, "Can only retrieve columns from object rows"); + goto err; + } // endif row + + all = GetBooleanTableOption(g, topt, "Fullarray", false); + jcol.Name = jcol.Fmt = NULL; + jcol.Next = NULL; + jcol.Found = true; + colname[0] = 0; + + if (!tdp->Uri) { + fmt[0] = '$'; + fmt[1] = '.'; + bf = 2; + } // endif Uri + + /*********************************************************************/ + /* Analyse the JSON tree and define columns. */ + /*********************************************************************/ + for (i = 1; ; i++) { + for (jpp = row; jpp; jpp = bp->GetNext(jpp)) { + strncpy(colname, bp->GetKey(jpp), 64); + fmt[bf] = 0; + + if (Find(g, bp->GetVal(jpp), colname, MY_MIN(lvl, 0))) + goto err; + + } // endfor jpp + + // Missing column can be null + for (jcp = fjcp; jcp; jcp = jcp->Next) { + jcp->Cbn |= !jcp->Found; + jcp->Found = false; + } // endfor jcp + + if (tdp->Pretty != 2) { + // Read next record + switch (tjnp->ReadDB(g)) { + case RC_EF: + jsp = NULL; + break; + case RC_FX: + goto err; + default: + jsp = bp->FindRow(g); + } // endswitch ReadDB + + } else + jsp = bp->GetArrayValue(bdp, i); + + if (!(row = (jsp) ? bp->GetObject(jsp) : NULL)) + break; + + } // endfor i + + if (tdp->Pretty != 2) + tjnp->CloseDB(g); + + return n; + +err: + if (tdp->Pretty != 2) + tjnp->CloseDB(g); + + return 0; +} // end of GetColumns + +bool BSONDISC::Find(PGLOBAL g, PBVAL jvp, PCSZ key, int j) +{ + char *p, *pc = colname + strlen(colname), buf[32]; + int ars; + size_t n; + PBPR job; + PBVAL jar; + + if (jvp && !bp->IsJson(jvp)) { + if (JsonAllPath() && !fmt[bf]) + strcat(fmt, colname); + + jcol.Type = (JTYP)jvp->Type; + + switch (jvp->Type) { + case TYPE_STRG: + case TYPE_DTM: + jcol.Len = (int)strlen(bp->GetString(jvp)); + break; + case TYPE_INTG: + case TYPE_BINT: + case TYPE_DBL: + jcol.Len = (int)strlen(bp->GetString(jvp, buf)); + break; + case TYPE_BOOL: + jcol.Len = 1; + break; + default: + jcol.Len = 0; + break; + } // endswitch Type + + jcol.Scale = jvp->Nd; + jcol.Cbn = jvp->Type == TYPE_NULL; + } else if (!jvp || bp->IsValueNull(jvp)) { + jcol.Type = TYPE_UNKNOWN; + jcol.Len = jcol.Scale = 0; + jcol.Cbn = true; + } else if (j < lvl) { + if (!fmt[bf]) + strcat(fmt, colname); + + p = fmt + strlen(fmt); + jsp = jvp; + + switch (jsp->Type) { + case TYPE_JOB: + job = bp->GetObject(jsp); + + for (PBPR jrp = job; jrp; jrp = bp->GetNext(jrp)) { + PCSZ k = bp->GetKey(jrp); + + if (*k != '$') { + n = sizeof(fmt) - strlen(fmt) - 1; + strncat(strncat(fmt, sep, n), k, n - strlen(sep)); + n = sizeof(colname) - strlen(colname) - 1; + strncat(strncat(colname, "_", n), k, n - 1); + } // endif Key + + if (Find(g, bp->GetVal(jrp), k, j + 1)) + return true; + + *p = *pc = 0; + } // endfor jrp + + return false; + case TYPE_JAR: + jar = bp->GetArray(jsp); + + if (all || (tdp->Xcol && !stricmp(tdp->Xcol, key))) + ars = MY_MIN(bp->GetArraySize(jar), limit); + else + ars = MY_MIN(bp->GetArraySize(jar), 1); + + for (int k = 0; k < ars; k++) { + n = sizeof(fmt) - (strlen(fmt) + 1); + + if (!tdp->Xcol || stricmp(tdp->Xcol, key)) { + sprintf(buf, "%d", k); + + if (tdp->Uri) { + strncat(strncat(fmt, sep, n), buf, n - strlen(sep)); + } else { + strncat(strncat(fmt, "[", n), buf, n - 1); + strncat(fmt, "]", n - (strlen(buf) + 1)); + } // endif uri + + if (all) { + n = sizeof(colname) - (strlen(colname) + 1); + strncat(strncat(colname, "_", n), buf, n - 1); + } // endif all + + } else { + strncat(fmt, (tdp->Uri ? sep : "[*]"), n); + } + + if (Find(g, bp->GetArrayValue(jar, k), "", j)) + return true; + + *p = *pc = 0; + } // endfor k + + return false; + default: + sprintf(g->Message, "Logical error after %s", fmt); + return true; + } // endswitch Type + + } else if (lvl >= 0) { + if (strfy) { + if (!fmt[bf]) + strcat(fmt, colname); + + strcat(fmt, ".*"); + } else if (JsonAllPath() && !fmt[bf]) + strcat(fmt, colname); + + jcol.Type = TYPE_STRG; + jcol.Len = sz; + jcol.Scale = 0; + jcol.Cbn = true; + } else + return false; + + AddColumn(g); + return false; +} // end of Find + +void BSONDISC::AddColumn(PGLOBAL g) { + bool b = fmt[bf] != 0; // True if formatted + + // Check whether this column was already found + for (jcp = fjcp; jcp; jcp = jcp->Next) + if (!strcmp(colname, jcp->Name)) + break; + + if (jcp) { + if (jcp->Type != jcol.Type) { + if (jcp->Type == TYPE_UNKNOWN || jcp->Type == TYPE_NULL) + jcp->Type = jcol.Type; + // else if (jcol.Type != TYPE_UNKNOWN && jcol.Type != TYPE_VOID) + // jcp->Type = TYPE_STRING; + else if (jcp->Type != TYPE_STRG) + switch (jcol.Type) { + case TYPE_STRG: + case TYPE_DBL: + jcp->Type = jcol.Type; + break; + case TYPE_BINT: + if (jcp->Type == TYPE_INTG || jcp->Type == TYPE_BOOL) + jcp->Type = jcol.Type; + + break; + case TYPE_INTG: + if (jcp->Type == TYPE_BOOL) + jcp->Type = jcol.Type; + + break; + default: + break; + } // endswith Type + + } // endif Type + + if (b && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) { + jcp->Fmt = PlugDup(g, fmt); + length[7] = MY_MAX(length[7], strlen(fmt)); + } // endif fmt + + jcp->Len = MY_MAX(jcp->Len, jcol.Len); + jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale); + jcp->Cbn |= jcol.Cbn; + jcp->Found = true; + } else if (jcol.Type != TYPE_UNKNOWN || tdp->Accept) { + // New column + jcp = (PJCL)PlugSubAlloc(g, NULL, sizeof(JCOL)); + *jcp = jcol; + jcp->Cbn |= (i > 1); + jcp->Name = PlugDup(g, colname); + length[0] = MY_MAX(length[0], strlen(colname)); + + if (b) { + jcp->Fmt = PlugDup(g, fmt); + length[7] = MY_MAX(length[7], strlen(fmt)); + } else + jcp->Fmt = NULL; + + if (pjcp) { + jcp->Next = pjcp->Next; + pjcp->Next = jcp; + } else + fjcp = jcp; + + n++; + } // endif jcp + + if (jcp) + pjcp = jcp; + +} // end of AddColumn + +/* -------------------------- Class BTUTIL --------------------------- */ + +/***********************************************************************/ +/* Find the row in the tree structure. */ +/***********************************************************************/ +PBVAL BTUTIL::FindRow(PGLOBAL g) +{ + char *p, *objpath; + PBVAL jsp = Tp->Row; + PBVAL val = NULL; + + for (objpath = PlugDup(g, Tp->Objname); jsp && objpath; objpath = p) { + if ((p = strchr(objpath, Tp->Sep))) + *p++ = 0; + + if (*objpath != '[' && !IsNum(objpath)) { // objpass is a key + val = (jsp->Type == TYPE_JOB) ? + GetKeyValue(GetObject(jsp), objpath) : NULL; + } else { + if (*objpath == '[') { + if (objpath[strlen(objpath) - 1] == ']') + objpath++; + else + return NULL; + } // endif [ + + val = (jsp->Type == TYPE_JAR) ? + GetArrayValue(GetArray(jsp), atoi(objpath) - Tp->B) : NULL; + } // endif objpath + + // jsp = (val) ? val->GetJson() : NULL; + jsp = val; + } // endfor objpath + + return jsp; +} // end of FindRow + +/***********************************************************************/ +/* Parse the read line. */ +/***********************************************************************/ +PBVAL BTUTIL::ParseLine(PGLOBAL g, int *pretty, bool *comma) +{ + return ParseJson(g, Tp->To_Line, strlen(Tp->To_Line), pretty, comma); +} // end of ParseLine + +/***********************************************************************/ +/* Make the top tree from the object path. */ +/***********************************************************************/ +PBVAL BTUTIL::MakeTopTree(PGLOBAL g, PBVAL jsp) +{ + PBVAL top = NULL; + + if (Tp->Objname) { + if (!Tp->Val) { + // Parse and allocate Objname item(s) + char* p; + char* objpath = PlugDup(g, Tp->Objname); + int i; + PBPR objp = NULL; + PBVAL arp = NULL; + PBVAL val = NULL; + + for (; objpath; objpath = p) { + if ((p = strchr(objpath, Tp->Sep))) + *p++ = 0; + + if (*objpath != '[' && !IsNum(objpath)) { + // objp = new(g) JOBJECT; + + if (!top) + top = NewVal(TYPE_JOB); + + if (val) + SetValueObj(val, objp); + + val = NewVal(); + SetKeyValue(objp, MOF(val), objpath); + } else { + if (*objpath == '[') { + // Old style + if (objpath[strlen(objpath) - 1] != ']') { + sprintf(g->Message, "Invalid Table path %s", Tp->Objname); + return NULL; + } else + objpath++; + + } // endif objpath + + if (!top) + top = NewVal(TYPE_JAR); + + if (val) + SetValueArr(val, arp); + + val = NewVal(); + i = atoi(objpath) - Tp->B; + SetArrayValue(arp, val, i); + } // endif objpath + + } // endfor p + + Tp->Val = val; + } // endif Val + + SetValueVal(Tp->Val, jsp); + } else + top = jsp; + + return top; +} // end of MakeTopTree + +PSZ BTUTIL::SerialVal(PGLOBAL g, PBVAL vlp, int pretty) +{ + return Serialize(g, vlp, NULL, pretty); +} // en of SerialTop + +/* -------------------------- Class BCUTIL --------------------------- */ + +/***********************************************************************/ +/* SetValue: Set a value from a BVALUE contains. */ +/***********************************************************************/ +void BCUTIL::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL jvp) +{ + if (jvp) { + vp->SetNull(false); + + switch (jvp->Type) { + case TYPE_STRG: + case TYPE_INTG: + case TYPE_BINT: + case TYPE_DBL: + case TYPE_DTM: + switch (vp->GetType()) { + case TYPE_STRING: + case TYPE_DATE: + vp->SetValue_psz(GetString(jvp)); + break; + case TYPE_INT: + case TYPE_SHORT: + case TYPE_TINY: + vp->SetValue(GetInteger(jvp)); + break; + case TYPE_BIGINT: + vp->SetValue(GetBigint(jvp)); + break; + case TYPE_DOUBLE: + vp->SetValue(GetDouble(jvp)); + + if (jvp->Type == TYPE_DBL) + vp->SetPrec(jvp->Nd); + + break; + default: + sprintf(G->Message, "Unsupported column type %d", vp->GetType()); + throw 888; + } // endswitch Type + + break; + case TYPE_BOOL: + if (vp->IsTypeNum()) + vp->SetValue(GetInteger(jvp) ? 1 : 0); + else + vp->SetValue_psz((PSZ)(GetInteger(jvp) ? "true" : "false")); + + break; + case TYPE_JAR: + case TYPE_JOB: + // SetJsonValue(g, vp, val->GetArray()->GetValue(0)); + vp->SetValue_psz(GetValueText(g, jvp, NULL)); + break; + default: + vp->Reset(); + vp->SetNull(true); + } // endswitch Type + + } else { + vp->Reset(); + vp->SetNull(true); + } // endif val + +} // end of SetJsonValue + +/***********************************************************************/ +/* MakeJson: Serialize the json item and set value to it. */ +/***********************************************************************/ +PVAL BCUTIL::MakeBson(PGLOBAL g, PBVAL jsp) +{ + if (Cp->Value->IsTypeNum()) { + strcpy(g->Message, "Cannot make Json for a numeric column"); + Cp->Value->Reset(); +#if 0 + } else if (Value->GetType() == TYPE_BIN) { + if ((unsigned)Value->GetClen() >= sizeof(BSON)) { + ulong len = Tjp->Lrecl ? Tjp->Lrecl : 500; + PBSON bsp = JbinAlloc(g, NULL, len, jsp); + + strcat(bsp->Msg, " column"); + ((BINVAL*)Value)->SetBinValue(bsp, sizeof(BSON)); + } else { + strcpy(g->Message, "Column size too small"); + Value->SetValue_char(NULL, 0); + } // endif Clen +#endif // 0 + } else + Cp->Value->SetValue_psz(Serialize(g, jsp, NULL, 0)); + + return Cp->Value; +} // end of MakeJson + + /***********************************************************************/ +/* GetColumnValue: */ +/***********************************************************************/ +PVAL BCUTIL::GetColumnValue(PGLOBAL g, PBVAL row, int i) +{ + int nod = Cp->Nod, n = nod - 1; + JNODE *nodes = Cp->Nodes; + PVAL value = Cp->Value; + PBVAL arp; + PBVAL bvp = NULL; + + for (; i < nod && row; i++) { + if (nodes[i].Op == OP_NUM) { + value->SetValue(row->Type == TYPE_JAR ? GetSize(row) : 1); + return(value); + } else if (nodes[i].Op == OP_XX) { + return MakeBson(g, row); + } else switch (row->Type) { + case TYPE_JOB: + if (!nodes[i].Key) { + // Expected Array was not there, wrap the value + if (i < nod - 1) + continue; + else + bvp = row; + + } else + bvp = 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) + bvp = GetArrayValue(arp, nodes[i].Rank); + else if (nodes[i].Op == OP_EXP) + return ExpandArray(g, arp, i); + else + return CalculateArray(arp, i); + + } else { + // Unexpected array, unwrap it as [0] + bvp = GetArrayValue(arp, 0); + i--; + } // endif's + + break; + case TYPE_JVAL: + bvp = row; + break; + default: + sprintf(g->Message, "Invalid row JSON type %d", row->Type); + bvp = NULL; + } // endswitch Type + + if (i < nod - 1) + row = bvp; + + } // endfor i + + SetJsonValue(g, value, bvp); + return value; +} // end of GetColumnValue + +/***********************************************************************/ +/* ExpandArray: */ +/***********************************************************************/ +PVAL BCUTIL::ExpandArray(PGLOBAL g, PBVAL arp, int n) +{ + int nod = Cp->Nod, ars = MY_MIN(Tp->Limit, GetArraySize(arp)); + JNODE *nodes = Cp->Nodes; + PVAL value = Cp->Value; + PBVAL bvp; + BVAL bval; + + if (!ars) { + value->Reset(); + value->SetNull(true); + Tp->NextSame = 0; + return value; + } // endif ars + + if (!(bvp = GetArrayValue(arp, (nodes[n].Rx = nodes[n].Nx)))) { + strcpy(g->Message, "Logical error expanding array"); + throw 666; + } // endif jvp + + if (n < nod - 1 && GetBson(bvp)) { + SetValue(&bval, GetColumnValue(g, GetBson(bvp), n + 1)); + bvp = &bval; + } // endif n + + if (n >= Tp->NextSame) { + if (++nodes[n].Nx == ars) { + nodes[n].Nx = 0; + Cp->Xnod = 0; + } else + Cp->Xnod = n; + + Tp->NextSame = Cp->Xnod; + } // endif NextSame + + SetJsonValue(g, value, bvp); + return value; +} // end of ExpandArray + + /***********************************************************************/ + /* CalculateArray: */ + /***********************************************************************/ +PVAL BCUTIL::CalculateArray(PBVAL arp, int n) +{ + throw("CalculateArray NIY"); +#if 0 + int i, ars, nv = 0, nextsame = Tjp->NextSame; + bool err; + OPVAL op = Nodes[n].Op; + PVAL val[2], vp = Nodes[n].Valp; + PJVAL jvrp, jvp; + JVALUE jval; + + vp->Reset(); + ars = MY_MIN(Tjp->Limit, arp->size()); + + if (trace(1)) + htrc("CalculateArray: size=%d op=%d nextsame=%d\n", + ars, op, nextsame); + + for (i = 0; i < ars; i++) { + jvrp = arp->GetArrayValue(i); + + if (trace(1)) + htrc("i=%d nv=%d\n", i, nv); + + if (!jvrp->IsNull() || (op == OP_CNC && GetJsonNull())) do { + if (jvrp->IsNull()) { + jvrp->Strp = PlugDup(g, GetJsonNull()); + jvrp->DataType = TYPE_STRG; + jvp = jvrp; + } else if (n < Nod - 1 && jvrp->GetJson()) { + Tjp->NextSame = nextsame; + jval.SetValue(g, GetColumnValue(g, jvrp->GetJson(), n + 1)); + jvp = &jval; + } 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 Null + + } while (Tjp->NextSame > nextsame); + + } // 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 + + Tjp->NextSame = nextsame; + return vp; +#endif // 0 +} // end of CalculateArray + +/***********************************************************************/ +/* GetRow: Get the object containing this column. */ +/***********************************************************************/ +PBVAL BCUTIL::GetRow(PGLOBAL g) +{ + int nod = Cp->Nod; + JNODE *nodes = Cp->Nodes; + PBVAL val = NULL; + PBVAL arp; + PBVAL nwr, row = Tp->Row; + + for (int i = 0; i < nod && row; i++) { + if (nodes[i + 1].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 = row; + + if (!nodes[i].Key) { + if (nodes[i].Op == OP_EQ) + val = GetArrayValue(arp, nodes[i].Rank); + else + val = GetArrayValue(arp, nodes[i].Rx); + + } else { + // Unexpected array, unwrap it as [0] + val = GetArrayValue(arp, 0); + i--; + } // endif Nodes + + break; + case TYPE_JVAL: + val = row; + break; + default: + sprintf(g->Message, "Invalid row JSON type %d", row->Type); + val = NULL; + } // endswitch Type + + if (val) { + row = GetBson(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 = NewVal(TYPE_JAR); + else + nwr = NewVal(TYPE_JOB); + + if (row->Type == TYPE_JOB) { + SetKeyValue(MPP(row->To_Val), MOF(nwr), nodes[i - 1].Key); + } else if (row->Type == TYPE_JAR) { + AddArrayValue(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 + + +/* -------------------------- Class BSONDEF -------------------------- */ + +BSONDEF::BSONDEF(void) +{ + Jmode = MODE_OBJECT; + Objname = NULL; + Xcol = NULL; + Pretty = 2; + Limit = 1; + Base = 0; + Strict = false; + Sep = '.'; + Uri = NULL; + Collname = Options = Filter = NULL; + Pipe = false; + Driver = NULL; + Version = 0; + Wrapname = NULL; +} // end of BSONDEF constructor + +/***********************************************************************/ +/* DefineAM: define specific AM block values. */ +/***********************************************************************/ +bool BSONDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) +{ + G = g; + Schema = GetStringCatInfo(g, "DBname", Schema); + Jmode = (JMODE)GetIntCatInfo("Jmode", MODE_OBJECT); + Objname = GetStringCatInfo(g, "Object", NULL); + Xcol = GetStringCatInfo(g, "Expand", NULL); + Pretty = GetIntCatInfo("Pretty", 2); + Limit = GetIntCatInfo("Limit", 10); + Base = GetIntCatInfo("Base", 0) ? 1 : 0; + Sep = *GetStringCatInfo(g, "Separator", "."); + Accept = GetBoolCatInfo("Accept", false); + + // Don't use url as MONGO uri when called from REST + if (stricmp(am, "REST") && (Uri = GetStringCatInfo(g, "Connect", NULL))) { +#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) + Collname = GetStringCatInfo(g, "Name", + (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name); + Collname = GetStringCatInfo(g, "Tabname", Collname); + Options = GetStringCatInfo(g, "Colist", NULL); + Filter = GetStringCatInfo(g, "Filter", NULL); + Pipe = GetBoolCatInfo("Pipeline", false); + Driver = GetStringCatInfo(g, "Driver", NULL); + Version = GetIntCatInfo("Version", 3); + Pretty = 0; +#if defined(JAVA_SUPPORT) + if (Version == 2) + Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface"); + else + Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface"); +#endif // JAVA_SUPPORT +#else // !MONGO_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); + return true; +#endif // !MONGO_SUPPORT + } // endif Uri + + return DOSDEF::DefineAM(g, (Uri ? "XMGO" : "DOS"), poff); +} // end of DefineAM + +/***********************************************************************/ +/* GetTable: makes a new Table Description Block. */ +/***********************************************************************/ +PTDB BSONDEF::GetTable(PGLOBAL g, MODE m) { + if (trace(1)) + htrc("BSON GetTable Pretty=%d Uri=%s\n", Pretty, SVP(Uri)); + + if (Catfunc == FNC_COL) + return new(g)TDBBCL(this); + + PTDBASE tdbp; + PTXF txfp = NULL; + + // JSN not used for pretty=1 for insert or delete + if (Pretty <= 0 || (Pretty == 1 && (m == MODE_READ || m == MODE_UPDATE))) { + PGLOBAL G; + USETEMP tmp = UseTemp(); + bool map = Mapped && Pretty >= 0 && m != MODE_INSERT && + !(tmp != TMP_NO && m == MODE_UPDATE) && + !(tmp == TMP_FORCE && + (m == MODE_UPDATE || m == MODE_DELETE)); + + if (Lrecl) { + // Allocate the parse work memory + G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); + memset(G, 0, sizeof(GLOBAL)); + G->Sarea_Size = (size_t)Lrecl * 6; + G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size); + PlugSubSet(G->Sarea, G->Sarea_Size); + G->jump_level = 0; +// ((TDBBSN*)tdbp)->G = G; +// ((TDBBSN*)tdbp)->Docp = new(g) BDOC(G->Sarea); + } else { + strcpy(g->Message, "LRECL is not defined"); + return NULL; + } // endif Lrecl + +#if 0 + if (Uri) { + if (Driver && toupper(*Driver) == 'C') { +#if defined(CMGO_SUPPORT) + txfp = new(g) CMGFAM(this); +#else + sprintf(g->Message, "Mongo %s Driver not available", "C"); + return NULL; +#endif + } else if (Driver && toupper(*Driver) == 'J') { +#if defined(JAVA_SUPPORT) + txfp = new(g) JMGFAM(this); +#else + sprintf(g->Message, "Mongo %s Driver not available", "Java"); + return NULL; +#endif + } else { // Driver not specified +#if defined(CMGO_SUPPORT) + txfp = new(g) CMGFAM(this); +#elif defined(JAVA_SUPPORT) + txfp = new(g) JMGFAM(this); +#else // !MONGO_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); + return NULL; +#endif // !MONGO_SUPPORT + } // endif Driver + + } else if (Zipped) { +#endif // 0 + if (Zipped) { +#if defined(ZIP_SUPPORT) + if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) { + txfp = new(g) UNZFAM(this); + } else if (m == MODE_INSERT) { + txfp = new(g) ZIPFAM(this); + } else { + strcpy(g->Message, "UPDATE/DELETE not supported for ZIP"); + return NULL; + } // endif's m +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; +#endif // !ZIP_SUPPORT + } else if (Compressed) { +#if defined(GZ_SUPPORT) + if (Compressed == 1) + txfp = new(g) GZFAM(this); + else + txfp = new(g) ZLBFAM(this); +#else // !GZ_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ"); + return NULL; +#endif // !GZ_SUPPORT + } else if (map) + txfp = new(g) MAPFAM(this); + else if (Pretty < 0) // BJsonfile + txfp = new(g) BINFAM(this); + else + txfp = new(g) DOSFAM(this); + + // Txfp must be set for TDBBSN + tdbp = new(g) TDBBSN(G, this, txfp); + } else { + if (Zipped) { +#if defined(ZIP_SUPPORT) + if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) { + txfp = new(g) UNZFAM(this); + } else if (m == MODE_INSERT) { + strcpy(g->Message, "INSERT supported only for zipped JSON when pretty=0"); + return NULL; + } else { + strcpy(g->Message, "UPDATE/DELETE not supported for ZIP"); + return NULL; + } // endif's m +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; +#endif // !ZIP_SUPPORT + } else + txfp = new(g) MAPFAM(this); + + tdbp = new(g) TDBBSON(g, this, txfp); + } // endif Pretty + + if (Multiple) + tdbp = new(g) TDBMUL(tdbp); + + return tdbp; +} // end of GetTable + +/* --------------------------- Class TDBBSN -------------------------- */ + +/***********************************************************************/ +/* Implementation of the TDBBSN class (Pretty < 2) */ +/***********************************************************************/ +TDBBSN::TDBBSN(PGLOBAL g, PBDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp) +{ + Bp = new(g) BTUTIL(tdp->G, this); + Top = NULL; + Row = NULL; + Val = NULL; + Colp = NULL; + + if (tdp) { + Jmode = tdp->Jmode; + Objname = tdp->Objname; + Xcol = tdp->Xcol; + Limit = tdp->Limit; + Pretty = tdp->Pretty; + B = tdp->Base ? 1 : 0; + Sep = tdp->Sep; + Strict = tdp->Strict; + } else { + Jmode = MODE_OBJECT; + Objname = NULL; + Xcol = NULL; + Limit = 1; + Pretty = 0; + B = 0; + Sep = '.'; + Strict = false; + } // endif tdp + + Fpos = -1; + N = M = 0; + NextSame = 0; + SameRow = 0; + Xval = -1; + Comma = false; +} // end of TDBBSN standard constructor + +TDBBSN::TDBBSN(TDBBSN* tdbp) : TDBDOS(NULL, tdbp) +{ + Bp = tdbp->Bp; + Top = tdbp->Top; + Row = tdbp->Row; + Val = tdbp->Val; + Colp = tdbp->Colp; + Jmode = tdbp->Jmode; + Objname = tdbp->Objname; + Xcol = tdbp->Xcol; + Fpos = tdbp->Fpos; + N = tdbp->N; + M = tdbp->M; + Limit = tdbp->Limit; + NextSame = tdbp->NextSame; + SameRow = tdbp->SameRow; + Xval = tdbp->Xval; + B = tdbp->B; + Sep = tdbp->Sep; + Pretty = tdbp->Pretty; + Strict = tdbp->Strict; + Comma = tdbp->Comma; +} // end of TDBBSN copy constructor + +// Used for update +PTDB TDBBSN::Clone(PTABS t) +{ + PTDB tp; + PBSCOL cp1, cp2; + PGLOBAL g = t->G; + + tp = new(g) TDBBSN(this); + + for (cp1 = (PBSCOL)Columns; cp1; cp1 = (PBSCOL)cp1->GetNext()) { + cp2 = new(g) BSONCOL(cp1, tp); // Make a copy + NewPointer(t, cp1, cp2); + } // endfor cp1 + + return tp; +} // end of Clone + +/***********************************************************************/ +/* Allocate JSN column description block. */ +/***********************************************************************/ +PCOL TDBBSN::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) { + PBSCOL colp = new(g) BSONCOL(g, cdp, this, cprec, n); + + return (colp->ParseJpath(g)) ? NULL : colp; +} // end of MakeCol + +/***********************************************************************/ +/* InsertSpecialColumn: Put a special column ahead of the column list.*/ +/***********************************************************************/ +PCOL TDBBSN::InsertSpecialColumn(PCOL colp) { + if (!colp->IsSpecial()) + return NULL; + + //if (Xcol && ((SPCBLK*)colp)->GetRnm()) + // colp->SetKey(0); // Rownum is no more a key + + colp->SetNext(Columns); + Columns = colp; + return colp; +} // end of InsertSpecialColumn + +/***********************************************************************/ +/* JSON Cardinality: returns table size in number of rows. */ +/***********************************************************************/ +int TDBBSN::Cardinality(PGLOBAL g) { + if (!g) + return 0; + else if (Cardinal < 0) { + Cardinal = TDBDOS::Cardinality(g); + + } // endif Cardinal + + return Cardinal; +} // end of Cardinality + +/***********************************************************************/ +/* JSON GetMaxSize: returns file size estimate in number of lines. */ +/***********************************************************************/ +int TDBBSN::GetMaxSize(PGLOBAL g) { + if (MaxSize < 0) + MaxSize = TDBDOS::GetMaxSize(g) * ((Xcol) ? Limit : 1); + + return MaxSize; +} // end of GetMaxSize + +/***********************************************************************/ +/* JSON EstimatedLength. Returns an estimated minimum line length. */ +/***********************************************************************/ +int TDBBSN::EstimatedLength(void) { + if (AvgLen <= 0) + return (Lrecl ? Lrecl : 1024) / 8; // TODO: make it better + else + return AvgLen; + +} // end of Estimated Length + +/***********************************************************************/ +/* OpenDB: Data Base open routine for JSN access method. */ +/***********************************************************************/ +bool TDBBSN::OpenDB(PGLOBAL g) { + if (Use == USE_OPEN) { + /*******************************************************************/ + /* Table already open replace it at its beginning. */ + /*******************************************************************/ + Fpos = -1; + NextSame = 0; + SameRow = 0; + } else { + /*******************************************************************/ + /* First opening. */ + /*******************************************************************/ +// Docp = new(g) BDOC(g->Sarea); + + if (Mode == MODE_INSERT) + switch (Jmode) { +// case MODE_OBJECT: Row = new(g) JOBJECT; break; +// case MODE_ARRAY: Row = new(g) JARRAY; break; +// case MODE_VALUE: Row = new(g) JVALUE; break; + default: + sprintf(g->Message, "Invalid Jmode %d", Jmode); + return true; + } // endswitch Jmode + + } // endif Use + + if (Pretty < 0) { +#if 0 + /*******************************************************************/ + /* Binary BJSON table. */ + /*******************************************************************/ + xtrc(1, "JSN OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n", + this, Tdb_No, Use, Mode); + + if (Use == USE_OPEN) { + /*******************************************************************/ + /* Table already open, just replace it at its beginning. */ + /*******************************************************************/ + if (!To_Kindex) { + Txfp->Rewind(); // see comment in Work.log + } else // Table is to be accessed through a sorted index table + To_Kindex->Reset(); + + return false; + } // endif use + + /*********************************************************************/ + /* Open according to logical input/output mode required. */ + /* Use conventionnal input/output functions. */ + /*********************************************************************/ + if (Txfp->OpenTableFile(g)) + return true; + + Use = USE_OPEN; // Do it now in case we are recursively called + + /*********************************************************************/ + /* Lrecl is Ok. */ + /*********************************************************************/ + size_t linelen = Lrecl; + + //To_Line = (char*)PlugSubAlloc(g, NULL, linelen); + //memset(To_Line, 0, linelen); + To_Line = Txfp->GetBuf(); + xtrc(1, "OpenJSN: R%hd mode=%d To_Line=%p\n", Tdb_No, Mode, To_Line); + return false; +#endif // 0 + strcpy(g->Message, "TDBBSN: Binary NIY"); + return true; + } else if (TDBDOS::OpenDB(g)) + return true; + + if (Xcol) + To_Filter = NULL; // Imcompatible + + return false; +} // end of OpenDB + +/***********************************************************************/ +/* SkipHeader: Physically skip first header line if applicable. */ +/* This is called from TDBDOS::OpenDB and must be executed before */ +/* Kindex construction if the file is accessed using an index. */ +/***********************************************************************/ +bool TDBBSN::SkipHeader(PGLOBAL g) { + int len = GetFileLength(g); + bool rc = false; + +#if defined(_DEBUG) + if (len < 0) + return true; +#endif // _DEBUG + + if (Pretty == 1) { + if (Mode == MODE_INSERT || Mode == MODE_DELETE) { + // Mode Insert and delete are no more handled here + DBUG_ASSERT(false); + } else if (len > 0) // !Insert && !Delete + rc = (Txfp->SkipRecord(g, false) == RC_FX || Txfp->RecordPos(g)); + + } // endif Pretty + + return rc; +} // end of SkipHeader + +/***********************************************************************/ +/* ReadDB: Data Base read routine for JSN access method. */ +/***********************************************************************/ +int TDBBSN::ReadDB(PGLOBAL g) { + int rc; + + N++; + + if (NextSame) { + SameRow = NextSame; + NextSame = 0; + M++; + return RC_OK; + } else if ((rc = TDBDOS::ReadDB(g)) == RC_OK) { + if (!IsRead() && ((rc = ReadBuffer(g)) != RC_OK)) + return rc; // Deferred reading failed + + if (Pretty >= 0) { + // Recover the memory used for parsing + Bp->SubSet(); + + if ((Row = Bp->ParseLine(g, &Pretty, &Comma))) { + Row = Bp->FindRow(g); + SameRow = 0; + Fpos++; + M = 1; + rc = RC_OK; + } else if (Pretty != 1 || strcmp(To_Line, "]")) { + Bp->GetMsg(g); + rc = RC_FX; + } else + rc = RC_EF; + + } else { +#if 0 + // Here we get a movable Json binary tree + PJSON jsp; + SWAP* swp; + + jsp = (PJSON)To_Line; + swp = new(g) SWAP(G, jsp); + swp->SwapJson(jsp, false); // Restore pointers from offsets + Row = jsp; + Row = FindRow(g); + SameRow = 0; + Fpos++; + M = 1; + rc = RC_OK; +#endif // 0 + strcpy(g->Message, "TDBBSN: Binary NIY"); + rc = RC_FX; + } // endif Pretty + + } // endif ReadDB + + return rc; +} // end of ReadDB + +/***********************************************************************/ +/* PrepareWriting: Prepare the line for WriteDB. */ +/***********************************************************************/ +bool TDBBSN::PrepareWriting(PGLOBAL g) { + PSZ s; + + if (!(Top = Bp->MakeTopTree(g, Row))) + return true; + + if ((s = Bp->SerialVal(g, Top, Pretty))) { + if (Comma) + strcat(s, ","); + + if ((signed)strlen(s) > Lrecl) { + strncpy(To_Line, s, Lrecl); + sprintf(g->Message, "Line truncated (lrecl=%d)", Lrecl); + return PushWarning(g, this); + } else + strcpy(To_Line, s); + + return false; + } else + return true; + +} // end of PrepareWriting + +/***********************************************************************/ +/* WriteDB: Data Base write routine for JSON access method. */ +/***********************************************************************/ +int TDBBSN::WriteDB(PGLOBAL g) { + int rc = TDBDOS::WriteDB(g); + + Bp->SubSet(); + Bp->Clear(Row); + return rc; +} // end of WriteDB + +/***********************************************************************/ +/* Data Base close routine for JSON access method. */ +/***********************************************************************/ +void TDBBSN::CloseDB(PGLOBAL g) +{ + TDBDOS::CloseDB(g); + ((PBDEF)To_Def)->G = PlugExit(((PBDEF)To_Def)->G); +} // end of CloseDB + + /* ---------------------------- BSONCOL ------------------------------ */ + +/***********************************************************************/ +/* BSONCOL public constructor. */ +/***********************************************************************/ +BSONCOL::BSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) + : DOSCOL(g, cdp, tdbp, cprec, i, "DOS") +{ + Tbp = (TDBBSN*)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp); + Cp = new(g) BCUTIL(((PBDEF)Tbp->To_Def)->G, this, Tbp); + Jpath = cdp->GetFmt(); + MulVal = NULL; + Nodes = NULL; + Nod = 0; + Sep = Tbp->Sep; + Xnod = -1; + Xpd = false; + Parsed = false; +} // end of BSONCOL constructor + +/***********************************************************************/ +/* BSONCOL constructor used for copying columns. */ +/* tdbp is the pointer to the new table descriptor. */ +/***********************************************************************/ +BSONCOL::BSONCOL(BSONCOL* col1, PTDB tdbp) : DOSCOL(col1, tdbp) +{ + Tbp = col1->Tbp; + Cp = col1->Cp; + Jpath = col1->Jpath; + MulVal = col1->MulVal; + Nodes = col1->Nodes; + Nod = col1->Nod; + Sep = col1->Sep; + Xnod = col1->Xnod; + Xpd = col1->Xpd; + Parsed = col1->Parsed; +} // end of BSONCOL copy constructor + +/***********************************************************************/ +/* SetBuffer: prepare a column block for write operation. */ +/***********************************************************************/ +bool BSONCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check) +{ + if (DOSCOL::SetBuffer(g, value, ok, check)) + return true; + + // Parse the json path + if (ParseJpath(g)) + return true; + + Tbp = (TDBBSN*)To_Tdb; + return false; +} // end of SetBuffer + +/***********************************************************************/ +/* Check whether this object is expanded. */ +/***********************************************************************/ +bool BSONCOL::CheckExpand(PGLOBAL g, int i, PSZ nm, bool b) { + if ((Tbp->Xcol && nm && !strcmp(nm, Tbp->Xcol) && + (Tbp->Xval < 0 || Tbp->Xval == i)) || Xpd) { + Xpd = true; // Expandable object + Nodes[i].Op = OP_EXP; + } else if (b) { + strcpy(g->Message, "Cannot expand more than one branch"); + return true; + } // endif Xcol + + return false; +} // end of CheckExpand + +/***********************************************************************/ +/* Analyse array processing options. */ +/***********************************************************************/ +bool BSONCOL::SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm) { + int n; + bool dg = true, b = false; + PJNODE jnp = &Nodes[i]; + + //if (*p == '[') p++; // Old syntax .[ or :[ + n = (int)strlen(p); + + if (*p) { + if (p[n - 1] == ']') { + p[--n] = 0; + } else if (!IsNum(p)) { + // Wrong array specification + sprintf(g->Message, "Invalid array specification %s for %s", p, Name); + return true; + } // endif p + + } else + b = true; + + // To check whether a numeric Rank was specified + dg = IsNum(p); + + if (!n) { + // Default specifications + if (CheckExpand(g, i, nm, false)) + return true; + else if (jnp->Op != OP_EXP) { + if (b) { + // Return 1st value (B is the index base) + jnp->Rank = Tbp->B; + jnp->Op = OP_EQ; + } else if (!Value->IsTypeNum()) { + jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING); + jnp->Op = OP_CNC; + } else + jnp->Op = OP_ADD; + + } // endif OP + + } else if (dg) { + // Return nth value + jnp->Rank = atoi(p) - Tbp->B; + jnp->Op = OP_EQ; + } else if (n == 1) { + // Set the Op value; + if (Sep == ':') + switch (*p) { + case '*': *p = 'x'; break; + case 'x': + case 'X': *p = '*'; break; // Expand this array + default: break; + } // endswitch p + + 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 + if (!Tbp->Xcol && nm) { + Xpd = true; + jnp->Op = OP_EXP; + Tbp->Xval = i; + Tbp->Xcol = nm; + } else if (CheckExpand(g, i, nm, true)) + return true; + + break; + default: + sprintf(g->Message, + "Invalid function specification %c for %s", *p, Name); + 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; + jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING); + } // endif n + + } else { + sprintf(g->Message, "Wrong array specification for %s", Name); + 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. */ +/***********************************************************************/ +bool BSONCOL::ParseJpath(PGLOBAL g) { + char* p, * p1 = NULL, * p2 = NULL, * pbuf = NULL; + int i; + bool a; + + if (Parsed) + return false; // Already done + else if (InitValue(g)) + return true; + else if (!Jpath) + Jpath = Name; + + if (To_Tdb->GetOrig()) { + // This is an updated column, get nodes from origin + for (PBSCOL colp = (PBSCOL)Tbp->GetColumns(); colp; + colp = (PBSCOL)colp->GetNext()) + if (!stricmp(Name, colp->GetName())) { + Nod = colp->Nod; + Nodes = colp->Nodes; + Xpd = colp->Xpd; + goto fin; + } // endif Name + + sprintf(g->Message, "Cannot parse updated column %s", Name); + return true; + } // endif To_Orig + + pbuf = PlugDup(g, Jpath); + if (*pbuf == '$') pbuf++; + if (*pbuf == Sep) pbuf++; + if (*pbuf == '[') p1 = pbuf++; + + // Estimate the required number of nodes + for (i = 0, p = pbuf; (p = NextChr(p, Sep)); i++, p++) + Nod++; // One path node found + + Nodes = (PJNODE)PlugSubAlloc(g, NULL, (++Nod) * sizeof(JNODE)); + 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, Sep); + + if (!p2) + p2 = p1; + else if (p1) { + if (p1 < p2) + p2 = p1; + else if (p1 == p2 + 1) + *p2++ = 0; // Old syntax .[ or :[ + 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 == '*') { + // Return JSON + Nodes[i].Op = OP_XX; + } else { + Nodes[i].Key = p; + Nodes[i].Op = OP_EXIST; + } // endif's + + } // endfor i, p + + Nod = i; + +fin: + MulVal = AllocateValue(g, Value); + Parsed = true; + return false; +} // end of ParseJpath + +/***********************************************************************/ +/* Get Jpath converted to Mongo path. */ +/***********************************************************************/ +PSZ BSONCOL::GetJpath(PGLOBAL g, bool proj) { + if (Jpath) { + char* p1, * p2, * mgopath; + int i = 0; + + if (strcmp(Jpath, "*")) { + p1 = Jpath; + if (*p1 == '$') p1++; + if (*p1 == '.') p1++; + mgopath = PlugDup(g, p1); + } else + return NULL; + + for (p1 = p2 = mgopath; *p1; p1++) + if (i) { // Inside [] + if (isdigit(*p1)) { + if (!proj) + *p2++ = *p1; + + } else if (*p1 == ']' && i == 1) { + if (proj && p1[1] == '.') + p1++; + + i = 0; + } else if (*p1 == '.' && i == 2) { + if (!proj) + *p2++ = '.'; + + i = 0; + } else if (!proj) + return NULL; + + } else switch (*p1) { + case ':': + case '.': + if (isdigit(p1[1])) + i = 2; + + *p2++ = '.'; + break; + case '[': + if (*(p2 - 1) != '.') + *p2++ = '.'; + + i = 1; + break; + case '*': + if (*(p2 - 1) == '.' && !*(p1 + 1)) { + p2--; // Suppress last :* + break; + } // endif p2 + + default: + *p2++ = *p1; + break; + } // endswitch p1; + + *p2 = 0; + return mgopath; + } else + return NULL; + +} // end of GetJpath + +/***********************************************************************/ +/* MakeJson: Serialize the json item and set value to it. */ +/***********************************************************************/ +PVAL BSONCOL::MakeBson(PGLOBAL g, PBVAL 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; + PBSON bsp = JbinAlloc(g, NULL, len, jsp); + + strcat(bsp->Msg, " column"); + ((BINVAL*)Value)->SetBinValue(bsp, sizeof(BSON)); + } else { + strcpy(g->Message, "Column size too small"); + Value->SetValue_char(NULL, 0); + } // endif Clen +#endif 0 + } else + Value->SetValue_psz(Cp->SerialVal(g, jsp, 0)); + + return Value; +} // end of MakeJson + +/***********************************************************************/ +/* ReadColumn: */ +/***********************************************************************/ +void BSONCOL::ReadColumn(PGLOBAL g) { + if (!Tbp->SameRow || Xnod >= Tbp->SameRow) + Value->SetValue_pval(Cp->GetColumnValue(g, Tbp->Row, 0)); + + if (Xpd && Value->IsNull() && !((PBDEF)Tbp->To_Def)->Accept) + throw("Null expandable JSON value"); + + // Set null when applicable + if (!Nullable) + Value->SetNull(false); + +} // end of ReadColumn + +/***********************************************************************/ +/* WriteColumn: */ +/***********************************************************************/ +void BSONCOL::WriteColumn(PGLOBAL g) { + if (Xpd && Tbp->Pretty < 2) { + strcpy(g->Message, "Cannot write expanded column when Pretty is not 2"); + throw 666; + } // endif Xpd + + /*********************************************************************/ + /* Check whether this node must be written. */ + /*********************************************************************/ + if (Value != To_Val) + Value->SetValue_pval(To_Val, FALSE); // Convert the updated value + + /*********************************************************************/ + /* On INSERT Null values are represented by no node. */ + /*********************************************************************/ + if (Value->IsNull() && Tbp->Mode == MODE_INSERT) + return; + + throw "Write BSON NIY"; + +#if 0 + char* s; + PBPR objp = NULL; + PBVAL arp = NULL; + PBVAL jvp = NULL; + PBVAL jsp, row = Cp->GetRow(); + + switch (row->Type) { + case TYPE_JOB: objp = (PJOB)row; break; + case TYPE_JAR: arp = (PJAR)row; break; + case TYPE_JVAL: jvp = (PJVAL)row; break; + default: row = NULL; // ??????????????????????????? + } // endswitch Type + + if (row) switch (Buf_Type) { + case TYPE_STRING: + if (Nodes[Nod - 1].Op == OP_XX) { + s = Value->GetCharValue(); + + if (!(jsp = ParseJson(G, s, strlen(s)))) { + strcpy(g->Message, s); + throw 666; + } // endif jsp + + if (arp) { + if (Nod > 1 && Nodes[Nod - 2].Op == OP_EQ) + arp->SetArrayValue(G, new(G) JVALUE(jsp), Nodes[Nod - 2].Rank); + else + arp->AddArrayValue(G, new(G) JVALUE(jsp)); + + arp->InitArray(G); + } else if (objp) { + if (Nod > 1 && Nodes[Nod - 2].Key) + objp->SetKeyValue(G, new(G) JVALUE(jsp), Nodes[Nod - 2].Key); + + } else if (jvp) + jvp->SetValue(jsp); + + break; + } // endif Op + + // fall through + case TYPE_DATE: + case TYPE_INT: + case TYPE_TINY: + case TYPE_SHORT: + case TYPE_BIGINT: + case TYPE_DOUBLE: + if (arp) { + if (Nodes[Nod - 1].Op == OP_EQ) + arp->SetArrayValue(G, new(G) JVALUE(G, Value), Nodes[Nod - 1].Rank); + else + arp->AddArrayValue(G, new(G) JVALUE(G, Value)); + + arp->InitArray(G); + } else if (objp) { + if (Nodes[Nod - 1].Key) + objp->SetKeyValue(G, new(G) JVALUE(G, Value), Nodes[Nod - 1].Key); + + } else if (jvp) + jvp->SetValue(g, Value); + + break; + default: // ?????????? + sprintf(g->Message, "Invalid column type %d", Buf_Type); + } // endswitch Type +#endif // 0 + +} // end of WriteColumn + +/* -------------------------- Class TDBBSON -------------------------- */ + +/***********************************************************************/ +/* Implementation of the TDBBSON class. */ +/***********************************************************************/ +TDBBSON::TDBBSON(PGLOBAL g, PBDEF tdp, PTXF txfp) : TDBBSN(g, tdp, txfp) +{ + Docp = NULL; + Multiple = tdp->Multiple; + Done = Changed = false; +} // end of TDBBSON standard constructor + +TDBBSON::TDBBSON(PBTDB tdbp) : TDBBSN(tdbp) +{ + Docp = tdbp->Docp; + Multiple = tdbp->Multiple; + Done = tdbp->Done; + Changed = tdbp->Changed; +} // end of TDBBSON copy constructor + +// Used for update +PTDB TDBBSON::Clone(PTABS t) +{ + PTDB tp; + PBSCOL cp1, cp2; + PGLOBAL g = t->G; + + tp = new(g) TDBBSON(this); + + for (cp1 = (PBSCOL)Columns; cp1; cp1 = (PBSCOL)cp1->GetNext()) { + cp2 = new(g) BSONCOL(cp1, tp); // Make a copy + NewPointer(t, cp1, cp2); + } // endfor cp1 + + return tp; +} // end of Clone + +/***********************************************************************/ +/* Make the document tree from the object path. */ +/***********************************************************************/ +int TDBBSON::MakeNewDoc(PGLOBAL g) +{ + // Create a void table that will be populated + Docp = Bp->NewVal(TYPE_JAR); + + if (Bp->MakeTopTree(g, Docp)) + return RC_FX; + + Done = true; + return RC_OK; +} // end of MakeNewDoc + +/***********************************************************************/ +/* Make the document tree from a file. */ +/***********************************************************************/ +int TDBBSON::MakeDocument(PGLOBAL g) +{ + char *p, *p1, *p2, *memory, *objpath, *key = NULL; + int i = 0; + size_t len; + my_bool a; + MODE mode = Mode; + PBVAL jsp; + PBPR objp = NULL; + PBVAL arp = NULL; + PBVAL val = NULL; + + if (Done) + return RC_OK; + + /*********************************************************************/ + /* Create the mapping file object in mode read. */ + /*********************************************************************/ + Mode = MODE_READ; + + if (!Txfp->OpenTableFile(g)) { + PFBLOCK fp = Txfp->GetTo_Fb(); + + if (fp) { + len = fp->Length; + memory = fp->Memory; + } else { + Mode = mode; // Restore saved Mode + return MakeNewDoc(g); + } // endif fp + + } else + return RC_FX; + + /*********************************************************************/ + /* Parse the json file and allocate its tree structure. */ + /*********************************************************************/ + g->Message[0] = 0; + jsp = Top = Bp->ParseJson(g, memory, len, &Pretty); + Txfp->CloseTableFile(g, false); + Mode = mode; // Restore saved Mode + + if (!jsp && g->Message[0]) + return RC_FX; + + if ((objpath = PlugDup(g, Objname))) { + if (*objpath == '$') objpath++; + if (*objpath == '.') objpath++; + p1 = (*objpath == '[') ? objpath++ : NULL; + + /*********************************************************************/ + /* Find the table in the tree structure. */ + /*********************************************************************/ + for (p = objpath; jsp && p; 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; + + if (!a && *p && *p != '[' && !IsNum(p)) { + // obj is a key + if (jsp->Type != TYPE_JOB) { + strcpy(g->Message, "Table path does not match the json file"); + return RC_FX; + } // endif Type + + key = p; + objp = Bp->GetObject(jsp); + arp = NULL; + val = Bp->GetKeyValue(objp, key); + + if (!val || !(jsp = Bp->GetBson(val))) { + sprintf(g->Message, "Cannot find object key %s", key); + return RC_FX; + } // endif val + + } else { + if (*p == '[') { + // Old style + if (p[strlen(p) - 1] != ']') { + sprintf(g->Message, "Invalid Table path near %s", p); + return RC_FX; + } else + p++; + + } // endif p + + if (jsp->Type != TYPE_JAR) { + strcpy(g->Message, "Table path does not match the json file"); + return RC_FX; + } // endif Type + + arp = Bp->GetArray(jsp); + objp = NULL; + i = atoi(p) - B; + val = Bp->GetArrayValue(arp, i); + + if (!val) { + sprintf(g->Message, "Cannot find array value %d", i); + return RC_FX; + } // endif val + + } // endif + + jsp = val; + } // endfor p + + } // endif objpath + + if (jsp && jsp->Type == TYPE_JAR) + Docp = jsp; + else { + // The table is void or is just one object or one value + Docp = Bp->NewVal(TYPE_JAR); + + if (val) + Bp->AddArrayValue(Docp, val); + else if (jsp) + Bp->AddArrayValue(Docp, Bp->DupVal(jsp)); + + if (objp) + Bp->SetKeyValue(objp, Bp->DupVal(Docp), key); + else if (arp) + Bp->SetArrayValue(arp, Bp->DupVal(Docp), i); + else + Top = Docp; + + } // endif jsp + + Done = true; + return RC_OK; +} // end of MakeDocument + +/***********************************************************************/ +/* JSON Cardinality: returns table size in number of rows. */ +/***********************************************************************/ +int TDBBSON::Cardinality(PGLOBAL g) +{ + if (!g) + return (Xcol || Multiple) ? 0 : 1; + else if (Cardinal < 0) { + if (!Multiple) { + if (MakeDocument(g) == RC_OK) + Cardinal = Bp->GetSize(Docp); + + } else + return 10; + + } // endif Cardinal + + return Cardinal; +} // end of Cardinality + +/***********************************************************************/ +/* JSON GetMaxSize: returns table size estimate in number of rows. */ +/***********************************************************************/ +int TDBBSON::GetMaxSize(PGLOBAL g) +{ + if (MaxSize < 0) + MaxSize = Cardinality(g) * ((Xcol) ? Limit : 1); + + return MaxSize; +} // end of GetMaxSize + +/***********************************************************************/ +/* ResetSize: call by TDBMUL when calculating size estimate. */ +/***********************************************************************/ +void TDBBSON::ResetSize(void) +{ + MaxSize = Cardinal = -1; + Fpos = -1; + N = 0; + Done = false; +} // end of ResetSize + +/***********************************************************************/ +/* TDBBSON is not indexable. */ +/***********************************************************************/ +int TDBBSON::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool) +{ + if (pxdf) { + strcpy(g->Message, "JSON not indexable when pretty = 2"); + return RC_FX; + } else + return RC_OK; + +} // end of MakeIndex + +/***********************************************************************/ +/* Return the position in the table. */ +/***********************************************************************/ +int TDBBSON::GetRecpos(void) +{ +#if 0 + union { + uint Rpos; + BYTE Spos[4]; + }; + + Rpos = htonl(Fpos); + Spos[0] = (BYTE)NextSame; + return Rpos; +#endif // 0 + return Fpos; +} // end of GetRecpos + +/***********************************************************************/ +/* Set the position in the table. */ +/***********************************************************************/ +bool TDBBSON::SetRecpos(PGLOBAL, int recpos) +{ +#if 0 + union { + uint Rpos; + BYTE Spos[4]; + }; + + Rpos = recpos; + NextSame = Spos[0]; + Spos[0] = 0; + Fpos = (signed)ntohl(Rpos); + + //if (Fpos != (signed)ntohl(Rpos)) { + // Fpos = ntohl(Rpos); + // same = false; + //} else + // same = true; +#endif // 0 + + Fpos = recpos - 1; + return false; +} // end of SetRecpos + +/***********************************************************************/ +/* JSON Access Method opening routine. */ +/***********************************************************************/ +bool TDBBSON::OpenDB(PGLOBAL g) +{ + if (Use == USE_OPEN) { + /*******************************************************************/ + /* Table already open replace it at its beginning. */ + /*******************************************************************/ + Fpos = -1; + NextSame = false; + SameRow = 0; + return false; + } // endif use + +/*********************************************************************/ +/* OpenDB: initialize the JSON file processing. */ +/*********************************************************************/ + if (MakeDocument(g) != RC_OK) + return true; + + if (Mode == MODE_INSERT) + switch (Jmode) { + case MODE_OBJECT: Row = Bp->NewVal(TYPE_JOB); break; + case MODE_ARRAY: Row = Bp->NewVal(TYPE_JAR); break; + case MODE_VALUE: Row = Bp->NewVal(); break; + default: + sprintf(g->Message, "Invalid Jmode %d", Jmode); + return true; + } // endswitch Jmode + + if (Xcol) + To_Filter = NULL; // Imcompatible + + Use = USE_OPEN; + return false; +} // end of OpenDB + +/***********************************************************************/ +/* ReadDB: Data Base read routine for JSON access method. */ +/***********************************************************************/ +int TDBBSON::ReadDB(PGLOBAL) +{ + int rc; + + N++; + + if (NextSame) { + SameRow = NextSame; + NextSame = false; + M++; + rc = RC_OK; + } else if (++Fpos < (signed)Bp->GetSize(Docp)) { + Row = Bp->GetArrayValue(Bp->GetBson(Docp), Fpos); + + if (Row->Type == TYPE_JVAL) + Row = Bp->GetBson(Row); + + SameRow = 0; + M = 1; + rc = RC_OK; + } else + rc = RC_EF; + + return rc; +} // end of ReadDB + +/***********************************************************************/ +/* WriteDB: Data Base write routine for JSON access method. */ +/***********************************************************************/ +int TDBBSON::WriteDB(PGLOBAL g) +{ + if (Jmode == MODE_OBJECT) { + PBVAL vp = Bp->DupVal(Row); + + if (Mode == MODE_INSERT) { + Bp->AddArrayValue(Docp, vp); + Row = Bp->NewVal(TYPE_JOB); + } else if (Bp->SetArrayValue(Docp, vp, Fpos)) + return RC_FX; + + } else if (Jmode == MODE_ARRAY) { + PBVAL vp = Bp->DupVal(Row); + + if (Mode == MODE_INSERT) { + Bp->AddArrayValue(Docp, vp); + Row = Bp->NewVal(TYPE_JAR); + } else if (Bp->SetArrayValue(Docp, vp, Fpos)) + return RC_FX; + + } else { // if (Jmode == MODE_VALUE) + if (Mode == MODE_INSERT) { + Bp->AddArrayValue(Docp, Row); + Row = Bp->NewVal(); + } else if (Bp->SetArrayValue(Docp, Row, Fpos)) + return RC_FX; + + } // endif Jmode + + Changed = true; + return RC_OK; +} // end of WriteDB + +/***********************************************************************/ +/* Data Base delete line routine for JSON access method. */ +/***********************************************************************/ +int TDBBSON::DeleteDB(PGLOBAL g, int irc) +{ + strcpy(g->Message, "BSON Delete NIY"); + return RC_FX; +#if 0 + if (irc == RC_OK) { + // Deleted current row + if (Doc->DeleteValue(Fpos)) { + sprintf(g->Message, "Value %d does not exist", Fpos + 1); + return RC_FX; + } // endif Delete + + Changed = true; + } else if (irc == RC_FX) + // Delete all + for (int i = 0; i < Doc->size(); i++) { + Doc->DeleteValue(i); + Changed = true; + } // endfor i + + return RC_OK; +#endif // 0 +} // end of DeleteDB + +/***********************************************************************/ +/* Data Base close routine for JSON access methods. */ +/***********************************************************************/ +void TDBBSON::CloseDB(PGLOBAL g) +{ + if (!Changed) + return; + + // Save the modified document + char filename[_MAX_PATH]; + +//Docp->InitArray(g); + + // We used the file name relative to recorded datapath + PlugSetPath(filename, ((PBDEF)To_Def)->Fn, GetPath()); + + // Serialize the modified table + if (!Bp->Serialize(g, Top, filename, Pretty)) + puts(g->Message); + +} // end of CloseDB + +/* ---------------------------TDBBCL class --------------------------- */ + +/***********************************************************************/ +/* TDBBCL class constructor. */ +/***********************************************************************/ +TDBBCL::TDBBCL(PBDEF tdp) : TDBCAT(tdp) { + Topt = tdp->GetTopt(); + Db = tdp->Schema; + Dsn = tdp->Uri; +} // end of TDBBCL constructor + +/***********************************************************************/ +/* GetResult: Get the list the JSON file columns. */ +/***********************************************************************/ +PQRYRES TDBBCL::GetResult(PGLOBAL g) { + return BSONColumns(g, Db, Dsn, Topt, false); +} // end of GetResult + +/* --------------------------- End of json --------------------------- */ diff --git a/storage/connect/tabbson.h b/storage/connect/tabbson.h new file mode 100644 index 00000000000..127370ce342 --- /dev/null +++ b/storage/connect/tabbson.h @@ -0,0 +1,342 @@ +/*************** tabbson H Declares Source Code File (.H) **************/ +/* Name: tabbson.h Version 1.0 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2020 */ +/* */ +/* This file contains the BSON classes declares. */ +/***********************************************************************/ +#pragma once +#include "block.h" +#include "colblk.h" +#include "bson.h" +#include "tabjson.h" + +typedef class BTUTIL* PBTUT; +typedef class BCUTIL* PBCUT; +typedef class BSONDEF* PBDEF; +typedef class TDBBSON* PBTDB; +typedef class BSONCOL* PBSCOL; +class TDBBSN; +DllExport PQRYRES BSONColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool); + +/***********************************************************************/ +/* Class used to get the columns of a mongo collection. */ +/***********************************************************************/ +class BSONDISC : public BLOCK { +public: + // Constructor + BSONDISC(PGLOBAL g, uint* lg); + + // Functions + int GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt); + bool Find(PGLOBAL g, PBVAL jvp, PCSZ key, int j); + void AddColumn(PGLOBAL g); + + // Members + JCOL jcol; + PJCL jcp, fjcp, pjcp; + //PVL vlp; + PBDEF tdp; + TDBBSN *tjnp; + PBTDB tjsp; + PBPR jpp; + PBVAL jsp; + PBPR row; + PBTUT bp; + PCSZ sep; + char colname[65], fmt[129], buf[16]; + uint *length; + int i, n, bf, ncol, lvl, sz, limit; + bool all, strfy; +}; // end of BSONDISC + +/***********************************************************************/ +/* JSON table. */ +/***********************************************************************/ +class DllExport BSONDEF : public DOSDEF { /* Table description */ + friend class TDBBSON; + friend class TDBBSN; + friend class TDBBCL; + friend class BSONDISC; + friend class BSONCOL; +#if defined(CMGO_SUPPORT) + friend class CMGFAM; +#endif // CMGO_SUPPORT +#if defined(JAVA_SUPPORT) + friend class JMGFAM; +#endif // JAVA_SUPPORT +public: + // Constructor + BSONDEF(void); + + // Implementation + virtual const char* GetType(void) { return "BSON"; } + + // Methods + virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); + virtual PTDB GetTable(PGLOBAL g, MODE m); + +protected: + // Members + PGLOBAL G; /* Bson utility memory */ + JMODE Jmode; /* MODE_OBJECT by default */ + PCSZ Objname; /* Name of first level object */ + PCSZ Xcol; /* Name of expandable column */ + int Limit; /* Limit of multiple values */ + int Pretty; /* Depends on file structure */ + int Base; /* The array index base */ + bool Strict; /* Strict syntax checking */ + char Sep; /* The Jpath separator */ + const char* Uri; /* MongoDB connection URI */ + PCSZ Collname; /* External collection name */ + PSZ Options; /* Colist ; Pipe */ + PSZ Filter; /* Filter */ + PSZ Driver; /* MongoDB Driver (C or JAVA) */ + bool Pipe; /* True if Colist is a pipeline */ + int Version; /* Driver version */ + PSZ Wrapname; /* MongoDB java wrapper name */ +}; // end of BSONDEF + + +/* -------------------------- BTUTIL class --------------------------- */ + +/***********************************************************************/ +/* Handles all BJSON actions for a BSON table. */ +/***********************************************************************/ +class BTUTIL : public BDOC { +public: + // Constructor + BTUTIL(PGLOBAL G, TDBBSN* tp) : BDOC(G) { Tp = tp; } + + // Utility functions + PBVAL FindRow(PGLOBAL g); + PBVAL ParseLine(PGLOBAL g, int *pretty, bool *comma); + PBVAL MakeTopTree(PGLOBAL g, PBVAL jsp); + PSZ SerialVal(PGLOBAL g, PBVAL top, int pretty); + +protected: + // Members + TDBBSN* Tp; +}; // end of class BTUTIL + +/* -------------------------- BCUTIL class --------------------------- */ + +/***********************************************************************/ +/* Handles all BJSON actions for a BSON columns. */ +/***********************************************************************/ +class BCUTIL : public BTUTIL { +public: + // Constructor + BCUTIL(PGLOBAL G, PBSCOL cp, TDBBSN* tp) : BTUTIL(G, tp) { Cp = cp; } + + // Utility functions + void SetJsonValue(PGLOBAL g, PVAL vp, PBVAL jvp); + PVAL MakeBson(PGLOBAL g, PBVAL jsp); + PVAL GetColumnValue(PGLOBAL g, PBVAL row, int i); + PVAL ExpandArray(PGLOBAL g, PBVAL arp, int n); + PVAL CalculateArray(PBVAL arp, int n); + PBVAL GetRow(PGLOBAL g); + +protected: + // Member + PBSCOL Cp; +}; // end of class BCUTIL + + /* -------------------------- TDBBSN class --------------------------- */ + +/***********************************************************************/ +/* This is the BSN Access Method class declaration. */ +/* The table is a DOS file, each record being a JSON object. */ +/***********************************************************************/ +class DllExport TDBBSN : public TDBDOS { + friend class BSONCOL; + friend class BSONDEF; + friend class BTUTIL; + friend class BCUTIL; + friend class BSONDISC; +#if defined(CMGO_SUPPORT) + friend class CMGFAM; +#endif // CMGO_SUPPORT +#if defined(JAVA_SUPPORT) + friend class JMGFAM; +#endif // JAVA_SUPPORT +public: + // Constructor + TDBBSN(PGLOBAL g, PBDEF tdp, PTXF txfp); + TDBBSN(TDBBSN* tdbp); + + // Implementation + virtual AMT GetAmType(void) { return TYPE_AM_JSN; } + virtual bool SkipHeader(PGLOBAL g); + virtual PTDB Duplicate(PGLOBAL g) { return (PTDB)new(g) TDBBSN(this); } + PBVAL GetRow(void) { return Row; } + + // Methods + virtual PTDB Clone(PTABS t); + virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual PCOL InsertSpecialColumn(PCOL colp); + virtual int RowNumber(PGLOBAL g, bool b = FALSE) {return (b) ? M : N;} + virtual bool CanBeFiltered(void) + {return Txfp->GetAmType() == TYPE_AM_MGO || !Xcol;} + + // Database routines + virtual int Cardinality(PGLOBAL g); + virtual int GetMaxSize(PGLOBAL g); + virtual bool OpenDB(PGLOBAL g); + virtual int ReadDB(PGLOBAL g); + virtual bool PrepareWriting(PGLOBAL g); + virtual int WriteDB(PGLOBAL g); + virtual void CloseDB(PGLOBAL g); + + // Specific routine + virtual int EstimatedLength(void); + +protected: + PBVAL FindRow(PGLOBAL g); +//int MakeTopTree(PGLOBAL g, PBVAL jsp); + + // Members + PBTUT Bp; // The BSUTIL handling class + PBVAL Top; // The top JSON tree + PBVAL Row; // The current row + PBVAL Val; // The value of the current row + PBSCOL Colp; // The multiple column + JMODE Jmode; // MODE_OBJECT by default + PCSZ Objname; // The table object name + PCSZ Xcol; // Name of expandable column + int Fpos; // The current row index + int N; // The current Rownum + int M; // Index of multiple value + int Limit; // Limit of multiple values + int Pretty; // Depends on file structure + int NextSame; // Same next row + int SameRow; // Same row nb + int Xval; // Index of expandable array + int B; // Array index base + char Sep; // The Jpath separator + bool Strict; // Strict syntax checking + bool Comma; // Row has final comma +}; // end of class TDBBSN + +/* -------------------------- BSONCOL class -------------------------- */ + +/***********************************************************************/ +/* Class BSONCOL: JSON access method column descriptor. */ +/***********************************************************************/ +class DllExport BSONCOL : public DOSCOL { + friend class TDBBSN; + friend class TDBBSON; + friend class BCUTIL; +#if defined(CMGO_SUPPORT) + friend class CMGFAM; +#endif // CMGO_SUPPORT +#if defined(JAVA_SUPPORT) + friend class JMGFAM; +#endif // JAVA_SUPPORT +public: + // Constructors + BSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i); + BSONCOL(BSONCOL* colp, PTDB tdbp); // Constructor used in copy process + + // Implementation + virtual int GetAmType(void) { return Tbp->GetAmType(); } + + // Methods + virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); + bool ParseJpath(PGLOBAL g); + virtual PSZ GetJpath(PGLOBAL g, bool proj); + virtual void ReadColumn(PGLOBAL g); + virtual void WriteColumn(PGLOBAL g); + +protected: + bool CheckExpand(PGLOBAL g, int i, PSZ nm, bool b); + 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 MakeBson(PGLOBAL g, PBVAL jsp); +//void SetJsonValue(PGLOBAL g, PVAL vp, PBVAL val); +//PBVAL GetRow(PGLOBAL g); + + // Default constructor not to be used + BSONCOL(void) {} + + // Members + TDBBSN *Tbp; // To the JSN table block + PBCUT Cp; // To the BCUTIL handling class + PVAL MulVal; // To value used by multiple column + char *Jpath; // The json path + JNODE *Nodes; // The intermediate objects + int Nod; // The number of intermediate objects + int Xnod; // Index of multiple values + char Sep; // The Jpath separator + bool Xpd; // True for expandable column + bool Parsed; // True when parsed +}; // end of class BSONCOL + +/* -------------------------- TDBBSON class -------------------------- */ + +/***********************************************************************/ +/* This is the JSON Access Method class declaration. */ +/***********************************************************************/ +class DllExport TDBBSON : public TDBBSN { + friend class BSONDEF; + friend class BSONCOL; +public: + // Constructor + TDBBSON(PGLOBAL g, PBDEF tdp, PTXF txfp); + TDBBSON(PBTDB tdbp); + + // Implementation + virtual AMT GetAmType(void) { return TYPE_AM_JSON; } + virtual PTDB Duplicate(PGLOBAL g) { return (PTDB)new(g) TDBBSON(this); } + PBVAL GetDoc(void) { return Docp; } + + // Methods + virtual PTDB Clone(PTABS t); + + // Database routines + virtual int Cardinality(PGLOBAL g); + virtual int GetMaxSize(PGLOBAL g); + virtual void ResetSize(void); + virtual int GetProgCur(void) { return N; } + virtual int GetRecpos(void); + virtual bool SetRecpos(PGLOBAL g, int recpos); + virtual bool OpenDB(PGLOBAL g); + virtual int ReadDB(PGLOBAL g); + virtual bool PrepareWriting(PGLOBAL g) { return false; } + virtual int WriteDB(PGLOBAL g); + virtual int DeleteDB(PGLOBAL g, int irc); + virtual void CloseDB(PGLOBAL g); + int MakeDocument(PGLOBAL g); + + // Optimization routines + virtual int MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add); + +protected: + int MakeNewDoc(PGLOBAL g); + + // Members + PBVAL Docp; // The document array + int Multiple; // 0: No 1: DIR 2: Section 3: filelist + bool Done; // True when document parsing is done + bool Changed; // After Update, Insert or Delete +}; // end of class TDBBSON + +/***********************************************************************/ +/* This is the class declaration for the JSON catalog table. */ +/***********************************************************************/ +class DllExport TDBBCL : public TDBCAT { +public: + // Constructor + TDBBCL(PBDEF tdp); + +protected: + // Specific routines + virtual PQRYRES GetResult(PGLOBAL g); + + // Members + PTOS Topt; + PCSZ Db; + PCSZ Dsn; +}; // end of class TDBBCL diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 336b0f371ca..af45cdab9f7 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -165,8 +165,9 @@ JSONDISC::JSONDISC(PGLOBAL g, uint *lg) int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) { - char filename[_MAX_PATH]; - bool mgo = (GetTypeID(topt->type) == TAB_MONGO); + char filename[_MAX_PATH]; + bool mgo = (GetTypeID(topt->type) == TAB_MONGO); + PGLOBAL G = NULL; lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth()); lvl = GetIntegerTableOption(g, topt, "Depth", lvl); @@ -296,12 +297,15 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) tjnp->SetMode(MODE_READ); // Allocate the parse work memory +#if 0 PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); memset(G, 0, sizeof(GLOBAL)); G->Sarea_Size = (size_t)tdp->Lrecl * (tdp->Pretty >= 0 ? 10 : 2); G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size); PlugSubSet(G->Sarea, G->Sarea_Size); G->jump_level = 0; +#endif // 0 + G = PlugInit(NULL, (size_t)tdp->Lrecl * (tdp->Pretty >= 0 ? 10 : 2)); tjnp->SetG(G); if (tjnp->OpenDB(g)) @@ -738,6 +742,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) if (Lrecl) { // Allocate the parse work memory +#if 0 PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); memset(G, 0, sizeof(GLOBAL)); G->Sarea_Size = (size_t)Lrecl * 10; @@ -745,6 +750,8 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) PlugSubSet(G->Sarea, G->Sarea_Size); G->jump_level = 0; ((TDBJSN*)tdbp)->G = G; +#endif // 0 + ((TDBJSN*)tdbp)->G = PlugInit(NULL, (size_t)Lrecl * (Pretty >= 0 ? 10 : 2)); } else { strcpy(g->Message, "LRECL is not defined"); return NULL; @@ -1226,7 +1233,16 @@ int TDBJSN::WriteDB(PGLOBAL g) return rc; } // end of WriteDB -/* ---------------------------- JSONCOL ------------------------------ */ +/***********************************************************************/ +/* Data Base close routine for JSON access method. */ +/***********************************************************************/ +void TDBJSN::CloseDB(PGLOBAL g) +{ + TDBDOS::CloseDB(g); + G = PlugExit(G); +} // end of CloseDB + + /* ---------------------------- JSONCOL ------------------------------ */ /***********************************************************************/ /* JSONCOL public constructor. */ @@ -1608,7 +1624,7 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp) strcpy(g->Message, "Column size too small"); Value->SetValue_char(NULL, 0); } // endif Clen -#endif 0 +#endif // 0 } else Value->SetValue_psz(Serialize(g, jsp, NULL, 0)); diff --git a/storage/connect/tabjson.h b/storage/connect/tabjson.h index c254c3429de..9b4f508880e 100644 --- a/storage/connect/tabjson.h +++ b/storage/connect/tabjson.h @@ -5,6 +5,7 @@ /* */ /* This file contains the JSON classes declares. */ /***********************************************************************/ +#pragma once //#include "osutil.h" // Unuseful and bad for OEM #include "block.h" #include "colblk.h" @@ -161,6 +162,7 @@ public: virtual int ReadDB(PGLOBAL g); virtual bool PrepareWriting(PGLOBAL g); virtual int WriteDB(PGLOBAL g); + virtual void CloseDB(PGLOBAL g); // Specific routine virtual int EstimatedLength(void); diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc index 09d6db1ad27..5268651d080 100644 --- a/storage/connect/user_connect.cc +++ b/storage/connect/user_connect.cc @@ -112,8 +112,7 @@ bool user_connect::user_init() if (g) printf("%s\n", g->Message); - int rc= PlugExit(g); - g= NULL; + g= PlugExit(g); if (dup) free(dup); |