summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Bertrand <bertrandop@gmail.com>2020-12-01 19:30:56 +0100
committerOlivier Bertrand <bertrandop@gmail.com>2020-12-01 19:39:09 +0100
commit4e8af8a6645136be34649abacb5b31ef64264584 (patch)
tree6395e9862ab27dc9879b9f68b87cc704458891d0
parent950bf6ab53d7b6d5db0e7d986b81fbd5709e98f6 (diff)
downloadmariadb-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.cpp218
-rw-r--r--storage/connect/bson.h83
-rw-r--r--storage/connect/bsonudf.cpp47
-rw-r--r--storage/connect/connect.cc3
-rw-r--r--storage/connect/global.h2
-rw-r--r--storage/connect/ha_connect.cc23
-rw-r--r--storage/connect/jsonudf.cpp6
-rw-r--r--storage/connect/mycat.cc27
-rw-r--r--storage/connect/mysql-test/connect/r/xml.result4
-rw-r--r--storage/connect/plgdbsem.h3
-rw-r--r--storage/connect/plugutil.cpp9
-rw-r--r--storage/connect/tabbson.cpp2599
-rw-r--r--storage/connect/tabbson.h342
-rw-r--r--storage/connect/tabjson.cpp24
-rw-r--r--storage/connect/tabjson.h2
-rw-r--r--storage/connect/user_connect.cc3
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);